Published
Edited
Sep 16, 2021
1 fork
Importers
26 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
mutable notified = undefined
Insert cell
best = notified[0][0]
Insert cell
Genetic = import("https://cdn.skypack.dev/genetic-js@0.1.14?min")
Insert cell
evaluate = poly === "Chebyshev" ? chebyshev : sumxn
Insert cell
function sumxn(coefficients, x) {
let s = 0,
p = 1,
i;
for (i = 0; i < coefficients.length; ++i) {
s += coefficients[i] * p;
p *= x;
}
return s;
}
Insert cell
// Clenshaw's method. see https://observablehq.com/@jrus/cheb
function chebyshev(coeffs, x) {
const x2 = 2 * x;
let d = coeffs.length - 1,
b2 = 0,
b1 = d % 2 ? coeffs[d--] : 0;
for (let i = d; i >= 2; i -= 2) {
b2 = coeffs[i] + x2 * b1 - b2;
b1 = coeffs[i - 1] + x2 * b2 - b1;
}
return coeffs[0] + x * b1 - b2;
}
Insert cell
genetic = {
const genetic = Genetic.create();

genetic.optimize = Genetic.Optimize.Minimize;
genetic.select1 = Genetic.Select1.Tournament2;
genetic.select2 = Genetic.Select2.FittestRandom;

const graph = { vertices: [] };

genetic.seed = function() {
var a = [];
// create coefficients for polynomial with values between (-0.5, 0.5)

var i;
for (i = 0; i < this.userData["terms"]; ++i) {
a.push(Math.random() - 0.5);
}

return a;
};

genetic.mutate = function(entity) {
// allow chromosomal drift with this range (-0.05, 0.05)
var drift = (Math.random() - 0.5) * 2 * 0.05;

var i = Math.floor(Math.random() * entity.length);
entity[i] += drift;

return entity;
};

genetic.crossover = function(mother, father) {
// crossover via interpolation
function lerp(a, b, p) {
return a + (b - a) * p;
}

var len = mother.length;
var i = Math.floor(Math.random() * len);
var r = Math.random();
var son = [].concat(father);
var daughter = [].concat(mother);

son[i] = lerp(father[i], mother[i], r);
daughter[i] = lerp(mother[i], father[i], r);

return [son, daughter];
};

// example 3 term polynomial: cx^0 + bx^1 + ax^2
genetic.evaluate = evaluate;

genetic.fitness = function(entity) {
var sumSqErr = 0;
var vertices = this.userData["vertices"];
var i;
for (i = 0; i < vertices.length; ++i) {
var err = this.evaluate(entity, vertices[i][0]) - vertices[i][1];
sumSqErr += err * err;
}
return sumSqErr;
};

genetic.generation = function(pop, generation, stats) {
stats.run = this.userData.run;
};

// this is in user space
genetic.notification = function(pop, generation, stats, isFinished) {
if (this.userData.run === stats.run) mutable notified = arguments;
else console.warn("skipping", this.userData.run);
};

return genetic;
}
Insert cell
config = ({
iterations: 2000,
size: 500,
crossover: 0.9,
mutation: 0.2,
maxResults: 3,
skip: 10
})
Insert cell
groundtruth = {
replay;
const freq = 5 + 3 * Math.random();
const phase = 3 * Math.random();
const len = 30 * (1+4*Math.random())|0
return { freq, phase, len };
}
Insert cell
vertices = {
return Array.from({ length: groundtruth.len }, (_, i) => {
const x = Math.random();
const y =
Math.sin(groundtruth.freq * x + groundtruth.phase) + 0.6 * Math.random();
return [x, y];
});
}
Insert cell
userData = ({ terms, vertices, run: Math.random(), poly })
Insert cell
{
genetic.evolve(config, userData);
}
Insert cell
genetic
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more