Skip to content

Instantly share code, notes, and snippets.

@szymonkaliski
Last active January 11, 2019 23:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save szymonkaliski/f2f58a38149d97db7ba10a7ef4ac163a to your computer and use it in GitHub Desktop.
Save szymonkaliski/f2f58a38149d97db7ba10a7ef4ac163a to your computer and use it in GitHub Desktop.
(un)constrained optimisation
const { uncmin } = require("numeric");
const fmin = require("fmin");
const data = require("./intervals-data.json");
document.body.style.display = "flex";
const makeDiv = title => {
const div = document.createElement("div");
const text = document.createElement("div");
text.innerText = title;
div.appendChild(text);
document.body.appendChild(div);
text.style["margin-bottom"] = "10px";
div.style.margin = "10px";
div.style["font-family"] = "sans-serif";
return div;
};
const [WIDTH, HEIGHT] = [800, 600];
const MARGIN = 20;
const LABEL_HEIGHT = 20;
const optim = (optimFn, getSolution, parentDiv) => {
const canvas = document.createElement("canvas");
canvas.width = WIDTH;
canvas.height = HEIGHT;
parentDiv.appendChild(canvas);
const context = canvas.getContext("2d");
context.fillStyle = "#eee";
context.fillRect(0, 0, WIDTH, HEIGHT);
context.strokeStyle = "#333";
data.forEach((d, i) => {
const y1 = d[0] * HEIGHT;
const y2 = d[1] * HEIGHT;
const x = i * MARGIN + MARGIN;
context.beginPath();
context.moveTo(x, y1);
context.lineTo(x, y2);
context.stroke();
});
// const x0 = data.map(() => Math.random() * HEIGHT);
// const x0 = data.map(d => d[0] + (d[1] - d[0]) * HEIGHT);
const x0 = data.map(d => ((d[0] + d[1]) / 2) * HEIGHT);
const clamp = (v, min, max) => Math.min(Math.max(v, min), max);
const constrain = xs =>
xs.map((x, i) =>
clamp(
clamp(x, data[i][0] * HEIGHT, data[i][1] * HEIGHT),
MARGIN,
HEIGHT - MARGIN
)
);
const calcOverlap = xs => {
let dist = 1e-8;
for (let i = 0; i < xs.length; i++) {
for (let j = 0; j < xs.length; j++) {
if (i !== j) {
const d = Math.abs(xs[i] - xs[j]);
dist += d < LABEL_HEIGHT + MARGIN ? (LABEL_HEIGHT + MARGIN) / d : 0;
}
}
}
return dist;
};
const minimized = optimFn(xs => {
const constrained = constrain(xs);
const overlap = calcOverlap(constrained);
return overlap;
}, x0);
const solution = getSolution(minimized);
const constrainedSolution = constrain(solution);
constrainedSolution.forEach((y, i) => {
const x = i * MARGIN + MARGIN;
const r = 8;
context.fillStyle = "#333";
context.fillRect(x - r / 2, y - r / 2, r, r);
context.fillStyle = "rgba(100,100,100,0.2)";
context.fillRect(0, y - LABEL_HEIGHT / 2, WIDTH, LABEL_HEIGHT);
});
};
optim(uncmin, optim => optim.solution, makeDiv("uncmin"));
optim(fmin.nelderMead, optim => optim.x, makeDiv("fmin"));
[
[0.0, 0.148],
[0.204, 0.352],
[0.235, 0.383],
[0.246, 0.394],
[0.328, 0.476],
[0.439, 0.587],
[0.138, 0.633],
[0.045, 0.782],
[0.212, 0.895],
[0.158, 0.931],
[0.795, 0.944],
[0.076, 0.954],
[0.258, 0.988],
[0.852, 1.0]
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment