tupali/librerias/gantt/code/es-modules/mixins/nelder-mead.js

133 lines
4.5 KiB
JavaScript
Raw Normal View History

2020-05-23 20:45:54 +00:00
/* *
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
/* eslint-disable valid-jsdoc */
var getCentroid = function (simplex) {
var arr = simplex.slice(0, -1), length = arr.length, result = [], sum = function (data, point) {
data.sum += point[data.i];
return data;
};
for (var i = 0; i < length; i++) {
result[i] = arr.reduce(sum, { sum: 0, i: i }).sum / length;
}
return result;
};
/**
* Finds an optimal position for a given point.
* @todo add unit tests.
* @todo add constraints to optimize the algorithm.
* @private
* @param {Highcharts.NelderMeadTestFunction} fn
* The function to test a point.
* @param {Highcharts.NelderMeadPointArray} initial
* The initial point to optimize.
* @return {Highcharts.NelderMeadPointArray}
* Returns the opimized position of a point.
*/
var nelderMead = function nelderMead(fn, initial) {
var maxIterations = 100, sortByFx = function (a, b) {
return a.fx - b.fx;
}, pRef = 1, // Reflection parameter
pExp = 2, // Expansion parameter
pCon = -0.5, // Contraction parameter
pOCon = pCon * pRef, // Outwards contraction parameter
pShrink = 0.5; // Shrink parameter
/**
* @private
*/
var weightedSum = function weightedSum(weight1, v1, weight2, v2) {
return v1.map(function (x, i) {
return weight1 * x + weight2 * v2[i];
});
};
/**
* @private
*/
var getSimplex = function getSimplex(initial) {
var n = initial.length, simplex = new Array(n + 1);
// Initial point to the simplex.
simplex[0] = initial;
simplex[0].fx = fn(initial);
// Create a set of extra points based on the initial.
for (var i = 0; i < n; ++i) {
var point = initial.slice();
point[i] = point[i] ? point[i] * 1.05 : 0.001;
point.fx = fn(point);
simplex[i + 1] = point;
}
return simplex;
};
var updateSimplex = function (simplex, point) {
point.fx = fn(point);
simplex[simplex.length - 1] = point;
return simplex;
};
var shrinkSimplex = function (simplex) {
var best = simplex[0];
return simplex.map(function (point) {
var p = weightedSum(1 - pShrink, best, pShrink, point);
p.fx = fn(p);
return p;
});
};
var getPoint = function (centroid, worst, a, b) {
var point = weightedSum(a, centroid, b, worst);
point.fx = fn(point);
return point;
};
// Create a simplex
var simplex = getSimplex(initial);
// Iterate from 0 to max iterations
for (var i = 0; i < maxIterations; i++) {
// Sort the simplex
simplex.sort(sortByFx);
// Create a centroid from the simplex
var worst = simplex[simplex.length - 1];
var centroid = getCentroid(simplex);
// Calculate the reflected point.
var reflected = getPoint(centroid, worst, 1 + pRef, -pRef);
if (reflected.fx < simplex[0].fx) {
// If reflected point is the best, then possibly expand.
var expanded = getPoint(centroid, worst, 1 + pExp, -pExp);
simplex = updateSimplex(simplex, (expanded.fx < reflected.fx) ? expanded : reflected);
}
else if (reflected.fx >= simplex[simplex.length - 2].fx) {
// If the reflected point is worse than the second worse, then
// contract.
var contracted;
if (reflected.fx > worst.fx) {
// If the reflected is worse than the worst point, do a
// contraction
contracted = getPoint(centroid, worst, 1 + pCon, -pCon);
if (contracted.fx < worst.fx) {
simplex = updateSimplex(simplex, contracted);
}
else {
simplex = shrinkSimplex(simplex);
}
}
else {
// Otherwise do an outwards contraction
contracted = getPoint(centroid, worst, 1 - pOCon, pOCon);
if (contracted.fx < reflected.fx) {
simplex = updateSimplex(simplex, contracted);
}
else {
simplex = shrinkSimplex(simplex);
}
}
}
else {
simplex = updateSimplex(simplex, reflected);
}
}
return simplex[0];
};
var content = {
getCentroid: getCentroid,
nelderMead: nelderMead
};
export default content;