/* RISO: an implementation of distributed belief networks.
* Copyright (C) 1999, Robert Dodier.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307, USA,
* or visit the GNU web site, www.gnu.org.
*/
package riso.numerical;
import java.io.*;
import riso.general.*;
public class FunctionCache extends TopDownSplayTree implements Callback_1d
{
/** If the interval containing <tt>x</tt> is this small or
* smaller, we can carry out the interpolation.
*/
public double close_enough = 1e-1;
/** If the estimated error from the interpolation is greater than this,
* then reject the interpolated value and compute a new one the hard way.
* IGNORED AT PRESENT; WILL USE WITH RATIONAL INTERPOLATION SCHEME !!!
*/
public double error_tolerance = 1e-4;
/** This is the function cached by this object.
*/
public Callback_1d target;
/** Sets the parameters for this function cache.
* @param close_enough Pass in -1 to use default value.
* @param error_tolerance Pass in -1 to use default value.
* @param target The function to approximate.
*/
public FunctionCache( double close_enough, double error_tolerance, Callback_1d target )
{
if ( close_enough > 0 ) this.close_enough = close_enough;
if ( close_enough > 0 ) this.error_tolerance = error_tolerance;
this.target = target;
}
/** Return a function value, either from the cache or newly computed.
* This method does nothing more than call <tt>lookup</tt>.
*/
public double f( double x ) throws Exception { return lookup(x); }
/** Compute a new function value, cache it, and return it.
*/
public double cache_new_value( double x ) throws Exception
{
double fx = target.f( x );
insert( x, fx );
// System.err.println( "FunctionCache.cache_new_value: x: "+x+" fx: "+fx );
if ( size % 400 == 0 ) System.err.println( "FunctionCache.cache_new_value: size now: "+size );
// if ( size % 1000 == 0 )
// { double[][] xy = dump();
// System.err.println( size+" pairs in FunctionCache: " );
// for ( int i = 0; i < xy.length; i++ )
// System.err.println( "x: "+xy[i][0]+" y: "+xy[i][1] ); }
return fx;
}
/** See if we can generate a value by interpolation;
* failing that, compute the function value, cache it,
* and return it.
*/
public double lookup( double x ) throws Exception
{
if ( root == null ) return cache_new_value( x );
root = TopDownSplayTree.splay( x, root );
TopDownSplayTree.TreeNode a, b;
if ( x > root.key )
{
if ( root.right == null ) return cache_new_value( x );
a = root;
b = TopDownSplayTree.min( root.right );
}
else if ( x < root.key )
{
if ( root.left == null ) return cache_new_value( x );
a = TopDownSplayTree.max( root.left );
b = root;
}
else
{
// System.err.println( "FunctionCache.lookup: exact match at "+x+"; return "+root.value );
return root.value;
}
double da = x-a.key, dab = b.key-a.key;
if ( dab < 0 ) throw new RuntimeException( "FunctionCache.lookup: dab: "+dab+" < 0." );
// If we're in a small interval (which should give us
// an accurate interpolation) return interpolated value.
if ( dab < close_enough )
{
double interpolated_value = (1-da/dab)*a.value + da/dab*b.value;
// System.err.println( "FunctionCache.lookup: interpolate at "+x+"; return "+interpolated_value );
return interpolated_value;
}
else
{
return cache_new_value( x );
}
}
}