/*
* File: LineBracketInterpolatorGoldenSection.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright Jun 16, 2008, Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the U.S. Government.
* Export of this program may require a license from the United States
* Government. See CopyrightHistory.txt for complete details.
*
*/
package gov.sandia.cognition.learning.algorithm.minimization.line.interpolator;
import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationReferences;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.evaluator.Evaluator;
import gov.sandia.cognition.learning.algorithm.minimization.line.LineBracket;
import gov.sandia.cognition.learning.data.InputOutputPair;
/**
* Interpolates between the two bound points of a LineBracket using the
* golden-section step rule, if that step fails, then the interpolator uses
* a linear (secant) interpolation. Neither of the bound points in the
* LineBracket need slope information.
* @author Kevin R. Dixon
* @since 2.1
*/
@PublicationReferences(
references={
@PublicationReference(
author="Wikipedia",
title="Golden section search",
type=PublicationType.WebPage,
url="http://en.wikipedia.org/wiki/Golden_section_search",
year=2008
),
@PublicationReference(
author={
"Jeffrey Naisbitt",
"Michael Heath"
},
title="Golden Section Search",
type=PublicationType.WebPage,
url="http://www.cse.uiuc.edu/iem/optimization/GoldenSection/",
year=2008
),
@PublicationReference(
author={
"William H. Press",
"Saul A. Teukolsky",
"William T. Vetterling",
"Brian P. Flannery"
},
title="Numerical Recipes in C, Second Edition",
type=PublicationType.Book,
year=1992,
pages={401,402},
url="http://www.nrbook.com/a/bookcpdf.php"
)
}
)
public class LineBracketInterpolatorGoldenSection
extends AbstractLineBracketInterpolator<Evaluator<Double,Double>>
{
/**
* Back-up interpolator using the secant method.
*/
private LineBracketInterpolatorLinear linearInterpolator;
/**
* Golden ratio, from the Fibonacci sequence, {@value}
*/
public final static double GOLDEN_RATIO = 1.618034;
/**
* The Golden Ratio conjugate, {@value}
*/
public final static double GOLDEN_RATIO_CONJUGATE = GOLDEN_RATIO - 1.0;
/**
* Creates a new instance of LineBracketInterpolatorGoldenSection
*/
public LineBracketInterpolatorGoldenSection()
{
super( DEFAULT_TOLERANCE );
this.linearInterpolator = new LineBracketInterpolatorLinear();
}
public double findMinimum(
LineBracket bracket,
double minx,
double maxx,
Evaluator<Double, Double> function )
{
double x = LineBracketInterpolatorGoldenSection.step(
bracket.getLowerBound(), bracket.getUpperBound(), this.getTolerance() );
// Make sure that "x" is between the required interval
if( (minx <= x) && (x <= maxx) )
{
return x;
}
// Shoot... we're not inside the require interval,
// so let's throw an exception. Not sure if there's a better way to
// handle it, other than trying out each boundary and seeing which is
// better.
else
{
// I know... let's interpolate using a linear interpolator!
return this.linearInterpolator.findMinimum( bracket, minx, maxx, function );
}
}
/**
* Takes a Golden Section step between the two points
* @param a First point
* @param b Second point
* @param tolerance Minimum below which to consider the points identical.
* @return
* Interpolated Golden Section step between the two points
*/
public static double step(
InputOutputPair<Double,Double> a,
InputOutputPair<Double,Double> b,
double tolerance )
{
double x;
double delta = b.getInput() - a.getInput();
if( Math.abs( delta ) < tolerance )
{
throw new IllegalArgumentException(
"Golden section delta has effectively collapsed: " + delta );
}
if (a.getOutput() < b.getOutput())
{
x = a.getInput() + GOLDEN_RATIO_CONJUGATE * delta;
}
else
{
x = b.getInput() - GOLDEN_RATIO_CONJUGATE * delta;
}
return x;
}
/**
* Golden section step only needs the bounds to operate, so we'll just
* check to make sure they're not null.
* @param bracket
* LineBracket to consider
* @return
* True if both bounds are not null, false otherwise
*/
public boolean hasSufficientPoints(
LineBracket bracket )
{
return (bracket.getLowerBound() != null) &&
(bracket.getUpperBound() != null);
}
}