all files / lib/ nodeo.js

92.68% Statements 76/82
62.5% Branches 15/24
100% Functions 8/8
92.59% Lines 75/81
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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159                                                                              16× 16×   16×   16×                         15× 15×     15×   212× 212× 228× 228× 80×     212×   15×         14× 196×   186×             29× 981× 29×         14× 14× 14× 14× 14× 14× 14×                    
// Evolutionary Algorithm, simplified, for node.js
/*jslint node: true */
'use strict';
// * @license GPL v3
// * @package nodeo
// * @author J. J. Merelo <jjmerelo@gmail.com>
 
 
// To avoid uncomprehensible radix complaint at charAt
/*jshint -W065 */
/*jshint smarttabs:true */
 
var nodeo = exports;
nodeo.FluxEO = require('./FluxEO.js');
nodeo.utils = require('./nodeo/Utils');
nodeo.Population = require('./nodeo/Population');
nodeo.ops = require('./nodeo/ops');
nodeo.Ackley = require('./nodeo/Ackley');
nodeo.classic = require('./nodeo/classic');
nodeo.classic_float = require('./nodeo/classic-float');
nodeo.MMDP = require('./nodeo/MMDP');
nodeo.HIFF = require('./nodeo/HIFF');
nodeo.chromosome = require('./nodeo/chromosome');
nodeo.chromosome_float = require('./nodeo/chromosome-float.js');
nodeo.trap = require('./nodeo/trap');
nodeo.vector = require('./nodeo/vector');
nodeo.functions = require('./nodeo/functions');
nodeo.Rastrigin = require('./nodeo/Rastrigin');
 
// 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 the
// `apply` method
// * `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.
// This function generates randomly a population which is used later
// on to start the evolutionary algorithms. 
function Nodeo( 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";
    }
    this.fitness_of = {};
    this.population = [];
//    console.log( this.fitness_obj.apply );
    do {
	var chromosome = nodeo.utils.random( this.chromosome_size );
	Eif ( ! (chromosome in this.fitness_of) ) {
//	    console.log(this.fitness_obj.apply);
	    this.fitness_of[chromosome] = this.fitness_obj.apply( chromosome );
//	    console.log(this.fitness_of[chromosome]);
	    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;
    this.incorporate=incorporate;
}
 
// 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 ( this.fitness_of[another] > this.fitness_of[best]) {
		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) {
	if ( !this.fitness_of[new_guys[i]]) {
//	    console.log( "eval " + new_guys[i] );
	    this.fitness_of[new_guys[i]] = this.fitness_obj.apply( new_guys[i]);
	}
    }
}
 
// sort population
function rank () {
    /*jshint validthis: true */
    var fitness_of = this.fitness_of;
    var sorted_population = this.population.sort( function(a,b){ return fitness_of[b] - fitness_of[a]; } );
    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 = nodeo.ops.reproduction( chosen);
    this.evaluation(new_population);
    this.population = the_best.concat( new_population );
    this.rank(); // ranking twice????
}
 
// Population should be sorted, so the worst is the last. Incorporates a new individual, taking out the worst one
function incorporate( chromosome ) {
    /*jshint validthis: true */
    Iif ( chromosome.length !== this.chromosome_size ) {
	throw "Bad chromosome length" + chromosome.length + "!=" + this.chromosome_size ;
    }
    this.fitness_of[chromosome] = this.fitness_obj.apply( chromosome );
    this.rank();
    this.population.pop(); // extracts the last
    
}
 
nodeo.Nodeo = Nodeo;