whychdw
2019-09-09 c0b9ce437d409b89ca0e5388344ca9c5a56d70a4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"use strict";
 
Object.defineProperty(exports, "__esModule", {
    value: true
});
/* *
 *
 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
 *
 * */
/* eslint-disable valid-jsdoc */
var getCentroid = function getCentroid(simplex) {
    var arr = simplex.slice(0, -1),
        length = arr.length,
        result = [],
        sum = function sum(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 sortByFx(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 updateSimplex(simplex, point) {
        point.fx = fn(point);
        simplex[simplex.length - 1] = point;
        return simplex;
    };
    var shrinkSimplex = function shrinkSimplex(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 getPoint(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
};
exports.default = content;