private unsafe ConjugateGradientCode cvsmod(ref double f, double[] s, ref double stp, ref int info,
ref int nfev, double[] wa, ref double dginit, ref double dgout)
{
int n = NumberOfVariables;
double[] x = Solution;
if (info == 1)
{
goto L321;
}
infoc = 1;
if (stp <= 0) // Check the input parameters for errors
{
return(ConjugateGradientCode.StepSize);
}
// Compute the initial gradient in the search direction
// and check that S is a descent direction.
if (dginit >= 0)
{
throw new LineSearchFailedException(0, "The search direction is not a descent direction.");
}
// Initialize local variables
brackt = false;
stage1 = true;
nfev = 0;
finit = f;
dgtest = ftol * dginit;
width = stpmax - stpmin;
width1 = width / 0.5;
for (int j = 0; j < x.Length; ++j)
{
wa[j] = x[j];
}
// The variables STX, FX, DGX contain the values of the step,
// function, and directional derivative at the best step.
// The variables STY, FY, DGY contain the value of the step,
// function, and derivative at the other endpoint of the interval
// of uncertainty.
// The variables STP, F, DG contain the values of the step,
// function, and derivative at the current step.
stx = 0;
fx = finit;
dgx = dginit;
sty = 0;
fy = finit;
dgy = dginit;
L30: // Start of iteration.
// Set the minimum and maximum steps to correspond
// to the present interval of uncertainty.
if (brackt)
{
stmin = Math.Min(stx, sty);
stmax = Math.Max(stx, sty);
}
else
{
stmin = stx;
stmax = stp + 4 * (stp - stx);
}
// Force the step to be within
// the bounds STPMAX and STPMIN.
stp = Math.Max(stp, stpmin);
stp = Math.Min(stp, stpmax);
// If an unusual termination is to occur then
// let STP be the lowest point obtained so far.
if (brackt && (stp <= stmin || stp >= stmax) || nfev >= maxfev - 1 ||
infoc == 0 || brackt && stmax - stmin <= xtol * stmax)
{
stp = stx;
}
// Evaluate the function and gradient at STP
// and compute the directional derivative.
for (int j = 0; j < s.Length; ++j)
{
x[j] = wa[j] + stp * s[j];
}
// Fetch function and gradient
f = Function(x);
g = Gradient(x);
info = 0;
nfev++;
dg2 = 0;
for (int j = 0; j < g.Length; ++j)
{
dg2 += g[j] * s[j];
}
ftest1 = finit + stp * dgtest;
if ((brackt && (stp <= stmin || stp >= stmax)) || infoc == 0)
{
return(ConjugateGradientCode.RoundingErrors);
}
if (stp == stpmax && f <= ftest1 && dg2 <= dgtest)
{
return(ConjugateGradientCode.StepHigh);
}
if (stp == stpmin && (f > ftest1 || dg2 >= dgtest))
{
return(ConjugateGradientCode.StepLow);
}
if (nfev >= maxfev)
{
return(ConjugateGradientCode.MaximumEvaluations);
}
if (brackt && stmax - stmin <= xtol * stmax)
{
return(ConjugateGradientCode.Precision);
}
// More's code has been modified so that at least one new
// function value is computed during the line search (enforcing
// at least one interpolation is not easy, since the code may
// override an interpolation)
if (f <= ftest1 && Math.Abs(dg2) <= gtol * (-dginit) && nfev > 1)
{
info = 1;
dgout = dg2;
return(ConjugateGradientCode.Success);
}
L321:
// In the first stage we seek a step for which the modified
// function has a nonpositive value and nonnegative derivative.
if (stage1 && f <= ftest1 && dg2 >= Math.Min(ftol, gtol) * dginit)
{
stage1 = false;
}
// A modified function is used to predict the step only if
// we have not obtained a step for which the modified function
// has a nonpositive function value and nonnegative derivative,
// and if a lower function value has been obtained but the
// decrease is not sufficient.
if (stage1 && f <= fx && f > ftest1)
{
// Define the modified function and derivative values
double fm = f - stp * dgtest;
double fxm = fx - stx * dgtest;
double fym = fy - sty * dgtest;
double dgm = dg2 - dgtest;
double dgxm = dgx - dgtest;
double dgym = dgy - dgtest;
// Call CSTEPM to update the interval of
// uncertainty and to compute the new step.
BoundedBroydenFletcherGoldfarbShanno.dcstep(ref stx, ref fxm, ref dgxm,
ref sty, ref fym, ref dgym, ref stp, fm, dgm, ref brackt, stpmin, stpmax);
// Reset the function and gradient values for f.
fx = fxm + stx * dgtest;
fy = fym + sty * dgtest;
dgx = dgxm + dgtest;
dgy = dgym + dgtest;
}
else
{
// Call CSTEPM to update the interval of
// uncertainty and to compute the new step.
BoundedBroydenFletcherGoldfarbShanno.dcstep(ref stx, ref fx, ref dgx,
ref sty, ref fy, ref dgy, ref stp, f, dg2, ref brackt, stpmin, stpmax);
}
// Force a sufficient decrease in the
// size of the interval of uncertainty.
if (brackt)
{
if ((Math.Abs(sty - stx)) >= 0.66 * width1)
{
stp = stx + 0.5 * (sty - stx);
}
width1 = width;
width = Math.Abs(sty - stx);
}
goto L30;
}