Last active
April 26, 2021 09:58
-
-
Save Tiagoperes/6849da791bf189bb2746e010b87b2c2f to your computer and use it in GitHub Desktop.
Routine for real variable SBX crossover (Javascript/functional)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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); | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Based on the following code: https://gist.github.com/Tiagoperes/1779d5f1c89bae0cfdb87b1960bba36d
Based on the following paper: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.33.7291&rep=rep1&type=pdf