EECS 391/491: PROBLEM SET #4 FAQ

Problem 4.2

"[Nilsson]" only means that I took the question from his AI book. You do not need to read his book to answer this question, though.

Problem 4.3

Here, all that Dr. Nilsson (the problem comes from his AI book) is looking for is a fitness function for a genetic algorithm.

Problem 4.5

You do not have to solve the problem more than once. You can can use a variety of techniques in solving it once. See the example below.

You do not have to draw a complete depth-first search tree. But do record your reasoning and justifications. Again, see the example below.

As an example, consider solving the the following problem:

   RA
  +AR
  ---
  AAH

The constraints are:

  A + R = H + 10 X
  R + A + X = A + 10 Y
  Y = A
  A not equal to 0 (leading zeros not allowed)
  AllDiff(A,R,H)
Here, X and Y are the auxiliary carry (0 or 1) variables.

My reasoning is as follows:

Problem 4.6

You are to use roulette selection INSTEAD of the ad hoc selection by threshold that I used in the pseudo-code of the handout.

Be reasonable in your choice of number of generations: a number between 20 and 50 should work well.

You can mutate before or after cross-over, your choice.

The function you are maximizing is a little different than one I used (which was set to zero between 0 and 0.3).

Problem 4.7

As stated in the Problem Set, I have placed my (non-optimized, no-guarantees) C++ code for the 8-Queens Problem in the course Code Repository on the course website: http://dora.case.edu/msb/AI/code/8queens.cc

Below are some useful patterns/subroutines and portability notes. Here are some other hints to make your life easier:

Useful Patterns/Subroutines

It only makes sense to place one queen per column. My encoding uses an array of 8 integers (with the column as the index) to encode the row location of the queen in each column.

To obtain a random encoding, merely use the pattern

  int enc[8];
  mutate(enc,1.0); // mutation in place
  // OR use mutate2(enc,newenc,1.0); to store mutation in newenc array
where the subroutines mutate and mutate2 are defined in the example code file in the repository.

The following routine is useful in a variety of local search algorithms. It returns the nth successor of an encoding, where n=1, ..., 56.

  void getsuccessor(int init[], int n, int succ[]) {
    n--;
    int remainder=(n%7);
    int quotient=(n-remainder)/7;
    // int newrow=1+((remainder+init[quotient]-1)%8);
    int newrow=init[quotient]+remainder+1;
    if (newrow>8) newrow-=8;
    for (int j=0; j<8; j++) {
      if (j==quotient) succ[j]=newrow;
      else succ[j]=init[j];
    }
  }

The following code generates all successors of 12345678, one-by-one, in order:

  int enc7[8]={1, 2, 3, 4, 5, 6, 7, 8};
  int enc8[8];
  for (int i=1; i<=56; i++) {
    getsuccessor(enc7, i, enc8);
  }

It can be modified to remember the best successor as follows:

  int bestE=0;
  int bestSuccIndex;   // to be index in {1, ..., 56} of highest fitness successor
  for (int i=1; i<=56; i++) {
    getsuccessor(enc7, i, enc8); 
    int f=fitness(enc8);
    if (f > bestE) { bestE=f; bestSuccIndex=i; }
    // The following line would add some randomness for equally-good ones
    // if ((f>bestE)||((f==bestE)&&(myrand()<0.1))) { bestE=f; bestSuccIndex=i; }
  } 
where the subroutine fitness and mutate2 is defined in the example code file in the repository.

To obtain a random successor, just call the subroutine with a random integer between 1 and 56. Thus, the following code generates a random successor of 12345678:

  int enc7[8]={1, 2, 3, 4, 5, 6, 7, 8};
  int enc8[8];
  int RandomSuccIndex = (int) ceil(myrand()*56);
    getsuccessor(enc7, RandomSuccIndex, enc8);
There, myrand() is assumed to be a function that returns a uniform random number on [0.0, 1.0].

The following subroutine is useful in simulated annealing:

  // Use: Metropolis Algorithm for Maximization
  //
  // Source: Based on the code and explanation
  // of a routine for minimization found in
  // Press et al., _Numerical_Recipes_in_C_,
  // Cambridge Univ. Press, 1988.  Page 351.
  //
  // Returns a boolean value on whether or not to
  // accept a reconfiguration which leads to a
  // change dE in the objective function E.
  // If dE>0, returns 1 (TRUE); if dE<=0, returns
  // 1 with probablity exp(dE/T), where T is a
  // temperature determined by the annealing schedule.
  //
  int metrop(double dE, double T) {
    double r=myrand();
    return ((dE > 0)||(r < exp(dE/T)));
  }
To avoid errors, you may have to cast the 8-queens' dE (always an integer) to a double when invoking this routine.

Portability Notes

The header files
  #include <sys/types.h>
  #include <unistd.h>
and the line in main()
  srand48((long) getpid());
are only there so each run of the program gives a different result (because the program id changes from run to run and is used as a seed for the random number generator). You can get rid of this line if you put a for loop around the code to perform your 100 trials.

The function myrand() may be replaced by any function that provides a uniform random number between 0.0 and 1.0.

The function ceil() returns the integer greater than or equal to its argument. There are many way to replace its functionality, for example it could be replaced by round(x+0.5) (assuming, say, 1.5 rounds to 2).


Created: 2008-02-04. Modified: 2008-02-04.