package hex.optimization;
import hex.optimization.OptimizationUtils.GradientInfo;
import hex.optimization.OptimizationUtils.GradientSolver;
import hex.optimization.OptimizationUtils.MoreThuente;
import org.junit.Test;
import water.TestUtil;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Created by tomasnykodym on 9/29/15.
*/
public class LineSearchTest extends TestUtil {
@Test public void testMoreThuenteMethod() {
GradientSolver f = new GradientSolver(){
@Override
public GradientInfo getGradient(double[] beta) {
GradientInfo ginfo = new GradientInfo(0,new double[1]);
double x = beta[0];
double b = 2;
double xx = x*x;
ginfo._gradient[0] = (xx - b)/((b+xx)*(b+xx));
ginfo._objVal = -x/(xx+b);
return ginfo;
}
@Override
public GradientInfo getObjective(double[] beta) {
return getGradient(beta);
}
};
double stp = 1;
double x = 100;
MoreThuente ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
boolean succ = ls.evaluate(new double[]{-1});
assertTrue(succ);
assertEquals(1,ls._returnStatus);
assertEquals(18,ls.nfeval());
assertEquals(-0.35355,ls.ginfo()._objVal,1e-5);
assertEquals(98586,Math.round(1000*ls.step()),1e-5);
x = 0;
stp = 100;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(5,ls.nfeval());
assertEquals(-0.34992,ls.ginfo()._objVal,1e-5);
assertEquals(1.6331,ls.step(),1e-5);
x = 0;
stp = 10;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(1, ls.nfeval());
x = 0;
stp = 1000;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertEquals(ls._returnStatus,1);
assertTrue(succ);
assertEquals(4,ls.nfeval());
assertEquals(37,Math.round(ls.step()));
x = 0;
stp = 1e-3;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertEquals(ls._returnStatus,1);
assertTrue(succ);
assertEquals(6,ls.nfeval());
assertEquals(14,Math.round(10*ls.step()));
f = new GradientSolver(){
@Override
public GradientInfo getGradient(double[] beta) {
GradientInfo ginfo = new GradientInfo(0,new double[1]);
double x = beta[0];
double b = 0.004;
ginfo._objVal = Math.pow(x+b,5) - 2*Math.pow(x+b,4);
ginfo._gradient[0] = Math.pow(b + x,3) * (5*(b + x)-8);
return ginfo;
}
@Override
public GradientInfo getObjective(double[] beta) {
return getGradient(beta);
}
};
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(12,ls.nfeval());
assertEquals(16,Math.round(10*ls.step()));
stp = 0.1;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(8,ls.nfeval());
assertEquals(16,Math.round(10*ls.step()));
stp = 10;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(8,ls.nfeval());
assertEquals(16,Math.round(10*ls.step()));
stp = 1000;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(11,ls.nfeval());
assertEquals(16, Math.round(10 * ls.step()));
f = new GradientSolver(){
final double beta = 0.01;
final double l = 39;
double phi0(double x) {
if(x <= 1 - beta) {
return 1 - x;
} else if(x >= 1 + beta) {
return x - 1;
} else {
return .5*((x-1)*(x-1)/beta + beta);
}
}
double phi0Prime(double x) {
if(x <= 1 - beta) {
return -1;
} else if(x >= 1 + beta) {
return 1;
} else {
return (x-1)/beta; // .5*((x-1)*(x-1)/beta + beta);
}
}
@Override
public GradientInfo getGradient(double[] ary) {
GradientInfo ginfo = new GradientInfo(0,new double[1]);
double x = ary[0];
double a = 2*(1-beta)/(Math.PI*l);
double b = .5*l*Math.PI;
ginfo._objVal = phi0(x) + a*Math.sin(b*x);
ginfo._gradient[0] = phi0Prime(x) + a*b*Math.cos(b*x);
return ginfo;
}
@Override
public GradientInfo getObjective(double[] beta) {
return getGradient(beta);
}
};
stp = 0.001;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertEquals(ls._returnStatus,1);
assertTrue(succ);
assertEquals(12,ls.nfeval());
assertEquals(10,Math.round(10*ls.step()));
stp = 0.1;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(12,ls.nfeval());
assertEquals(10,Math.round(10*ls.step()));
stp = 10;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertEquals(ls._returnStatus,1);
assertTrue(succ);
assertEquals(10,ls.nfeval());
assertEquals(10,Math.round(10*ls.step()));
stp = 1000;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-1,1e-1,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(13,ls.nfeval());
assertEquals(10, Math.round(10 * ls.step()));
f = new F(1e-3,1e-3);
stp = 0.001;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(4,ls.nfeval());
assertEquals(9, Math.round(100 * ls.step()));
stp = 0.1;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(1,ls.nfeval());
assertEquals(10, Math.round(100 * ls.step()));
stp = 10;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(3,ls.nfeval());
assertEquals(35, Math.round(100 * ls.step()));
stp = 1000;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(4,ls.nfeval());
assertEquals(83, Math.round(100 * ls.step()));
f = new F(0.01,1e-3);
stp = 0.001;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(6,ls.nfeval());
assertEquals(75, Math.round(1000 * ls.step()));
stp = 0.1;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(3,ls.nfeval());
assertEquals(78, Math.round(1000 * ls.step()));
stp = 10;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(7,ls.nfeval());
assertEquals(73, Math.round(1000 * ls.step()));
stp = 1000;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate( new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(8,ls.nfeval());
assertEquals(76, Math.round(1000 * ls.step()));
f = new F(1e-3,0.01);
stp = 0.001;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(13,ls.nfeval());
assertEquals(93, Math.round(100 * ls.step()));
stp = 0.1;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(11,ls.nfeval());
assertEquals(93, Math.round(100 * ls.step()));
stp = 10;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(8,ls.nfeval());
assertEquals(92, Math.round(100 * ls.step()));
stp = 1000;
ls = new OptimizationUtils.MoreThuente(f,new double[]{x},f.getGradient(new double[]{x}),1e-3,1e-3,1e-5).setInitialStep(stp);
succ = ls.evaluate(new double[]{1});
assertTrue(succ);
assertEquals(ls._returnStatus,1);
assertEquals(11,ls.nfeval());
assertEquals(92, Math.round(100 * ls.step()));
}
private static class F implements GradientSolver {
final double a;
final double b;
public F(double a, double b) {
this.a = a;
this.b = b;
}
private double gamma(double x) {
return Math.sqrt(x * x + 1)-x;
}
@Override
public GradientInfo getGradient(double[] beta) {
double x = beta[0];
double ga = gamma(a);
double gb = gamma(b);
GradientInfo ginfo = new GradientInfo(0, new double[1]);
ginfo._objVal = ga*Math.sqrt((1-x)*(1-x) + b*b) + gb*Math.sqrt(x * x + a * a);
ginfo._gradient[0] = ga*(x-1)/Math.sqrt((1-x)*(1-x) + b*b) +gb*x/Math.sqrt(x * x + a * a);
return ginfo;
}
@Override
public GradientInfo getObjective(double[] beta) {
return getGradient(beta);
}
}
}