UNPKG

intelligence

Version:

Machine learning library written in javascript

124 lines (117 loc) 5.34 kB
var utils = require('./../infrastructure/utils'); /** * Throws an exception if any individuals have less than two genes * @param {Individual[]} individuals - An array of individuals to validate * @throws An exception is thrown if any individuals have less than two genes */ var validateMinimumLength = function (individuals) { if (individuals[0].body.length < 2 || individuals[0].body.length < 2) { throw "individuals must have at least two genes for crossover"; } }; /** * Throws an exception if any individuals are not fixed length or of different lengths * @param {Individual[]} individuals - An array of individuals to validate * @throws An exception is thrown if any individuals are not fixed length */ var validateFixedLength = function (individuals) { if (!(individuals[0].isFixedLength() && individuals[1].isFixedLength()) || (individuals[0].body.length !== individuals[1].body.length)) { throw "individuals must be of a fixed length and equal in length for crossover"; } }; /** * Swaps genes between two individuals at the specified index * @param {Individual} indvidualA - The first individual * @param {Individual} indvidualB - The second individual * @param {number} index - Body array index to swap genes at */ var swapGenes = function (indvidualA, indvidualB, index) { var temp = indvidualA.body[index]; indvidualA.body[index] = indvidualB.body[index]; indvidualB.body[index] = temp; }; /** * Performs uniform crossover * @param {Individual[]} individuals - An array containing two individuals * @returns {Individual[]} An array containing two offspring */ exports.uniform = function (individuals) { validateMinimumLength(individuals); validateFixedLength(individuals); var offspringA = individuals[0].copy(); var offspringB = individuals[1].copy(); for (var i = 0; i < offspringA.body.length; i++) { if (utils.random() < 0.5) { swapGenes(offspringA, offspringB, i); } } return [offspringA, offspringB]; }; /** * Performs one point crossover * @param {Individual[]} individuals - An array containing two individuals * @returns {Individual[]} An array containing two offspring */ exports.onePoint = function (individuals) { validateMinimumLength(individuals); var offspringA = individuals[0].copy(); var offspringB = individuals[1].copy(); var indexA, indexB, newSizeA, newSizeB, cuts; var validCuts = []; var indexA = utils.randBetween(0, offspringA.body.length); for (indexB = 0; indexB < offspringB.body.length; indexB++) { newSizeA = indexA + (offspringB.body.length - indexB); newSizeB = indexB + (offspringA.body.length - indexA); if (newSizeA >= offspringA.options.minLength && newSizeA <= offspringA.options.maxLength && newSizeB >= offspringB.options.minLength && newSizeB <= offspringB.options.maxLength) { validCuts.push({ a: indexA, b: indexB }); } } cuts = utils.selectRandom(validCuts); offspringA.body = individuals[0].body.slice(0, cuts.a).concat(individuals[1].body.slice(cuts.b)); offspringB.body = individuals[1].body.slice(0, cuts.b).concat(individuals[0].body.slice(cuts.a)); return [offspringA, offspringB]; }; /** * Performs two point crossover * @param {Individual[]} individuals - An array containing two individuals * @returns {Individual[]} An array containing two offspring */ exports.twoPoint = function (individuals) { validateMinimumLength(individuals); var offspringA = individuals[0].copy(); var offspringB = individuals[1].copy(); var indexC, indexD, cuts, newSizeA, newSizeB; var validCuts = []; var indexA = utils.randBetween(0, offspringA.body.length - 1); var indexB = utils.randBetween(indexA + 1, offspringA.body.length); for (indexC = 0; indexC < offspringB.body.length; indexC++) { for (indexD = indexC + 1; indexD < offspringB.body.length; indexD++) { newSizeA = offspringA.body.length - (indexB - indexA) + (indexD - indexC); newSizeB = offspringB.body.length - (indexD - indexC) + (indexB - indexA); if (newSizeA <= offspringA.options.maxLength && newSizeA >= offspringA.options.minLength && newSizeB <= offspringB.options.maxLength && newSizeB >= offspringB.options.minLength) { validCuts.push({ a: indexA, b: indexB, c: indexC, d: indexD }); } } } cuts = utils.selectRandom(validCuts); offspringA.body = individuals[0].body.slice(0, cuts.a); offspringB.body = individuals[1].body.slice(0, cuts.c); offspringA.body = offspringA.body.concat(individuals[1].body.slice(cuts.c, cuts.d + 1)); offspringB.body = offspringB.body.concat(individuals[0].body.slice(cuts.a, cuts.b + 1)); offspringA.body = offspringA.body.concat(individuals[0].body.slice(cuts.b + 1)); offspringB.body = offspringB.body.concat(individuals[1].body.slice(cuts.d + 1)); return [offspringA, offspringB]; };