Package com.opengamma.analytics.math.differentiation

Source Code of com.opengamma.analytics.math.differentiation.VectorFieldFirstOrderDifferentiator

/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.math.differentiation;

import org.apache.commons.lang.Validate;

import com.opengamma.analytics.math.MathException;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.util.ArgumentChecker;

/**
* Differentiates a vector field (i.e. there is a vector value for every point
* in some vector space) with respect to the vector space using finite
* difference.
* <p>
* For a function $\mathbf{y} = f(\mathbf{x})$ where $\mathbf{x}$ is a
* n-dimensional vector and $\mathbf{y}$ is a m-dimensional vector, this class
* produces the Jacobian function $\mathbf{J}(\mathbf{x})$, i.e. a function
* that returns the Jacobian for each point $\mathbf{x}$, where
* $\mathbf{J}$ is the $m \times n$ matrix $\frac{dy_i}{dx_j}$
*/
public class VectorFieldFirstOrderDifferentiator implements Differentiator<DoubleMatrix1D, DoubleMatrix1D, DoubleMatrix2D> {
  private static final double DEFAULT_EPS = 1e-5;
  private static final FiniteDifferenceType DIFF_TYPE = FiniteDifferenceType.CENTRAL;

  private final double _eps;
  private final double _twoEps;
  private final FiniteDifferenceType _differenceType;

  /**
   * Uses the default values of differencing type (central) and eps (1e-5).
   */
  public VectorFieldFirstOrderDifferentiator() {
    this(DIFF_TYPE, DEFAULT_EPS);
  }

  /**
   * Uses the default value of eps (10<sup>-5</sup>)
   * @param differenceType The differencing type to be used in calculating the gradient function
   */
  public VectorFieldFirstOrderDifferentiator(final FiniteDifferenceType differenceType) {
    this(differenceType, DEFAULT_EPS);
  }

  /**
   * Approximates the derivative of a vector function by finite difference. If the size of the domain is very small or very large, consider re-scaling first.
   * @param differenceType {@link FiniteDifferenceType#FORWARD}, {@link FiniteDifferenceType#BACKWARD}, or {@link FiniteDifferenceType#CENTRAL}. In most situations,
   * {@link FiniteDifferenceType#CENTRAL} is preferable. Not null
   * @param eps The step size used to approximate the derivative. If this value is too small, the result will most likely be dominated by noise.
   * Use around 10<sup>-5</sup> times the domain size.
   */
  public VectorFieldFirstOrderDifferentiator(final FiniteDifferenceType differenceType, final double eps) {
    Validate.notNull(differenceType);
    _differenceType = differenceType;
    _eps = eps;
    _twoEps = 2 * _eps;
  }

  /**
   * Approximates the derivative of a vector function by finite difference. If the size of the domain is very small or very large, consider re-scaling first.
   * @param eps The step size used to approximate the derivative. If this value is too small, the result will most likely be dominated by noise.
   * Use around 10<sup>-5</sup> times the domain size.
   */
  public VectorFieldFirstOrderDifferentiator(final double eps) {
    this(DIFF_TYPE, eps);
  }

