forked from tsai/mathnet-numerics
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
65 lines
1.9 KiB
65 lines
1.9 KiB
using MathNet.Numerics.LinearAlgebra;
|
|
using System;
|
|
|
|
namespace MathNet.Numerics.Optimization.Subproblems
|
|
{
|
|
internal class NewtonCGSubproblem : ITrustRegionSubproblem
|
|
{
|
|
public Vector<double> Pstep { get; private set; }
|
|
|
|
public bool HitBoundary { get; private set; }
|
|
|
|
public void Solve(IObjectiveModel objective, double delta)
|
|
{
|
|
var Jacobian = objective.Jacobian;
|
|
var Gradient = objective.Gradient;
|
|
var Hessian = objective.Hessian;
|
|
|
|
// define tolerance
|
|
var tolerance = Math.Min(0.5, Math.Sqrt(Gradient.L2Norm())) * Gradient.L2Norm();
|
|
|
|
// initialize internal variables
|
|
var z = Vector<double>.Build.Dense(Hessian.RowCount);
|
|
var r = -Gradient;
|
|
var d = -r;
|
|
|
|
while (true)
|
|
{
|
|
var Bd = Hessian * d;
|
|
var dBd = d.DotProduct(Bd);
|
|
|
|
if (dBd <= 0)
|
|
{
|
|
var t = Util.FindBeta(1, z, d, delta);
|
|
Pstep = z + t.Item1 * d;
|
|
HitBoundary = true;
|
|
return;
|
|
}
|
|
|
|
var r_sq = r.DotProduct(r);
|
|
var alpha = r_sq / dBd;
|
|
var znext = z + alpha * d;
|
|
if(znext.L2Norm() >= delta)
|
|
{
|
|
var t = Util.FindBeta(1, z, d, delta);
|
|
Pstep = z + t.Item2 * d;
|
|
HitBoundary = true;
|
|
return;
|
|
}
|
|
|
|
var rnext = r + alpha * Bd;
|
|
var rnext_sq = rnext.DotProduct(rnext);
|
|
if (Math.Sqrt(rnext_sq) < tolerance)
|
|
{
|
|
Pstep = znext;
|
|
HitBoundary = false;
|
|
return;
|
|
}
|
|
|
|
z = znext;
|
|
r = rnext;
|
|
d = -rnext + rnext_sq / r_sq * d; ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|