using System;
namespace Legalsoft.Truffer
{
public class Powell : Linemethod
{
private int iter { get; set; }
private double fret { get; set; }
private double ftol { get; set; }
public Powell(RealValueFun func, double ftoll = 3.0e-8) : base(func)
{
//this.Linemethod < T > = func;
this.ftol = ftoll;
}
public double[] minimize(double[] pp)
{
int n = pp.Length;
double[,] ximat = new double[n, n];
for (int i = 0; i < n; i++)
{
ximat[i, i] = 1.0;
}
return (minimize(pp, ximat));
}
public double[] minimize(double[] pp, double[,] ximat)
{
const int ITMAX = 200;
const double TINY = 1.0e-25;
double fptt;
int n = pp.Length;
//p = pp;
p = Globals.CopyFrom(pp);
double[] pt = new double[n];
double[] ptt = new double[n];
//xi.resize(n);
xi = new double[n];
fret = func.funk(p);
for (int j = 0; j < n; j++)
{
pt[j] = p[j];
}
for (iter = 0; ; ++iter)
{
double fp = fret;
int ibig = 0;
double del = 0.0;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
xi[j] = ximat[j, i];
}
fptt = fret;
fret = linmin();
if (fptt - fret > del)
{
del = fptt - fret;
ibig = i + 1;
}
}
if (2.0 * (fp - fret) <= ftol * (Math.Abs(fp) + Math.Abs(fret)) + TINY)
{
return p;
}
if (iter == ITMAX)
{
throw new Exception("powell exceeding maximum iterations.");
}
for (int j = 0; j < n; j++)
{
ptt[j] = 2.0 * p[j] - pt[j];
xi[j] = p[j] - pt[j];
pt[j] = p[j];
}
fptt = func.funk(ptt);
if (fptt < fp)
{
double t = 2.0 * (fp - 2.0 * fret + fptt) * Globals.SQR(fp - fret - del) - del * Globals.SQR(fp - fptt);
if (t < 0.0)
{
fret = linmin();
for (int j = 0; j < n; j++)
{
ximat[j, ibig - 1] = ximat[j, n - 1];
ximat[j, n - 1] = xi[j];
}
}
}
}
}
}
}