package edu.berkeley.nlp.math; import edu.berkeley.nlp.util.Logger; public class SubgradientMinimizer implements GradientMinimizer { private static final double initialStepSize = 1.0; int minIterations = -1; double initialStepSizeMultiplier = 0.01; double stepSizeMultiplier = .5; double EPS = 1e-10; int maxIterations = 2000; /** * After each iteration, we grow the step size */ double stepSizeGrowthAmount = 0.0; // this is multiplicatve public double[] minimize(DifferentiableFunction function, double[] initial, double tolerance, boolean project){ return null; } public double[] minimize(DifferentiableFunction function, double[] initial, double tolerance) { boolean printProgress = true; BacktrackingLineSearcher lineSearcher = new BacktrackingLineSearcher(); double[] guess = DoubleArrays.clone(initial); //this grows linearly as the iterations go on (if stepSizeGrowthAmount > 0.0) //but gets scaled back geometrically by lineSearcher double stepSize = initialStepSize; for (int iteration = 0; iteration < maxIterations; iteration++) { if (stepSizeGrowthAmount == 0.0) stepSize = initialStepSize; else { stepSize *= stepSizeGrowthAmount; } double[] subgradient = function.derivativeAt(guess); double value = function.valueAt(guess); double[] direction = subgradient; DoubleArrays.scale(direction, -1.0); if (iteration == 0) lineSearcher.stepSizeMultiplier = initialStepSizeMultiplier; else lineSearcher.stepSizeMultiplier = stepSizeMultiplier; lineSearcher.initialStepSize = stepSize; double[] nextGuess = doLineSearch(function, lineSearcher, guess, direction); stepSize = lineSearcher.getFinalStepSize(); double[] nextDerivative = function.derivativeAt(nextGuess); double nextValue = function.valueAt(nextGuess); if (printProgress) { Logger.i().logs("[Subgradient] Iteration %d: %.6f", iteration, nextValue); } if (iteration >= minIterations && converged(value, nextValue, tolerance)) { return nextGuess; } guess = nextGuess; value = nextValue; subgradient = nextDerivative; } return guess; } /** * @param function * @param lineSearcher * @param guess * @param direction * @return */ protected double[] doLineSearch(DifferentiableFunction function, BacktrackingLineSearcher lineSearcher, double[] guess, double[] direction) { return lineSearcher.minimize(function, guess, direction); } private boolean converged(double value, double nextValue, double tolerance) { if (value == nextValue) return true; double valueChange = Math.abs(nextValue - value); double valueAverage = Math.abs(nextValue + value + EPS) / 2.0; if (valueChange / valueAverage < tolerance) return true; return false; } public void setMaxIterations(int maxIterations2) { maxIterations = maxIterations2; } public void setMinIteratons(int minIterations2) { minIterations = minIterations2; } public void setStepSizeGrowthAmount(double amount) { this.stepSizeGrowthAmount = amount; } }