DirectionalDerivativeEvaluator.java

/*
 * Copyright (C) 2012 Alberto Irurueta Carro (alberto@irurueta.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.irurueta.numerical;

/**
 * This class evaluates a multidimensional function and obtains its gradient
 * along a line; such line is defined by an input point and a given direction.
 * Using provided input point and direction, the multidimensional function's
 * input parameters are determined, so they all lay on a line.
 */
public class DirectionalDerivativeEvaluator extends DirectionalEvaluator {

    /**
     * Listener to evaluate a multidimensional function's gradient.
     */
    private GradientFunctionEvaluatorListener gradientListener;

    /**
     * Array containing gradient at point p. This is used internally.
     */
    final double[] dft;

    /**
     * Constructor.
     *
     * @param listener         Listener to evaluate a multidimensional function.
     * @param gradientListener Listener to evaluate a multidimensional
     *                         function's gradient.
     * @param point            Point used as a reference to determine the function's input
     *                         parameters along a line.
     * @param direction        Vector indicating the direction of the line where the
     *                         function is evaluated.
     * @throws IllegalArgumentException Raised if point and direction don't have
     *                                  the same length.
     */
    public DirectionalDerivativeEvaluator(
            final MultiDimensionFunctionEvaluatorListener listener,
            final GradientFunctionEvaluatorListener gradientListener, final double[] point, final double[] direction) {
        super(listener, point, direction);

        this.gradientListener = gradientListener;
        dft = new double[point.length];
    }

    /**
     * Returns gradient listener that evaluates a multidimensional function
     * gradient.
     * If the gradient expression is not known (e.g. is not a closed
     * expression), then a GradientEstimator can be used internally in the
     * listener implementation.
     *
     * @return Gradient listener.
     */
    public GradientFunctionEvaluatorListener getGradientListener() {
        return gradientListener;
    }

    /**
     * Sets gradient listener that evaluates a multidimensional function
     * gradient.
     * If the gradient expression is not known (e.g. is not a closed
     * expression), then a GradientEstimator can be used internally in the
     * listener implementation being provided.
     *
     * @param gradientListener Gradient listener
     */
    public void setGradientListener(final GradientFunctionEvaluatorListener gradientListener) {
        this.gradientListener = gradientListener;
    }

    /**
     * Computes derivative on current direction of a function at distance x from
     * current point and using current listener and gradient listener.
     *
     * @param x Distance from current point using current direction where
     *          function is being evaluated.
     * @return Result of evaluating function.
     * @throws EvaluationException Thrown if function evaluation fails.
     */
    public double differentiateAt(final double x) throws EvaluationException {
        final var length = point.length;

        for (var i = 0; i < length; i++) {
            p[i] = point[i] + x * direction[i];
        }

        // Compute gradient at such point
        gradientListener.evaluateGradient(p, dft);

        // Obtain 1D derivative on corresponding direction
        var df1 = 0.0;
        for (var i = 0; i < length; i++) {
            df1 += dft[i] * direction[i];
        }
        return df1;
    }
}