DifferentiatorVectorMultivariateJacobianFunction.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.commons.math4.legacy.fitting.leastsquares;
import org.apache.commons.math4.legacy.analysis.MultivariateVectorFunction;
import org.apache.commons.math4.legacy.analysis.UnivariateVectorFunction;
import org.apache.commons.math4.legacy.analysis.differentiation.DerivativeStructure;
import org.apache.commons.math4.legacy.analysis.differentiation.UnivariateVectorFunctionDifferentiator;
import org.apache.commons.math4.legacy.linear.Array2DRowRealMatrix;
import org.apache.commons.math4.legacy.linear.ArrayRealVector;
import org.apache.commons.math4.legacy.linear.RealMatrix;
import org.apache.commons.math4.legacy.linear.RealVector;
import org.apache.commons.math4.legacy.core.Pair;
import java.util.Arrays;
/**
* A MultivariateJacobianFunction (a thing that requires a derivative)
* combined with the thing that can find derivatives.
*
* Can be used with a LeastSquaresProblem, a LeastSquaresFactory, or a LeastSquaresBuilder.
*/
public class DifferentiatorVectorMultivariateJacobianFunction implements MultivariateJacobianFunction {
/**
* The input function to find a jacobian for.
*/
private final MultivariateVectorFunction function;
/**
* The differentiator to use to find the jacobian.
*/
private final UnivariateVectorFunctionDifferentiator differentiator;
/**
* Build the jacobian function using a differentiator.
*
* @param function the function to turn into a jacobian
* @param differentiator the differentiator to find the derivative
*/
public DifferentiatorVectorMultivariateJacobianFunction(MultivariateVectorFunction function, UnivariateVectorFunctionDifferentiator differentiator) {
this.function = function;
this.differentiator = differentiator;
}
/** {@inheritDoc} */
@Override
public Pair<RealVector, RealMatrix> value(RealVector point) {
double[] testArray = point.toArray();
RealVector value = new ArrayRealVector(function.value(testArray));
RealMatrix jacobian = new Array2DRowRealMatrix(value.getDimension(), point.getDimension());
for(int column = 0; column < point.getDimension(); column++) {
final int columnFinal = column;
double originalPoint = point.getEntry(column);
double[] partialDerivatives = getPartialDerivative(testPoint -> {
testArray[columnFinal] = testPoint;
return function.value(testArray);
}, originalPoint);
testArray[column] = originalPoint; //set it back
jacobian.setColumn(column, partialDerivatives);
}
return new Pair<>(value, jacobian);
}
/**
* Returns first order derivative for the function passed in using a differentiator.
* @param univariateVectorFunction the function to differentiate
* @param atParameterValue the point at which to differentiate it at
* @return the slopes at that point
*/
private double[] getPartialDerivative(UnivariateVectorFunction univariateVectorFunction, double atParameterValue) {
DerivativeStructure[] derivatives = differentiator
.differentiate(univariateVectorFunction)
.value(new DerivativeStructure(1, 1, 0, atParameterValue));
return Arrays.stream(derivatives).mapToDouble(derivative -> derivative.getPartialDerivative(1)).toArray();
}
}