/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.math.function; import org.apache.commons.lang.Validate; import com.opengamma.analytics.math.differentiation.FiniteDifferenceType; /** * Parent class for a family of functions that take real arguments and return real values. The functionality of {@link Function1D} is * extended; this class allows arithmetic operations on functions and defines a derivative function. */ public abstract class DoubleFunction1D extends Function1D<Double, Double> { private static final double EPS = 1e-5; /** * Returns a function that calculates the first derivative. The method used * is central finite difference, with $\epsilon = 10^{-5}$. Implementing * classes can override this method to return a function that is the exact * functional representation of the first derivative. * @return A function that calculates the first derivative of this function */ public DoubleFunction1D derivative() { return derivative(FiniteDifferenceType.CENTRAL, EPS); } /** * Returns a function that calculates the first derivative. The method used * is finite difference, with the differencing type and $\epsilon$ as * arguments * @param differenceType The differencing type to use * @param eps The $\epsilon$ to use * @return A function that calculates the first derivative of this function */ public DoubleFunction1D derivative(final FiniteDifferenceType differenceType, final double eps) { Validate.notNull(differenceType, "difference type"); switch (differenceType) { case CENTRAL: return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return (DoubleFunction1D.this.evaluate(x + eps) - DoubleFunction1D.this.evaluate(x - eps)) / 2 / eps; } }; case BACKWARD: return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return (DoubleFunction1D.this.evaluate(x) - DoubleFunction1D.this.evaluate(x - eps)) / eps; } }; case FORWARD: return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return (DoubleFunction1D.this.evaluate(x + eps) - DoubleFunction1D.this.evaluate(x)) / eps; } }; default: throw new IllegalArgumentException("Unhandled FiniteDifferenceType " + differenceType); } } /** * For a DoubleFunction1D $g(x)$, adding a function $f(x)$ returns the * function $h(x) = f(x) + g(x)$. * @param f The function to add, not null * @return A function $h(x) = f(x) + g(x)$ */ public DoubleFunction1D add(final DoubleFunction1D f) { Validate.notNull(f, "f"); return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return DoubleFunction1D.this.evaluate(x) + f.evaluate(x); } }; } /** * For a DoubleFunction1D $g(x)$, adding a constant $a$ returns the function * $h(x) = g(x) + a$. * @param a The constant to add * @return A function $h(x) = g(x) + a$ */ public DoubleFunction1D add(final double a) { return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return DoubleFunction1D.this.evaluate(x) + a; } }; } /** * For a DoubleFunction1D $g(x)$, dividing by a function $f(x)$ returns the * function $h(x) = \frac{g(x)}{f(x)}$. * @param f The function to divide by, not null * @return A function $h(x) = \frac{f(x)}{g(x)}$ */ public DoubleFunction1D divide(final DoubleFunction1D f) { Validate.notNull(f, "f"); return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return DoubleFunction1D.this.evaluate(x) / f.evaluate(x); } }; } /** * For a DoubleFunction1D $g(x)$, dividing by a constant $a$ returns the * function $h(x) = \frac{g(x)}{a}$. * @param a The constant to add * @return A function $h(x) = \frac{g(x)}{a}$ */ public DoubleFunction1D divide(final double a) { return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return DoubleFunction1D.this.evaluate(x) / a; } }; } /** * For a DoubleFunction1D $g(x)$, multiplying by a function $f(x)$ returns * the function $h(x) = f(x) g(x)$. * @param f The function to multiply by, not null * @return A function $h(x) = f(x) g(x)$ */ public DoubleFunction1D multiply(final DoubleFunction1D f) { Validate.notNull(f, "f"); return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return DoubleFunction1D.this.evaluate(x) * f.evaluate(x); } }; } /** * For a DoubleFunction1D $g(x)$, multiplying by a constant $a$ returns the * function $h(x) = a g(x)$. * @param a The constant to add * @return A function $h(x) = a g(x)$ */ public DoubleFunction1D multiply(final double a) { return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return DoubleFunction1D.this.evaluate(x) * a; } }; } /** * For a DoubleFunction1D $g(x)$, subtracting a function $f(x)$ returns the * function $h(x) = f(x) - g(x)$. * @param f The function to subtract, not null * @return A function $h(x) = g(x) - f(x)$ */ public DoubleFunction1D subtract(final DoubleFunction1D f) { Validate.notNull(f, "f"); return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return DoubleFunction1D.this.evaluate(x) - f.evaluate(x); } }; } /** * For a DoubleFunction1D $g(x)$, subtracting a constant $a$ returns the * function $h(x) = g(x) - a$. * @param a The constant to add * @return A function $h(x) = g(x) - a$ */ public DoubleFunction1D subtract(final double a) { return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return DoubleFunction1D.this.evaluate(x) - a; } }; } /** * Converts a Function1D<Double, Double> into a DoubleFunction1D. * @param f The function to convert * @return The converted function */ public static DoubleFunction1D from(final Function1D<Double, Double> f) { Validate.notNull(f, "f"); return new DoubleFunction1D() { @Override public Double evaluate(final Double x) { return f.evaluate(x); } }; } }