I am looking for a generic optimized lookup object that takes a function f(x) and creates a linear piecewise approximation with configurable parameters for the range of x and the intervals of population.
Obviously this is not hard to write, but given that it is useful for a lot of expensive functions (trig, yield, distance), I thought a generic one might already exist. Please let me know.
Another useful feature would be to serialize / deserialize the lookup table as a rather precise 100,000 point+ table can take several minutes to construct.
I don't believe anything exists in the .NET class libraries directly. Something may exist in a third party library (like C5 perhaps).
Creating a generic version of a function that can accept ranges is a bit tricky in C#, since there is no unifying type or interface which provides arithmetic operators. However, with some creativity, it's possible to craft something:
// generic linear lookup class, supports any comparable type T
public class LinearLookup<T> where T : IComparable<T>
{
private readonly List<T> m_DomainValues = new List<T>();
public LinearLookup( Func<T,T> domainFunc, Func<T,T> rangeFunc,
T lowerBound, T upperBound )
{
m_DomainValues = Range( domainFunc, rangeFunc,
lowerBound, upperBound )
.ToList();
}
public T Lookup( T rangeValue )
{
// this could be improved for numeric types
var index = m_DomainValues.BinarySearch( rangeValue );
if( index < 0 )
index = (-index)-1;
return m_DomainValues[index];
}
private static IEnumerable<T> Range( Func<T,T> domainFunc,
Func<T,T> rangeFunc, T lower, T upper )
{
var rangeVal = lower;
do
{
yield return domainFunc( rangeVal );
rangeVal = rangeFunc( rangeVal );
} while( rangeVal.CompareTo( upper ) < 0 );
}
}
This class will precompute a set of domain values for the function domainFunc
over the range [lower,upper>. It uses binary search for lookup - a compromise that allows any comparable type to be used - not just built in numeric types. The function rangeFunc
allows the increment to be controlled by external code. So, here's a linear lookup for Math.Sin
over the range [0,PI/2> with an increment of 0.01:
var sinLookup = new LinearLookup( Math.Sin, x => x + 0.01d, 0, Math.PI/2 );
var lookupPI4 = sinLookup[Math.PI/4]; // fetch the value sin(π/4)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With