oms3.ngmf.util.cosu.NelderMead Maven / Gradle / Ivy
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package oms3.ngmf.util.cosu;
/**
*
* @author od
*/
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
public class NelderMead {
static class SampleComperator implements Comparator {
private int order = 1;
public SampleComperator(boolean decreasing_order) {
order = decreasing_order ? -1 : 1;
}
@Override
public int compare(Sample d1, Sample d2) {
if (d1.fx < d2.fx) {
return -1 * order;
} else if (d1.fx == d2.fx) {
return 0 * order;
} else {
return 1 * order;
}
}
}
Sample[] initialSimplex = null;
//number of parameters!!
int n;
double[] lowBound;
double[] upBound;
double x0[] = null;
int mode;
Random generator = new Random();
int currentSampleCount;
double effValue;
int maxn;
double[] parameters;
void sort(Sample[] array) {
Arrays.sort(array, new SampleComperator(false));
}
double normalizedgeometricRange(Sample x[]) {
if (x.length == 0) {
return 0;
}
double min[] = new double[n];
double max[] = new double[n];
double mean = 0;
for (int i = 0; i < n; i++) {
min[i] = Double.POSITIVE_INFINITY;
max[i] = Double.NEGATIVE_INFINITY;
for (int j = 0; j < x.length; j++) {
min[i] = Math.min(x[j].x[i], min[i]);
max[i] = Math.max(x[j].x[i], max[i]);
}
mean += Math.log(max[i] - min[i]);
}
return Math.exp(mean / n);
}
boolean feasible(double point[]) {
for (int i = 0; i < point.length; i++) {
if (point[i] < lowBound[i] || point[i] > upBound[i]) {
return false;
}
}
return true;
}
Sample getSample(double[] x) {
return new Sample(x, funct(x));
}
public double funct(double x[]) {
//RefreshDataHandles();
for (int j = 0; j < parameters.length; j++) {
try {
parameters[j] = x[j];
} catch (Exception e) {
throw new RuntimeException("Error! Parameter No. " + j + " wasn^t found" + e.toString());
}
}
// singleRun();
double value = effValue;
//sometimes its a bad idea to calculate with NaN or Infty
double bigNumber = 10000000;
effValue = Math.max(effValue, -bigNumber);
effValue = Math.min(effValue, bigNumber);
if (Double.isNaN(effValue)) {
effValue = -bigNumber;
}
currentSampleCount++;
switch (mode) {
case Efficiencies.MINIMIZATION:
return value;
case Efficiencies.MAXIMIZATION:
return -value;
case Efficiencies.ABSMINIMIZATION:
return Math.abs(value);
case Efficiencies.ABSMAXIMIZATION:
return -Math.abs(value);
default:
return 0.0;
}
}
double[] randomSample() {
double[] sample = new double[n];
for (int i = 0; i < n; i++) {
sample[i] = (lowBound[i] + generator.nextDouble() * (upBound[i] - lowBound[i]));
}
return sample;
}
public void run() {
//first draw n+1 random points
Sample[] simplex = new Sample[n + 1];
if (initialSimplex != null) {
simplex = initialSimplex;
} else {
for (int i = 0; i < n + 1; i++) {
if (i == 0 && x0 != null) {
simplex[i] = getSample(x0);
} else {
simplex[i] = getSample(randomSample());
}
}
}
int m = simplex.length;
double alpha = 1.0;
double gamma = 2.0;
double rho = 0.5;
double sigma = 0.5;
double epsilon = 0.01;
double max_restart_count = 5;
int restart_counter = 0;
int iterationcounter = 0;
while (true) {
if (iterationcounter++ > maxn) {
System.out.println("*********************************************************");
System.out.println("Maximum number of iterations reached, finished optimization");
System.out.println("Bestpoint:" + simplex[0]);
System.out.println("*********************************************************");
return;
}
if (normalizedgeometricRange(simplex) < epsilon) {
if (max_restart_count < ++restart_counter) {
System.out.println("*********************************************************");
System.out.println("Maximum number of restarts reached, finished optimization");
System.out.println("Bestpoint:" + simplex[0]);
System.out.println("*********************************************************");
return;
}
System.out.println("restart");
for (int i = 1; i < m; i++) {
simplex[i] = getSample(randomSample());
}
}
sort(simplex);
// Compute the centroid of the simplex
double centroid[] = new double[n];
for (int j = 0; j < n; j++) {
centroid[j] = 0;
for (int i = 0; i < m - 1; i++) {
centroid[j] += simplex[i].x[j] * (1.0 / (m - 1.0));
}
}
//reflect
double reflection[] = new double[n];
for (int i = 0; i < n; i++) {
reflection[i] = centroid[i] + alpha * (centroid[i] - simplex[m - 1].x[i]);
}
Sample reflection_sample = null;
if (feasible(reflection)) {
System.out.println("reflection step");
reflection_sample = getSample(reflection);
if (simplex[0].fx < reflection_sample.fx && reflection_sample.fx < simplex[m - 1].fx) {
simplex[m - 1] = reflection_sample;
continue;
}
}
//expand
if (feasible(reflection) && simplex[0].fx >= reflection_sample.fx) {
double expansion[] = new double[n];
for (int i = 0; i < n; i++) {
expansion[i] = centroid[i] + gamma * (centroid[i] - simplex[m - 1].x[i]);
}
System.out.println("expansion step");
Sample expansion_sample = getSample(expansion);
if (feasible(expansion) && expansion_sample.fx < reflection_sample.fx) {
simplex[m - 1] = expansion_sample;
} else {
simplex[m - 1] = reflection_sample;
}
continue;
}
//contraction
if (!feasible(reflection) || simplex[m - 1].fx <= reflection_sample.fx) {
double contraction[] = new double[n];
for (int i = 0; i < n; i++) {
contraction[i] = centroid[i] + rho * (centroid[i] - simplex[m - 1].x[i]);
}
System.out.println("contraction step");
//this should not happen ..
Sample contraction_sample = null;
if (!feasible(contraction)) {
System.out.println("not feasible after contraction step");
contraction_sample = getSample(randomSample());
} else {
contraction_sample = getSample(contraction);
}
if (contraction_sample.fx < simplex[m - 1].fx) {
simplex[m - 1] = contraction_sample;
continue;
}
}
//shrink
for (int i = 1; i < m; i++) {
double shrink[] = new double[n];
for (int j = 0; j < n; j++) {
shrink[j] = simplex[0].x[j] + sigma * (simplex[i].x[j] - simplex[0].x[j]);
}
System.out.println("shrink step");
simplex[i] = getSample(shrink);
}
}
}
}