win-nsga
Version:
Create and manage an evolutionary algorithm that runs the NSGA-II multiobjective search algorithm (bit redundant). This is a WIN module.
344 lines (284 loc) • 8.14 kB
JavaScript
//here we test the insert functions
//making sure the database is filled with objects of the schema type
var assert = require('assert');
var should = require('should');
var colors = require('colors');
var traverse = require('optimuslime-traverse');
var Q = require('q');
var util = require('util');
var winnsga = require('../');
var wMath = require('win-utils').math;
var winback = require('win-backbone');
var backbone, generator, backEmit, backLog;
var evoTestEnd;
var count = 0;
var emptyModule =
{
winFunction : "test",
eventCallbacks : function(){ return {}; },
requiredEvents : function() {
return [
"evolution:nsga-startEvolution"
];
}
};
var cIx = 0;
//sample encoding that known how to create its own children -- randomly clone a parent
var sampleEncoding =
{
winFunction : "encoding",
encodingName : "sample",
sampleSchema : {
value : "string"
},
eventCallbacks : function()
{
return {
"encoding:sample-createFullOffspring" : function(genProps, parentProps, override, done) {
// backLog('called create full offspring ', override ? override.forceParents : "");
var parents = parentProps.parents;
var count = genProps.count;
var allParents = [];
var children = [];
for(var c=0; c < count; c++)
{
var ixs = [];
var pIx = wMath.next(parents.length);
var rOffspring = traverse(parents[pIx]).clone();
rOffspring.value = parents[pIx].value.split("-")[0] + "-" + cIx + "-" + c;
// rOffspring.second = "This will be erased.";
ixs.push(pIx);
children.push(rOffspring);
allParents.push(ixs);
}
cIx++;
//done, send er back
done(undefined, children, allParents);
return;
}
};
},
requiredEvents : function() {
return [
"schema:addSchema",
"generator:createArtifacts"
];
},
initialize : function(done)
{
backLog("Init encoding");
var emitter = backbone.getEmitter(sampleEncoding);
emitter.emit("schema:addSchema", sampleEncoding.encodingName, sampleEncoding.sampleSchema, function(err)
{
if(err){
done(new Error(err));
return;
}
done();
})
}
};
//handle the evaluation!
var sampleEvaluate = {
winFunction : "evaluate",
eventCallbacks : function()
{
return {
"evaluate:evaluateArtifacts" : function(population){
// throw new Error("evaluateArtifacts: Not implemented");
var done = arguments[arguments.length-1];
var popEvals = {};
var evals = [];
//we do stuff with the population, or with the objects
//this is where we would use novelty or genomic novelty or whatever
for(var i=0; i < population.length; i++)
{
evals.push({realFitness: i, behaviors : []});//[Math.random(), Math.random(), Math.random()]});
}
done(undefined, {evaluations: evals});
}
,"evaluate:measureObjectives":function(population, popEvaluations)
{
var done = arguments[arguments.length-1];
//for measuring the objectives of all the pop objects
var measured = [];
//we do stuff with the population, or with the objects
//this is where we would use novelty or genomic novelty or whatever
for(var i=0; i < population.length; i++)
{
measured.push([Math.random(), Math.random()]);
}
done(undefined, measured);
}
}
},
requiredEvents : function() {
return [];
}
};
var maxGens = 2;
var sampleEvolution = {
winFunction : "evaluate",
eventCallbacks : function()
{
return {
"evolution:shouldEndEvolution" : function(gens)
{
backLog("Gen Count: " + gens);
var done = arguments[arguments.length-1];
if(gens < maxGens)
done(undefined, false);
else
done(undefined, true);
},
"evolution:finishedEvolution" : function(pop, eval)
{
var done = arguments[arguments.length-1];
done();
//end callback if it exists
if(evoTestEnd)
evoTestEnd.apply(this, arguments);
}
};
},
requiredEvents : function() {
return [];
}
};
var qBackboneResponse = function()
{
var defer = Q.defer();
// self.log('qBBRes: Original: ', arguments);
//first add our own function type
var augmentArgs = arguments;
// [].splice.call(augmentArgs, 0, 0, self.winFunction);
//make some assumptions about the returning call
var callback = function(err)
{
if(err)
{
defer.reject(err);
}
else
{
//remove the error object, send the info onwards
[].shift.call(arguments);
if(arguments.length > 1)
defer.resolve(arguments);
else
defer.resolve.apply(defer, arguments);
}
};
//then we add our callback to the end of our function -- which will get resolved here with whatever arguments are passed back
[].push.call(augmentArgs, callback);
// self.log('qBBRes: Augmented: ', augmentArgs);
//make the call, we'll catch it inside the callback!
backEmit.apply(backEmit, augmentArgs);
return defer.promise;
}
describe('Testing win-NSGA running -',function(){
//we need to start up the WIN backend
before(function(done){
//do this up front yo
backbone = new winback();
var sampleJSON =
{
"win-nsga" : winnsga,
"win-gen" : "win-gen",
"win-schema" : "win-schema",
"sample-encoding" : sampleEncoding,
"evaluate" : sampleEvaluate,
"evolution" : sampleEvolution,
"test" : emptyModule
};
var configurations =
{
"global" : {
},
"win-nsga" : {
genomeType : "sample"
,logLevel : backbone.testing
},
"win-gen" : {
"encodings" : [
"sample"
]
,validateParents : true
,validateOffspring : true
// ,logLevel : backbone.testing
},
"win-schema" : {
multipleErrors : true
// ,logLevel : backbone.testing
},
"stuff" :
{
}
};
backbone.logLevel = backbone.testing;
backEmit = backbone.getEmitter(emptyModule);
backLog = backbone.getLogger({winFunction:"mocha"});
backLog.logLevel = backbone.testing;
//loading modules is synchronous
backbone.loadModules(sampleJSON, configurations);
var registeredEvents = backbone.registeredEvents();
var requiredEvents = backbone.moduleRequirements();
backLog('Backbone Events registered: ', registeredEvents);
backLog('Required: ', requiredEvents);
backbone.initializeModules(function()
{
backLog("Finished Module Init");
done();
});
});
it('Should run evolution for 10 generations',function(done){
var exampleSeeds = [
{ value : "nothing"
,wid : "012345", parents : [], dbType : "sample"
},
{ value : "something"
,wid : "543210", parents : [], dbType : "sample"
}
// {"simple" : "stuff", "more" : "things"}
];
var evoProps = {genomeType : "sample", populationSize : 10};
//throw errors while running evolution
var evoError = function(err)
{
if(typeof err == "string")
done(new Error(err));
else
done(err);
};
evoTestEnd = function(popObject)
{
var pop = popObject.population;
var eval = popObject.evaluations;
for(var i=0; i < pop.length; i++)
{
var singleEval = eval[pop[i].wid];
backLog("Final Eval: ".magenta, singleEval);
}
// backLog("Objs: ", util.inspect(arguments[0].population, false, 10));
// backLog("Evals: ", util.inspect(arguments[0].evaluations, false, 10));
// backLog("Evals: ", util.inspect(arguments[1], false, 10));
//finished evolution
done();
}
//now we call asking for
qBackboneResponse("evolution:nsga-startEvolution", evoProps, exampleSeeds, evoError)
.then(function(artifacts)
{
//evolution started!
backLog('\tFinished starting evolution, '.cyan, util.inspect(artifacts, false,10));
// done();
})
.fail(function(err)
{
if(err.errno)
done(err);
else
done(new Error(err.message));
});
});
});