All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.sandia.cognition.learning.algorithm.root.RootBracketExpander Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                RootBracketExpander.java
 * Authors:             Kevin R. Dixon
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Foundry
 * 
 * Copyright Feb 5, 2009, 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.root;

import gov.sandia.cognition.evaluator.Evaluator;
import gov.sandia.cognition.learning.algorithm.AbstractAnytimeBatchLearner;
import gov.sandia.cognition.learning.algorithm.minimization.line.InputOutputSlopeTriplet;
import gov.sandia.cognition.learning.algorithm.minimization.line.LineBracket;
import gov.sandia.cognition.learning.algorithm.minimization.line.interpolator.LineBracketInterpolatorGoldenSection;

/**
 * The root-bracketing expansion algorithm.  This function repeatedly expands
 * a root bracket about an initial guess until it finds a region where it
 * can be demonstrated that the function makes a zero-crossing (root).  The
 * algorithm can fail on functions where the function "kisses" zero, or
 * has a "notch" type look.
 * @author Kevin R. Dixon
 * @since 3.0
 */
public class RootBracketExpander
    extends AbstractAnytimeBatchLearner, LineBracket>
    implements RootBracketer
{

    /**
     * Default scale factor on expansion, the golden ratio, {@value}
     */
    public static final double SCALE_FACTOR = LineBracketInterpolatorGoldenSection.GOLDEN_RATIO;
    
    /**
     * Default max iterations, {@value}
     */
    public static final int DEFAULT_MAX_ITERATIONS = 100;
    
    /**
     * Default initial guess, {@value}
     */
    public static final double DEFAULT_INITIAL_GUESS = 0.0;
    
    /**
     * Bracket on the root location.
     */
    private LineBracket bracket;
    
    /**
     * Initial guess of the root's location.
     */
    private double initialGuess;
    
    /** 
     * Creates a new instance of RootBracketExpander 
     */
    public RootBracketExpander()
    {
        super( DEFAULT_MAX_ITERATIONS );
        this.setInitialGuess( DEFAULT_INITIAL_GUESS );
        this.setBracket( null );
    }

    @Override
    protected boolean initializeAlgorithm()
    {
        Evaluator f = this.data;
        double x0 = this.getInitialGuess();
        Double y0 = f.evaluate( x0 );
        InputOutputSlopeTriplet initial = new InputOutputSlopeTriplet(
            x0, y0, null );
        
        double x1 = x0 + SCALE_FACTOR;
//        double x1 = x0 + SCALE_FACTOR * y0;
        Double y1 = f.evaluate( x1 );
        InputOutputSlopeTriplet guess = new InputOutputSlopeTriplet(
            x1, y1, null );
        
        this.setBracket( new LineBracket( initial, guess, initial.clone() ) );
        
        return true;
                
    }

    @Override
    protected boolean step()
    {
        
        double x0 = this.getBracket().getLowerBound().getInput();
        double y0 = this.getBracket().getLowerBound().getOutput();
        
        double x1 = this.getBracket().getUpperBound().getInput();
        double y1 = this.getBracket().getUpperBound().getOutput();
        
        if( y0*y1 < 0.0 )
        {
            return false;
        }
        
        if( Math.abs(y0) < Math.abs(y1) )
        {
            x0 += SCALE_FACTOR * (x0-x1);
            y0 = this.data.evaluate( x0 );
            this.getBracket().getLowerBound().setInput( x0 );
            this.getBracket().getLowerBound().setOutput( y0 );
        }
        else
        {
            x1 += SCALE_FACTOR * (x1-x0);
            y1 = this.data.evaluate( x1 );
            this.getBracket().getUpperBound().setInput( x1 );
            this.getBracket().getUpperBound().setOutput( y1 );
        }

        // Keep going while the outputs are the same sign.
        // Stop when they've got opposite signs, then we definitely know
        // there's a root between them.
        return y0*y1 > 0.0;
        
    }

    @Override
    protected void cleanupAlgorithm()
    {
        
        // Make sure that a.x < b.x
        InputOutputSlopeTriplet a = this.getBracket().getLowerBound();
        InputOutputSlopeTriplet b = this.getBracket().getUpperBound();
        if( a.getInput() > b.getInput() )
        {
            this.getBracket().setLowerBound( b );
            this.getBracket().setUpperBound( a );
        }
        
        
    }

    public LineBracket getResult()
    {
        return this.getBracket();
    }

    @Override
    public boolean isResultValid()
    {
        return super.isResultValid() &&
            (this.getBracket().getLowerBound().getOutput() * this.getBracket().getUpperBound().getOutput() < 0.0);
    }
    
    /**
     * Getter for initialGuess.
     * @return
     * Initial guess of the root's location.
     */
    public double getInitialGuess()
    {
        return this.initialGuess;
    }

    public void setInitialGuess(
        double initialGuess )
    {
        this.initialGuess = initialGuess;
    }

    /**
     * Getter for bracket.
     * @return
     * Bracket on the root location.
     */
    public LineBracket getBracket()
    {
        return this.bracket;
    }

    /**
     * Setter for bracket.
     * @param bracket
     * Bracket on the root location.
     */
    protected void setBracket(
        LineBracket bracket )
    {
        this.bracket = bracket;
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy