001package models;
002
003import java.util.SortedMap;
004import java.util.TreeMap;
005import java.util.Comparator;
006
007import org.apache.commons.math3.analysis.UnivariateFunction;
008
009/**
010 * A univariate real function that caches previous evaluations, 
011 * so that they can be returned faster if the function is evaluated
012 * at the same point several times.
013 * 
014 * The actual function to be evaluated is passed to the constructor
015 * as a <code>UnivariateFunction</code> object   
016 */
017public class CachedFunction implements UnivariateFunction
018{
019    private SortedMap<Double,Double> cache;
020    private long cacheHits = 0;
021    private long evaluations = 0;
022    private UnivariateFunction f;
023
024    /**
025     * Constructs a cached function, using a given function f for obtaining the actual values of the function.
026     * 
027     * For the purposes of caching, two arguments of the function will be considered equal if they are closer than
028     * the given precision <code>epsilon</code>. That is, the function may return the same value for two arguments
029     * that are closed that <code>epsilon</code>.
030     * 
031     * @param f the function to be cached
032     * @param epsilon the precision used for caching, see above
033     */
034    public CachedFunction(UnivariateFunction f, final double epsilon) {
035        
036        this.f = f;
037        
038        Comparator<Double> epsComp = new Comparator<Double>(){
039                        public int compare(Double d1, Double d2) {
040                                if (Math.abs(d1-d2) < epsilon) {
041                                        return 0;
042                                } else if (d1 > d2) {
043                                        return 1;
044                                } else {
045                                        return -1;
046                                }
047                        }                               
048        };
049
050        cache = new TreeMap<Double,Double>(epsComp);
051    }
052
053    
054    public double value(double x) {
055        Double cached = cache.get(x);
056        if (cached != null) {
057                cacheHits++;
058                return cached;
059        } else {                
060                evaluations++;
061                double val = f.value(x);
062                cache.put(x, val);
063            return val;
064        }       
065    }
066
067    /**
068     * Retrieve the number of cache hits, that is, the number of times that an evaluation of the function was actually
069     * done using the cache. This is for testing purposes only.
070     * 
071     * @return the number of cache hits
072     */
073    public long getCacheHits() {
074        return cacheHits;
075    }
076
077}