From 02112f45999276fbaad9d8bbd602808b80cac26e Mon Sep 17 00:00:00 2001 From: Vladimir Chalupecky Date: Fri, 22 Jan 2016 17:10:54 +0900 Subject: [PATCH 1/3] Rename GradConst in Bisection to CurvatureFactor --- bisection.go | 21 ++++++++++++--------- linesearcher_test.go | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/bisection.go b/bisection.go index 40b6f30..e0d6584 100644 --- a/bisection.go +++ b/bisection.go @@ -7,11 +7,14 @@ package optimize import "math" // Bisection is a Linesearcher that uses a bisection to find a point that -// satisfies the strong Wolfe conditions with the given gradient constant and -// function constant of zero. If GradConst is zero, it will be set to a reasonable -// value. Bisection will panic if GradConst is not between zero and one. +// satisfies the strong Wolfe conditions with the given curvature factor and +// sufficient decrease factor of zero. type Bisection struct { - GradConst float64 + // CurvatureFactor is the constant factor in the curvature condition. + // Smaller values result in a more exact line search. + // A set value must be in the interval (0, 1), otherwise Init will panic. + // If it is zero, it will be defaulted to 0.9. + CurvatureFactor float64 minStep float64 maxStep float64 @@ -35,11 +38,11 @@ func (b *Bisection) Init(f, g float64, step float64) Operation { panic("bisection: initial derivative is non-negative") } - if b.GradConst == 0 { - b.GradConst = 0.9 + if b.CurvatureFactor == 0 { + b.CurvatureFactor = 0.9 } - if b.GradConst <= 0 || b.GradConst >= 1 { - panic("bisection: GradConst not between 0 and 1") + if b.CurvatureFactor <= 0 || b.CurvatureFactor >= 1 { + panic("bisection: CurvatureFactor not between 0 and 1") } b.minStep = 0 @@ -94,7 +97,7 @@ func (b *Bisection) Iterate(f, g float64) (Operation, float64, error) { f = b.lastF // The function value was lower. Check if this location is sufficient to // converge the linesearch, otherwise iterate. - if StrongWolfeConditionsMet(f, g, minF, b.initGrad, b.currStep, 0, b.GradConst) { + if StrongWolfeConditionsMet(f, g, minF, b.initGrad, b.currStep, 0, b.CurvatureFactor) { b.lastOp = MajorIteration return b.lastOp, b.currStep, nil } diff --git a/linesearcher_test.go b/linesearcher_test.go index ef5417d..42f32fb 100644 --- a/linesearcher_test.go +++ b/linesearcher_test.go @@ -26,7 +26,7 @@ func TestMoreThuente(t *testing.T) { func TestBisection(t *testing.T) { c := 0.1 ls := &Bisection{ - GradConst: c, + CurvatureFactor: c, } testLinesearcher(t, ls, 0, c, true) } From 53d53a19b71c44fd5fd4e59231c7a151e3bff564 Mon Sep 17 00:00:00 2001 From: Vladimir Chalupecky Date: Fri, 22 Jan 2016 17:27:50 +0900 Subject: [PATCH 2/3] Rename FuncConst and Decrease in Backtracking ... to DecreaseFactor and ContractionFactor, respectively. --- backtracking.go | 41 ++++++++++++++++++++--------------------- linesearcher_test.go | 2 +- unconstrained_test.go | 2 +- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/backtracking.go b/backtracking.go index aa7b5d0..313077f 100644 --- a/backtracking.go +++ b/backtracking.go @@ -5,15 +5,14 @@ package optimize const ( - defaultBacktrackingDecrease = 0.5 - defaultBacktrackingFuncConst = 1e-4 - minimumBacktrackingStepSize = 1e-20 + defaultBacktrackingContraction = 0.5 + defaultBacktrackingDecrease = 1e-4 + minimumBacktrackingStepSize = 1e-20 ) // Backtracking is a Linesearcher that uses backtracking to find a point that -// satisfies the Armijo condition with the given function constant FuncConst. If -// the Armijo condition has not been met, the step size is decreased by a -// factor of Decrease. +// satisfies the Armijo condition with the given decrease factor. If the Armijo +// condition has not been met, the step size is decreased by ContractionFactor. // // The Armijo condition only requires the gradient at the beginning of each // major iteration (not at successive step locations), and so Backtracking may @@ -21,12 +20,12 @@ const ( // not appropriate for optimizers that require the Wolfe conditions to be met, // such as BFGS. // -// Both FuncConst and Decrease must be between zero and one, and Backtracking will -// panic otherwise. If either FuncConst or Decrease are zero, it will be set to a -// reasonable default. +// Both DecreaseFactor and ContractionFactor must be between zero and one, and +// Backtracking will panic otherwise. If either DecreaseFactor or +// ContractionFactor are zero, it will be set to a reasonable default. type Backtracking struct { - FuncConst float64 // Necessary function descrease for Armijo condition. - Decrease float64 // Step size multiplier at each iteration (stepSize *= Decrease). + DecreaseFactor float64 // Constant factor in the sufficient decrease (Armijo) condition. + ContractionFactor float64 // Step size multiplier at each iteration (step *= ContractionFactor). stepSize float64 initF float64 @@ -43,17 +42,17 @@ func (b *Backtracking) Init(f, g float64, step float64) Operation { panic("backtracking: initial derivative is non-negative") } - if b.Decrease == 0 { - b.Decrease = defaultBacktrackingDecrease + if b.ContractionFactor == 0 { + b.ContractionFactor = defaultBacktrackingContraction } - if b.FuncConst == 0 { - b.FuncConst = defaultBacktrackingFuncConst + if b.DecreaseFactor == 0 { + b.DecreaseFactor = defaultBacktrackingDecrease } - if b.Decrease <= 0 || b.Decrease >= 1 { - panic("backtracking: Decrease must be between 0 and 1") + if b.ContractionFactor <= 0 || b.ContractionFactor >= 1 { + panic("backtracking: ContractionFactor must be between 0 and 1") } - if b.FuncConst <= 0 || b.FuncConst >= 1 { - panic("backtracking: FuncConst must be between 0 and 1") + if b.DecreaseFactor <= 0 || b.DecreaseFactor >= 1 { + panic("backtracking: DecreaseFactor must be between 0 and 1") } b.stepSize = step @@ -69,11 +68,11 @@ func (b *Backtracking) Iterate(f, _ float64) (Operation, float64, error) { panic("backtracking: Init has not been called") } - if ArmijoConditionMet(f, b.initF, b.initG, b.stepSize, b.FuncConst) { + if ArmijoConditionMet(f, b.initF, b.initG, b.stepSize, b.DecreaseFactor) { b.lastOp = MajorIteration return b.lastOp, b.stepSize, nil } - b.stepSize *= b.Decrease + b.stepSize *= b.ContractionFactor if b.stepSize < minimumBacktrackingStepSize { b.lastOp = NoOperation return b.lastOp, b.stepSize, ErrLinesearcherFailure diff --git a/linesearcher_test.go b/linesearcher_test.go index 42f32fb..493ad2d 100644 --- a/linesearcher_test.go +++ b/linesearcher_test.go @@ -34,7 +34,7 @@ func TestBisection(t *testing.T) { func TestBacktracking(t *testing.T) { d := 0.001 ls := &Backtracking{ - FuncConst: d, + DecreaseFactor: d, } testLinesearcher(t, ls, d, 0, false) } diff --git a/unconstrained_test.go b/unconstrained_test.go index e782b9f..6dc9023 100644 --- a/unconstrained_test.go +++ b/unconstrained_test.go @@ -1016,7 +1016,7 @@ func TestGradientDescent(t *testing.T) { func TestGradientDescentBacktracking(t *testing.T) { testLocal(t, gradientDescentTests, &GradientDescent{ Linesearcher: &Backtracking{ - FuncConst: 0.1, + DecreaseFactor: 0.1, }, }) } From ee51ef5eaaf85f06bc0286bca8f0bfb47801fb07 Mon Sep 17 00:00:00 2001 From: Vladimir Chalupecky Date: Fri, 22 Jan 2016 17:34:43 +0900 Subject: [PATCH 3/3] Rename funcConst and gradConst parameters to Armijo and Wolfe functions --- linesearch.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/linesearch.go b/linesearch.go index dfdba51..8ec5fd7 100644 --- a/linesearch.go +++ b/linesearch.go @@ -183,9 +183,9 @@ func (ls *LinesearchMethod) initNextLinesearch(loc *Location) (Operation, error) // true, though this is not enforced: // - initGrad < 0 // - step > 0 -// - 0 < funcConst < 1 -func ArmijoConditionMet(currObj, initObj, initGrad, step, funcConst float64) bool { - return currObj <= initObj+funcConst*step*initGrad +// - 0 < decrease < 1 +func ArmijoConditionMet(currObj, initObj, initGrad, step, decrease float64) bool { + return currObj <= initObj+decrease*step*initGrad } // StrongWolfeConditionsMet returns true if the strong Wolfe conditions have been met. @@ -195,12 +195,12 @@ func ArmijoConditionMet(currObj, initObj, initGrad, step, funcConst float64) boo // enforced: // - initGrad < 0 // - step > 0 -// - 0 <= funcConst < gradConst < 1 -func StrongWolfeConditionsMet(currObj, currGrad, initObj, initGrad, step, funcConst, gradConst float64) bool { - if currObj > initObj+funcConst*step*initGrad { +// - 0 <= decrease < curvature < 1 +func StrongWolfeConditionsMet(currObj, currGrad, initObj, initGrad, step, decrease, curvature float64) bool { + if currObj > initObj+decrease*step*initGrad { return false } - return math.Abs(currGrad) < gradConst*math.Abs(initGrad) + return math.Abs(currGrad) < curvature*math.Abs(initGrad) } // WeakWolfeConditionsMet returns true if the weak Wolfe conditions have been met. @@ -209,10 +209,10 @@ func StrongWolfeConditionsMet(currObj, currGrad, initObj, initGrad, step, funcCo // conditions, the following should be true, though this is not enforced: // - initGrad < 0 // - step > 0 -// - 0 <= funcConst < gradConst < 1 -func WeakWolfeConditionsMet(currObj, currGrad, initObj, initGrad, step, funcConst, gradConst float64) bool { - if currObj > initObj+funcConst*step*initGrad { +// - 0 <= decrease < curvature< 1 +func WeakWolfeConditionsMet(currObj, currGrad, initObj, initGrad, step, decrease, curvature float64) bool { + if currObj > initObj+decrease*step*initGrad { return false } - return currGrad >= gradConst*initGrad + return currGrad >= curvature*initGrad }