Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsIntegrator.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsIntegrator.java?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsIntegrator.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsIntegrator.java Sun Sep 25 15:04:39 2011 @@ -20,7 +20,7 @@ package org.apache.commons.math.ode.nons import org.apache.commons.math.exception.MathIllegalArgumentException; import org.apache.commons.math.exception.MathIllegalStateException; import org.apache.commons.math.linear.Array2DRowRealMatrix; -import org.apache.commons.math.ode.FirstOrderDifferentialEquations; +import org.apache.commons.math.ode.ExpandableFirstOrderDifferentialEquations; import org.apache.commons.math.ode.MultistepIntegrator; @@ -86,7 +86,7 @@ public abstract class AdamsIntegrator ex /** {@inheritDoc} */ @Override - public abstract double integrate(final FirstOrderDifferentialEquations equations, + public abstract double integrate(final ExpandableFirstOrderDifferentialEquations equations, final double t0, final double[] y0, final double t, final double[] y) throws MathIllegalStateException, MathIllegalArgumentException;
Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsMoultonIntegrator.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsMoultonIntegrator.java?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsMoultonIntegrator.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdamsMoultonIntegrator.java Sun Sep 25 15:04:39 2011 @@ -23,7 +23,7 @@ import org.apache.commons.math.exception import org.apache.commons.math.exception.MathIllegalStateException; import org.apache.commons.math.linear.Array2DRowRealMatrix; import org.apache.commons.math.linear.RealMatrixPreservingVisitor; -import org.apache.commons.math.ode.FirstOrderDifferentialEquations; +import org.apache.commons.math.ode.ExpandableFirstOrderDifferentialEquations; import org.apache.commons.math.ode.sampling.NordsieckStepInterpolator; import org.apache.commons.math.ode.sampling.StepHandler; import org.apache.commons.math.util.FastMath; @@ -206,24 +206,29 @@ public class AdamsMoultonIntegrator exte /** {@inheritDoc} */ @Override - public double integrate(final FirstOrderDifferentialEquations equations, - final double t0, final double[] y0, - final double t, final double[] y) + public double integrate(final ExpandableFirstOrderDifferentialEquations equations, + final double t0, final double[] z0, + final double t, final double[] z) throws MathIllegalStateException, MathIllegalArgumentException { - final int n = y0.length; - sanityChecks(equations, t0, y0, t, y); + sanityChecks(equations, t0, z0, t, z); setEquations(equations); resetEvaluations(); final boolean forward = t > t0; // initialize working arrays + final int totalDim = equations.getDimension(); + final int mainDim = equations.getMainSetDimension(); + final double[] y0 = new double[totalDim]; + final double[] y = new double[totalDim]; + System.arraycopy(z0, 0, y0, 0, mainDim); + System.arraycopy(equations.getCurrentAdditionalStates(), 0, y0, mainDim, totalDim - mainDim); if (y != y0) { - System.arraycopy(y0, 0, y, 0, n); + System.arraycopy(y0, 0, y, 0, totalDim); } - final double[] yDot = new double[y0.length]; - final double[] yTmp = new double[y0.length]; - final double[] predictedScaled = new double[y0.length]; + final double[] yDot = new double[totalDim]; + final double[] yTmp = new double[totalDim]; + final double[] predictedScaled = new double[totalDim]; Array2DRowRealMatrix nordsieckTmp = null; // set up two interpolators sharing the integrator arrays @@ -290,7 +295,7 @@ public class AdamsMoultonIntegrator exte updateHighOrderDerivativesPhase2(predictedScaled, correctedScaled, nordsieckTmp); // discrete events handling - System.arraycopy(yTmp, 0, y, 0, n); + System.arraycopy(yTmp, 0, y, 0, totalDim); interpolator.reinitialize(stepEnd, stepSize, correctedScaled, nordsieckTmp); interpolator.storeTime(stepStart); interpolator.shift(); @@ -330,6 +335,10 @@ public class AdamsMoultonIntegrator exte } while (!isLastStep); + // dispatch result between main and additional states + System.arraycopy(y, 0, z, 0, z.length); + equations.setCurrentAdditionalState(y); + final double stopTime = stepStart; stepStart = Double.NaN; stepSize = Double.NaN; Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdaptiveStepsizeIntegrator.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdaptiveStepsizeIntegrator.java?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdaptiveStepsizeIntegrator.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/AdaptiveStepsizeIntegrator.java Sun Sep 25 15:04:39 2011 @@ -23,7 +23,7 @@ import org.apache.commons.math.exception import org.apache.commons.math.exception.NumberIsTooSmallException; import org.apache.commons.math.exception.util.LocalizedFormats; import org.apache.commons.math.ode.AbstractIntegrator; -import org.apache.commons.math.ode.ExtendedFirstOrderDifferentialEquations; +import org.apache.commons.math.ode.ExpandableFirstOrderDifferentialEquations; import org.apache.commons.math.ode.FirstOrderDifferentialEquations; import org.apache.commons.math.util.FastMath; @@ -42,12 +42,11 @@ import org.apache.commons.math.util.Fast * component. The user can also use only two scalar values absTol and * relTol which will be used for all components. * </p> - * - * <p>If the Ordinary Differential Equations is an {@link ExtendedFirstOrderDifferentialEquations - * extended ODE} rather than a {@link FirstOrderDifferentialEquations basic ODE}, - * then <em>only</em> the {@link ExtendedFirstOrderDifferentialEquations#getMainSetDimension() - * main set} part of the state vector is used for stepsize control, not the complete - * state vector. + * <p> + * If the Ordinary Differential Equations is an {@link ExpandableFirstOrderDifferentialEquations + * extended ODE} rather than a {@link FirstOrderDifferentialEquations basic ODE}, then + * <em>only</em> the {@link ExpandableFirstOrderDifferentialEquations#getMainSet() main part} + * of the state vector is used for stepsize control, not the complete state vector. * </p> * * <p>If the estimated error for ym+1 is such that @@ -224,18 +223,14 @@ public abstract class AdaptiveStepsizeIn * @exception NumberIsTooSmallException if integration span is too small */ @Override - protected void sanityChecks(final FirstOrderDifferentialEquations equations, + protected void sanityChecks(final ExpandableFirstOrderDifferentialEquations equations, final double t0, final double[] y0, final double t, final double[] y) throws DimensionMismatchException, NumberIsTooSmallException { super.sanityChecks(equations, t0, y0, t, y); - if (equations instanceof ExtendedFirstOrderDifferentialEquations) { - mainSetDimension = ((ExtendedFirstOrderDifferentialEquations) equations).getMainSetDimension(); - } else { - mainSetDimension = equations.getDimension(); - } + mainSetDimension = equations.getMainSetDimension(); if ((vecAbsoluteTolerance != null) && (vecAbsoluteTolerance.length != mainSetDimension)) { throw new DimensionMismatchException(mainSetDimension, vecAbsoluteTolerance.length); @@ -248,7 +243,6 @@ public abstract class AdaptiveStepsizeIn } /** Initialize the integration step. - * @param equations differential equations set * @param forward forward integration indicator * @param order order of the method * @param scale scaling vector for the state vector (can be shorter than state vector) @@ -259,8 +253,7 @@ public abstract class AdaptiveStepsizeIn * @param yDot1 work array for the first time derivative of y1 * @return first integration step */ - public double initializeStep(final FirstOrderDifferentialEquations equations, - final boolean forward, final int order, final double[] scale, + public double initializeStep(final boolean forward, final int order, final double[] scale, final double t0, final double[] y0, final double[] yDot0, final double[] y1, final double[] yDot1) { @@ -356,7 +349,7 @@ public abstract class AdaptiveStepsizeIn } /** {@inheritDoc} */ - public abstract double integrate (FirstOrderDifferentialEquations equations, + public abstract double integrate (ExpandableFirstOrderDifferentialEquations equations, double t0, double[] y0, double t, double[] y) throws MathIllegalStateException, MathIllegalArgumentException; Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java Sun Sep 25 15:04:39 2011 @@ -19,7 +19,7 @@ package org.apache.commons.math.ode.nons import org.apache.commons.math.exception.MathIllegalArgumentException; import org.apache.commons.math.exception.MathIllegalStateException; -import org.apache.commons.math.ode.FirstOrderDifferentialEquations; +import org.apache.commons.math.ode.ExpandableFirstOrderDifferentialEquations; import org.apache.commons.math.ode.sampling.StepHandler; import org.apache.commons.math.util.FastMath; @@ -189,24 +189,30 @@ public abstract class EmbeddedRungeKutta /** {@inheritDoc} */ @Override - public double integrate(final FirstOrderDifferentialEquations equations, - final double t0, final double[] y0, - final double t, final double[] y) + public double integrate(final ExpandableFirstOrderDifferentialEquations equations, + final double t0, final double[] z0, + final double t, final double[] z) throws MathIllegalStateException, MathIllegalArgumentException { - sanityChecks(equations, t0, y0, t, y); + sanityChecks(equations, t0, z0, t, z); setEquations(equations); resetEvaluations(); final boolean forward = t > t0; // create some internal working arrays + final int totalDim = equations.getDimension(); + final int mainDim = equations.getMainSetDimension(); + final double[] y0 = new double[totalDim]; + final double[] y = new double[totalDim]; + System.arraycopy(z0, 0, y0, 0, mainDim); + System.arraycopy(equations.getCurrentAdditionalStates(), 0, y0, mainDim, totalDim - mainDim); final int stages = c.length + 1; if (y != y0) { - System.arraycopy(y0, 0, y, 0, y0.length); + System.arraycopy(y0, 0, y, 0, totalDim); } - final double[][] yDotK = new double[stages][y0.length]; - final double[] yTmp = new double[y0.length]; - final double[] yDotTmp = new double[y0.length]; + final double[][] yDotK = new double[stages][totalDim]; + final double[] yTmp = new double[totalDim]; + final double[] yDotTmp = new double[totalDim]; // set up an interpolator sharing the integrator arrays final RungeKuttaStepInterpolator interpolator = (RungeKuttaStepInterpolator) prototype.copy(); @@ -248,7 +254,7 @@ public abstract class EmbeddedRungeKutta scale[i] = vecAbsoluteTolerance[i] + vecRelativeTolerance[i] * FastMath.abs(y[i]); } } - hNew = initializeStep(equations, forward, getOrder(), scale, + hNew = initializeStep(forward, getOrder(), scale, stepStart, y, yDotK[0], yTmp, yDotK[1]); firstTime = false; } @@ -325,6 +331,10 @@ public abstract class EmbeddedRungeKutta } while (!isLastStep); + // dispatch result between main and additional states + System.arraycopy(y, 0, z, 0, z.length); + equations.setCurrentAdditionalState(y); + final double stopTime = stepStart; resetInternalState(); return stopTime; Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java Sun Sep 25 15:04:39 2011 @@ -20,7 +20,7 @@ package org.apache.commons.math.ode.nons import org.apache.commons.math.analysis.solvers.UnivariateRealSolver; import org.apache.commons.math.exception.MathIllegalArgumentException; import org.apache.commons.math.exception.MathIllegalStateException; -import org.apache.commons.math.ode.FirstOrderDifferentialEquations; +import org.apache.commons.math.ode.ExpandableFirstOrderDifferentialEquations; import org.apache.commons.math.ode.events.EventHandler; import org.apache.commons.math.ode.sampling.AbstractStepInterpolator; import org.apache.commons.math.ode.sampling.StepHandler; @@ -541,26 +541,32 @@ public class GraggBulirschStoerIntegrato /** {@inheritDoc} */ @Override - public double integrate(final FirstOrderDifferentialEquations equations, - final double t0, final double[] y0, final double t, final double[] y) + public double integrate(final ExpandableFirstOrderDifferentialEquations equations, + final double t0, final double[] z0, final double t, final double[] z) throws MathIllegalStateException, MathIllegalArgumentException { - sanityChecks(equations, t0, y0, t, y); + sanityChecks(equations, t0, z0, t, z); setEquations(equations); resetEvaluations(); final boolean forward = t > t0; // create some internal working arrays - final double[] yDot0 = new double[y0.length]; - final double[] y1 = new double[y0.length]; - final double[] yTmp = new double[y0.length]; - final double[] yTmpDot = new double[y0.length]; + final int totalDim = equations.getDimension(); + final int mainDim = equations.getMainSetDimension(); + final double[] y0 = new double[totalDim]; + final double[] y = new double[totalDim]; + System.arraycopy(z0, 0, y0, 0, mainDim); + System.arraycopy(equations.getCurrentAdditionalStates(), 0, y0, mainDim, totalDim - mainDim); + final double[] yDot0 = new double[totalDim]; + final double[] y1 = new double[totalDim]; + final double[] yTmp = new double[totalDim]; + final double[] yTmpDot = new double[totalDim]; final double[][] diagonal = new double[sequence.length-1][]; final double[][] y1Diag = new double[sequence.length-1][]; for (int k = 0; k < sequence.length-1; ++k) { - diagonal[k] = new double[y0.length]; - y1Diag[k] = new double[y0.length]; + diagonal[k] = new double[totalDim]; + y1Diag[k] = new double[totalDim]; } final double[][][] fk = new double[sequence.length][][]; @@ -631,8 +637,7 @@ public class GraggBulirschStoerIntegrato } if (firstTime) { - hNew = initializeStep(equations, forward, - 2 * targetIter + 1, scale, + hNew = initializeStep(forward, 2 * targetIter + 1, scale, stepStart, y, yDot0, yTmp, yTmpDot); } Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/RungeKuttaIntegrator.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/RungeKuttaIntegrator.java?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/RungeKuttaIntegrator.java (original) +++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/ode/nonstiff/RungeKuttaIntegrator.java Sun Sep 25 15:04:39 2011 @@ -21,7 +21,7 @@ package org.apache.commons.math.ode.nons import org.apache.commons.math.exception.MathIllegalArgumentException; import org.apache.commons.math.exception.MathIllegalStateException; import org.apache.commons.math.ode.AbstractIntegrator; -import org.apache.commons.math.ode.FirstOrderDifferentialEquations; +import org.apache.commons.math.ode.ExpandableFirstOrderDifferentialEquations; import org.apache.commons.math.ode.sampling.StepHandler; import org.apache.commons.math.util.FastMath; @@ -90,17 +90,23 @@ public abstract class RungeKuttaIntegrat } /** {@inheritDoc} */ - public double integrate(final FirstOrderDifferentialEquations equations, - final double t0, final double[] y0, - final double t, final double[] y) + public double integrate(final ExpandableFirstOrderDifferentialEquations equations, + final double t0, final double[] z0, + final double t, final double[] z) throws MathIllegalStateException, MathIllegalArgumentException { - sanityChecks(equations, t0, y0, t, y); + sanityChecks(equations, t0, z0, t, z); setEquations(equations); resetEvaluations(); final boolean forward = t > t0; // create some internal working arrays + final int totalDim = equations.getDimension(); + final int mainDim = equations.getMainSetDimension(); + final double[] y0 = new double[totalDim]; + final double[] y = new double[totalDim]; + System.arraycopy(z0, 0, y0, 0, mainDim); + System.arraycopy(equations.getCurrentAdditionalStates(), 0, y0, mainDim, totalDim - mainDim); final int stages = c.length + 1; if (y != y0) { System.arraycopy(y0, 0, y, 0, y0.length); @@ -179,6 +185,10 @@ public abstract class RungeKuttaIntegrat } while (!isLastStep); + // dispatch result between main and additional states + System.arraycopy(y, 0, z, 0, z.length); + equations.setCurrentAdditionalState(y); + final double stopTime = stepStart; stepStart = Double.NaN; stepSize = Double.NaN; Modified: commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties (original) +++ commons/proper/math/trunk/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties Sun Sep 25 15:04:39 2011 @@ -279,6 +279,9 @@ UNABLE_TO_PERFORM_QR_DECOMPOSITION_ON_JA UNABLE_TO_SOLVE_SINGULAR_PROBLEM = r\u00e9solution impossible : probl\u00e8me singulier UNBOUNDED_SOLUTION = solution non born\u00e9e UNKNOWN_MODE = mode {0} inconnu, modes connus : {1} ({2}), {3} ({4}), {5} ({6}), {7} ({8}), {9} ({10}) et {11} ({12}) +UNKNOWN_ADDITIONAL_EQUATION = \u00e9quation additionnelle inconnue +UNKNOWN_PARAMETER = param\u00e8tre {0} inconnu +UNMATCHED_ODE_IN_EXTENDED_SET = l''\u00e9quation diff\u00e9rentielle ne correspond pas \u00e0 l''\u00e9quation principale du jeu \u00e9tendu CANNOT_PARSE_AS_TYPE = cha\u00eene {0} non analysable (\u00e0 partir de la position {1}) en un objet de type {2} CANNOT_PARSE = cha\u00eene {0} non analysable (\u00e0 partir de la position {1}) UNPARSEABLE_3D_VECTOR = vecteur 3D non analysable : "{0}" Modified: commons/proper/math/trunk/src/site/xdoc/changes.xml URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/site/xdoc/changes.xml?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/site/xdoc/changes.xml (original) +++ commons/proper/math/trunk/src/site/xdoc/changes.xml Sun Sep 25 15:04:39 2011 @@ -52,6 +52,12 @@ The <action> type attribute can be add,u If the output is not quite correct, check for invisible trailing spaces! --> <release version="3.0" date="TBD" description="TBD"> + <action dev="luc" type="fix" issue="MATH-380" due-to="Pascal Parraud"> + Completely revamped the computation of Jacobians in ODE. This computation is now + included in the mainstream class hierarchy, not in a separate package anymore, + and it allows adding other types of equations to a main ODE, not only variational + equations for Jacobians computation. + </action> <action dev="gregs" type="update" issue="MATH-607"> SimpleRegression implements UpdatingMultipleLinearRegression interface. </action> Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/JacobianMatricesTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/JacobianMatricesTest.java?rev=1175409&view=auto ============================================================================== --- commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/JacobianMatricesTest.java (added) +++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/JacobianMatricesTest.java Sun Sep 25 15:04:39 2011 @@ -0,0 +1,598 @@ +/* + * 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.math.ode; + +import org.apache.commons.math.ode.nonstiff.DormandPrince54Integrator; +import org.apache.commons.math.stat.descriptive.SummaryStatistics; +import org.apache.commons.math.util.FastMath; +import org.junit.Assert; +import org.junit.Test; + +public class JacobianMatricesTest { + + @Test + public void testLowAccuracyExternalDifferentiation() { + // this test does not really test FirstOrderIntegratorWithJacobians, + // it only shows that WITHOUT this class, attempting to recover + // the jacobians from external differentiation on simple integration + // results with low accuracy gives very poor results. In fact, + // the curves dy/dp = g(b) when b varies from 2.88 to 3.08 are + // essentially noise. + // This test is taken from Hairer, Norsett and Wanner book + // Solving Ordinary Differential Equations I (Nonstiff problems), + // the curves dy/dp = g(b) are in figure 6.5 + FirstOrderIntegrator integ = + new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 }); + double hP = 1.0e-12; + SummaryStatistics residualsP0 = new SummaryStatistics(); + SummaryStatistics residualsP1 = new SummaryStatistics(); + for (double b = 2.88; b < 3.08; b += 0.001) { + Brusselator brusselator = new Brusselator(b); + double[] y = { 1.3, b }; + integ.integrate(brusselator, 0, y, 20.0, y); + double[] yP = { 1.3, b + hP }; + integ.integrate(brusselator, 0, yP, 20.0, yP); + residualsP0.addValue((yP[0] - y[0]) / hP - brusselator.dYdP0()); + residualsP1.addValue((yP[1] - y[1]) / hP - brusselator.dYdP1()); + } + Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) > 500); + Assert.assertTrue(residualsP0.getStandardDeviation() > 30); + Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) > 700); + Assert.assertTrue(residualsP1.getStandardDeviation() > 40); + } + + @Test + public void testHighAccuracyExternalDifferentiation() { + FirstOrderIntegrator integ = + new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 }); + double hP = 1.0e-12; + SummaryStatistics residualsP0 = new SummaryStatistics(); + SummaryStatistics residualsP1 = new SummaryStatistics(); + for (double b = 2.88; b < 3.08; b += 0.001) { + ParamBrusselator brusselator = new ParamBrusselator(b); + double[] y = { 1.3, b }; + integ.integrate(brusselator, 0, y, 20.0, y); + double[] yP = { 1.3, b + hP }; + brusselator.setParameter("b", b + hP); + integ.integrate(brusselator, 0, yP, 20.0, yP); + residualsP0.addValue((yP[0] - y[0]) / hP - brusselator.dYdP0()); + residualsP1.addValue((yP[1] - y[1]) / hP - brusselator.dYdP1()); + } + Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) > 0.02); + Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.03); + Assert.assertTrue(residualsP0.getStandardDeviation() > 0.003); + Assert.assertTrue(residualsP0.getStandardDeviation() < 0.004); + Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) > 0.04); + Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.05); + Assert.assertTrue(residualsP1.getStandardDeviation() > 0.007); + Assert.assertTrue(residualsP1.getStandardDeviation() < 0.008); + } + + @Test + public void testInternalDifferentiation() { + ExpandableFirstOrderIntegrator integ = + new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 }); + double hP = 1.0e-12; + double hY = 1.0e-12; + SummaryStatistics residualsP0 = new SummaryStatistics(); + SummaryStatistics residualsP1 = new SummaryStatistics(); + for (double b = 2.88; b < 3.08; b += 0.001) { + ParamBrusselator brusselator = new ParamBrusselator(b); + brusselator.setParameter(ParamBrusselator.B, b); + double[] z = { 1.3, b }; + double[][] dZdZ0 = new double[2][2]; + double[] dZdP = new double[2]; + ExpandableFirstOrderDifferentialEquations efode = new ExpandableFirstOrderDifferentialEquations(brusselator); + JacobianMatrices jacob = new JacobianMatrices(efode, brusselator); + jacob.setParameterizedODE(brusselator); + jacob.selectParameters(ParamBrusselator.B); + jacob.setMainStateSteps(new double[] { hY, hY }); + jacob.setParameterStep(ParamBrusselator.B, hP); + jacob.setInitialParameterJacobian(ParamBrusselator.B, new double[] { 0.0, 1.0 }); + integ.setMaxEvaluations(5000); + integ.integrate(efode, 0, z, 20.0, z); + jacob.getCurrentMainSetJacobian(dZdZ0); + jacob.getCurrentParameterJacobian(ParamBrusselator.B, dZdP); +// Assert.assertEquals(5000, integ.getMaxEvaluations()); +// Assert.assertTrue(integ.getEvaluations() > 1500); +// Assert.assertTrue(integ.getEvaluations() < 2100); +// Assert.assertEquals(4 * integ.getEvaluations(), integ.getEvaluations()); + residualsP0.addValue(dZdP[0] - brusselator.dYdP0()); + residualsP1.addValue(dZdP[1] - brusselator.dYdP1()); + } + Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.02); + Assert.assertTrue(residualsP0.getStandardDeviation() < 0.003); + Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.05); + Assert.assertTrue(residualsP1.getStandardDeviation() < 0.01); + } + + @Test + public void testAnalyticalDifferentiation() { + ExpandableFirstOrderIntegrator integ = + new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-4, 1.0e-4 }, new double[] { 1.0e-4, 1.0e-4 }); + SummaryStatistics residualsP0 = new SummaryStatistics(); + SummaryStatistics residualsP1 = new SummaryStatistics(); + for (double b = 2.88; b < 3.08; b += 0.001) { + Brusselator brusselator = new Brusselator(b); + double[] z = { 1.3, b }; + double[][] dZdZ0 = new double[2][2]; + double[] dZdP = new double[2]; + ExpandableFirstOrderDifferentialEquations efode = new ExpandableFirstOrderDifferentialEquations(brusselator); + JacobianMatrices jacob = new JacobianMatrices(efode, brusselator); + jacob.setParameterJacobianProvider(brusselator); + jacob.selectParameters(Brusselator.B); + jacob.setInitialParameterJacobian(Brusselator.B, new double[] { 0.0, 1.0 }); + integ.setMaxEvaluations(5000); + integ.integrate(efode, 0, z, 20.0, z); + jacob.getCurrentMainSetJacobian(dZdZ0); + jacob.getCurrentParameterJacobian(Brusselator.B, dZdP); +// Assert.assertEquals(5000, integ.getMaxEvaluations()); +// Assert.assertTrue(integ.getEvaluations() > 350); +// Assert.assertTrue(integ.getEvaluations() < 510); + residualsP0.addValue(dZdP[0] - brusselator.dYdP0()); + residualsP1.addValue(dZdP[1] - brusselator.dYdP1()); + } + Assert.assertTrue((residualsP0.getMax() - residualsP0.getMin()) < 0.014); + Assert.assertTrue(residualsP0.getStandardDeviation() < 0.003); + Assert.assertTrue((residualsP1.getMax() - residualsP1.getMin()) < 0.05); + Assert.assertTrue(residualsP1.getStandardDeviation() < 0.01); + } + + @Test + public void testFinalResult() { + + ExpandableFirstOrderIntegrator integ = + new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 }); + double[] y = new double[] { 0.0, 1.0 }; + Circle circle = new Circle(y, 1.0, 1.0, 0.1); + + ExpandableFirstOrderDifferentialEquations efode = new ExpandableFirstOrderDifferentialEquations(circle); + JacobianMatrices jacob = new JacobianMatrices(efode, circle); + jacob.setParameterJacobianProvider(circle); + jacob.selectParameters(Circle.CX, Circle.CY, Circle.OMEGA); + jacob.setInitialMainStateJacobian(circle.exactDyDy0(0)); + jacob.setInitialParameterJacobian(Circle.CX, circle.exactDyDcx(0)); + jacob.setInitialParameterJacobian(Circle.CY, circle.exactDyDcy(0)); + jacob.setInitialParameterJacobian(Circle.OMEGA, circle.exactDyDom(0)); + integ.setMaxEvaluations(5000); + + double t = 18 * FastMath.PI; + integ.integrate(efode, 0, y, t, y); + for (int i = 0; i < y.length; ++i) { + Assert.assertEquals(circle.exactY(t)[i], y[i], 1.0e-9); + } + + double[][] dydy0 = new double[2][2]; + jacob.getCurrentMainSetJacobian(dydy0); + for (int i = 0; i < dydy0.length; ++i) { + for (int j = 0; j < dydy0[i].length; ++j) { + Assert.assertEquals(circle.exactDyDy0(t)[i][j], dydy0[i][j], 1.0e-9); + } + } + double[] dydcx = new double[2]; + jacob.getCurrentParameterJacobian(Circle.CX, dydcx); + for (int i = 0; i < dydcx.length; ++i) { + Assert.assertEquals(circle.exactDyDcx(t)[i], dydcx[i], 1.0e-7); + } + double[] dydcy = new double[2]; + jacob.getCurrentParameterJacobian(Circle.CY, dydcy); + for (int i = 0; i < dydcy.length; ++i) { + Assert.assertEquals(circle.exactDyDcy(t)[i], dydcy[i], 1.0e-7); + } + double[] dydom = new double[2]; + jacob.getCurrentParameterJacobian(Circle.OMEGA, dydom); + for (int i = 0; i < dydom.length; ++i) { + Assert.assertEquals(circle.exactDyDom(t)[i], dydom[i], 1.0e-7); + } + } + + @Test + public void testParameterizable() { + + ExpandableFirstOrderIntegrator integ = + new DormandPrince54Integrator(1.0e-8, 100.0, new double[] { 1.0e-10, 1.0e-10 }, new double[] { 1.0e-10, 1.0e-10 }); + double[] y = new double[] { 0.0, 1.0 }; + ParameterizedCircle pcircle = new ParameterizedCircle(y, 1.0, 1.0, 0.1); +// pcircle.setParameter(ParameterizedCircle.CX, 1.0); +// pcircle.setParameter(ParameterizedCircle.CY, 1.0); +// pcircle.setParameter(ParameterizedCircle.OMEGA, 0.1); + + ExpandableFirstOrderDifferentialEquations efode = new ExpandableFirstOrderDifferentialEquations(pcircle); + + double hP = 1.0e-12; + double hY = 1.0e-12; + + JacobianMatrices jacob = new JacobianMatrices(efode, pcircle); + jacob.setParameterJacobianProvider(pcircle); + jacob.setParameterizedODE(pcircle); + jacob.selectParameters(Circle.CX, Circle.OMEGA); + jacob.setMainStateSteps(new double[] { hY, hY }); + jacob.setParameterStep(Circle.OMEGA, hP); + jacob.setInitialMainStateJacobian(pcircle.exactDyDy0(0)); + jacob.setInitialParameterJacobian(Circle.CX, pcircle.exactDyDcx(0)); +// jacob.setInitialParameterJacobian(Circle.CY, circle.exactDyDcy(0)); + jacob.setInitialParameterJacobian(Circle.OMEGA, pcircle.exactDyDom(0)); + integ.setMaxEvaluations(50000); + + double t = 18 * FastMath.PI; + integ.integrate(efode, 0, y, t, y); + for (int i = 0; i < y.length; ++i) { + Assert.assertEquals(pcircle.exactY(t)[i], y[i], 1.0e-9); + } + + double[][] dydy0 = new double[2][2]; + jacob.getCurrentMainSetJacobian(dydy0); + for (int i = 0; i < dydy0.length; ++i) { + for (int j = 0; j < dydy0[i].length; ++j) { + Assert.assertEquals(pcircle.exactDyDy0(t)[i][j], dydy0[i][j], 5.0e-4); + } + } + + double[] dydp0 = new double[2]; + jacob.getCurrentParameterJacobian(Circle.CX, dydp0); + for (int i = 0; i < dydp0.length; ++i) { + Assert.assertEquals(pcircle.exactDyDcx(t)[i], dydp0[i], 5.0e-4); + } + + double[] dydp1 = new double[2]; + jacob.getCurrentParameterJacobian(Circle.OMEGA, dydp1); + for (int i = 0; i < dydp1.length; ++i) { + Assert.assertEquals(pcircle.exactDyDom(t)[i], dydp1[i], 1.0e-2); + } + } + + private static class Brusselator extends AbstractParameterizable + implements MainStateJacobianProvider, ParameterJacobianProvider { + + public static final String B = "b"; + + private double b; + + public Brusselator(double b) { + super(B); + this.b = b; + } + + public int getDimension() { + return 2; + } + + public void computeDerivatives(double t, double[] y, double[] yDot) { + double prod = y[0] * y[0] * y[1]; + yDot[0] = 1 + prod - (b + 1) * y[0]; + yDot[1] = b * y[0] - prod; + } + + public void computeMainStateJacobian(double t, double[] y, double[] yDot, + double[][] dFdY) { + double p = 2 * y[0] * y[1]; + double y02 = y[0] * y[0]; + dFdY[0][0] = p - (1 + b); + dFdY[0][1] = y02; + dFdY[1][0] = b - p; + dFdY[1][1] = -y02; + } + + public void computeParameterJacobian(double t, double[] y, double[] yDot, + String paramName, double[] dFdP) { + complainIfNotSupported(paramName); + dFdP[0] = -y[0]; + dFdP[1] = y[0]; + } + + public double dYdP0() { + return -1088.232716447743 + (1050.775747149553 + (-339.012934631828 + 36.52917025056327 * b) * b) * b; + } + + public double dYdP1() { + return 1502.824469929139 + (-1438.6974831849952 + (460.959476642384 - 49.43847385647082 * b) * b) * b; + } + + } + + private static class ParamBrusselator extends AbstractParameterizable + implements FirstOrderDifferentialEquations, ParameterizedODE { + + public static final String B = "b"; + + private double b; + + public ParamBrusselator(double b) { + super(B); + this.b = b; + } + + public int getDimension() { + return 2; + } + + /** {@inheritDoc} */ + public double getParameter(final String name) + throws IllegalArgumentException { + complainIfNotSupported(name); + return b; + } + + /** {@inheritDoc} */ + public void setParameter(final String name, final double value) + throws IllegalArgumentException { + complainIfNotSupported(name); + b = value; + } + + public void computeDerivatives(double t, double[] y, double[] yDot) { + double prod = y[0] * y[0] * y[1]; + yDot[0] = 1 + prod - (b + 1) * y[0]; + yDot[1] = b * y[0] - prod; + } + + public double dYdP0() { + return -1088.232716447743 + (1050.775747149553 + (-339.012934631828 + 36.52917025056327 * b) * b) * b; + } + + public double dYdP1() { + return 1502.824469929139 + (-1438.6974831849952 + (460.959476642384 - 49.43847385647082 * b) * b) * b; + } + + } + + /** ODE representing a point moving on a circle with provided center and angular rate. */ + private static class Circle extends AbstractParameterizable + implements MainStateJacobianProvider, ParameterJacobianProvider { + + public static final String CX = "cx"; + public static final String CY = "cy"; + public static final String OMEGA = "omega"; + + private final double[] y0; + private double cx; + private double cy; + private double omega; + + public Circle(double[] y0, double cx, double cy, double omega) { + super(CX,CY,OMEGA); + this.y0 = y0.clone(); + this.cx = cx; + this.cy = cy; + this.omega = omega; + } + + public int getDimension() { + return 2; + } + + public void computeDerivatives(double t, double[] y, double[] yDot) { + yDot[0] = omega * (cy - y[1]); + yDot[1] = omega * (y[0] - cx); + } + + public void computeMainStateJacobian(double t, double[] y, + double[] yDot, double[][] dFdY) { + dFdY[0][0] = 0; + dFdY[0][1] = -omega; + dFdY[1][0] = omega; + dFdY[1][1] = 0; + } + + public void computeParameterJacobian(double t, double[] y, double[] yDot, + String paramName, double[] dFdP) { + complainIfNotSupported(paramName); + if (paramName.equals(CX)) { + dFdP[0] = 0; + dFdP[1] = -omega; + } else if (paramName.equals(CY)) { + dFdP[0] = omega; + dFdP[1] = 0; + } else { + dFdP[0] = cy - y[1]; + dFdP[1] = y[0] - cx; + } + } + + public double[] exactY(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + double dx0 = y0[0] - cx; + double dy0 = y0[1] - cy; + return new double[] { + cx + cos * dx0 - sin * dy0, + cy + sin * dx0 + cos * dy0 + }; + } + + public double[][] exactDyDy0(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + return new double[][] { + { cos, -sin }, + { sin, cos } + }; + } + + public double[] exactDyDcx(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + return new double[] {1 - cos, -sin}; + } + + public double[] exactDyDcy(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + return new double[] {sin, 1 - cos}; + } + + public double[] exactDyDom(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + double dx0 = y0[0] - cx; + double dy0 = y0[1] - cy; + return new double[] { -t * (sin * dx0 + cos * dy0) , t * (cos * dx0 - sin * dy0) }; + } + + public double[][] exactDyDp(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + double dx0 = y0[0] - cx; + double dy0 = y0[1] - cy; + return new double[][] { + { 1 - cos, sin, -t * (sin * dx0 + cos * dy0) }, + { -sin, 1 - cos, t * (cos * dx0 - sin * dy0) } + }; + } + + public double[] exactYDot(double t) { + double oCos = omega * FastMath.cos(omega * t); + double oSin = omega * FastMath.sin(omega * t); + double dx0 = y0[0] - cx; + double dy0 = y0[1] - cy; + return new double[] { + -oSin * dx0 - oCos * dy0, + oCos * dx0 - oSin * dy0 + }; + } + + public double[][] exactDyDy0Dot(double t) { + double oCos = omega * FastMath.cos(omega * t); + double oSin = omega * FastMath.sin(omega * t); + return new double[][] { + { -oSin, -oCos }, + { oCos, -oSin } + }; + } + + public double[][] exactDyDpDot(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + double oCos = omega * cos; + double oSin = omega * sin; + double dx0 = y0[0] - cx; + double dy0 = y0[1] - cy; + return new double[][] { + { oSin, oCos, -sin * dx0 - cos * dy0 - t * ( oCos * dx0 - oSin * dy0) }, + { -oCos, oSin, cos * dx0 - sin * dy0 + t * (-oSin * dx0 - oCos * dy0) } + }; + } + + } + + /** ODE representing a point moving on a circle with provided center and angular rate. */ + private static class ParameterizedCircle extends AbstractParameterizable + implements FirstOrderDifferentialEquations, ParameterJacobianProvider, ParameterizedODE { + + public static final String CX = "cx"; + public static final String CY = "cy"; + public static final String OMEGA = "omega"; + + private final double[] y0; + private double cx; + private double cy; + private double omega; + + public ParameterizedCircle(double[] y0, double cx, double cy, double omega) { + super(CX,CY,OMEGA); + this.y0 = y0.clone(); + this.cx = cx; + this.cy = cy; + this.omega = omega; + } + + public int getDimension() { + return 2; + } + + public void computeDerivatives(double t, double[] y, double[] yDot) { + yDot[0] = omega * (cy - y[1]); + yDot[1] = omega * (y[0] - cx); + } + + public void computeParameterJacobian(double t, double[] y, double[] yDot, + String paramName, double[] dFdP) + throws IllegalArgumentException { + if (paramName.equals(CX)) { + dFdP[0] = 0; + dFdP[1] = -omega; + } else { + throw new IllegalArgumentException(); + } + } + + public double getParameter(final String name) + throws IllegalArgumentException { + if (name.equals(CY)) { + return cy; + } else if (name.equals(OMEGA)) { + return omega; + } else { + throw new IllegalArgumentException(); + } + } + + public void setParameter(final String name, final double value) + throws IllegalArgumentException { + if (name.equals(CY)) { + cy = value; + } else if (name.equals(OMEGA)) { + omega = value; + } else { + throw new IllegalArgumentException(); + } + } + + public double[] exactY(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + double dx0 = y0[0] - cx; + double dy0 = y0[1] - cy; + return new double[] { + cx + cos * dx0 - sin * dy0, + cy + sin * dx0 + cos * dy0 + }; + } + + public double[][] exactDyDy0(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + return new double[][] { + { cos, -sin }, + { sin, cos } + }; + } + + public double[] exactDyDcx(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + return new double[] {1 - cos, -sin}; + } + + public double[] exactDyDcy(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + return new double[] {sin, 1 - cos}; + } + + public double[] exactDyDom(double t) { + double cos = FastMath.cos(omega * t); + double sin = FastMath.sin(omega * t); + double dx0 = y0[0] - cx; + double dy0 = y0[1] - cy; + return new double[] { -t * (sin * dx0 + cos * dy0) , t * (cos * dx0 - sin * dy0) }; + } + + } + +} Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/JacobianMatricesTest.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/JacobianMatricesTest.java ------------------------------------------------------------------------------ svn:keywords = "Author Date Id Revision" Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegratorTest.java URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegratorTest.java?rev=1175409&r1=1175408&r2=1175409&view=diff ============================================================================== --- commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegratorTest.java (original) +++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegratorTest.java Sun Sep 25 15:04:39 2011 @@ -256,8 +256,7 @@ public class GraggBulirschStoerIntegrato } @Test - public void testUnstableDerivative() - { + public void testUnstableDerivative() { final StepProblem stepProblem = new StepProblem(0.0, 1.0, 2.0); FirstOrderIntegrator integ = new GraggBulirschStoerIntegrator(0.1, 10, 1.0e-12, 0.0);