not as good as general conjugate gradient @author johnmount
| 15 | * |
| 16 | */ |
| 17 | public final class GradientDescent implements VectorOptimizer { |
| 18 | private final Log log = LogFactory.getLog(GradientDescent.class); |
| 19 | private final double minGNormSQ = 1.0e-12; |
| 20 | private final double boxBound = 10000.0; // TODO: set this |
| 21 | private final double relImprovementTarget = 1.0e-3; |
| 22 | |
| 23 | public enum StepStatus { |
| 24 | goodGradientDescentStep, |
| 25 | linMinFailure, |
| 26 | noImprovement, |
| 27 | smallGNorm, |
| 28 | } |
| 29 | |
| 30 | |
| 31 | public StepStatus gradientPolish(final VectorFn f, final VEval lastEval, final VEval[] bestEval) { |
| 32 | // try for a partial steepest descent step (gradient)- usually not reached |
| 33 | final int dim = f.dim(); |
| 34 | double normGsq = 0.0; |
| 35 | double maxAbsG = 0.0; |
| 36 | for(int i=0;i<dim;++i) { |
| 37 | maxAbsG = Math.max(maxAbsG,Math.abs(lastEval.gx[i])); |
| 38 | normGsq += lastEval.gx[i]*lastEval.gx[i]; |
| 39 | } |
| 40 | if(normGsq<minGNormSQ) { |
| 41 | return StepStatus.smallGNorm; |
| 42 | } |
| 43 | final double unitScale = 1.0/Math.max(1.0,maxAbsG); |
| 44 | final SFun g = new SFun(f,lastEval.x,lastEval.gx,boxBound,lastEval); |
| 45 | final LinMax lmax = new LinMax(); |
| 46 | lmax.maximize(g, lastEval.fx, unitScale,20); |
| 47 | if(g.max==null) { |
| 48 | return StepStatus.linMinFailure; |
| 49 | } |
| 50 | if((bestEval[0]==null)||(g.max.fx>bestEval[0].fx)) { |
| 51 | bestEval[0] = g.max; |
| 52 | } |
| 53 | if((g.max!=null)&&(g.max.fx>lastEval.fx)) { |
| 54 | return StepStatus.goodGradientDescentStep; |
| 55 | } else { |
| 56 | return StepStatus.noImprovement; |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | |
| 61 | @Override |
| 62 | public VEval maximize(final VectorFn f, final double[] x, final int maxRounds) { |
| 63 | final VEval[] bestEval = new VEval[] { f.eval(x,true,false) }; |
| 64 | log.info("GDstart: " + bestEval[0].fx); |
| 65 | for(int round=0;round<maxRounds;++round) { |
| 66 | final VEval lastEval; |
| 67 | if(bestEval[0].gx!=null) { |
| 68 | lastEval = bestEval[0]; |
| 69 | } else { |
| 70 | lastEval = f.eval(bestEval[0].x,true,false); |
| 71 | } |
| 72 | final double lastRecord = bestEval[0].fx; |
| 73 | final StepStatus ri = gradientPolish(f,lastEval,bestEval); |
| 74 | log.info("GDstatus: " + ri + "\t" + bestEval[0].fx); |
nothing calls this directly
no outgoing calls
no test coverage detected