all files / lib/nodeo/ classic-float.js

91.67% Statements 55/60
59.09% Branches 13/22
100% Functions 7/7
91.53% Lines 54/59
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136                                                                                            16× 16× 256×   16×   16×                       95× 95×     95×   1332× 1332× 1348× 1348× 614×     1332×   95×         94× 1316×           8186× 188×         94× 94× 94× 94× 94× 94× 94×        
// Evolutionary Algorithm, simplified, for node, using `ChromosomeFloat` data structure
'use strict';
// * @license GPL v3
// * @package nodeo
// * @author V. M. Rivas <vrivas@ujaen.es>
// *         From classic.js authored J. J. Merelo <jjmerelo@gmail.com>
 
 
// To avoid uncomprehensible radix complaint at charAt
/*jshint -W065 */
/*jshint smarttabs:true */
 
var utils = require('./Utils'),
    CF = require('./chromosome-float'),
    ops = require('./ops');
 
 
// Nodeo creates an evolutionary algorithms.
// `options` include
// * `population_size`
// * `fitness_func` that is the fitness used to evaluate all
// individuals. Can be either a function or a fitness object with `apply`
// * `tournament_size` using tournament selection. This is the number
// of individuals in each one
// * `pool_size` reproductive pool size
// * `chromosome_size` used to generate random chromosomes.
// * `minvalue` minimum value for floats
// * `maxvalue` minimum value for floats
// This function generates randomly a population which is used later
// on to start the evolutionary algorithms. 
module.exports = function( options ) {
/*jshint validthis: true */
    for ( var i in options ) {
	this[i] = options[i];
    }
    Iif ( ! this.population_size ) {
	return new Error ("0 population size");
    }
    Iif ( ! this.fitness_func ) {
	return new Error ("No fitness func");
    } else Eif ( typeof( this.fitness_func) === 'function' ) {
	this.fitness_obj = new Fitness( options.fitness_func );
    } else {
	this.fitness_obj = this.fitness_func;
    }
    Eif ( !this.tournament_size ) {
	this.tournament_size = 2;
    }
    Eif ( !this.pool_size ) {
	this.pool_size = this.population_size - 2;
    }
 
    Iif ( !this.chromosome_size || isNaN(this.chromosome_size) ) {
	throw "Chromosome size error";
    }
 
    Eif ( !this.minvalue || !this.maxvalue ) {
       this.minvalue=0.0;
       this.maxvalue=1.0;
    }
 
    this.population = [];
//    console.log( this.fitness_obj.apply );
    do {
	var vector=[];
    for( var i=0; i<this.chromosome_size; ++i ) {
        vector[i]=Math.random()*(this.maxvalue-this.minvalue)+this.minvalue;
    }
	var chromosome = new CF.Chromosome( vector,
					 this.fitness_obj.apply( vector ) );
	this.population.push( chromosome );
    } while( this.population.length < this.population_size );
 
    // Methods
    this.tournament_selection = tournament_selection;
    this.evaluation = evaluation;
    this.generation= generation;
    this.rank=rank;
};
 
// create fitness function object if it does not exist
function Fitness ( f ) {
 /*jshint validthis: true */  
    this.apply = f;  
}
 
// Selects a new population of size pool_size via comparing tournament_size chromosomes and taking the best
function tournament_selection( tournament_size, pool_size ) {
/*jshint validthis: true */
    var pool = [];
    Iif ( tournament_size <= 1 ) {
	return new Error ("Tournament size too small");
    }
    do {
//	var joust = [];
	var best =  this.population[ Math.floor(Math.random()*this.population.length) ] ;
	for ( var i = 1; i < tournament_size; i ++) {
	    var another= this.population[ Math.floor(Math.random()*this.population.length) ];
	    if ( another.fitness > best.fitness) {
		best = another;
	    }
	}
	pool.push( best );
    } while (pool.length < pool_size );
    return pool;
}
 
// Evaluates all the population not in cache
function evaluation( new_guys ) {
/*jshint validthis: true */
    for (var i in new_guys) {	
	new_guys[i].fitness = this.fitness_obj.apply( new_guys[i].vector );
    }
}
 
// sort population
function rank () {
    /*jshint validthis: true */
    var sorted_population = this.population.sort( function(a,b){ return b.fitness - a.fitness; } );
    this.population = sorted_population;
}
 
// Single generation
function generation() {
    /*jshint validthis: true */
    var chosen = this.tournament_selection( this.tournament_size, this.pool_size);
    this.rank(); // to get the best
    var the_best = [this.population[0],this.population[1]];
    var new_population = CF.reproduction( chosen);
    this.evaluation(new_population);
    this.population = the_best.concat( new_population );
    this.rank(); // ranking twice????
}