diff --git a/src/main/java/org/apache/commons/math/exception/util/LocalizedFormats.java b/src/main/java/org/apache/commons/math/exception/util/LocalizedFormats.java
index 1c766144e..afa3376f4 100644
--- a/src/main/java/org/apache/commons/math/exception/util/LocalizedFormats.java
+++ b/src/main/java/org/apache/commons/math/exception/util/LocalizedFormats.java
@@ -315,6 +315,9 @@ public enum LocalizedFormats implements Localizable {
UNABLE_TO_SOLVE_SINGULAR_PROBLEM("unable to solve: singular problem"),
UNBOUNDED_SOLUTION("unbounded solution"),
UNKNOWN_MODE("unknown mode {0}, known modes: {1} ({2}), {3} ({4}), {5} ({6}), {7} ({8}), {9} ({10}) and {11} ({12})"),
+ UNKNOWN_ADDITIONAL_EQUATION("unknown additional equation"),
+ UNKNOWN_PARAMETER("unknown parameter {0}"),
+ UNMATCHED_ODE_IN_EXTENDED_SET("ode does not match the main ode set in the extended set"),
CANNOT_PARSE_AS_TYPE("string {0} unparseable (from position {1}) as an object of type {2}"), /* keep */
CANNOT_PARSE("string {0} unparseable (from position {1})"), /* keep */
UNPARSEABLE_3D_VECTOR("unparseable 3D vector: \"{0}\""),
diff --git a/src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java b/src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java
index ad423c995..ebad65b2e 100644
--- a/src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/AbstractIntegrator.java
@@ -29,6 +29,7 @@ import java.util.TreeSet;
import org.apache.commons.math.analysis.solvers.BracketingNthOrderBrentSolver;
import org.apache.commons.math.analysis.solvers.UnivariateRealSolver;
import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.MathIllegalArgumentException;
import org.apache.commons.math.exception.MathIllegalStateException;
import org.apache.commons.math.exception.MaxCountExceededException;
import org.apache.commons.math.exception.NumberIsTooSmallException;
@@ -46,7 +47,7 @@ import org.apache.commons.math.util.MathUtils;
* @version $Id$
* @since 2.0
*/
-public abstract class AbstractIntegrator implements FirstOrderIntegrator {
+public abstract class AbstractIntegrator implements ExpandableFirstOrderIntegrator {
/** Step handler. */
protected Collection
+ * In some cases users may need to integrate some problem-specific equations along
+ * with a main set of differential equations. One example is optimal control where
+ * adjoined parameters linked to the minimized hamiltonian must be integrated.
+ *
+ * This interface allows users to add such equations to a main set of {@link
+ * FirstOrderDifferentialEquations first order differential equations}
+ * thanks to the {@link
+ * ExpandableFirstOrderDifferentialEquations#addAdditionalEquations(AdditionalEquations)}
+ * method.
+ *
+ * It is a container allowing the integrator to keep constant consistency between
+ * additional states and the corresponding equations. It allows to set additional
+ * state values, get current additional state value and derivatives by reference
+ * on the associated additional equations.
+ * The array returned is a true reference to the state array, so it may be
+ * used to store data into it.>
+ * @return a reference current value of the additional state.
+ */
+ public double[] getAdditionalState() {
+ return addState;
+ }
+
+ /** Get a reference to the current value of the additional state derivatives.
+ * The array returned is a true reference to the state array, so it may be
+ * used to store data into it.>
+ * @return a reference current value of the additional state derivatives.
+ */
+ public double[] getAdditionalStateDot() {
+ return addStateDot;
+ }
+
+ /** Get the instance of the current additional equations.
+ * @return current value of the additional equations.
+ */
+ public AdditionalEquations getAdditionalEquations() {
+ return addEquations;
+ }
+
+ /** Set a value to additional state.
+ * @param state additional state value.
+ */
+ public void setAdditionalState(final double[] state) {
+ this.addState = state.clone();
+ this.addStateDot = new double[state.length];
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/ode/ExpandableFirstOrderDifferentialEquations.java b/src/main/java/org/apache/commons/math/ode/ExpandableFirstOrderDifferentialEquations.java
new file mode 100644
index 000000000..a89f3813e
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/ode/ExpandableFirstOrderDifferentialEquations.java
@@ -0,0 +1,272 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math.exception.MathIllegalArgumentException;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+
+
+/**
+ * This class represents a combined set of first order differential equations,
+ * with at least a main set of equations expandable by some sets of additional
+ * equations.
+ *
+ * This class extends the {@link FirstOrderDifferentialEquations}. It allows to
+ * identify which part of a complete set of differential equations correspond to
+ * the main set and which part correspond to the expansion sets.
+ *
+ * One typical use case is the computation of the jacobian matrix for some ODE.
+ * The main set of equations corresponds to the raw ODE, and we add to this set
+ * another bunch of equations which represent the jacobian matrix of the main
+ * set. In that case, we want the integrator to use only the main set
+ * to estimate the errors and hence the step sizes. It should not use
+ * the additional equations in this computation.
+ * The {@link ExpandableFirstOrderIntegrator integrator} will be able to know
+ * where the main set ends and so where the expansion sets begin.
+ *
+ * We consider that the main set always corresponds to the first equations and
+ * the expansion sets to the last equations.
+ *
+ * The whole state vector results in the assembly of the main set of
+ * equations and, if there are some, the added sets of equations.
+ *
+ * The main set of equations represents the first part of an ODE state.
+ * The error estimations and adaptive step size computation should be
+ * done on this first part only, not on the final part of the state
+ * which represents expansion sets of equations considered as secondary.
+ *
+ * The total current state computed by the integrator
+ * is dispatched here to the various additional states.
+ *
+ * The classes devoted to solve expandable first order differential equations
+ * should implement this interface. The problems which can be handled should
+ * implement the {@link ExpandableFirstOrderDifferentialEquations} interface.
+ * This method solves an Initial Value Problem (IVP). The set of differential equations is composed of a main set, which
+ * can be extended by some sets of additional equations. Since this method stores some internal state variables made
+ * available in its public interface during integration ({@link
+ * #getCurrentSignedStepsize()}), it is not thread-safe.
+ * It is intended to be packed into an {@link ExpandableFirstOrderDifferentialEquations}
+ * in conjunction with a main set of ODE, which may be:
+ * t0
for backward integration)
+ * @param y placeholder where to put the main state vector at each successful
+ * step (and hence at the end of integration), can be the same object as y0
+ * @return stop time, will be the same as target time if integration reached its
+ * target, but may be different if some {@link
+ * org.apache.commons.math.ode.events.EventHandler} stops it at some point.
+ * @throws MathIllegalStateException if the integrator cannot perform integration
+ * @throws MathIllegalArgumentException if integration parameters are wrong (typically
+ * too small integration span)
+ */
+ double integrate(ExpandableFirstOrderDifferentialEquations equations,
+ double t0, double[] y0, double t, double[] y)
+ throws MathIllegalStateException, MathIllegalArgumentException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/ode/JacobianMatrices.java b/src/main/java/org/apache/commons/math/ode/JacobianMatrices.java
new file mode 100644
index 000000000..a33d2b941
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/ode/JacobianMatrices.java
@@ -0,0 +1,471 @@
+/*
+ * 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 java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.MathIllegalArgumentException;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+
+/**
+ * This class defines a set of {@link AdditionalEquations additional equations} to
+ * compute the jacobian matrices with respect to the initial state vector and, if
+ * any, to some parameters of the main ODE set.
+ *
+ *
+ * In order to compute jacobian matrices with respect to some parameters of the
+ * main ODE set, the following parameter jacobian providers may be set:
+ *
+ *
+ *
This additional equations set is added internally to the expandable + * first order differential equations set thanks to the + * {@link ExpandableFirstOrderDifferentialEquations#addAdditionalEquations(AdditionalEquations)} + * method. + * @param extended the expandable first order differential equations set + * @param jode the main first order differential equations set to extend + * @exception IllegalArgumentException if jode does not match the main set to be extended given by + * {@link ExpandableFirstOrderDifferentialEquations#getMainSet() extended.getMainSet()} + */ + public JacobianMatrices(final ExpandableFirstOrderDifferentialEquations extended, + final MainStateJacobianProvider jode) + throws IllegalArgumentException { + + checkCompatibility(extended, jode); + + efode = extended; + stateDim = efode.getMainSetDimension(); + mainJacobianInARow = new double[stateDim * stateDim]; + this.jode = jode; + efode.addAdditionalEquations(this); + setInitialMainStateJacobian(); + } + + /** Simple constructor for an additional equations set computing jacobian matrices. + *
This additional equations set is added internally to the expandable + * first order differential equations set thanks to the + * {@link ExpandableFirstOrderDifferentialEquations#addAdditionalEquations(AdditionalEquations)} + * method. + * @param extended the expandable first order differential equations set + * @param fode the main first order differential equations set to extend + * @exception IllegalArgumentException if fode does not match the main set to be extended given by + * {@link ExpandableFirstOrderDifferentialEquations#getMainSet() extended.getMainSet()} + */ + public JacobianMatrices(final ExpandableFirstOrderDifferentialEquations extended, + final FirstOrderDifferentialEquations fode) + throws IllegalArgumentException { + + checkCompatibility(extended, fode); + + efode = extended; + stateDim = efode.getMainSetDimension(); + mainJacobianInARow = new double[stateDim * stateDim]; + this.fode = fode; + dirtyMainState = true; + efode.addAdditionalEquations(this); + setInitialMainStateJacobian(); + } + + /** Add a parameter jacobian provider. + * @param pjp the parameter jacobian provider to compute exactly the parameter jacobian matrix + */ + public void setParameterJacobianProvider(final ParameterJacobianProvider pjp) { + this.pjp.add(pjp); + } + + /** Add a parameter jacobian provider. + * @param pjp the parameterized ODE to compute by finite difference the parameter jacobian matrix + */ + public void setParameterizedODE(final ParameterizedODE pode) { + this.pode = pode; + dirtyParameter = true; + } + + /** Select the parameters to consider for jacobian matrices processing. + *
+ * Parameters must belong to the supported ones given by {@link + * Parameterizable#getParametersNames()}, so the main set of differential + * equations must be {@link Parameterizable}. + *
+ *Note that each selection clears the previous selected parameters.
+ * + * @param parameters parameters to consider for jacobian matrices processing + * @exception IllegalArgumentException if one parameter is not supported + */ + public void selectParameters(final String... parameters) throws IllegalArgumentException { + + selectedParameters = new ArrayList+ * Needed if and only if the main ODE set is a {@link ParameterizedODE} + * and the parameter has been {@link #selectParameters(String ...) selected} + *
+ *+ * For pval, a non zero value of the parameter, pval * Math.sqrt(MathUtils.EPSILON) + * is a reasonable value for such a step. + *
+ *+ * A zero value for such a step doesn't enable to compute the parameter jacobian matrix. + *
+ * @param parameter parameter to consider for jacobian processing + * @param hP step for jacobian finite difference computation w.r.t. the specified parameter + * @see ParameterizedODE + * @exception IllegalArgumentException if the parameter is not supported + */ + public void setParameterStep(final String parameter, final double hP) { + + boolean found = false; + for (ParameterConfiguration param: selectedParameters) { + if (parameter.equals(param.getParameterName())) { + param.setHP(hP); + found = true; + dirtyParameter = true; + break; + } + } + if (!found) { + throw new MathIllegalArgumentException(LocalizedFormats.UNKNOWN_PARAMETER, + parameter); + } + } + + /** Set the steps in order to compute by finite difference the jacobian + * matrix with respect to main state. + *+ * Needed if and only if the main set is a {@link FirstOrderDifferentialEquations}. + *
+ *+ * Zero values for those steps don't enable to compute the main state jacobian matrix. + *
+ * @param hY step used for finite difference computation with respect to state vector + * @exception IllegalArgumentException if the hY has not the dimension of the main state + * given by {@link ExpandableFirstOrderDifferentialEquations#getMainSetDimension()} + */ + public void setMainStateSteps(final double[] hY) { + + if (fode != null) { + // Check dimension + checkDimension(stateDim, hY); + this.hY = hY.clone(); + dirtyMainState = true; + } + } + + /** Set the initial value of the jacobian matrix with respect to state. + * @param dYdY0 initial jacobian matrix w.r.t. state + * @exception IllegalArgumentException if matrix dimensions are incorrect + */ + public void setInitialMainStateJacobian(final double[][] dYdY0) { + + // Check dimensions + checkDimension(stateDim, dYdY0); + checkDimension(stateDim, dYdY0[0]); + + // store the matrix in row major order as a single dimension array + int index = 0; + for (final double[] row : dYdY0) { + System.arraycopy(row, 0, mainJacobianInARow, index, stateDim); + index += stateDim; + } + // set initial additional state value in expandable fode + efode.setInitialAdditionalState(mainJacobianInARow, this); + } + + /** Set the initial value of the jacobian matrix with respect to one parameter. + *The parameter must be {@link #selectParameters(String...) selected}.
+ * @param pName parameter name + * @param dYdP initial jacobian matrix w.r.t. the parameter + * @exception IllegalArgumentException if matrix dimensions are incorrect + */ + public void setInitialParameterJacobian(final String pName, final double[] dYdP) { + + // Check dimensions + checkDimension(stateDim, dYdP); + + // store the matrix in a global single dimension array + boolean found = false; + int index = 0; + for (ParameterConfiguration param: selectedParameters) { + if (pName.equals(param.getParameterName())) { + System.arraycopy(dYdP, 0, parameterJacobiansInARow, index, stateDim); + double[] p = new double[this.getDimension()]; + index = stateDim * stateDim; + System.arraycopy(mainJacobianInARow, 0, p, 0, index); + System.arraycopy(parameterJacobiansInARow, 0, p, index, stateDim * paramDim); + // set initial additional state value in expandable fode + efode.setInitialAdditionalState(p, this); + found = true; + break; + } + index += stateDim; + } + if (! found) { + throw new MathIllegalArgumentException(LocalizedFormats.UNKNOWN_PARAMETER, + pName); + } + } + + /** Set the default initial value of the jacobian matrix with respect to state. + *dYdY0 is set to the identity matrix.
+ */ + public void setInitialMainStateJacobian() { + final double[][] dYdY0 = new double[stateDim][stateDim]; + for (int i = 0; i < stateDim; ++i) { + dYdY0[i][i] = 1.0; + } + setInitialMainStateJacobian(dYdY0); + } + + /** Set the default initial value of the jacobian matrix with respect to one parameter. + *The parameter must be {@link #selectParameters(String...) selected}.
+ *dYdP is set to the null matrix.
+ * @param pName parameter name + */ + public void setInitialParameterJacobian(final String pName) { + setInitialParameterJacobian(pName, new double[stateDim]); + } + + /** Set the default initial values of jacobian matrices with respect to all parameters. + */ + public void setInitialParameterJacobians() { + for (ParameterConfiguration param: selectedParameters) { + setInitialParameterJacobian(param.getParameterName()); + } + } + + /** Set default initial values for jacobian matrices. + *dYdY0 is set to the identity matrix and all dYdP are set to zero.
+ */ + public void setInitialJacobians() { + setInitialMainStateJacobian(); + setInitialParameterJacobians(); + } + + /** Get the current value of the jacobian matrix with respect to state. + * @param dYdY0 current jacobian matrix with respect to state. + */ + public void getCurrentMainSetJacobian(final double[][] dYdY0) { + + // get current state for this set of equations from the expandable fode + double[] p = efode.getCurrentAdditionalState(this); + + int index = 0; + for (int i = 0; i < stateDim; i++) { + System.arraycopy(p, index, dYdY0[i], 0, stateDim); + index += stateDim; + } + + } + + /** Get the current value of the jacobian matrix with respect to one parameter. + * @param pName name of the parameter for the computed jacobian matrix + * @param dYdP current jacobian matrix with respect to the named parameter + */ + public void getCurrentParameterJacobian(String pName, final double[] dYdP) { + + // get current state for this set of equations from the expandable fode + double[] p = efode.getCurrentAdditionalState(this); + + int index = stateDim * stateDim; + for (ParameterConfiguration param: selectedParameters) { + if (param.getParameterName().equals(pName)) { + System.arraycopy(p, index, dYdP, 0, stateDim); + break; + } + index += stateDim; + } + + } + + /** {@inheritDoc} */ + public int getDimension() { + return stateDim * (stateDim + paramDim); + } + + /** {@inheritDoc} */ + public void computeDerivatives(final double t, final double[] y, final double[] yDot, + final double[] z, final double[] zDot) { + + // Lazy initialization + if (dirtyMainState) { + jode = new MainStateJacobianWrapper(fode, hY); + dirtyMainState = false; + } + if (dirtyParameter && (paramDim != 0)) { + pjp.add(new ParameterJacobianWrapper(jode, pode, selectedParameters)); + dirtyParameter = false; + } + + // variational equations: + // from d[dy/dt]/dy0 and d[dy/dt]/dp to d[dy/dy0]/dt and d[dy/dp]/dt + + // compute jacobian matrix with respect to main state + double[][] dFdY = new double[stateDim][stateDim]; + jode.computeMainStateJacobian(t, y, yDot, dFdY); + + // Dispatch jacobian matrix in the compound additional state vector + for (int i = 0; i < stateDim; ++i) { + final double[] dFdYi = dFdY[i]; + for (int j = 0; j < stateDim; ++j) { + double s = 0; + final int startIndex = j; + int zIndex = startIndex; + for (int l = 0; l < stateDim; ++l) { + s += dFdYi[l] * z[zIndex]; + zIndex += stateDim; + } + zDot[startIndex + i * stateDim] = s; + } + } + + if (paramDim != 0) { + // compute jacobian matrices with respect to parameters + double[] dFdP = new double[stateDim]; + int startIndex = stateDim * stateDim; + for (ParameterConfiguration param: selectedParameters) { + boolean found = false; + for (ParameterJacobianProvider provider: pjp) { + if (provider.isSupported(param.getParameterName())) { + try { + provider.computeParameterJacobian(t, y, yDot, param.getParameterName(), dFdP); + for (int i = 0; i < stateDim; ++i) { + final double[] dFdYi = dFdY[i]; + int zIndex = startIndex; + double s = dFdP[i]; + for (int l = 0; l < stateDim; ++l) { + s += dFdYi[l] * z[zIndex]; + zIndex++; + } + zDot[startIndex + i] = s; + } + startIndex += stateDim; + found = true; + break; + } catch (IllegalArgumentException iae) { + } + } + } + if (! found) { + throw new MathIllegalArgumentException(LocalizedFormats.UNKNOWN_PARAMETER, + param); + } + } + } + + } + + /** Check compatibility between the main set in the expandable ode and an ordinary ode. + * @param expended expandable ode containing a main set + * @param ode single ode to check + * @throws MathIllegalArgumentException if single ode doesn't match the main ode set in the extended ode + */ + private void checkCompatibility(final ExpandableFirstOrderDifferentialEquations extended, + final FirstOrderDifferentialEquations ode) + throws MathIllegalArgumentException { + + if (!(ode == extended.getMainSet())) { + throw new MathIllegalArgumentException(LocalizedFormats.UNMATCHED_ODE_IN_EXTENDED_SET); + } + } + + /** Check array dimensions. + * @param expected expected dimension + * @param array (may be null if expected is 0) + * @throws DimensionMismatchException if the array dimension does not match the expected one + */ + private void checkDimension(final int expected, final Object array) + throws DimensionMismatchException { + int arrayDimension = (array == null) ? 0 : Array.getLength(array); + if (arrayDimension != expected) { + throw new DimensionMismatchException(arrayDimension, expected); + } + } + +} + diff --git a/src/main/java/org/apache/commons/math/ode/MainStateJacobianProvider.java b/src/main/java/org/apache/commons/math/ode/MainStateJacobianProvider.java new file mode 100644 index 000000000..935f3685d --- /dev/null +++ b/src/main/java/org/apache/commons/math/ode/MainStateJacobianProvider.java @@ -0,0 +1,36 @@ +/* + * 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; + +/** Interface expanding {@link FirstOrderDifferentialEquations first order + * differential equations} in order to compute exactly the main state jacobian + * matrix for {@link JacobianMatrices partial derivatives equations}. + * + * @version $Id$ + * @since 3.0 + */ +public interface MainStateJacobianProvider extends FirstOrderDifferentialEquations { + + /** Compute the jacobian matrix of ODE with respect to main state. + * @param t current value of the independent time variable + * @param y array containing the current value of the main state vector + * @param yDot array containing the current value of the time derivative of the main state vector + * @param dFdY placeholder array where to put the jacobian matrix of the ODE w.r.t. the main state vector + */ + void computeMainStateJacobian(double t, double[] y, double[] yDot, double[][] dFdY); + +} diff --git a/src/main/java/org/apache/commons/math/ode/MainStateJacobianWrapper.java b/src/main/java/org/apache/commons/math/ode/MainStateJacobianWrapper.java new file mode 100644 index 000000000..edb4c9670 --- /dev/null +++ b/src/main/java/org/apache/commons/math/ode/MainStateJacobianWrapper.java @@ -0,0 +1,72 @@ +/* + * 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; + +/** Wrapper class to compute jacobian matrices by finite differences for ODE + * which do not compute them by themselves. + * + * @version $Id$ + * @since 3.0 + */ +class MainStateJacobianWrapper implements MainStateJacobianProvider { + + /** Raw ODE without jacobians computation skill to be wrapped into a MainStateJacobianProvider. */ + private final FirstOrderDifferentialEquations ode; + + /** Steps for finite difference computation of the jacobian df/dy w.r.t. state. */ + private final double[] hY; + + /** Wrap a {@link FirstOrderDifferentialEquations} into a {@link MainStateJacobianProvider}. + * @param ode original ODE problem, without jacobians computation skill + * @param hY step sizes to compute the jacobian df/dy + * @see JacobianMatrices#setMainStateSteps(double[]) + */ + public MainStateJacobianWrapper(final FirstOrderDifferentialEquations ode, + final double[] hY) { + this.ode = ode; + this.hY = hY.clone(); + } + + /** {@inheritDoc} */ + public int getDimension() { + return ode.getDimension(); + } + + /** {@inheritDoc} */ + public void computeDerivatives(double t, double[] y, double[] yDot) { + ode.computeDerivatives(t, y, yDot); + } + + /** {@inheritDoc} */ + public void computeMainStateJacobian(double t, double[] y, double[] yDot, + double[][] dFdY) { + + final int n = ode.getDimension(); + final double[] tmpDot = new double[n]; + + for (int j = 0; j < n; ++j) { + final double savedYj = y[j]; + y[j] += hY[j]; + ode.computeDerivatives(t, y, tmpDot); + for (int i = 0; i < n; ++i) { + dFdY[i][j] = (tmpDot[i] - yDot[i]) / hY[j]; + } + y[j] = savedYj; + } + } + +} diff --git a/src/main/java/org/apache/commons/math/ode/MultistepIntegrator.java b/src/main/java/org/apache/commons/math/ode/MultistepIntegrator.java index 3f742bdfc..0a390bc21 100644 --- a/src/main/java/org/apache/commons/math/ode/MultistepIntegrator.java +++ b/src/main/java/org/apache/commons/math/ode/MultistepIntegrator.java @@ -403,7 +403,7 @@ public abstract class MultistepIntegrator extends AdaptiveStepsizeIntegrator { } /** Wrapper for differential equations, ensuring start evaluations are counted. */ - private class CountingDifferentialEquations implements ExtendedFirstOrderDifferentialEquations { + private class CountingDifferentialEquations implements FirstOrderDifferentialEquations { /** Dimension of the problem. */ private final int dimension; @@ -425,10 +425,6 @@ public abstract class MultistepIntegrator extends AdaptiveStepsizeIntegrator { return dimension; } - /** {@inheritDoc} */ - public int getMainSetDimension() { - return mainSetDimension; - } } } diff --git a/src/main/java/org/apache/commons/math/ode/ParameterConfiguration.java b/src/main/java/org/apache/commons/math/ode/ParameterConfiguration.java new file mode 100644 index 000000000..a86ada92f --- /dev/null +++ b/src/main/java/org/apache/commons/math/ode/ParameterConfiguration.java @@ -0,0 +1,67 @@ +/* + * 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 java.io.Serializable; + +/** Simple container pairing a parameter name with a step in order to compute + * the associated jacobian matrix by finite difference. + * + * @version $Id$ + * @since 3.0 + */ +class ParameterConfiguration implements Serializable { + + /** Serializable UID. */ + private static final long serialVersionUID = 2247518849090889379L; + + /** Parameter name. */ + private String parameterName; + + /** Parameter step for finite difference computation. */ + private double hP; + + /** Parameter name and step pair constructor. + * @param parameterName parameter name + * @param hP parameter step */ + public ParameterConfiguration(final String parameterName, final double hP) { + this.parameterName = parameterName; + this.hP = hP; + } + + /** Get parameter name. + * @return parameterName parameter name + */ + public String getParameterName() { + return parameterName; + } + + /** Get parameter step. + * @return hP parameter step + */ + public double getHP() { + return hP; + } + + /** Set parameter step. + * @param hP parameter step + */ + public void setHP(final double hP) { + this.hP = hP; + } + +} diff --git a/src/main/java/org/apache/commons/math/ode/ParameterJacobianProvider.java b/src/main/java/org/apache/commons/math/ode/ParameterJacobianProvider.java new file mode 100644 index 000000000..e9b914f37 --- /dev/null +++ b/src/main/java/org/apache/commons/math/ode/ParameterJacobianProvider.java @@ -0,0 +1,43 @@ +/* + * 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.exception.MathIllegalArgumentException; + +/** Interface to compute exactly jacobian matrix for some parameter + * when computing {@link JacobianMatrices partial derivatives equations}. + * + * @version $Id$ + * @since 3.0 + */ +public interface ParameterJacobianProvider extends Parameterizable { + + /** Compute the jacobian matrix of ODE with respect to one parameter. + *The parameter must be one given by {@link #getParametersNames()}.
+ * @param t current value of the independent time variable + * @param y array containing the current value of the main state vector + * @param yDot array containing the current value of the time derivative + * of the main state vector + * @param paramName name of the parameter to consider + * @param dFdP placeholder array where to put the jacobian matrix of the + * ODE with respect to the parameter + * @throws MathIllegalArgumentException if the parameter is not supported + */ + void computeParameterJacobian(double t, double[] y, double[] yDot, + String paramName, double[] dFdP) + throws MathIllegalArgumentException; +} diff --git a/src/main/java/org/apache/commons/math/ode/ParameterJacobianWrapper.java b/src/main/java/org/apache/commons/math/ode/ParameterJacobianWrapper.java new file mode 100644 index 000000000..15b62b20b --- /dev/null +++ b/src/main/java/org/apache/commons/math/ode/ParameterJacobianWrapper.java @@ -0,0 +1,91 @@ +/* + * 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 java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** Wrapper class to compute jacobian matrices by finite differences for ODE + * which do not compute them by themselves. + * + * @version $Id$ + * @since 3.0 + */ +class ParameterJacobianWrapper implements ParameterJacobianProvider { + + /** Main ODE set. */ + private final FirstOrderDifferentialEquations fode; + + /** Raw ODE without jacobian computation skill to be wrapped into a ParameterJacobianProvider. */ + private final ParameterizedODE pode; + + /** Steps for finite difference computation of the jacobian df/dp w.r.t. parameters. */ + private final MapSupported parameters are those listed by {@link #getParametersNames()}.
+ * @param name parameter name to check + * @return true if the parameter is supported + * @see #getParametersNames() + */ + boolean isSupported(String name); + +} diff --git a/src/main/java/org/apache/commons/math/ode/ParameterizedODE.java b/src/main/java/org/apache/commons/math/ode/ParameterizedODE.java new file mode 100644 index 000000000..053d27d17 --- /dev/null +++ b/src/main/java/org/apache/commons/math/ode/ParameterizedODE.java @@ -0,0 +1,42 @@ +/* + * 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; + +/** Interface to compute by finite difference jacobian matrix for some parameter + * when computing {@link JacobianMatrices partial derivatives equations}. + * + * @version $Id$ + * @since 3.0 + */ + +public interface ParameterizedODE extends Parameterizable { + + /** Get parameter value from its name. + * @param name parameter name + * @return parameter value + * @exception IllegalArgumentException if parameter is not supported + */ + double getParameter(String name) throws IllegalArgumentException; + + /** Set the value for a given parameter. + * @param name parameter name + * @param value parameter value + * @exception IllegalArgumentException if parameter is not supported + */ + void setParameter(String name, double value) throws IllegalArgumentException; + +} diff --git a/src/main/java/org/apache/commons/math/ode/ParameterizedWrapper.java b/src/main/java/org/apache/commons/math/ode/ParameterizedWrapper.java new file mode 100644 index 000000000..6ab3efb59 --- /dev/null +++ b/src/main/java/org/apache/commons/math/ode/ParameterizedWrapper.java @@ -0,0 +1,77 @@ +/* + * 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 java.util.ArrayList; +import java.util.Collection; + +import org.apache.commons.math.exception.MathIllegalArgumentException; +import org.apache.commons.math.exception.util.LocalizedFormats; + + +/** Wrapper class enabling {@link FirstOrderDifferentialEquations basic simple} + * ODE instances to be used when processing {@link JacobianMatrices}. + * + * @version $Id$ + * @since 3.0 + */ +class ParameterizedWrapper implements ParameterizedODE { + + /** Basic FODE without parameter. */ + private final FirstOrderDifferentialEquations fode; + + /** Simple constructor. + * @param ode original first order differential equations + */ + public ParameterizedWrapper(final FirstOrderDifferentialEquations ode) { + this.fode = ode; + } + + /** {@inheritDoc} */ + public int getDimension() { + return fode.getDimension(); + } + + /** {@inheritDoc} */ + public void computeDerivatives(double t, double[] y, double[] yDot) { + fode.computeDerivatives(t, y, yDot); + } + + /** {@inheritDoc} */ + public CollectionIf the Ordinary Differential Equations is an {@link ExtendedFirstOrderDifferentialEquations - * extended ODE} rather than a {@link FirstOrderDifferentialEquations basic ODE}, - * then only the {@link ExtendedFirstOrderDifferentialEquations#getMainSetDimension() - * main set} part of the state vector is used for stepsize control, not the complete - * state vector. + *
+ * If the Ordinary Differential Equations is an {@link ExpandableFirstOrderDifferentialEquations + * extended ODE} rather than a {@link FirstOrderDifferentialEquations basic ODE}, then + * only the {@link ExpandableFirstOrderDifferentialEquations#getMainSet() main part} + * of the state vector is used for stepsize control, not the complete state vector. *
* *If the estimated error for ym+1 is such that
@@ -224,18 +223,14 @@ public abstract class AdaptiveStepsizeIntegrator
* @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 AdaptiveStepsizeIntegrator
}
/** 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 AdaptiveStepsizeIntegrator
* @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 AdaptiveStepsizeIntegrator
}
/** {@inheritDoc} */
- public abstract double integrate (FirstOrderDifferentialEquations equations,
+ public abstract double integrate (ExpandableFirstOrderDifferentialEquations equations,
double t0, double[] y0,
double t, double[] y)
throws MathIllegalStateException, MathIllegalArgumentException;
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java
index 538f399a8..90b9d59ba 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/EmbeddedRungeKuttaIntegrator.java
@@ -19,7 +19,7 @@ package org.apache.commons.math.ode.nonstiff;
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 EmbeddedRungeKuttaIntegrator
/** {@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 EmbeddedRungeKuttaIntegrator
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 EmbeddedRungeKuttaIntegrator
} 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;
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java
index 855564ad8..ea38e62b0 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/GraggBulirschStoerIntegrator.java
@@ -20,7 +20,7 @@ package org.apache.commons.math.ode.nonstiff;
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 GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
/** {@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 GraggBulirschStoerIntegrator extends AdaptiveStepsizeIntegrator {
}
if (firstTime) {
- hNew = initializeStep(equations, forward,
- 2 * targetIter + 1, scale,
+ hNew = initializeStep(forward, 2 * targetIter + 1, scale,
stepStart, y, yDot0, yTmp, yTmpDot);
}
diff --git a/src/main/java/org/apache/commons/math/ode/nonstiff/RungeKuttaIntegrator.java b/src/main/java/org/apache/commons/math/ode/nonstiff/RungeKuttaIntegrator.java
index e1f5ad82c..5ead850ce 100644
--- a/src/main/java/org/apache/commons/math/ode/nonstiff/RungeKuttaIntegrator.java
+++ b/src/main/java/org/apache/commons/math/ode/nonstiff/RungeKuttaIntegrator.java
@@ -21,7 +21,7 @@ package org.apache.commons.math.ode.nonstiff;
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 RungeKuttaIntegrator extends AbstractIntegrator {
}
/** {@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 RungeKuttaIntegrator extends AbstractIntegrator {
} 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;
diff --git a/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties b/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties
index ace42b9ba..d225d8e36 100644
--- a/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties
+++ b/src/main/resources/META-INF/localization/LocalizedFormats_fr.properties
@@ -279,6 +279,9 @@ UNABLE_TO_PERFORM_QR_DECOMPOSITION_ON_JACOBIAN = impossible de calculer la facto
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}"
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index ba45d1144..146421723 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -52,6 +52,12 @@ The