public void GoldfarbIdnaniConstructorTest9()
{
// Solve the following optimization problem:
//
// min f(x) = 2x² + xy + y² - 5y
//
// s.t. -x - 3y >= -2
// -x - y >= 0
// x >= 0
// y >= 0
//
double x = 0, y = 0;
var f = new QuadraticObjectiveFunction(() => 2 * (x * x) + (x * y) + (y * y) - 5 * y);
List<LinearConstraint> constraints = new List<LinearConstraint>();
constraints.Add(new LinearConstraint(f, () => -x - 3 * y >= -2));
constraints.Add(new LinearConstraint(f, () => -x - y >= 0));
constraints.Add(new LinearConstraint(f, () => x >= 0));
constraints.Add(new LinearConstraint(f, () => y >= 0));
GoldfarbIdnani target = new GoldfarbIdnani(f, constraints);
double[,] expectedA =
{
{ -1, -3 },
{ -1, -1 },
{ 1, 0 },
{ 0, 1 },
};
double[] expectedb =
{
-2, 0, 0, 0
};
double[,] expectedQ =
{
{ 4, 1 },
{ 1, 2 },
};
double[] expectedd =
{
0, -5
};
// Tested against R's QuadProg package
/*
Qmat = matrix(c(4,1,1,2),2,2)
dvec = -c(0, -5)
Amat = matrix(c(-1, -3, -1, -1, 1, 0, 0, 1), 2,4)
bvec = c(-2, 0, 0, 0)
solve.QP(Qmat, dvec, Amat, bvec)
*/
var actualA = target.ConstraintMatrix;
var actualb = target.ConstraintValues;
var actualQ = f.QuadraticTerms;
var actuald = f.LinearTerms;
Assert.IsTrue(expectedA.IsEqual(actualA));
Assert.IsTrue(expectedb.IsEqual(actualb));
Assert.IsTrue(expectedQ.IsEqual(actualQ));
Assert.IsTrue(expectedd.IsEqual(actuald));
Assert.IsTrue(target.Minimize());
double min = target.Value;
double[] solution = target.Solution;
Assert.AreEqual(0, solution[0], 1e-10);
Assert.AreEqual(0, solution[1], 1e-10);
Assert.AreEqual(0.0, min, 1e-10);
Assert.AreEqual(0, target.Lagrangian[0], 1e-10);
Assert.AreEqual(5, target.Lagrangian[1], 1e-10);
Assert.AreEqual(5, target.Lagrangian[2], 1e-10);
Assert.AreEqual(0, target.Lagrangian[3], 1e-10);
Assert.IsFalse(Double.IsNaN(min));
foreach (double v in target.Solution)
Assert.IsFalse(double.IsNaN(v));
foreach (double v in target.Lagrangian)
Assert.IsFalse(double.IsNaN(v));
}