Skip to content

Instantly share code, notes, and snippets.

@Tiagoperes
Last active April 26, 2021 09:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Tiagoperes/6849da791bf189bb2746e010b87b2c2f to your computer and use it in GitHub Desktop.
Save Tiagoperes/6849da791bf189bb2746e010b87b2c2f to your computer and use it in GitHub Desktop.
Routine for real variable SBX crossover (Javascript/functional)
/* Routine for real variable SBX crossover based on the original implementation by Kalyanmoy Deb.
* The following implementation is written in Javascript using functional programming, in my
* opinion, it's easier to understand than the original C version (procedural).
*
* Implementation by Tiago Peres França
*
* OBS1: Based on the following code and paper: https://gist.github.com/Tiagoperes/1779d5f1c89bae0cfdb87b1960bba36d
*
* OBS2: functions starting by "_." are from the functional library Lodash.
*
* To execute the sbx procedure, call genetics.real.sbx(parentArray1, parentArray2, boundsArray, nc). The boundsArray is
* an array of objects in the format {min: number, max: other_number}.
*/
(function () {
'use strict';
const EPS = 1e-14;
function equals(a, b) {
return Math.abs(a - b) <= EPS;
}
function betaq(minParent, maxParent, betaTerm, nc) {
var beta = 1 + 2 * betaTerm / (maxParent - minParent),
alpha = 2 - Math.pow(beta, -(nc + 1)),
rand = Math.random();
return rand <= 1 / alpha ?
(Math.pow(rand * alpha, 1 / (nc + 1))) :
(Math.pow(1 / (2 - rand * alpha), 1 / (nc + 1)));
}
function makeChild(minParent, maxParent, betaq) {
return 0.5 * (minParent + maxParent) + betaq * (maxParent - minParent);
}
function ensureBounds(number, bounds) {
if (number < bounds.min) return bounds.min;
if (number > bounds.max) return bounds.max;
return number;
}
function cross(p1, p2, bounds, nc) {
var minParent, maxParent, betaq1, betaq2;
if (equals(p1, p2)) {
return [p1, p2];
}
minParent = _.min([p1, p2]);
maxParent = _.max([p1, p2]);
betaq1 = -betaq(minParent, maxParent, minParent - bounds.min, nc);
betaq2 = betaq(minParent, maxParent, bounds.max - maxParent, nc);
return [
ensureBounds(makeChild(minParent, maxParent, betaq1), bounds),
ensureBounds(makeChild(minParent, maxParent, betaq2), bounds)
];
}
function sbx(p1, p2, bounds, nc) {
var c1 = [],
c2 = [],
crossProbability = p1.length > 1 ? 0.5 : 1;
for (let i = 0; i < p1.length; i++) {
if (Math.random() < crossProbability) {
let childrenValues = cross(p1[i], p2[i], bounds[i], nc);
c1[i] = childrenValues[0];
c2[i] = childrenValues[1];
} else {
c1[i] = p1[i];
c2[i] = p2[i];
}
}
return [c1, c2];
}
window.genetic = window.genetic || {};
_.set(genetic, 'real.sbx', sbx);
}());
@Tiagoperes
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment