Added a wrapper class to compute Jacobian from differentiable function.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1383886 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2012-09-12 11:23:23 +00:00
parent 88678b58a4
commit 84f92e1928
2 changed files with 167 additions and 0 deletions

View File

@ -0,0 +1,71 @@
/*
* 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.math3.analysis.differentiation;
import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
/** Class representing the Jacobian of a multivariate vector function.
* <p>
* The rows iterate on the model functions while the columns iterate on the parameters; thus,
* the numbers of rows is equal to the dimension of the underlying function vector
* value and the number of columns is equal to the number of free parameters of
* the underlying function.
* </p>
* @version $Id$
* @since 3.1
*/
public class JacobianFunction implements MultivariateMatrixFunction {
/** Underlying vector-valued function. */
private final MultivariateDifferentiableVectorFunction f;
/** Simple constructor.
* @param f underlying vector-valued function
*/
public JacobianFunction(final MultivariateDifferentiableVectorFunction f) {
this.f = f;
}
/** {@inheritDoc} */
public double[][] value(double[] point)
throws IllegalArgumentException {
// set up parameters
final DerivativeStructure[] dsX = new DerivativeStructure[point.length];
for (int i = 0; i < point.length; ++i) {
dsX[i] = new DerivativeStructure(point.length, 1, i, point[i]);
}
// compute the derivatives
final DerivativeStructure[] dsY = f.value(dsX);
// extract the Jacobian
final double[][] y = new double[dsY.length][point.length];
final int[] orders = new int[point.length];
for (int i = 0; i < dsY.length; ++i) {
for (int j = 0; j < point.length; ++j) {
orders[j] = 1;
y[i][j] = dsY[i].getPartialDerivative(orders);
orders[j] = 0;
}
}
return y;
}
}

View File

@ -0,0 +1,96 @@
/*
* 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.math3.analysis.differentiation;
import junit.framework.Assert;
import org.apache.commons.math3.TestUtils;
import org.apache.commons.math3.util.FastMath;
import org.junit.Test;
/**
* Test for class {@link JacobianFunction}.
*/
public class JacobianFunctionTest {
@Test
public void testSphere() {
SphereMapping f = new SphereMapping(10.0);
JacobianFunction j = new JacobianFunction(f);
for (double latitude = -1.5; latitude < 1.5; latitude += 0.1) {
for (double longitude = -3.1; longitude < 3.1; longitude += 0.1) {
double[] point = new double[] { latitude, longitude };
double[][] referenceJacobian = f.jacobian(point);
double[][] testJacobian = j.value(point);
Assert.assertEquals(referenceJacobian.length, testJacobian.length);
for (int i = 0; i < 3; ++i) {
TestUtils.assertEquals(referenceJacobian[i], testJacobian[i], 2.0e-15);
}
}
}
}
/* Maps (latitude, longitude) to (x, y, z) */
private static class SphereMapping implements MultivariateDifferentiableVectorFunction {
private final double radius;
public SphereMapping(final double radius) {
this.radius = radius;
}
public double[] value(double[] point) {
final double cLat = FastMath.cos(point[0]);
final double sLat = FastMath.sin(point[0]);
final double cLon = FastMath.cos(point[1]);
final double sLon = FastMath.sin(point[1]);
return new double[] {
radius * cLon * cLat,
radius * sLon * cLat,
radius * sLat
};
}
public DerivativeStructure[] value(DerivativeStructure[] point) {
final DerivativeStructure cLat = point[0].cos();
final DerivativeStructure sLat = point[0].sin();
final DerivativeStructure cLon = point[1].cos();
final DerivativeStructure sLon = point[1].sin();
return new DerivativeStructure[] {
cLon.multiply(cLat).multiply(radius),
sLon.multiply(cLat).multiply(radius),
sLat.multiply(radius)
};
}
public double[][] jacobian(double[] point) {
final double cLat = FastMath.cos(point[0]);
final double sLat = FastMath.sin(point[0]);
final double cLon = FastMath.cos(point[1]);
final double sLon = FastMath.sin(point[1]);
return new double[][] {
{ -radius * cLon * sLat, -radius * sLon * cLat },
{ -radius * sLon * sLat, radius * cLon * cLat },
{ radius * cLat, 0 }
};
}
}
}