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}