  @Override
  public Function1D<DoubleMatrix1D, DoubleMatrix2D> differentiate(final Function1D<DoubleMatrix1D, DoubleMatrix1D> function) {
    Validate.notNull(function);
    switch (_differenceType) {
      case FORWARD:
        return new Function1D<DoubleMatrix1D, DoubleMatrix2D>() {

          @SuppressWarnings("synthetic-access")
          @Override
          public DoubleMatrix2D evaluate(final DoubleMatrix1D x) {
            Validate.notNull(x, "x");
            final DoubleMatrix1D y = function.evaluate(x);
            final int n = x.getNumberOfElements();
            final int m = y.getNumberOfElements();
            final double[] xData = x.getData();
            double oldValue;
            final double[][] res = new double[m][n];
            int i, j;
            DoubleMatrix1D up;
            for (j = 0; j < n; j++) {
              oldValue = xData[j];
              xData[j] += _eps;
              up = function.evaluate(x);
              for (i = 0; i < m; i++) {
                res[i][j] = (up.getEntry(i) - y.getEntry(i)) / _eps;
              }
              xData[j] = oldValue;
            }
            return new DoubleMatrix2D(res);
          }
        };
      case CENTRAL:
        return new Function1D<DoubleMatrix1D, DoubleMatrix2D>() {

          @SuppressWarnings("synthetic-access")
          @Override
          public DoubleMatrix2D evaluate(final DoubleMatrix1D x) {
            Validate.notNull(x, "x");
            final DoubleMatrix1D y = function.evaluate(x); // need this unused evaluation to get size of y
            final int n = x.getNumberOfElements();
            final int m = y.getNumberOfElements();
            final double[] xData = x.getData();
            double oldValue;
            final double[][] res = new double[m][n];
            int i, j;
            DoubleMatrix1D up, down;
            for (j = 0; j < n; j++) {
              oldValue = xData[j];
              xData[j] += _eps;
              up = function.evaluate(x);
              xData[j] -= _twoEps;
              down = function.evaluate(x);
              for (i = 0; i < m; i++) {
                res[i][j] = (up.getEntry(i) - down.getEntry(i)) / _twoEps;
              }
              xData[j] = oldValue;
            }
            return new DoubleMatrix2D(res);
          }
        };
      case BACKWARD:
        return new Function1D<DoubleMatrix1D, DoubleMatrix2D>() {

          @SuppressWarnings("synthetic-access")
          @Override
          public DoubleMatrix2D evaluate(final DoubleMatrix1D x) {
            Validate.notNull(x, "x");
            final DoubleMatrix1D y = function.evaluate(x);
            final int n = x.getNumberOfElements();
            final int m = y.getNumberOfElements();
            final double[] xData = x.getData();
            double oldValue;
            final double[][] res = new double[m][n];
            int i, j;
            DoubleMatrix1D down;
            for (j = 0; j < n; j++) {
              oldValue = xData[j];
              xData[j] -= _eps;
              down = function.evaluate(x);
              for (i = 0; i < m; i++) {
                res[i][j] = (y.getEntry(i) - down.getEntry(i)) / _eps;
              }
              xData[j] = oldValue;
            }
            return new DoubleMatrix2D(res);
          }
        };
      default:
        throw new IllegalArgumentException("Can only handle forward, backward and central differencing");
    }
  }

  @Override
  public Function1D<DoubleMatrix1D, DoubleMatrix2D> differentiate(final Function1D<DoubleMatrix1D, DoubleMatrix1D> function, final Function1D<DoubleMatrix1D, Boolean> domain) {
    Validate.notNull(function);
    Validate.notNull(domain);

    final double[] wFwd = new double[] {-3., 4., -1. };
    final double[] wCent = new double[] {-1., 0., 1. };
    final double[] wBack = new double[] {1., -4., 3. };

    return new Function1D<DoubleMatrix1D, DoubleMatrix2D>() {

      @SuppressWarnings("synthetic-access")
      @Override
      public DoubleMatrix2D evaluate(final DoubleMatrix1D x) {
        Validate.notNull(x, "x");
        ArgumentChecker.isTrue(domain.evaluate(x), "point {} is not in the function domain", x.toString());

        final DoubleMatrix1D mid = function.evaluate(x); // need this unused evaluation to get size of y
        final int n = x.getNumberOfElements();
        final int m = mid.getNumberOfElements();
        final double[] xData = x.getData();
        double oldValue;
        final double[][] res = new double[m][n];
        int i, j;
        final DoubleMatrix1D[] y = new DoubleMatrix1D[3];
        double[] w;

        for (j = 0; j < n; j++) {
          oldValue = xData[j];
          xData[j] += _eps;
          if (!domain.evaluate(x)) {
            xData[j] = oldValue - _twoEps;
            if (!domain.evaluate(x)) {
              throw new MathException("cannot get derivative at point " + x.toString() + " in direction " + j);
            }
            y[2] = mid;
            y[0] = function.evaluate(x);
            xData[j] = oldValue - _eps;
            y[1] = function.evaluate(x);
            w = wBack;
          } else {
            final DoubleMatrix1D temp = function.evaluate(x);
            xData[j] = oldValue - _eps;
            if (!domain.evaluate(x)) {
              y[0] = mid;
              y[1] = temp;
              xData[j] = oldValue + _twoEps;
              y[2] = function.evaluate(x);
              w = wFwd;
            } else {
              y[2] = temp;
              xData[j] = oldValue - _eps;
              y[0] = function.evaluate(x);
              y[1] = mid;
              w = wCent;
            }
          }

          for (i = 0; i < m; i++) {
            double sum = 0;
            for (int k = 0; k < 3; k++) {
              if (w[k] != 0.0) {
                sum += w[k] * y[k].getEntry(i);
              }
            }
            res[i][j] = sum / _twoEps;
          }
          xData[j] = oldValue;
        }
        return new DoubleMatrix2D(res);
      }
    };

  }

}
TOP

Related Classes of com.opengamma.analytics.math.differentiation.VectorFieldFirstOrderDifferentiator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.