next up previous
Next: Population Up: Doing GAs with Previous: Looking at chromosomes

Computing fitness

 

Once chromosomes have been created, massaged and watched in many different ways, it's about time we evaluate them. In genetic algorithms, success is usually defined by the evaluation of a function, which tells us how good is the chromosome at solving the problem it has been instructed to solve.

Following the spirit of past sections, fitness will also be a class. Usually fitness is only a floating point number, but in some cases, there are several things to take into account when evaluating a chromosome: success rate and size, for instance. If fitness is an scalar number, nothing needs to be defined anew, but if we are going to use a structured fitness, some functions need to be defined: mainly comparison functions, since fitness is used to rank chromosomes. This would be an example of how to define and use fitness

#include <gagsview.hpp>         // Chromosomes already included

struct fitness_t {
  float evaluation;                // Scalar fitness value
  unsigned len;                    // Vector length

  fitness_t( float _d = 0, unsigned _l = 0 ): evaluation(_d), len(_l) {};
  
  int biggerThan( fitness_t _f ) const {
    if (evaluation > _f.evaluation) {
      return 1;
    } else if ( evaluation == _f.evaluation ) 
        return ( len < _f.len )?1:0; 
    return 0;   
  };

  int operator > ( fitness_t _f ) const { return biggerThan( _f ); };
  int operator < ( fitness_t _f ) const { return !biggerThan( _f ); };
  int operator == ( fitness_t _f ) const { 
    return (( evaluation == _f.evaluation) && (len == _f.len ));
  }
};

inline ostream& operator <<(class ostream& s, fitness_t _f) {
  return s << _f.evaluation << " & " << _f.len << endl;
}

// Fitness function
fitness_t fitness( const chrom& _chrom, const view<float>& _vista ) {
  // Evaluates fitness by adding gene values
  for ( unsigned i = 0, float eval = 0; i < _vista.size(&_chrom); i ++ ) {
        eval += _vista( &_chrom, i);
  }
  return fitness_t( eval, _vista.size(&_chrom) );
}

main () {
    const unsigned NUMGENES = 4;        // Usual prologue
    const bitLength_t SIZEGENES = 3;
    seed_random( time( (time_t) 0 ) );// From randcl
    chrom aChromosome( NUMGENES*SIZEGENES ); // Create chromosome

    view<float> vista( SIZEGENES, -1, 2 );

    cout << "Fitness is " << fitness( aChromosome, vista );
}
Obviously, you don't always need to go to these lengths to define fitness; most of the times, a simple scalar fitness is used. Evaluation function, or fitness function, will usually be a method of an object that will be constructed from a chromosome.

In any case, the previous example describes how to define a fitness class, which in this case is defined as a struct to have all members public by default; three operators: ;SPMlt;,;SPMgt; and == are defined, a default constructor, and a function to print it; then, a function to evaluate fitness is defined; in this case, it adds the total value of the genes and sets it as evaluation, and then the length of the chromosome, which will be the second component in the fitness.

The main program then creates a chromosome and evaluates it. A view must be created so that the fitness function can evaluate the chromosome; both, chromosome and instantiated view, are passed to the fitness function.

Most of the GA components are already in place, so that we can now go ahead to creating a population, which is the class that really deals with the genetic algorithm in the next section


next up previous
Next: Population Up: Doing GAs with Previous: Looking at chromosomes

J.J. Merelo Guervos
Fri Aug 22 12:58:28 MDT 1997