summaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/commons/math/analysis
diff options
context:
space:
mode:
authorRaymond <siuchow@google.com>2015-04-02 10:43:13 -0700
committerRaymond <siuchow@google.com>2015-04-02 10:43:13 -0700
commitdee0849a9704d532af0b550146cbafbaa6ee1d19 (patch)
tree8ccce3a046c214fb609977b7fc53c40cef7f9ea5 /src/main/java/org/apache/commons/math/analysis
parent55b0a5efc929efa9615babd3e760547f94e3518e (diff)
downloadapache-commons-math-dee0849a9704d532af0b550146cbafbaa6ee1d19.tar.gz
third party library: apache-commons-mathandroid-cts-6.0_r9android-cts-6.0_r8android-cts-6.0_r7android-cts-6.0_r6android-cts-6.0_r5android-cts-6.0_r4android-cts-6.0_r32android-cts-6.0_r31android-cts-6.0_r30android-cts-6.0_r3android-cts-6.0_r29android-cts-6.0_r28android-cts-6.0_r27android-cts-6.0_r26android-cts-6.0_r25android-cts-6.0_r24android-cts-6.0_r23android-cts-6.0_r22android-cts-6.0_r21android-cts-6.0_r20android-cts-6.0_r2android-cts-6.0_r19android-cts-6.0_r18android-cts-6.0_r17android-cts-6.0_r16android-cts-6.0_r15android-cts-6.0_r14android-cts-6.0_r13android-cts-6.0_r12android-cts-6.0_r1android-6.0.1_r9android-6.0.1_r81android-6.0.1_r80android-6.0.1_r8android-6.0.1_r79android-6.0.1_r78android-6.0.1_r77android-6.0.1_r74android-6.0.1_r73android-6.0.1_r72android-6.0.1_r70android-6.0.1_r7android-6.0.1_r69android-6.0.1_r68android-6.0.1_r67android-6.0.1_r66android-6.0.1_r65android-6.0.1_r63android-6.0.1_r62android-6.0.1_r61android-6.0.1_r60android-6.0.1_r59android-6.0.1_r58android-6.0.1_r57android-6.0.1_r56android-6.0.1_r55android-6.0.1_r54android-6.0.1_r53android-6.0.1_r52android-6.0.1_r51android-6.0.1_r50android-6.0.1_r5android-6.0.1_r49android-6.0.1_r48android-6.0.1_r47android-6.0.1_r46android-6.0.1_r45android-6.0.1_r43android-6.0.1_r42android-6.0.1_r41android-6.0.1_r40android-6.0.1_r4android-6.0.1_r33android-6.0.1_r32android-6.0.1_r31android-6.0.1_r30android-6.0.1_r3android-6.0.1_r28android-6.0.1_r27android-6.0.1_r26android-6.0.1_r25android-6.0.1_r24android-6.0.1_r22android-6.0.1_r21android-6.0.1_r20android-6.0.1_r18android-6.0.1_r17android-6.0.1_r16android-6.0.1_r13android-6.0.1_r12android-6.0.1_r11android-6.0.1_r10android-6.0.1_r1android-6.0.0_r7android-6.0.0_r6android-6.0.0_r5android-6.0.0_r41android-6.0.0_r4android-6.0.0_r3android-6.0.0_r26android-6.0.0_r25android-6.0.0_r24android-6.0.0_r23android-6.0.0_r2android-6.0.0_r13android-6.0.0_r12android-6.0.0_r11android-6.0.0_r1marshmallow-releasemarshmallow-mr3-releasemarshmallow-mr2-releasemarshmallow-mr1-releasemarshmallow-mr1-devmarshmallow-dr1.6-releasemarshmallow-dr1.5-releasemarshmallow-dr1.5-devmarshmallow-dr-releasemarshmallow-dr-dragon-releasemarshmallow-dr-devmarshmallow-devmarshmallow-cts-release
Change-Id: I52a325624a7f0dd652b362a9840626d6d9f3c42b
Diffstat (limited to 'src/main/java/org/apache/commons/math/analysis')
-rw-r--r--src/main/java/org/apache/commons/math/analysis/BinaryFunction.java120
-rw-r--r--src/main/java/org/apache/commons/math/analysis/BivariateRealFunction.java40
-rw-r--r--src/main/java/org/apache/commons/math/analysis/ComposableFunction.java506
-rw-r--r--src/main/java/org/apache/commons/math/analysis/DifferentiableMultivariateRealFunction.java51
-rw-r--r--src/main/java/org/apache/commons/math/analysis/DifferentiableMultivariateVectorialFunction.java36
-rw-r--r--src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateMatrixFunction.java35
-rw-r--r--src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateRealFunction.java34
-rw-r--r--src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateVectorialFunction.java35
-rw-r--r--src/main/java/org/apache/commons/math/analysis/MultivariateMatrixFunction.java40
-rw-r--r--src/main/java/org/apache/commons/math/analysis/MultivariateRealFunction.java39
-rw-r--r--src/main/java/org/apache/commons/math/analysis/MultivariateVectorialFunction.java39
-rw-r--r--src/main/java/org/apache/commons/math/analysis/TrivariateRealFunction.java40
-rw-r--r--src/main/java/org/apache/commons/math/analysis/UnivariateMatrixFunction.java37
-rw-r--r--src/main/java/org/apache/commons/math/analysis/UnivariateRealFunction.java36
-rw-r--r--src/main/java/org/apache/commons/math/analysis/UnivariateVectorialFunction.java37
-rw-r--r--src/main/java/org/apache/commons/math/analysis/integration/LegendreGaussIntegrator.java236
-rw-r--r--src/main/java/org/apache/commons/math/analysis/integration/RombergIntegrator.java121
-rw-r--r--src/main/java/org/apache/commons/math/analysis/integration/SimpsonIntegrator.java112
-rw-r--r--src/main/java/org/apache/commons/math/analysis/integration/TrapezoidIntegrator.java142
-rw-r--r--src/main/java/org/apache/commons/math/analysis/integration/UnivariateRealIntegrator.java106
-rw-r--r--src/main/java/org/apache/commons/math/analysis/integration/UnivariateRealIntegratorImpl.java183
-rw-r--r--src/main/java/org/apache/commons/math/analysis/integration/package.html22
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/BicubicSplineInterpolatingFunction.java558
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/BicubicSplineInterpolator.java145
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/BivariateRealGridInterpolator.java44
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/DividedDifferenceInterpolator.java117
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/LinearInterpolator.java75
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/LoessInterpolator.java463
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/MicrosphereInterpolatingFunction.java244
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/MicrosphereInterpolator.java118
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/MultivariateRealInterpolator.java46
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/NevilleInterpolator.java54
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/SmoothingBicubicSplineInterpolator.java178
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/SmoothingPolynomialBicubicSplineInterpolator.java143
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/SplineInterpolator.java127
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/TricubicSplineInterpolatingFunction.java483
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/TricubicSplineInterpolator.java198
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/TrivariateRealGridInterpolator.java49
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/UnivariateRealInterpolator.java39
-rw-r--r--src/main/java/org/apache/commons/math/analysis/interpolation/package.html22
-rw-r--r--src/main/java/org/apache/commons/math/analysis/package.html33
-rw-r--r--src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunction.java350
-rw-r--r--src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunctionLagrangeForm.java305
-rw-r--r--src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunctionNewtonForm.java221
-rw-r--r--src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialSplineFunction.java224
-rw-r--r--src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialsUtils.java281
-rw-r--r--src/main/java/org/apache/commons/math/analysis/polynomials/package.html23
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/BisectionSolver.java133
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/BrentSolver.java399
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/LaguerreSolver.java434
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/MullerSolver.java415
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/NewtonSolver.java183
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/RiddersSolver.java247
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/SecantSolver.java230
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolver.java165
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverFactory.java90
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverFactoryImpl.java64
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverImpl.java304
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java240
-rw-r--r--src/main/java/org/apache/commons/math/analysis/solvers/package.html22
60 files changed, 9513 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math/analysis/BinaryFunction.java b/src/main/java/org/apache/commons/math/analysis/BinaryFunction.java
new file mode 100644
index 0000000..227b72e
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/BinaryFunction.java
@@ -0,0 +1,120 @@
+/*
+ * 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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.util.FastMath;
+
+
+
+/**
+ * Base class for {@link BivariateRealFunction} that can be composed with other functions.
+ *
+ * @since 2.1
+ * @version $Revision: 1073498 $ $Date: 2011-02-22 21:57:26 +0100 (mar. 22 févr. 2011) $
+ * @deprecated in 2.2
+ */
+@Deprecated
+public abstract class BinaryFunction implements BivariateRealFunction {
+
+ /** The + operator method wrapped as a {@link BinaryFunction}. */
+ public static final BinaryFunction ADD = new BinaryFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double x, double y) {
+ return x + y;
+ }
+ };
+
+ /** The - operator method wrapped as a {@link BinaryFunction}. */
+ public static final BinaryFunction SUBTRACT = new BinaryFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double x, double y) {
+ return x - y;
+ }
+ };
+
+ /** The * operator method wrapped as a {@link BinaryFunction}. */
+ public static final BinaryFunction MULTIPLY = new BinaryFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double x, double y) {
+ return x * y;
+ }
+ };
+
+ /** The / operator method wrapped as a {@link BinaryFunction}. */
+ public static final BinaryFunction DIVIDE = new BinaryFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double x, double y) {
+ return x / y;
+ }
+ };
+
+ /** The {@code FastMath.pow} method wrapped as a {@link BinaryFunction}. */
+ public static final BinaryFunction POW = new BinaryFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double x, double y) {
+ return FastMath.pow(x, y);
+ }
+ };
+
+ /** The {@code FastMath.atan2} method wrapped as a {@link BinaryFunction}. */
+ public static final BinaryFunction ATAN2 = new BinaryFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double x, double y) {
+ return FastMath.atan2(x, y);
+ }
+ };
+
+ /** {@inheritDoc} */
+ public abstract double value(double x, double y) throws FunctionEvaluationException;
+
+ /** Get a composable function by fixing the first argument of the instance.
+ * @param fixedX fixed value of the first argument
+ * @return a function such that {@code f.value(y) == value(fixedX, y)}
+ */
+ public ComposableFunction fix1stArgument(final double fixedX) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return BinaryFunction.this.value(fixedX, x);
+ }
+ };
+ }
+
+ /** Get a composable function by fixing the second argument of the instance.
+ * @param fixedY fixed value of the second argument
+ * @return a function such that {@code f.value(x) == value(x, fixedY)}
+ */
+ public ComposableFunction fix2ndArgument(final double fixedY) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return BinaryFunction.this.value(x, fixedY);
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/BivariateRealFunction.java b/src/main/java/org/apache/commons/math/analysis/BivariateRealFunction.java
new file mode 100644
index 0000000..4b12312
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/BivariateRealFunction.java
@@ -0,0 +1,40 @@
+/*
+ * 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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ * An interface representing a bivariate real function.
+ *
+ * @since 2.1
+ * @version $Revision: 1073498 $ $Date: 2011-02-22 21:57:26 +0100 (mar. 22 févr. 2011) $
+ */
+public interface BivariateRealFunction {
+ /**
+ * Compute the value for the function.
+ *
+ * @param x Abscissa for which the function value should be computed.
+ * @param y Ordinate for which the function value should be computed.
+ * @return the value.
+ * @throws FunctionEvaluationException if the function evaluation fails.
+ */
+ double value(double x, double y)
+ throws FunctionEvaluationException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/ComposableFunction.java b/src/main/java/org/apache/commons/math/analysis/ComposableFunction.java
new file mode 100644
index 0000000..91c8132
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/ComposableFunction.java
@@ -0,0 +1,506 @@
+/*
+ * 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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.util.FastMath;
+
+
+/**
+ * Base class for {@link UnivariateRealFunction} that can be composed with other functions.
+ *
+ * @since 2.1
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ */
+public abstract class ComposableFunction implements UnivariateRealFunction {
+
+ /** The constant function always returning 0. */
+ public static final ComposableFunction ZERO = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return 0;
+ }
+ };
+
+ /** The constant function always returning 1. */
+ public static final ComposableFunction ONE = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return 1;
+ }
+ };
+
+ /** The identity function. */
+ public static final ComposableFunction IDENTITY = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return d;
+ }
+ };
+
+ /** The {@code FastMath.abs} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction ABS = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.abs(d);
+ }
+ };
+
+ /** The - operator wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction NEGATE = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return -d;
+ }
+ };
+
+ /** The invert operator wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction INVERT = new ComposableFunction () {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d){
+ return 1/d;
+ }
+ };
+
+ /** The {@code FastMath.sin} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction SIN = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.sin(d);
+ }
+ };
+
+ /** The {@code FastMath.sqrt} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction SQRT = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.sqrt(d);
+ }
+ };
+
+ /** The {@code FastMath.sinh} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction SINH = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.sinh(d);
+ }
+ };
+
+ /** The {@code FastMath.exp} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction EXP = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.exp(d);
+ }
+ };
+
+ /** The {@code FastMath.expm1} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction EXPM1 = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.expm1(d);
+ }
+ };
+
+ /** The {@code FastMath.asin} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction ASIN = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.asin(d);
+ }
+ };
+
+ /** The {@code FastMath.atan} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction ATAN = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.atan(d);
+ }
+ };
+
+ /** The {@code FastMath.tan} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction TAN = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.tan(d);
+ }
+ };
+
+ /** The {@code FastMath.tanh} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction TANH = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.tanh(d);
+ }
+ };
+
+ /** The {@code FastMath.cbrt} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction CBRT = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.cbrt(d);
+ }
+ };
+
+ /** The {@code FastMath.ceil} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction CEIL = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.ceil(d);
+ }
+ };
+
+ /** The {@code FastMath.floor} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction FLOOR = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.floor(d);
+ }
+ };
+
+ /** The {@code FastMath.log} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction LOG = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.log(d);
+ }
+ };
+
+ /** The {@code FastMath.log10} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction LOG10 = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.log10(d);
+ }
+ };
+
+ /** The {@code FastMath.log1p} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction LOG1P = new ComposableFunction () {
+ @Override
+ public double value(double d){
+ return FastMath.log1p(d);
+ }
+ };
+
+ /** The {@code FastMath.cos} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction COS = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.cos(d);
+ }
+ };
+
+ /** The {@code FastMath.abs} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction ACOS = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.acos(d);
+ }
+ };
+
+ /** The {@code FastMath.cosh} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction COSH = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.cosh(d);
+ }
+ };
+
+ /** The {@code FastMath.rint} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction RINT = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.rint(d);
+ }
+ };
+
+ /** The {@code FastMath.signum} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction SIGNUM = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.signum(d);
+ }
+ };
+
+ /** The {@code FastMath.ulp} method wrapped as a {@link ComposableFunction}. */
+ public static final ComposableFunction ULP = new ComposableFunction() {
+ /** {@inheritDoc} */
+ @Override
+ public double value(double d) {
+ return FastMath.ulp(d);
+ }
+ };
+
+ /** Precompose the instance with another function.
+ * <p>
+ * The composed function h created by {@code h = g.of(f)} is such
+ * that {@code h.value(x) == g.value(f.value(x))} for all x.
+ * </p>
+ * @param f function to compose with
+ * @return a new function which computes {@code this.value(f.value(x))}
+ * @see #postCompose(UnivariateRealFunction)
+ */
+ public ComposableFunction of(final UnivariateRealFunction f) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return ComposableFunction.this.value(f.value(x));
+ }
+ };
+ }
+
+ /** Postcompose the instance with another function.
+ * <p>
+ * The composed function h created by {@code h = g.postCompose(f)} is such
+ * that {@code h.value(x) == f.value(g.value(x))} for all x.
+ * </p>
+ * @param f function to compose with
+ * @return a new function which computes {@code f.value(this.value(x))}
+ * @see #of(UnivariateRealFunction)
+ */
+ public ComposableFunction postCompose(final UnivariateRealFunction f) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return f.value(ComposableFunction.this.value(x));
+ }
+ };
+ }
+
+ /**
+ * Return a function combining the instance and another function.
+ * <p>
+ * The function h created by {@code h = g.combine(f, combiner)} is such that
+ * {@code h.value(x) == combiner.value(g.value(x), f.value(x))} for all x.
+ * </p>
+ * @param f function to combine with the instance
+ * @param combiner bivariate function used for combining
+ * @return a new function which computes {@code combine.value(this.value(x), f.value(x))}
+ */
+ public ComposableFunction combine(final UnivariateRealFunction f,
+ final BivariateRealFunction combiner) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return combiner.value(ComposableFunction.this.value(x), f.value(x));
+ }
+ };
+ }
+
+ /**
+ * Return a function adding the instance and another function.
+ * @param f function to combine with the instance
+ * @return a new function which computes {@code this.value(x) + f.value(x)}
+ */
+ public ComposableFunction add(final UnivariateRealFunction f) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return ComposableFunction.this.value(x) + f.value(x);
+ }
+ };
+ }
+
+ /**
+ * Return a function adding a constant term to the instance.
+ * @param a term to add
+ * @return a new function which computes {@code this.value(x) + a}
+ */
+ public ComposableFunction add(final double a) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return ComposableFunction.this.value(x) + a;
+ }
+ };
+ }
+
+ /**
+ * Return a function subtracting another function from the instance.
+ * @param f function to combine with the instance
+ * @return a new function which computes {@code this.value(x) - f.value(x)}
+ */
+ public ComposableFunction subtract(final UnivariateRealFunction f) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return ComposableFunction.this.value(x) - f.value(x);
+ }
+ };
+ }
+
+ /**
+ * Return a function multiplying the instance and another function.
+ * @param f function to combine with the instance
+ * @return a new function which computes {@code this.value(x) * f.value(x)}
+ */
+ public ComposableFunction multiply(final UnivariateRealFunction f) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return ComposableFunction.this.value(x) * f.value(x);
+ }
+ };
+ }
+
+ /**
+ * Return a function scaling the instance by a constant factor.
+ * @param scaleFactor constant scaling factor
+ * @return a new function which computes {@code this.value(x) * scaleFactor}
+ */
+ public ComposableFunction multiply(final double scaleFactor) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return ComposableFunction.this.value(x) * scaleFactor;
+ }
+ };
+ }
+ /**
+ * Return a function dividing the instance by another function.
+ * @param f function to combine with the instance
+ * @return a new function which computes {@code this.value(x) / f.value(x)}
+ */
+ public ComposableFunction divide(final UnivariateRealFunction f) {
+ return new ComposableFunction() {
+ @Override
+ /** {@inheritDoc} */
+ public double value(double x) throws FunctionEvaluationException {
+ return ComposableFunction.this.value(x) / f.value(x);
+ }
+ };
+ }
+
+ /**
+ * Generates a function that iteratively apply instance function on all
+ * elements of an array.
+ * <p>
+ * The generated function behaves as follows:
+ * <ul>
+ * <li>initialize result = initialValue</li>
+ * <li>iterate: {@code result = combiner.value(result,
+ * this.value(nextMultivariateEntry));}</li>
+ * <li>return result</li>
+ * </ul>
+ * </p>
+ * @param combiner combiner to use between entries
+ * @param initialValue initial value to use before first entry
+ * @return a new function that iteratively apply instance function on all
+ * elements of an array.
+ */
+ public MultivariateRealFunction asCollector(final BivariateRealFunction combiner,
+ final double initialValue) {
+ return new MultivariateRealFunction() {
+ /** {@inheritDoc} */
+ public double value(double[] point)
+ throws FunctionEvaluationException, IllegalArgumentException {
+ double result = initialValue;
+ for (final double entry : point) {
+ result = combiner.value(result, ComposableFunction.this.value(entry));
+ }
+ return result;
+ }
+ };
+ }
+
+ /**
+ * Generates a function that iteratively apply instance function on all
+ * elements of an array.
+ * <p>
+ * Calling this method is equivalent to call {@link
+ * #asCollector(BivariateRealFunction, double) asCollector(BivariateRealFunction, 0.0)}.
+ * </p>
+ * @param combiner combiner to use between entries
+ * @return a new function that iteratively apply instance function on all
+ * elements of an array.
+ * @see #asCollector(BivariateRealFunction, double)
+ */
+ public MultivariateRealFunction asCollector(final BivariateRealFunction combiner) {
+ return asCollector(combiner, 0.0);
+ }
+
+ /**
+ * Generates a function that iteratively apply instance function on all
+ * elements of an array.
+ * <p>
+ * Calling this method is equivalent to call {@link
+ * #asCollector(BivariateRealFunction, double) asCollector(BinaryFunction.ADD, initialValue)}.
+ * </p>
+ * @param initialValue initial value to use before first entry
+ * @return a new function that iteratively apply instance function on all
+ * elements of an array.
+ * @see #asCollector(BivariateRealFunction, double)
+ * @see BinaryFunction#ADD
+ */
+ public MultivariateRealFunction asCollector(final double initialValue) {
+ return asCollector(BinaryFunction.ADD, initialValue);
+ }
+
+ /**
+ * Generates a function that iteratively apply instance function on all
+ * elements of an array.
+ * <p>
+ * Calling this method is equivalent to call {@link
+ * #asCollector(BivariateRealFunction, double) asCollector(BinaryFunction.ADD, 0.0)}.
+ * </p>
+ * @return a new function that iteratively apply instance function on all
+ * elements of an array.
+ * @see #asCollector(BivariateRealFunction, double)
+ * @see BinaryFunction#ADD
+ */
+ public MultivariateRealFunction asCollector() {
+ return asCollector(BinaryFunction.ADD, 0.0);
+ }
+
+ /** {@inheritDoc} */
+ public abstract double value(double x) throws FunctionEvaluationException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/DifferentiableMultivariateRealFunction.java b/src/main/java/org/apache/commons/math/analysis/DifferentiableMultivariateRealFunction.java
new file mode 100644
index 0000000..8d4f0c9
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/DifferentiableMultivariateRealFunction.java
@@ -0,0 +1,51 @@
+/*
+ * 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.analysis;
+
+/**
+ * Extension of {@link MultivariateRealFunction} representing a differentiable
+ * multivariate real function.
+ * @version $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $
+ * @since 2.0
+ */
+public interface DifferentiableMultivariateRealFunction extends MultivariateRealFunction {
+
+ /**
+ * Returns the partial derivative of the function with respect to a point coordinate.
+ * <p>
+ * The partial derivative is defined with respect to point coordinate
+ * x<sub>k</sub>. If the partial derivatives with respect to all coordinates are
+ * needed, it may be more efficient to use the {@link #gradient()} method which will
+ * compute them all at once.
+ * </p>
+ * @param k index of the coordinate with respect to which the partial
+ * derivative is computed
+ * @return the partial derivative function with respect to k<sup>th</sup> point coordinate
+ */
+ MultivariateRealFunction partialDerivative(int k);
+
+ /**
+ * Returns the gradient function.
+ * <p>If only one partial derivative with respect to a specific coordinate is
+ * needed, it may be more efficient to use the {@link #partialDerivative(int)} method
+ * which will compute only the specified component.</p>
+ * @return the gradient function
+ */
+ MultivariateVectorialFunction gradient();
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/DifferentiableMultivariateVectorialFunction.java b/src/main/java/org/apache/commons/math/analysis/DifferentiableMultivariateVectorialFunction.java
new file mode 100644
index 0000000..cc4ab8e
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/DifferentiableMultivariateVectorialFunction.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.analysis;
+
+
+/**
+ * Extension of {@link MultivariateVectorialFunction} representing a differentiable
+ * multivariate vectorial function.
+ * @version $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $
+ * @since 2.0
+ */
+public interface DifferentiableMultivariateVectorialFunction
+ extends MultivariateVectorialFunction {
+
+ /**
+ * Returns the jacobian function.
+ * @return the jacobian function
+ */
+ MultivariateMatrixFunction jacobian();
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateMatrixFunction.java b/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateMatrixFunction.java
new file mode 100644
index 0000000..5f2f11b
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateMatrixFunction.java
@@ -0,0 +1,35 @@
+/*
+ * 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.analysis;
+
+/**
+ * Extension of {@link UnivariateMatrixFunction} representing a differentiable univariate matrix function.
+ *
+ * @version $Revision: 811786 $ $Date: 2009-09-06 11:36:08 +0200 (dim. 06 sept. 2009) $
+ * @since 2.0
+ */
+public interface DifferentiableUnivariateMatrixFunction
+ extends UnivariateMatrixFunction {
+
+ /**
+ * Returns the derivative of the function
+ *
+ * @return the derivative function
+ */
+ UnivariateMatrixFunction derivative();
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateRealFunction.java b/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateRealFunction.java
new file mode 100644
index 0000000..1faaad3
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateRealFunction.java
@@ -0,0 +1,34 @@
+/*
+ * 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.analysis;
+
+/**
+ * Extension of {@link UnivariateRealFunction} representing a differentiable univariate real function.
+ *
+ * @version $Revision: 811786 $ $Date: 2009-09-06 11:36:08 +0200 (dim. 06 sept. 2009) $
+ */
+public interface DifferentiableUnivariateRealFunction
+ extends UnivariateRealFunction {
+
+ /**
+ * Returns the derivative of the function
+ *
+ * @return the derivative function
+ */
+ UnivariateRealFunction derivative();
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateVectorialFunction.java b/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateVectorialFunction.java
new file mode 100644
index 0000000..6566afe
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/DifferentiableUnivariateVectorialFunction.java
@@ -0,0 +1,35 @@
+/*
+ * 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.analysis;
+
+/**
+ * Extension of {@link UnivariateVectorialFunction} representing a differentiable univariate vectorial function.
+ *
+ * @version $Revision: 811786 $ $Date: 2009-09-06 11:36:08 +0200 (dim. 06 sept. 2009) $
+ * @since 2.0
+ */
+public interface DifferentiableUnivariateVectorialFunction
+ extends UnivariateVectorialFunction {
+
+ /**
+ * Returns the derivative of the function
+ *
+ * @return the derivative function
+ */
+ UnivariateVectorialFunction derivative();
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/MultivariateMatrixFunction.java b/src/main/java/org/apache/commons/math/analysis/MultivariateMatrixFunction.java
new file mode 100644
index 0000000..a5bad26
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/MultivariateMatrixFunction.java
@@ -0,0 +1,40 @@
+/*
+ * 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.analysis;
+
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ * An interface representing a multivariate matrix function.
+ * @version $Revision: 1073158 $ $Date: 2011-02-21 22:46:52 +0100 (lun. 21 févr. 2011) $
+ * @since 2.0
+ */
+public interface MultivariateMatrixFunction {
+
+ /**
+ * Compute the value for the function at the given point.
+ * @param point point at which the function must be evaluated
+ * @return function value for the given point
+ * @exception FunctionEvaluationException if the function evaluation fails
+ * @exception IllegalArgumentException if points dimension is wrong
+ */
+ double[][] value(double[] point)
+ throws FunctionEvaluationException, IllegalArgumentException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/MultivariateRealFunction.java b/src/main/java/org/apache/commons/math/analysis/MultivariateRealFunction.java
new file mode 100644
index 0000000..f054c51
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/MultivariateRealFunction.java
@@ -0,0 +1,39 @@
+/*
+ * 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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ * An interface representing a multivariate real function.
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 2.0
+ */
+public interface MultivariateRealFunction {
+
+ /**
+ * Compute the value for the function at the given point.
+ * @param point point at which the function must be evaluated
+ * @return function value for the given point
+ * @exception FunctionEvaluationException if the function evaluation fails
+ * @exception IllegalArgumentException if points dimension is wrong
+ */
+ double value(double[] point)
+ throws FunctionEvaluationException, IllegalArgumentException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/MultivariateVectorialFunction.java b/src/main/java/org/apache/commons/math/analysis/MultivariateVectorialFunction.java
new file mode 100644
index 0000000..7e83a7c
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/MultivariateVectorialFunction.java
@@ -0,0 +1,39 @@
+/*
+ * 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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ * An interface representing a multivariate vectorial function.
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 2.0
+ */
+public interface MultivariateVectorialFunction {
+
+ /**
+ * Compute the value for the function at the given point.
+ * @param point point at which the function must be evaluated
+ * @return function value for the given point
+ * @exception FunctionEvaluationException if the function evaluation fails
+ * @exception IllegalArgumentException if points dimension is wrong
+ */
+ double[] value(double[] point)
+ throws FunctionEvaluationException, IllegalArgumentException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/TrivariateRealFunction.java b/src/main/java/org/apache/commons/math/analysis/TrivariateRealFunction.java
new file mode 100644
index 0000000..3ebf24d
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/TrivariateRealFunction.java
@@ -0,0 +1,40 @@
+/*
+ * 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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ * An interface representing a trivariate real function.
+ *
+ * @since 2.2
+ * @version $Revision$ $Date$
+ */
+public interface TrivariateRealFunction {
+ /**
+ * Compute the value for the function.
+ *
+ * @param x x-coordinate for which the function value should be computed.
+ * @param y y-coordinate for which the function value should be computed.
+ * @param z z-coordinate for which the function value should be computed.
+ * @return the value.
+ * @throws FunctionEvaluationException if the function evaluation fails.
+ */
+ double value(double x, double y, double z)
+ throws FunctionEvaluationException;
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/UnivariateMatrixFunction.java b/src/main/java/org/apache/commons/math/analysis/UnivariateMatrixFunction.java
new file mode 100644
index 0000000..2db7349
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/UnivariateMatrixFunction.java
@@ -0,0 +1,37 @@
+/*
+ * 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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ * An interface representing a univariate matrix function.
+ *
+ * @version $Revision: 1073498 $ $Date: 2011-02-22 21:57:26 +0100 (mar. 22 févr. 2011) $
+ * @since 2.0
+ */
+public interface UnivariateMatrixFunction {
+
+ /**
+ * Compute the value for the function.
+ * @param x the point for which the function value should be computed
+ * @return the value
+ * @throws FunctionEvaluationException if the function evaluation fails
+ */
+ double[][] value(double x) throws FunctionEvaluationException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/UnivariateRealFunction.java b/src/main/java/org/apache/commons/math/analysis/UnivariateRealFunction.java
new file mode 100644
index 0000000..298d8a7
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/UnivariateRealFunction.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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ * An interface representing a univariate real function.
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ */
+public interface UnivariateRealFunction {
+
+ /**
+ * Compute the value for the function.
+ * @param x the point for which the function value should be computed
+ * @return the value
+ * @throws FunctionEvaluationException if the function evaluation fails
+ */
+ double value(double x) throws FunctionEvaluationException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/UnivariateVectorialFunction.java b/src/main/java/org/apache/commons/math/analysis/UnivariateVectorialFunction.java
new file mode 100644
index 0000000..64e7e15
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/UnivariateVectorialFunction.java
@@ -0,0 +1,37 @@
+/*
+ * 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.analysis;
+
+import org.apache.commons.math.FunctionEvaluationException;
+
+/**
+ * An interface representing a univariate vectorial function.
+ *
+ * @version $Revision: 1073498 $ $Date: 2011-02-22 21:57:26 +0100 (mar. 22 févr. 2011) $
+ * @since 2.0
+ */
+public interface UnivariateVectorialFunction {
+
+ /**
+ * Compute the value for the function.
+ * @param x the point for which the function value should be computed
+ * @return the value
+ * @throws FunctionEvaluationException if the function evaluation fails
+ */
+ double[] value(double x) throws FunctionEvaluationException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/integration/LegendreGaussIntegrator.java b/src/main/java/org/apache/commons/math/analysis/integration/LegendreGaussIntegrator.java
new file mode 100644
index 0000000..db6b76c
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/integration/LegendreGaussIntegrator.java
@@ -0,0 +1,236 @@
+/*
+ * 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.analysis.integration;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/Legendre-GaussQuadrature.html">
+ * Legendre-Gauss</a> quadrature formula.
+ * <p>
+ * Legendre-Gauss integrators are efficient integrators that can
+ * accurately integrate functions with few functions evaluations. A
+ * Legendre-Gauss integrator using an n-points quadrature formula can
+ * integrate exactly 2n-1 degree polynomials.
+ * </p>
+ * <p>
+ * These integrators evaluate the function on n carefully chosen
+ * abscissas in each step interval (mapped to the canonical [-1 1] interval).
+ * The evaluation abscissas are not evenly spaced and none of them are
+ * at the interval endpoints. This implies the function integrated can be
+ * undefined at integration interval endpoints.
+ * </p>
+ * <p>
+ * The evaluation abscissas x<sub>i</sub> are the roots of the degree n
+ * Legendre polynomial. The weights a<sub>i</sub> of the quadrature formula
+ * integrals from -1 to +1 &int; Li<sup>2</sup> where Li (x) =
+ * &prod; (x-x<sub>k</sub>)/(x<sub>i</sub>-x<sub>k</sub>) for k != i.
+ * </p>
+ * <p>
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 1.2
+ */
+
+public class LegendreGaussIntegrator extends UnivariateRealIntegratorImpl {
+
+ /** Abscissas for the 2 points method. */
+ private static final double[] ABSCISSAS_2 = {
+ -1.0 / FastMath.sqrt(3.0),
+ 1.0 / FastMath.sqrt(3.0)
+ };
+
+ /** Weights for the 2 points method. */
+ private static final double[] WEIGHTS_2 = {
+ 1.0,
+ 1.0
+ };
+
+ /** Abscissas for the 3 points method. */
+ private static final double[] ABSCISSAS_3 = {
+ -FastMath.sqrt(0.6),
+ 0.0,
+ FastMath.sqrt(0.6)
+ };
+
+ /** Weights for the 3 points method. */
+ private static final double[] WEIGHTS_3 = {
+ 5.0 / 9.0,
+ 8.0 / 9.0,
+ 5.0 / 9.0
+ };
+
+ /** Abscissas for the 4 points method. */
+ private static final double[] ABSCISSAS_4 = {
+ -FastMath.sqrt((15.0 + 2.0 * FastMath.sqrt(30.0)) / 35.0),
+ -FastMath.sqrt((15.0 - 2.0 * FastMath.sqrt(30.0)) / 35.0),
+ FastMath.sqrt((15.0 - 2.0 * FastMath.sqrt(30.0)) / 35.0),
+ FastMath.sqrt((15.0 + 2.0 * FastMath.sqrt(30.0)) / 35.0)
+ };
+
+ /** Weights for the 4 points method. */
+ private static final double[] WEIGHTS_4 = {
+ (90.0 - 5.0 * FastMath.sqrt(30.0)) / 180.0,
+ (90.0 + 5.0 * FastMath.sqrt(30.0)) / 180.0,
+ (90.0 + 5.0 * FastMath.sqrt(30.0)) / 180.0,
+ (90.0 - 5.0 * FastMath.sqrt(30.0)) / 180.0
+ };
+
+ /** Abscissas for the 5 points method. */
+ private static final double[] ABSCISSAS_5 = {
+ -FastMath.sqrt((35.0 + 2.0 * FastMath.sqrt(70.0)) / 63.0),
+ -FastMath.sqrt((35.0 - 2.0 * FastMath.sqrt(70.0)) / 63.0),
+ 0.0,
+ FastMath.sqrt((35.0 - 2.0 * FastMath.sqrt(70.0)) / 63.0),
+ FastMath.sqrt((35.0 + 2.0 * FastMath.sqrt(70.0)) / 63.0)
+ };
+
+ /** Weights for the 5 points method. */
+ private static final double[] WEIGHTS_5 = {
+ (322.0 - 13.0 * FastMath.sqrt(70.0)) / 900.0,
+ (322.0 + 13.0 * FastMath.sqrt(70.0)) / 900.0,
+ 128.0 / 225.0,
+ (322.0 + 13.0 * FastMath.sqrt(70.0)) / 900.0,
+ (322.0 - 13.0 * FastMath.sqrt(70.0)) / 900.0
+ };
+
+ /** Abscissas for the current method. */
+ private final double[] abscissas;
+
+ /** Weights for the current method. */
+ private final double[] weights;
+
+ /**
+ * Build a Legendre-Gauss integrator.
+ * @param n number of points desired (must be between 2 and 5 inclusive)
+ * @param defaultMaximalIterationCount maximum number of iterations
+ * @exception IllegalArgumentException if the number of points is not
+ * in the supported range
+ */
+ public LegendreGaussIntegrator(final int n, final int defaultMaximalIterationCount)
+ throws IllegalArgumentException {
+ super(defaultMaximalIterationCount);
+ switch(n) {
+ case 2 :
+ abscissas = ABSCISSAS_2;
+ weights = WEIGHTS_2;
+ break;
+ case 3 :
+ abscissas = ABSCISSAS_3;
+ weights = WEIGHTS_3;
+ break;
+ case 4 :
+ abscissas = ABSCISSAS_4;
+ weights = WEIGHTS_4;
+ break;
+ case 5 :
+ abscissas = ABSCISSAS_5;
+ weights = WEIGHTS_5;
+ break;
+ default :
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.N_POINTS_GAUSS_LEGENDRE_INTEGRATOR_NOT_SUPPORTED,
+ n, 2, 5);
+ }
+
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double integrate(final double min, final double max)
+ throws ConvergenceException, FunctionEvaluationException, IllegalArgumentException {
+ return integrate(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ public double integrate(final UnivariateRealFunction f, final double min, final double max)
+ throws ConvergenceException, FunctionEvaluationException, IllegalArgumentException {
+
+ clearResult();
+ verifyInterval(min, max);
+ verifyIterationCount();
+
+ // compute first estimate with a single step
+ double oldt = stage(f, min, max, 1);
+
+ int n = 2;
+ for (int i = 0; i < maximalIterationCount; ++i) {
+
+ // improve integral with a larger number of steps
+ final double t = stage(f, min, max, n);
+
+ // estimate error
+ final double delta = FastMath.abs(t - oldt);
+ final double limit =
+ FastMath.max(absoluteAccuracy,
+ relativeAccuracy * (FastMath.abs(oldt) + FastMath.abs(t)) * 0.5);
+
+ // check convergence
+ if ((i + 1 >= minimalIterationCount) && (delta <= limit)) {
+ setResult(t, i);
+ return result;
+ }
+
+ // prepare next iteration
+ double ratio = FastMath.min(4, FastMath.pow(delta / limit, 0.5 / abscissas.length));
+ n = FastMath.max((int) (ratio * n), n + 1);
+ oldt = t;
+
+ }
+
+ throw new MaxIterationsExceededException(maximalIterationCount);
+
+ }
+
+ /**
+ * Compute the n-th stage integral.
+ * @param f the integrand function
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param n number of steps
+ * @return the value of n-th stage integral
+ * @throws FunctionEvaluationException if an error occurs evaluating the
+ * function
+ */
+ private double stage(final UnivariateRealFunction f,
+ final double min, final double max, final int n)
+ throws FunctionEvaluationException {
+
+ // set up the step for the current stage
+ final double step = (max - min) / n;
+ final double halfStep = step / 2.0;
+
+ // integrate over all elementary steps
+ double midPoint = min + halfStep;
+ double sum = 0.0;
+ for (int i = 0; i < n; ++i) {
+ for (int j = 0; j < abscissas.length; ++j) {
+ sum += weights[j] * f.value(midPoint + halfStep * abscissas[j]);
+ }
+ midPoint += step;
+ }
+
+ return halfStep * sum;
+
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/integration/RombergIntegrator.java b/src/main/java/org/apache/commons/math/analysis/integration/RombergIntegrator.java
new file mode 100644
index 0000000..9650af5
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/integration/RombergIntegrator.java
@@ -0,0 +1,121 @@
+/*
+ * 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.analysis.integration;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/RombergIntegration.html">
+ * Romberg Algorithm</a> for integration of real univariate functions. For
+ * reference, see <b>Introduction to Numerical Analysis</b>, ISBN 038795452X,
+ * chapter 3.
+ * <p>
+ * Romberg integration employs k successive refinements of the trapezoid
+ * rule to remove error terms less than order O(N^(-2k)). Simpson's rule
+ * is a special case of k = 2.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 1.2
+ */
+public class RombergIntegrator extends UnivariateRealIntegratorImpl {
+
+ /**
+ * Construct an integrator for the given function.
+ *
+ * @param f function to integrate
+ * @deprecated as of 2.0 the integrand function is passed as an argument
+ * to the {@link #integrate(UnivariateRealFunction, double, double)}method.
+ */
+ @Deprecated
+ public RombergIntegrator(UnivariateRealFunction f) {
+ super(f, 32);
+ }
+
+ /**
+ * Construct an integrator.
+ */
+ public RombergIntegrator() {
+ super(32);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double integrate(final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException, IllegalArgumentException {
+ return integrate(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ public double integrate(final UnivariateRealFunction f, final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException, IllegalArgumentException {
+
+ final int m = maximalIterationCount + 1;
+ double previousRow[] = new double[m];
+ double currentRow[] = new double[m];
+
+ clearResult();
+ verifyInterval(min, max);
+ verifyIterationCount();
+
+ TrapezoidIntegrator qtrap = new TrapezoidIntegrator();
+ currentRow[0] = qtrap.stage(f, min, max, 0);
+ double olds = currentRow[0];
+ for (int i = 1; i <= maximalIterationCount; ++i) {
+
+ // switch rows
+ final double[] tmpRow = previousRow;
+ previousRow = currentRow;
+ currentRow = tmpRow;
+
+ currentRow[0] = qtrap.stage(f, min, max, i);
+ for (int j = 1; j <= i; j++) {
+ // Richardson extrapolation coefficient
+ final double r = (1L << (2 * j)) - 1;
+ final double tIJm1 = currentRow[j - 1];
+ currentRow[j] = tIJm1 + (tIJm1 - previousRow[j - 1]) / r;
+ }
+ final double s = currentRow[i];
+ if (i >= minimalIterationCount) {
+ final double delta = FastMath.abs(s - olds);
+ final double rLimit = relativeAccuracy * (FastMath.abs(olds) + FastMath.abs(s)) * 0.5;
+ if ((delta <= rLimit) || (delta <= absoluteAccuracy)) {
+ setResult(s, i);
+ return result;
+ }
+ }
+ olds = s;
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void verifyIterationCount() throws IllegalArgumentException {
+ super.verifyIterationCount();
+ // at most 32 bisection refinements due to higher order divider
+ if (maximalIterationCount > 32) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.INVALID_ITERATIONS_LIMITS,
+ 0, 32);
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/integration/SimpsonIntegrator.java b/src/main/java/org/apache/commons/math/analysis/integration/SimpsonIntegrator.java
new file mode 100644
index 0000000..045b54e
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/integration/SimpsonIntegrator.java
@@ -0,0 +1,112 @@
+/*
+ * 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.analysis.integration;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/SimpsonsRule.html">
+ * Simpson's Rule</a> for integration of real univariate functions. For
+ * reference, see <b>Introduction to Numerical Analysis</b>, ISBN 038795452X,
+ * chapter 3.
+ * <p>
+ * This implementation employs basic trapezoid rule as building blocks to
+ * calculate the Simpson's rule of alternating 2/3 and 4/3.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 1.2
+ */
+public class SimpsonIntegrator extends UnivariateRealIntegratorImpl {
+
+ /**
+ * Construct an integrator for the given function.
+ *
+ * @param f function to integrate
+ * @deprecated as of 2.0 the integrand function is passed as an argument
+ * to the {@link #integrate(UnivariateRealFunction, double, double)}method.
+ */
+ @Deprecated
+ public SimpsonIntegrator(UnivariateRealFunction f) {
+ super(f, 64);
+ }
+
+ /**
+ * Construct an integrator.
+ */
+ public SimpsonIntegrator() {
+ super(64);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double integrate(final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException, IllegalArgumentException {
+ return integrate(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ public double integrate(final UnivariateRealFunction f, final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException, IllegalArgumentException {
+
+ clearResult();
+ verifyInterval(min, max);
+ verifyIterationCount();
+
+ TrapezoidIntegrator qtrap = new TrapezoidIntegrator();
+ if (minimalIterationCount == 1) {
+ final double s = (4 * qtrap.stage(f, min, max, 1) - qtrap.stage(f, min, max, 0)) / 3.0;
+ setResult(s, 1);
+ return result;
+ }
+ // Simpson's rule requires at least two trapezoid stages.
+ double olds = 0;
+ double oldt = qtrap.stage(f, min, max, 0);
+ for (int i = 1; i <= maximalIterationCount; ++i) {
+ final double t = qtrap.stage(f, min, max, i);
+ final double s = (4 * t - oldt) / 3.0;
+ if (i >= minimalIterationCount) {
+ final double delta = FastMath.abs(s - olds);
+ final double rLimit =
+ relativeAccuracy * (FastMath.abs(olds) + FastMath.abs(s)) * 0.5;
+ if ((delta <= rLimit) || (delta <= absoluteAccuracy)) {
+ setResult(s, i);
+ return result;
+ }
+ }
+ olds = s;
+ oldt = t;
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void verifyIterationCount() throws IllegalArgumentException {
+ super.verifyIterationCount();
+ // at most 64 bisection refinements
+ if (maximalIterationCount > 64) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.INVALID_ITERATIONS_LIMITS,
+ 0, 64);
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/integration/TrapezoidIntegrator.java b/src/main/java/org/apache/commons/math/analysis/integration/TrapezoidIntegrator.java
new file mode 100644
index 0000000..88903f5
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/integration/TrapezoidIntegrator.java
@@ -0,0 +1,142 @@
+/*
+ * 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.analysis.integration;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/TrapezoidalRule.html">
+ * Trapezoidal Rule</a> for integration of real univariate functions. For
+ * reference, see <b>Introduction to Numerical Analysis</b>, ISBN 038795452X,
+ * chapter 3.
+ * <p>
+ * The function should be integrable.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 1.2
+ */
+public class TrapezoidIntegrator extends UnivariateRealIntegratorImpl {
+
+ /** Intermediate result. */
+ private double s;
+
+ /**
+ * Construct an integrator for the given function.
+ *
+ * @param f function to integrate
+ * @deprecated as of 2.0 the integrand function is passed as an argument
+ * to the {@link #integrate(UnivariateRealFunction, double, double)}method.
+ */
+ @Deprecated
+ public TrapezoidIntegrator(UnivariateRealFunction f) {
+ super(f, 64);
+ }
+
+ /**
+ * Construct an integrator.
+ */
+ public TrapezoidIntegrator() {
+ super(64);
+ }
+
+ /**
+ * Compute the n-th stage integral of trapezoid rule. This function
+ * should only be called by API <code>integrate()</code> in the package.
+ * To save time it does not verify arguments - caller does.
+ * <p>
+ * The interval is divided equally into 2^n sections rather than an
+ * arbitrary m sections because this configuration can best utilize the
+ * alrealy computed values.</p>
+ *
+ * @param f the integrand function
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param n the stage of 1/2 refinement, n = 0 is no refinement
+ * @return the value of n-th stage integral
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ */
+ double stage(final UnivariateRealFunction f,
+ final double min, final double max, final int n)
+ throws FunctionEvaluationException {
+
+ if (n == 0) {
+ s = 0.5 * (max - min) * (f.value(min) + f.value(max));
+ return s;
+ } else {
+ final long np = 1L << (n-1); // number of new points in this stage
+ double sum = 0;
+ final double spacing = (max - min) / np; // spacing between adjacent new points
+ double x = min + 0.5 * spacing; // the first new point
+ for (long i = 0; i < np; i++) {
+ sum += f.value(x);
+ x += spacing;
+ }
+ // add the new sum to previously calculated result
+ s = 0.5 * (s + sum * spacing);
+ return s;
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double integrate(final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException, IllegalArgumentException {
+ return integrate(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ public double integrate(final UnivariateRealFunction f, final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException, IllegalArgumentException {
+
+ clearResult();
+ verifyInterval(min, max);
+ verifyIterationCount();
+
+ double oldt = stage(f, min, max, 0);
+ for (int i = 1; i <= maximalIterationCount; ++i) {
+ final double t = stage(f, min, max, i);
+ if (i >= minimalIterationCount) {
+ final double delta = FastMath.abs(t - oldt);
+ final double rLimit =
+ relativeAccuracy * (FastMath.abs(oldt) + FastMath.abs(t)) * 0.5;
+ if ((delta <= rLimit) || (delta <= absoluteAccuracy)) {
+ setResult(t, i);
+ return result;
+ }
+ }
+ oldt = t;
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void verifyIterationCount() throws IllegalArgumentException {
+ super.verifyIterationCount();
+ // at most 64 bisection refinements
+ if (maximalIterationCount > 64) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.INVALID_ITERATIONS_LIMITS,
+ 0, 64);
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/integration/UnivariateRealIntegrator.java b/src/main/java/org/apache/commons/math/analysis/integration/UnivariateRealIntegrator.java
new file mode 100644
index 0000000..184bb44
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/integration/UnivariateRealIntegrator.java
@@ -0,0 +1,106 @@
+/*
+ * 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.analysis.integration;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.ConvergingAlgorithm;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+
+/**
+ * Interface for univariate real integration algorithms.
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 1.2
+ */
+public interface UnivariateRealIntegrator extends ConvergingAlgorithm {
+
+ /**
+ * Set the lower limit for the number of iterations.
+ * <p>
+ * Minimal iteration is needed to avoid false early convergence, e.g.
+ * the sample points happen to be zeroes of the function. Users can
+ * use the default value or choose one that they see as appropriate.</p>
+ * <p>
+ * A <code>ConvergenceException</code> will be thrown if this number
+ * is not met.</p>
+ *
+ * @param count minimum number of iterations
+ */
+ void setMinimalIterationCount(int count);
+
+ /**
+ * Get the lower limit for the number of iterations.
+ *
+ * @return the actual lower limit
+ */
+ int getMinimalIterationCount();
+
+ /**
+ * Reset the lower limit for the number of iterations to the default.
+ * <p>
+ * The default value is supplied by the implementation.</p>
+ *
+ * @see #setMinimalIterationCount(int)
+ */
+ void resetMinimalIterationCount();
+
+ /**
+ * Integrate the function in the given interval.
+ *
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @return the value of integral
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the integrator detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the
+ * function
+ * @throws IllegalArgumentException if min > max or the endpoints do not
+ * satisfy the requirements specified by the integrator
+ * @deprecated replaced by {@link #integrate(UnivariateRealFunction, double, double)}
+ * since 2.0
+ */
+ @Deprecated
+ double integrate(double min, double max)
+ throws ConvergenceException, FunctionEvaluationException, IllegalArgumentException;
+
+ /**
+ * Integrate the function in the given interval.
+ *
+ * @param f the integrand function
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @return the value of integral
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the integrator detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min > max or the endpoints do not
+ * satisfy the requirements specified by the integrator
+ */
+ double integrate(UnivariateRealFunction f, double min, double max)
+ throws ConvergenceException, FunctionEvaluationException, IllegalArgumentException;
+
+ /**
+ * Get the result of the last run of the integrator.
+ *
+ * @return the last result
+ * @throws IllegalStateException if there is no result available, either
+ * because no result was yet computed or the last attempt failed
+ */
+ double getResult() throws IllegalStateException;
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/integration/UnivariateRealIntegratorImpl.java b/src/main/java/org/apache/commons/math/analysis/integration/UnivariateRealIntegratorImpl.java
new file mode 100644
index 0000000..655a852
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/integration/UnivariateRealIntegratorImpl.java
@@ -0,0 +1,183 @@
+/*
+ * 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.analysis.integration;
+
+import org.apache.commons.math.ConvergingAlgorithmImpl;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.exception.NullArgumentException;
+
+/**
+ * Provide a default implementation for several generic functions.
+ *
+ * @version $Revision: 1072409 $ $Date: 2011-02-19 19:50:36 +0100 (sam. 19 févr. 2011) $
+ * @since 1.2
+ */
+public abstract class UnivariateRealIntegratorImpl
+ extends ConvergingAlgorithmImpl implements UnivariateRealIntegrator {
+
+ /** Serializable version identifier. */
+ private static final long serialVersionUID = 6248808456637441533L;
+
+ /** minimum number of iterations */
+ protected int minimalIterationCount;
+
+ /** default minimum number of iterations */
+ protected int defaultMinimalIterationCount;
+
+ /** indicates whether an integral has been computed */
+ protected boolean resultComputed = false;
+
+ /** the last computed integral */
+ protected double result;
+
+ /**
+ * The integrand function.
+ *
+ * @deprecated as of 2.0 the integrand function is passed as an argument
+ * to the {@link #integrate(UnivariateRealFunction, double, double)}method.
+ */
+ @Deprecated
+ protected UnivariateRealFunction f;
+
+ /**
+ * Construct an integrator with given iteration count and accuracy.
+ *
+ * @param f the integrand function
+ * @param defaultMaximalIterationCount maximum number of iterations
+ * @throws IllegalArgumentException if f is null or the iteration
+ * limits are not valid
+ * @deprecated as of 2.0 the integrand function is passed as an argument
+ * to the {@link #integrate(UnivariateRealFunction, double, double)}method.
+ */
+ @Deprecated
+ protected UnivariateRealIntegratorImpl(final UnivariateRealFunction f,
+ final int defaultMaximalIterationCount)
+ throws IllegalArgumentException {
+ super(defaultMaximalIterationCount, 1.0e-15);
+ if (f == null) {
+ throw new NullArgumentException(LocalizedFormats.FUNCTION);
+ }
+
+ this.f = f;
+
+ // parameters that are problem specific
+ setRelativeAccuracy(1.0e-6);
+ this.defaultMinimalIterationCount = 3;
+ this.minimalIterationCount = defaultMinimalIterationCount;
+
+ verifyIterationCount();
+ }
+
+ /**
+ * Construct an integrator with given iteration count and accuracy.
+ *
+ * @param defaultMaximalIterationCount maximum number of iterations
+ * @throws IllegalArgumentException if f is null or the iteration
+ * limits are not valid
+ */
+ protected UnivariateRealIntegratorImpl(final int defaultMaximalIterationCount)
+ throws IllegalArgumentException {
+ super(defaultMaximalIterationCount, 1.0e-15);
+
+ // parameters that are problem specific
+ setRelativeAccuracy(1.0e-6);
+ this.defaultMinimalIterationCount = 3;
+ this.minimalIterationCount = defaultMinimalIterationCount;
+
+ verifyIterationCount();
+ }
+
+ /**
+ * Access the last computed integral.
+ *
+ * @return the last computed integral
+ * @throws IllegalStateException if no integral has been computed
+ */
+ public double getResult() throws IllegalStateException {
+ if (resultComputed) {
+ return result;
+ } else {
+ throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_RESULT_AVAILABLE);
+ }
+ }
+
+ /**
+ * Convenience function for implementations.
+ *
+ * @param newResult the result to set
+ * @param iterationCount the iteration count to set
+ */
+ protected final void setResult(double newResult, int iterationCount) {
+ this.result = newResult;
+ this.iterationCount = iterationCount;
+ this.resultComputed = true;
+ }
+
+ /**
+ * Convenience function for implementations.
+ */
+ protected final void clearResult() {
+ this.iterationCount = 0;
+ this.resultComputed = false;
+ }
+
+ /** {@inheritDoc} */
+ public void setMinimalIterationCount(int count) {
+ minimalIterationCount = count;
+ }
+
+ /** {@inheritDoc} */
+ public int getMinimalIterationCount() {
+ return minimalIterationCount;
+ }
+
+ /** {@inheritDoc} */
+ public void resetMinimalIterationCount() {
+ minimalIterationCount = defaultMinimalIterationCount;
+ }
+
+ /**
+ * Verifies that the endpoints specify an interval.
+ *
+ * @param lower lower endpoint
+ * @param upper upper endpoint
+ * @throws IllegalArgumentException if not interval
+ */
+ protected void verifyInterval(double lower, double upper) throws
+ IllegalArgumentException {
+ if (lower >= upper) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
+ lower, upper);
+ }
+ }
+
+ /**
+ * Verifies that the upper and lower limits of iterations are valid.
+ *
+ * @throws IllegalArgumentException if not valid
+ */
+ protected void verifyIterationCount() throws IllegalArgumentException {
+ if ((minimalIterationCount <= 0) || (maximalIterationCount <= minimalIterationCount)) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.INVALID_ITERATIONS_LIMITS,
+ minimalIterationCount, maximalIterationCount);
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/integration/package.html b/src/main/java/org/apache/commons/math/analysis/integration/package.html
new file mode 100644
index 0000000..5bbab0e
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/integration/package.html
@@ -0,0 +1,22 @@
+<html>
+<!--
+ 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.
+ -->
+ <!-- $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $ -->
+ <body>
+ Numerical integration (quadrature) algorithms for univariate real functions.
+ </body>
+</html>
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/BicubicSplineInterpolatingFunction.java b/src/main/java/org/apache/commons/math/analysis/interpolation/BicubicSplineInterpolatingFunction.java
new file mode 100644
index 0000000..c786a4d
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/BicubicSplineInterpolatingFunction.java
@@ -0,0 +1,558 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.DimensionMismatchException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.analysis.BivariateRealFunction;
+import org.apache.commons.math.exception.NoDataException;
+import org.apache.commons.math.exception.OutOfRangeException;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Function that implements the
+ * <a href="http://en.wikipedia.org/wiki/Bicubic_interpolation">
+ * bicubic spline interpolation</a>.
+ *
+ * @version $Revision$ $Date$
+ * @since 2.1
+ */
+public class BicubicSplineInterpolatingFunction
+ implements BivariateRealFunction {
+ /**
+ * Matrix to compute the spline coefficients from the function values
+ * and function derivatives values
+ */
+ private static final double[][] AINV = {
+ { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 },
+ { -3,3,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0 },
+ { 2,-2,0,0,1,1,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0 },
+ { 0,0,0,0,0,0,0,0,-3,3,0,0,-2,-1,0,0 },
+ { 0,0,0,0,0,0,0,0,2,-2,0,0,1,1,0,0 },
+ { -3,0,3,0,0,0,0,0,-2,0,-1,0,0,0,0,0 },
+ { 0,0,0,0,-3,0,3,0,0,0,0,0,-2,0,-1,0 },
+ { 9,-9,-9,9,6,3,-6,-3,6,-6,3,-3,4,2,2,1 },
+ { -6,6,6,-6,-3,-3,3,3,-4,4,-2,2,-2,-2,-1,-1 },
+ { 2,0,-2,0,0,0,0,0,1,0,1,0,0,0,0,0 },
+ { 0,0,0,0,2,0,-2,0,0,0,0,0,1,0,1,0 },
+ { -6,6,6,-6,-4,-2,4,2,-3,3,-3,3,-2,-1,-2,-1 },
+ { 4,-4,-4,4,2,2,-2,-2,2,-2,2,-2,1,1,1,1 }
+ };
+
+ /** Samples x-coordinates */
+ private final double[] xval;
+ /** Samples y-coordinates */
+ private final double[] yval;
+ /** Set of cubic splines patching the whole data grid */
+ private final BicubicSplineFunction[][] splines;
+ /**
+ * Partial derivatives
+ * The value of the first index determines the kind of derivatives:
+ * 0 = first partial derivatives wrt x
+ * 1 = first partial derivatives wrt y
+ * 2 = second partial derivatives wrt x
+ * 3 = second partial derivatives wrt y
+ * 4 = cross partial derivatives
+ */
+ private BivariateRealFunction[][][] partialDerivatives = null;
+
+ /**
+ * @param x Sample values of the x-coordinate, in increasing order.
+ * @param y Sample values of the y-coordinate, in increasing order.
+ * @param f Values of the function on every grid point.
+ * @param dFdX Values of the partial derivative of function with respect
+ * to x on every grid point.
+ * @param dFdY Values of the partial derivative of function with respect
+ * to y on every grid point.
+ * @param d2FdXdY Values of the cross partial derivative of function on
+ * every grid point.
+ * @throws DimensionMismatchException if the various arrays do not contain
+ * the expected number of elements.
+ * @throws org.apache.commons.math.exception.NonMonotonousSequenceException
+ * if {@code x} or {@code y} are not strictly increasing.
+ * @throws NoDataException if any of the arrays has zero length.
+ */
+ public BicubicSplineInterpolatingFunction(double[] x,
+ double[] y,
+ double[][] f,
+ double[][] dFdX,
+ double[][] dFdY,
+ double[][] d2FdXdY)
+ throws DimensionMismatchException {
+ final int xLen = x.length;
+ final int yLen = y.length;
+
+ if (xLen == 0 || yLen == 0 || f.length == 0 || f[0].length == 0) {
+ throw new NoDataException();
+ }
+ if (xLen != f.length) {
+ throw new DimensionMismatchException(xLen, f.length);
+ }
+ if (xLen != dFdX.length) {
+ throw new DimensionMismatchException(xLen, dFdX.length);
+ }
+ if (xLen != dFdY.length) {
+ throw new DimensionMismatchException(xLen, dFdY.length);
+ }
+ if (xLen != d2FdXdY.length) {
+ throw new DimensionMismatchException(xLen, d2FdXdY.length);
+ }
+
+ MathUtils.checkOrder(x);
+ MathUtils.checkOrder(y);
+
+ xval = x.clone();
+ yval = y.clone();
+
+ final int lastI = xLen - 1;
+ final int lastJ = yLen - 1;
+ splines = new BicubicSplineFunction[lastI][lastJ];
+
+ for (int i = 0; i < lastI; i++) {
+ if (f[i].length != yLen) {
+ throw new DimensionMismatchException(f[i].length, yLen);
+ }
+ if (dFdX[i].length != yLen) {
+ throw new DimensionMismatchException(dFdX[i].length, yLen);
+ }
+ if (dFdY[i].length != yLen) {
+ throw new DimensionMismatchException(dFdY[i].length, yLen);
+ }
+ if (d2FdXdY[i].length != yLen) {
+ throw new DimensionMismatchException(d2FdXdY[i].length, yLen);
+ }
+ final int ip1 = i + 1;
+ for (int j = 0; j < lastJ; j++) {
+ final int jp1 = j + 1;
+ final double[] beta = new double[] {
+ f[i][j], f[ip1][j], f[i][jp1], f[ip1][jp1],
+ dFdX[i][j], dFdX[ip1][j], dFdX[i][jp1], dFdX[ip1][jp1],
+ dFdY[i][j], dFdY[ip1][j], dFdY[i][jp1], dFdY[ip1][jp1],
+ d2FdXdY[i][j], d2FdXdY[ip1][j], d2FdXdY[i][jp1], d2FdXdY[ip1][jp1]
+ };
+
+ splines[i][j] = new BicubicSplineFunction(computeSplineCoefficients(beta));
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public double value(double x, double y) {
+ final int i = searchIndex(x, xval);
+ if (i == -1) {
+ throw new OutOfRangeException(x, xval[0], xval[xval.length - 1]);
+ }
+ final int j = searchIndex(y, yval);
+ if (j == -1) {
+ throw new OutOfRangeException(y, yval[0], yval[yval.length - 1]);
+ }
+
+ final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
+ final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
+
+ return splines[i][j].value(xN, yN);
+ }
+
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the first partial derivative with
+ * respect to x.
+ * @since 2.2
+ */
+ public double partialDerivativeX(double x, double y) {
+ return partialDerivative(0, x, y);
+ }
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the first partial derivative with
+ * respect to y.
+ * @since 2.2
+ */
+ public double partialDerivativeY(double x, double y) {
+ return partialDerivative(1, x, y);
+ }
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the second partial derivative with
+ * respect to x.
+ * @since 2.2
+ */
+ public double partialDerivativeXX(double x, double y) {
+ return partialDerivative(2, x, y);
+ }
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the second partial derivative with
+ * respect to y.
+ * @since 2.2
+ */
+ public double partialDerivativeYY(double x, double y) {
+ return partialDerivative(3, x, y);
+ }
+ /**
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the second partial cross-derivative.
+ * @since 2.2
+ */
+ public double partialDerivativeXY(double x, double y) {
+ return partialDerivative(4, x, y);
+ }
+
+ /**
+ * @param which First index in {@link #partialDerivatives}.
+ * @param x x-coordinate.
+ * @param y y-coordinate.
+ * @return the value at point (x, y) of the selected partial derivative.
+ * @throws FunctionEvaluationException
+ */
+ private double partialDerivative(int which, double x, double y) {
+ if (partialDerivatives == null) {
+ computePartialDerivatives();
+ }
+
+ final int i = searchIndex(x, xval);
+ if (i == -1) {
+ throw new OutOfRangeException(x, xval[0], xval[xval.length - 1]);
+ }
+ final int j = searchIndex(y, yval);
+ if (j == -1) {
+ throw new OutOfRangeException(y, yval[0], yval[yval.length - 1]);
+ }
+
+ final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
+ final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
+
+ try {
+ return partialDerivatives[which][i][j].value(xN, yN);
+ } catch (FunctionEvaluationException fee) {
+ // this should never happen
+ throw new RuntimeException(fee);
+ }
+
+ }
+
+ /**
+ * Compute all partial derivatives.
+ */
+ private void computePartialDerivatives() {
+ final int lastI = xval.length - 1;
+ final int lastJ = yval.length - 1;
+ partialDerivatives = new BivariateRealFunction[5][lastI][lastJ];
+
+ for (int i = 0; i < lastI; i++) {
+ for (int j = 0; j < lastJ; j++) {
+ final BicubicSplineFunction f = splines[i][j];
+ partialDerivatives[0][i][j] = f.partialDerivativeX();
+ partialDerivatives[1][i][j] = f.partialDerivativeY();
+ partialDerivatives[2][i][j] = f.partialDerivativeXX();
+ partialDerivatives[3][i][j] = f.partialDerivativeYY();
+ partialDerivatives[4][i][j] = f.partialDerivativeXY();
+ }
+ }
+ }
+
+ /**
+ * @param c Coordinate.
+ * @param val Coordinate samples.
+ * @return the index in {@code val} corresponding to the interval
+ * containing {@code c}, or {@code -1} if {@code c} is out of the
+ * range defined by the end values of {@code val}.
+ */
+ private int searchIndex(double c, double[] val) {
+ if (c < val[0]) {
+ return -1;
+ }
+
+ final int max = val.length;
+ for (int i = 1; i < max; i++) {
+ if (c <= val[i]) {
+ return i - 1;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Compute the spline coefficients from the list of function values and
+ * function partial derivatives values at the four corners of a grid
+ * element. They must be specified in the following order:
+ * <ul>
+ * <li>f(0,0)</li>
+ * <li>f(1,0)</li>
+ * <li>f(0,1)</li>
+ * <li>f(1,1)</li>
+ * <li>f<sub>x</sub>(0,0)</li>
+ * <li>f<sub>x</sub>(1,0)</li>
+ * <li>f<sub>x</sub>(0,1)</li>
+ * <li>f<sub>x</sub>(1,1)</li>
+ * <li>f<sub>y</sub>(0,0)</li>
+ * <li>f<sub>y</sub>(1,0)</li>
+ * <li>f<sub>y</sub>(0,1)</li>
+ * <li>f<sub>y</sub>(1,1)</li>
+ * <li>f<sub>xy</sub>(0,0)</li>
+ * <li>f<sub>xy</sub>(1,0)</li>
+ * <li>f<sub>xy</sub>(0,1)</li>
+ * <li>f<sub>xy</sub>(1,1)</li>
+ * </ul>
+ * where the subscripts indicate the partial derivative with respect to
+ * the corresponding variable(s).
+ *
+ * @param beta List of function values and function partial derivatives
+ * values.
+ * @return the spline coefficients.
+ */
+ private double[] computeSplineCoefficients(double[] beta) {
+ final double[] a = new double[16];
+
+ for (int i = 0; i < 16; i++) {
+ double result = 0;
+ final double[] row = AINV[i];
+ for (int j = 0; j < 16; j++) {
+ result += row[j] * beta[j];
+ }
+ a[i] = result;
+ }
+
+ return a;
+ }
+}
+
+/**
+ * 2D-spline function.
+ *
+ * @version $Revision$ $Date$
+ */
+class BicubicSplineFunction
+ implements BivariateRealFunction {
+
+ /** Number of points. */
+ private static final short N = 4;
+
+ /** Coefficients */
+ private final double[][] a;
+
+ /** First partial derivative along x. */
+ private BivariateRealFunction partialDerivativeX;
+
+ /** First partial derivative along y. */
+ private BivariateRealFunction partialDerivativeY;
+
+ /** Second partial derivative along x. */
+ private BivariateRealFunction partialDerivativeXX;
+
+ /** Second partial derivative along y. */
+ private BivariateRealFunction partialDerivativeYY;
+
+ /** Second crossed partial derivative. */
+ private BivariateRealFunction partialDerivativeXY;
+
+ /**
+ * Simple constructor.
+ * @param a Spline coefficients
+ */
+ public BicubicSplineFunction(double[] a) {
+ this.a = new double[N][N];
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ this.a[i][j] = a[i + N * j];
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public double value(double x, double y) {
+ if (x < 0 || x > 1) {
+ throw new OutOfRangeException(x, 0, 1);
+ }
+ if (y < 0 || y > 1) {
+ throw new OutOfRangeException(y, 0, 1);
+ }
+
+ final double x2 = x * x;
+ final double x3 = x2 * x;
+ final double[] pX = {1, x, x2, x3};
+
+ final double y2 = y * y;
+ final double y3 = y2 * y;
+ final double[] pY = {1, y, y2, y3};
+
+ return apply(pX, pY, a);
+ }
+
+ /**
+ * Compute the value of the bicubic polynomial.
+ *
+ * @param pX Powers of the x-coordinate.
+ * @param pY Powers of the y-coordinate.
+ * @param coeff Spline coefficients.
+ * @return the interpolated value.
+ */
+ private double apply(double[] pX, double[] pY, double[][] coeff) {
+ double result = 0;
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ result += coeff[i][j] * pX[i] * pY[j];
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @return the partial derivative wrt {@code x}.
+ */
+ public BivariateRealFunction partialDerivativeX() {
+ if (partialDerivativeX == null) {
+ computePartialDerivatives();
+ }
+
+ return partialDerivativeX;
+ }
+ /**
+ * @return the partial derivative wrt {@code y}.
+ */
+ public BivariateRealFunction partialDerivativeY() {
+ if (partialDerivativeY == null) {
+ computePartialDerivatives();
+ }
+
+ return partialDerivativeY;
+ }
+ /**
+ * @return the second partial derivative wrt {@code x}.
+ */
+ public BivariateRealFunction partialDerivativeXX() {
+ if (partialDerivativeXX == null) {
+ computePartialDerivatives();
+ }
+
+ return partialDerivativeXX;
+ }
+ /**
+ * @return the second partial derivative wrt {@code y}.
+ */
+ public BivariateRealFunction partialDerivativeYY() {
+ if (partialDerivativeYY == null) {
+ computePartialDerivatives();
+ }
+
+ return partialDerivativeYY;
+ }
+ /**
+ * @return the second partial cross-derivative.
+ */
+ public BivariateRealFunction partialDerivativeXY() {
+ if (partialDerivativeXY == null) {
+ computePartialDerivatives();
+ }
+
+ return partialDerivativeXY;
+ }
+
+ /**
+ * Compute all partial derivatives functions.
+ */
+ private void computePartialDerivatives() {
+ final double[][] aX = new double[N][N];
+ final double[][] aY = new double[N][N];
+ final double[][] aXX = new double[N][N];
+ final double[][] aYY = new double[N][N];
+ final double[][] aXY = new double[N][N];
+
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ final double c = a[i][j];
+ aX[i][j] = i * c;
+ aY[i][j] = j * c;
+ aXX[i][j] = (i - 1) * aX[i][j];
+ aYY[i][j] = (j - 1) * aY[i][j];
+ aXY[i][j] = j * aX[i][j];
+ }
+ }
+
+ partialDerivativeX = new BivariateRealFunction() {
+ public double value(double x, double y) {
+ final double x2 = x * x;
+ final double[] pX = {0, 1, x, x2};
+
+ final double y2 = y * y;
+ final double y3 = y2 * y;
+ final double[] pY = {1, y, y2, y3};
+
+ return apply(pX, pY, aX);
+ }
+ };
+ partialDerivativeY = new BivariateRealFunction() {
+ public double value(double x, double y) {
+ final double x2 = x * x;
+ final double x3 = x2 * x;
+ final double[] pX = {1, x, x2, x3};
+
+ final double y2 = y * y;
+ final double[] pY = {0, 1, y, y2};
+
+ return apply(pX, pY, aY);
+ }
+ };
+ partialDerivativeXX = new BivariateRealFunction() {
+ public double value(double x, double y) {
+ final double[] pX = {0, 0, 1, x};
+
+ final double y2 = y * y;
+ final double y3 = y2 * y;
+ final double[] pY = {1, y, y2, y3};
+
+ return apply(pX, pY, aXX);
+ }
+ };
+ partialDerivativeYY = new BivariateRealFunction() {
+ public double value(double x, double y) {
+ final double x2 = x * x;
+ final double x3 = x2 * x;
+ final double[] pX = {1, x, x2, x3};
+
+ final double[] pY = {0, 0, 1, y};
+
+ return apply(pX, pY, aYY);
+ }
+ };
+ partialDerivativeXY = new BivariateRealFunction() {
+ public double value(double x, double y) {
+ final double x2 = x * x;
+ final double[] pX = {0, 1, x, x2};
+
+ final double y2 = y * y;
+ final double[] pY = {0, 1, y, y2};
+
+ return apply(pX, pY, aXY);
+ }
+ };
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/BicubicSplineInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/BicubicSplineInterpolator.java
new file mode 100644
index 0000000..42f73c8
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/BicubicSplineInterpolator.java
@@ -0,0 +1,145 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.DimensionMismatchException;
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+import org.apache.commons.math.exception.NoDataException;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Generates a bicubic interpolating function.
+ *
+ * @version $Revision: 980944 $ $Date: 2010-07-30 22:31:11 +0200 (ven. 30 juil. 2010) $
+ * @since 2.2
+ */
+public class BicubicSplineInterpolator
+ implements BivariateRealGridInterpolator {
+ /**
+ * {@inheritDoc}
+ */
+ public BicubicSplineInterpolatingFunction interpolate(final double[] xval,
+ final double[] yval,
+ final double[][] fval)
+ throws MathException, IllegalArgumentException {
+ if (xval.length == 0 || yval.length == 0 || fval.length == 0) {
+ throw new NoDataException();
+ }
+ if (xval.length != fval.length) {
+ throw new DimensionMismatchException(xval.length, fval.length);
+ }
+
+ MathUtils.checkOrder(xval);
+ MathUtils.checkOrder(yval);
+
+ final int xLen = xval.length;
+ final int yLen = yval.length;
+
+ // Samples (first index is y-coordinate, i.e. subarray variable is x)
+ // 0 <= i < xval.length
+ // 0 <= j < yval.length
+ // fX[j][i] = f(xval[i], yval[j])
+ final double[][] fX = new double[yLen][xLen];
+ for (int i = 0; i < xLen; i++) {
+ if (fval[i].length != yLen) {
+ throw new DimensionMismatchException(fval[i].length, yLen);
+ }
+
+ for (int j = 0; j < yLen; j++) {
+ fX[j][i] = fval[i][j];
+ }
+ }
+
+ final SplineInterpolator spInterpolator = new SplineInterpolator();
+
+ // For each line y[j] (0 <= j < yLen), construct a 1D spline with
+ // respect to variable x
+ final PolynomialSplineFunction[] ySplineX = new PolynomialSplineFunction[yLen];
+ for (int j = 0; j < yLen; j++) {
+ ySplineX[j] = spInterpolator.interpolate(xval, fX[j]);
+ }
+
+ // For each line x[i] (0 <= i < xLen), construct a 1D spline with
+ // respect to variable y generated by array fY_1[i]
+ final PolynomialSplineFunction[] xSplineY = new PolynomialSplineFunction[xLen];
+ for (int i = 0; i < xLen; i++) {
+ xSplineY[i] = spInterpolator.interpolate(yval, fval[i]);
+ }
+
+ // Partial derivatives with respect to x at the grid knots
+ final double[][] dFdX = new double[xLen][yLen];
+ for (int j = 0; j < yLen; j++) {
+ final UnivariateRealFunction f = ySplineX[j].derivative();
+ for (int i = 0; i < xLen; i++) {
+ dFdX[i][j] = f.value(xval[i]);
+ }
+ }
+
+ // Partial derivatives with respect to y at the grid knots
+ final double[][] dFdY = new double[xLen][yLen];
+ for (int i = 0; i < xLen; i++) {
+ final UnivariateRealFunction f = xSplineY[i].derivative();
+ for (int j = 0; j < yLen; j++) {
+ dFdY[i][j] = f.value(yval[j]);
+ }
+ }
+
+ // Cross partial derivatives
+ final double[][] d2FdXdY = new double[xLen][yLen];
+ for (int i = 0; i < xLen ; i++) {
+ final int nI = nextIndex(i, xLen);
+ final int pI = previousIndex(i);
+ for (int j = 0; j < yLen; j++) {
+ final int nJ = nextIndex(j, yLen);
+ final int pJ = previousIndex(j);
+ d2FdXdY[i][j] = (fval[nI][nJ] - fval[nI][pJ] -
+ fval[pI][nJ] + fval[pI][pJ]) /
+ ((xval[nI] - xval[pI]) * (yval[nJ] - yval[pJ]));
+ }
+ }
+
+ // Create the interpolating splines
+ return new BicubicSplineInterpolatingFunction(xval, yval, fval,
+ dFdX, dFdY, d2FdXdY);
+ }
+
+ /**
+ * Compute the next index of an array, clipping if necessary.
+ * It is assumed (but not checked) that {@code i} is larger than or equal to 0}.
+ *
+ * @param i Index
+ * @param max Upper limit of the array
+ * @return the next index
+ */
+ private int nextIndex(int i, int max) {
+ final int index = i + 1;
+ return index < max ? index : index - 1;
+ }
+ /**
+ * Compute the previous index of an array, clipping if necessary.
+ * It is assumed (but not checked) that {@code i} is smaller than the size of the array.
+ *
+ * @param i Index
+ * @return the previous index
+ */
+ private int previousIndex(int i) {
+ final int index = i - 1;
+ return index >= 0 ? index : 0;
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/BivariateRealGridInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/BivariateRealGridInterpolator.java
new file mode 100644
index 0000000..218d328
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/BivariateRealGridInterpolator.java
@@ -0,0 +1,44 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.BivariateRealFunction;
+
+/**
+ * Interface representing a bivariate real interpolating function where the
+ * sample points must be specified on a regular grid.
+ *
+ * @version $Revision: 936391 $ $Date: 2010-04-21 19:00:56 +0200 (mer. 21 avril 2010) $
+ */
+public interface BivariateRealGridInterpolator {
+ /**
+ * Computes an interpolating function for the data set.
+ *
+ * @param xval All the x-coordinates of the interpolation points, sorted
+ * in increasing order.
+ * @param yval All the y-coordinates of the interpolation points, sorted
+ * in increasing order.
+ * @param fval The values of the interpolation points on all the grid knots:
+ * {@code fval[i][j] = f(xval[i], yval[j])}.
+ * @return a function which interpolates the data set.
+ * @throws MathException if arguments violate assumptions made by the
+ * interpolation algorithm.
+ */
+ BivariateRealFunction interpolate(double[] xval, double[] yval, double[][] fval)
+ throws MathException;
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/DividedDifferenceInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/DividedDifferenceInterpolator.java
new file mode 100644
index 0000000..9b80079
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/DividedDifferenceInterpolator.java
@@ -0,0 +1,117 @@
+/*
+ * 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.analysis.interpolation;
+
+import java.io.Serializable;
+
+import org.apache.commons.math.DuplicateSampleAbscissaException;
+import org.apache.commons.math.analysis.polynomials.PolynomialFunctionLagrangeForm;
+import org.apache.commons.math.analysis.polynomials.PolynomialFunctionNewtonForm;
+
+/**
+ * Implements the <a href="
+ * "http://mathworld.wolfram.com/NewtonsDividedDifferenceInterpolationFormula.html">
+ * Divided Difference Algorithm</a> for interpolation of real univariate
+ * functions. For reference, see <b>Introduction to Numerical Analysis</b>,
+ * ISBN 038795452X, chapter 2.
+ * <p>
+ * The actual code of Neville's evaluation is in PolynomialFunctionLagrangeForm,
+ * this class provides an easy-to-use interface to it.</p>
+ *
+ * @version $Revision: 825919 $ $Date: 2009-10-16 16:51:55 +0200 (ven. 16 oct. 2009) $
+ * @since 1.2
+ */
+public class DividedDifferenceInterpolator implements UnivariateRealInterpolator,
+ Serializable {
+
+ /** serializable version identifier */
+ private static final long serialVersionUID = 107049519551235069L;
+
+ /**
+ * Computes an interpolating function for the data set.
+ *
+ * @param x the interpolating points array
+ * @param y the interpolating values array
+ * @return a function which interpolates the data set
+ * @throws DuplicateSampleAbscissaException if arguments are invalid
+ */
+ public PolynomialFunctionNewtonForm interpolate(double x[], double y[]) throws
+ DuplicateSampleAbscissaException {
+
+ /**
+ * a[] and c[] are defined in the general formula of Newton form:
+ * p(x) = a[0] + a[1](x-c[0]) + a[2](x-c[0])(x-c[1]) + ... +
+ * a[n](x-c[0])(x-c[1])...(x-c[n-1])
+ */
+ PolynomialFunctionLagrangeForm.verifyInterpolationArray(x, y);
+
+ /**
+ * When used for interpolation, the Newton form formula becomes
+ * p(x) = f[x0] + f[x0,x1](x-x0) + f[x0,x1,x2](x-x0)(x-x1) + ... +
+ * f[x0,x1,...,x[n-1]](x-x0)(x-x1)...(x-x[n-2])
+ * Therefore, a[k] = f[x0,x1,...,xk], c[k] = x[k].
+ * <p>
+ * Note x[], y[], a[] have the same length but c[]'s size is one less.</p>
+ */
+ final double[] c = new double[x.length-1];
+ System.arraycopy(x, 0, c, 0, c.length);
+
+ final double[] a = computeDividedDifference(x, y);
+ return new PolynomialFunctionNewtonForm(a, c);
+
+ }
+
+ /**
+ * Returns a copy of the divided difference array.
+ * <p>
+ * The divided difference array is defined recursively by <pre>
+ * f[x0] = f(x0)
+ * f[x0,x1,...,xk] = (f(x1,...,xk) - f(x0,...,x[k-1])) / (xk - x0)
+ * </pre></p>
+ * <p>
+ * The computational complexity is O(N^2).</p>
+ *
+ * @param x the interpolating points array
+ * @param y the interpolating values array
+ * @return a fresh copy of the divided difference array
+ * @throws DuplicateSampleAbscissaException if any abscissas coincide
+ */
+ protected static double[] computeDividedDifference(final double x[], final double y[])
+ throws DuplicateSampleAbscissaException {
+
+ PolynomialFunctionLagrangeForm.verifyInterpolationArray(x, y);
+
+ final double[] divdiff = y.clone(); // initialization
+
+ final int n = x.length;
+ final double[] a = new double [n];
+ a[0] = divdiff[0];
+ for (int i = 1; i < n; i++) {
+ for (int j = 0; j < n-i; j++) {
+ final double denominator = x[j+i] - x[j];
+ if (denominator == 0.0) {
+ // This happens only when two abscissas are identical.
+ throw new DuplicateSampleAbscissaException(x[j], j, j+i);
+ }
+ divdiff[j] = (divdiff[j+1] - divdiff[j]) / denominator;
+ }
+ a[i] = divdiff[0];
+ }
+
+ return a;
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/LinearInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/LinearInterpolator.java
new file mode 100644
index 0000000..71ab9a9
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/LinearInterpolator.java
@@ -0,0 +1,75 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.exception.NumberIsTooSmallException;
+import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Implements a linear function for interpolation of real univariate functions.
+ * @version $Revision$ $Date$
+ * @since 2.2
+ */
+public class LinearInterpolator implements UnivariateRealInterpolator {
+ /**
+ * Computes a linear interpolating function for the data set.
+ * @param x the arguments for the interpolation points
+ * @param y the values for the interpolation points
+ * @return a function which interpolates the data set
+ * @throws DimensionMismatchException if {@code x} and {@code y}
+ * have different sizes.
+ * @throws org.apache.commons.math.exception.NonMonotonousSequenceException
+ * if {@code x} is not sorted in strict increasing order.
+ * @throws NumberIsTooSmallException if the size of {@code x} is smaller
+ * than 2.
+ */
+ public PolynomialSplineFunction interpolate(double x[], double y[]) {
+ if (x.length != y.length) {
+ throw new DimensionMismatchException(x.length, y.length);
+ }
+
+ if (x.length < 2) {
+ throw new NumberIsTooSmallException(LocalizedFormats.NUMBER_OF_POINTS,
+ x.length, 2, true);
+ }
+
+ // Number of intervals. The number of data points is n + 1.
+ int n = x.length - 1;
+
+ MathUtils.checkOrder(x);
+
+ // Slope of the lines between the datapoints.
+ final double m[] = new double[n];
+ for (int i = 0; i < n; i++) {
+ m[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]);
+ }
+
+ PolynomialFunction polynomials[] = new PolynomialFunction[n];
+ final double coefficients[] = new double[2];
+ for (int i = 0; i < n; i++) {
+ coefficients[0] = y[i];
+ coefficients[1] = m[i];
+ polynomials[i] = new PolynomialFunction(coefficients);
+ }
+
+ return new PolynomialSplineFunction(x, polynomials);
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/LoessInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/LoessInterpolator.java
new file mode 100644
index 0000000..5f00e14
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/LoessInterpolator.java
@@ -0,0 +1,463 @@
+/*
+ * 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.analysis.interpolation;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+import org.apache.commons.math.exception.util.Localizable;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the <a href="http://en.wikipedia.org/wiki/Local_regression">
+ * Local Regression Algorithm</a> (also Loess, Lowess) for interpolation of
+ * real univariate functions.
+ * <p/>
+ * For reference, see
+ * <a href="http://www.math.tau.ac.il/~yekutiel/MA seminar/Cleveland 1979.pdf">
+ * William S. Cleveland - Robust Locally Weighted Regression and Smoothing
+ * Scatterplots</a>
+ * <p/>
+ * This class implements both the loess method and serves as an interpolation
+ * adapter to it, allowing to build a spline on the obtained loess fit.
+ *
+ * @version $Revision: 990655 $ $Date: 2010-08-29 23:49:40 +0200 (dim. 29 août 2010) $
+ * @since 2.0
+ */
+public class LoessInterpolator
+ implements UnivariateRealInterpolator, Serializable {
+
+ /** Default value of the bandwidth parameter. */
+ public static final double DEFAULT_BANDWIDTH = 0.3;
+
+ /** Default value of the number of robustness iterations. */
+ public static final int DEFAULT_ROBUSTNESS_ITERS = 2;
+
+ /**
+ * Default value for accuracy.
+ * @since 2.1
+ */
+ public static final double DEFAULT_ACCURACY = 1e-12;
+
+ /** serializable version identifier. */
+ private static final long serialVersionUID = 5204927143605193821L;
+
+ /**
+ * The bandwidth parameter: when computing the loess fit at
+ * a particular point, this fraction of source points closest
+ * to the current point is taken into account for computing
+ * a least-squares regression.
+ * <p/>
+ * A sensible value is usually 0.25 to 0.5.
+ */
+ private final double bandwidth;
+
+ /**
+ * The number of robustness iterations parameter: this many
+ * robustness iterations are done.
+ * <p/>
+ * A sensible value is usually 0 (just the initial fit without any
+ * robustness iterations) to 4.
+ */
+ private final int robustnessIters;
+
+ /**
+ * If the median residual at a certain robustness iteration
+ * is less than this amount, no more iterations are done.
+ */
+ private final double accuracy;
+
+ /**
+ * Constructs a new {@link LoessInterpolator}
+ * with a bandwidth of {@link #DEFAULT_BANDWIDTH},
+ * {@link #DEFAULT_ROBUSTNESS_ITERS} robustness iterations
+ * and an accuracy of {#link #DEFAULT_ACCURACY}.
+ * See {@link #LoessInterpolator(double, int, double)} for an explanation of
+ * the parameters.
+ */
+ public LoessInterpolator() {
+ this.bandwidth = DEFAULT_BANDWIDTH;
+ this.robustnessIters = DEFAULT_ROBUSTNESS_ITERS;
+ this.accuracy = DEFAULT_ACCURACY;
+ }
+
+ /**
+ * Constructs a new {@link LoessInterpolator}
+ * with given bandwidth and number of robustness iterations.
+ * <p>
+ * Calling this constructor is equivalent to calling {link {@link
+ * #LoessInterpolator(double, int, double) LoessInterpolator(bandwidth,
+ * robustnessIters, LoessInterpolator.DEFAULT_ACCURACY)}
+ * </p>
+ *
+ * @param bandwidth when computing the loess fit at
+ * a particular point, this fraction of source points closest
+ * to the current point is taken into account for computing
+ * a least-squares regression.</br>
+ * A sensible value is usually 0.25 to 0.5, the default value is
+ * {@link #DEFAULT_BANDWIDTH}.
+ * @param robustnessIters This many robustness iterations are done.</br>
+ * A sensible value is usually 0 (just the initial fit without any
+ * robustness iterations) to 4, the default value is
+ * {@link #DEFAULT_ROBUSTNESS_ITERS}.
+ * @throws MathException if bandwidth does not lie in the interval [0,1]
+ * or if robustnessIters is negative.
+ * @see #LoessInterpolator(double, int, double)
+ */
+ public LoessInterpolator(double bandwidth, int robustnessIters) throws MathException {
+ this(bandwidth, robustnessIters, DEFAULT_ACCURACY);
+ }
+
+ /**
+ * Constructs a new {@link LoessInterpolator}
+ * with given bandwidth, number of robustness iterations and accuracy.
+ *
+ * @param bandwidth when computing the loess fit at
+ * a particular point, this fraction of source points closest
+ * to the current point is taken into account for computing
+ * a least-squares regression.</br>
+ * A sensible value is usually 0.25 to 0.5, the default value is
+ * {@link #DEFAULT_BANDWIDTH}.
+ * @param robustnessIters This many robustness iterations are done.</br>
+ * A sensible value is usually 0 (just the initial fit without any
+ * robustness iterations) to 4, the default value is
+ * {@link #DEFAULT_ROBUSTNESS_ITERS}.
+ * @param accuracy If the median residual at a certain robustness iteration
+ * is less than this amount, no more iterations are done.
+ * @throws MathException if bandwidth does not lie in the interval [0,1]
+ * or if robustnessIters is negative.
+ * @see #LoessInterpolator(double, int)
+ * @since 2.1
+ */
+ public LoessInterpolator(double bandwidth, int robustnessIters, double accuracy) throws MathException {
+ if (bandwidth < 0 || bandwidth > 1) {
+ throw new MathException(LocalizedFormats.BANDWIDTH_OUT_OF_INTERVAL,
+ bandwidth);
+ }
+ this.bandwidth = bandwidth;
+ if (robustnessIters < 0) {
+ throw new MathException(LocalizedFormats.NEGATIVE_ROBUSTNESS_ITERATIONS, robustnessIters);
+ }
+ this.robustnessIters = robustnessIters;
+ this.accuracy = accuracy;
+ }
+
+ /**
+ * Compute an interpolating function by performing a loess fit
+ * on the data at the original abscissae and then building a cubic spline
+ * with a
+ * {@link org.apache.commons.math.analysis.interpolation.SplineInterpolator}
+ * on the resulting fit.
+ *
+ * @param xval the arguments for the interpolation points
+ * @param yval the values for the interpolation points
+ * @return A cubic spline built upon a loess fit to the data at the original abscissae
+ * @throws MathException if some of the following conditions are false:
+ * <ul>
+ * <li> Arguments and values are of the same size that is greater than zero</li>
+ * <li> The arguments are in a strictly increasing order</li>
+ * <li> All arguments and values are finite real numbers</li>
+ * </ul>
+ */
+ public final PolynomialSplineFunction interpolate(
+ final double[] xval, final double[] yval) throws MathException {
+ return new SplineInterpolator().interpolate(xval, smooth(xval, yval));
+ }
+
+ /**
+ * Compute a weighted loess fit on the data at the original abscissae.
+ *
+ * @param xval the arguments for the interpolation points
+ * @param yval the values for the interpolation points
+ * @param weights point weights: coefficients by which the robustness weight of a point is multiplied
+ * @return values of the loess fit at corresponding original abscissae
+ * @throws MathException if some of the following conditions are false:
+ * <ul>
+ * <li> Arguments and values are of the same size that is greater than zero</li>
+ * <li> The arguments are in a strictly increasing order</li>
+ * <li> All arguments and values are finite real numbers</li>
+ * </ul>
+ * @since 2.1
+ */
+ public final double[] smooth(final double[] xval, final double[] yval, final double[] weights)
+ throws MathException {
+ if (xval.length != yval.length) {
+ throw new MathException(LocalizedFormats.MISMATCHED_LOESS_ABSCISSA_ORDINATE_ARRAYS,
+ xval.length, yval.length);
+ }
+
+ final int n = xval.length;
+
+ if (n == 0) {
+ throw new MathException(LocalizedFormats.LOESS_EXPECTS_AT_LEAST_ONE_POINT);
+ }
+
+ checkAllFiniteReal(xval, LocalizedFormats.NON_REAL_FINITE_ABSCISSA);
+ checkAllFiniteReal(yval, LocalizedFormats.NON_REAL_FINITE_ORDINATE);
+ checkAllFiniteReal(weights, LocalizedFormats.NON_REAL_FINITE_WEIGHT);
+
+ checkStrictlyIncreasing(xval);
+
+ if (n == 1) {
+ return new double[]{yval[0]};
+ }
+
+ if (n == 2) {
+ return new double[]{yval[0], yval[1]};
+ }
+
+ int bandwidthInPoints = (int) (bandwidth * n);
+
+ if (bandwidthInPoints < 2) {
+ throw new MathException(LocalizedFormats.TOO_SMALL_BANDWIDTH,
+ n, 2.0 / n, bandwidth);
+ }
+
+ final double[] res = new double[n];
+
+ final double[] residuals = new double[n];
+ final double[] sortedResiduals = new double[n];
+
+ final double[] robustnessWeights = new double[n];
+
+ // Do an initial fit and 'robustnessIters' robustness iterations.
+ // This is equivalent to doing 'robustnessIters+1' robustness iterations
+ // starting with all robustness weights set to 1.
+ Arrays.fill(robustnessWeights, 1);
+
+ for (int iter = 0; iter <= robustnessIters; ++iter) {
+ final int[] bandwidthInterval = {0, bandwidthInPoints - 1};
+ // At each x, compute a local weighted linear regression
+ for (int i = 0; i < n; ++i) {
+ final double x = xval[i];
+
+ // Find out the interval of source points on which
+ // a regression is to be made.
+ if (i > 0) {
+ updateBandwidthInterval(xval, weights, i, bandwidthInterval);
+ }
+
+ final int ileft = bandwidthInterval[0];
+ final int iright = bandwidthInterval[1];
+
+ // Compute the point of the bandwidth interval that is
+ // farthest from x
+ final int edge;
+ if (xval[i] - xval[ileft] > xval[iright] - xval[i]) {
+ edge = ileft;
+ } else {
+ edge = iright;
+ }
+
+ // Compute a least-squares linear fit weighted by
+ // the product of robustness weights and the tricube
+ // weight function.
+ // See http://en.wikipedia.org/wiki/Linear_regression
+ // (section "Univariate linear case")
+ // and http://en.wikipedia.org/wiki/Weighted_least_squares
+ // (section "Weighted least squares")
+ double sumWeights = 0;
+ double sumX = 0;
+ double sumXSquared = 0;
+ double sumY = 0;
+ double sumXY = 0;
+ double denom = FastMath.abs(1.0 / (xval[edge] - x));
+ for (int k = ileft; k <= iright; ++k) {
+ final double xk = xval[k];
+ final double yk = yval[k];
+ final double dist = (k < i) ? x - xk : xk - x;
+ final double w = tricube(dist * denom) * robustnessWeights[k] * weights[k];
+ final double xkw = xk * w;
+ sumWeights += w;
+ sumX += xkw;
+ sumXSquared += xk * xkw;
+ sumY += yk * w;
+ sumXY += yk * xkw;
+ }
+
+ final double meanX = sumX / sumWeights;
+ final double meanY = sumY / sumWeights;
+ final double meanXY = sumXY / sumWeights;
+ final double meanXSquared = sumXSquared / sumWeights;
+
+ final double beta;
+ if (FastMath.sqrt(FastMath.abs(meanXSquared - meanX * meanX)) < accuracy) {
+ beta = 0;
+ } else {
+ beta = (meanXY - meanX * meanY) / (meanXSquared - meanX * meanX);
+ }
+
+ final double alpha = meanY - beta * meanX;
+
+ res[i] = beta * x + alpha;
+ residuals[i] = FastMath.abs(yval[i] - res[i]);
+ }
+
+ // No need to recompute the robustness weights at the last
+ // iteration, they won't be needed anymore
+ if (iter == robustnessIters) {
+ break;
+ }
+
+ // Recompute the robustness weights.
+
+ // Find the median residual.
+ // An arraycopy and a sort are completely tractable here,
+ // because the preceding loop is a lot more expensive
+ System.arraycopy(residuals, 0, sortedResiduals, 0, n);
+ Arrays.sort(sortedResiduals);
+ final double medianResidual = sortedResiduals[n / 2];
+
+ if (FastMath.abs(medianResidual) < accuracy) {
+ break;
+ }
+
+ for (int i = 0; i < n; ++i) {
+ final double arg = residuals[i] / (6 * medianResidual);
+ if (arg >= 1) {
+ robustnessWeights[i] = 0;
+ } else {
+ final double w = 1 - arg * arg;
+ robustnessWeights[i] = w * w;
+ }
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * Compute a loess fit on the data at the original abscissae.
+ *
+ * @param xval the arguments for the interpolation points
+ * @param yval the values for the interpolation points
+ * @return values of the loess fit at corresponding original abscissae
+ * @throws MathException if some of the following conditions are false:
+ * <ul>
+ * <li> Arguments and values are of the same size that is greater than zero</li>
+ * <li> The arguments are in a strictly increasing order</li>
+ * <li> All arguments and values are finite real numbers</li>
+ * </ul>
+ */
+ public final double[] smooth(final double[] xval, final double[] yval)
+ throws MathException {
+ if (xval.length != yval.length) {
+ throw new MathException(LocalizedFormats.MISMATCHED_LOESS_ABSCISSA_ORDINATE_ARRAYS,
+ xval.length, yval.length);
+ }
+
+ final double[] unitWeights = new double[xval.length];
+ Arrays.fill(unitWeights, 1.0);
+
+ return smooth(xval, yval, unitWeights);
+ }
+
+ /**
+ * Given an index interval into xval that embraces a certain number of
+ * points closest to xval[i-1], update the interval so that it embraces
+ * the same number of points closest to xval[i], ignoring zero weights.
+ *
+ * @param xval arguments array
+ * @param weights weights array
+ * @param i the index around which the new interval should be computed
+ * @param bandwidthInterval a two-element array {left, right} such that: <p/>
+ * <tt>(left==0 or xval[i] - xval[left-1] > xval[right] - xval[i])</tt>
+ * <p/> and also <p/>
+ * <tt>(right==xval.length-1 or xval[right+1] - xval[i] > xval[i] - xval[left])</tt>.
+ * The array will be updated.
+ */
+ private static void updateBandwidthInterval(final double[] xval, final double[] weights,
+ final int i,
+ final int[] bandwidthInterval) {
+ final int left = bandwidthInterval[0];
+ final int right = bandwidthInterval[1];
+
+ // The right edge should be adjusted if the next point to the right
+ // is closer to xval[i] than the leftmost point of the current interval
+ int nextRight = nextNonzero(weights, right);
+ if (nextRight < xval.length && xval[nextRight] - xval[i] < xval[i] - xval[left]) {
+ int nextLeft = nextNonzero(weights, bandwidthInterval[0]);
+ bandwidthInterval[0] = nextLeft;
+ bandwidthInterval[1] = nextRight;
+ }
+ }
+
+ /**
+ * Returns the smallest index j such that j > i && (j==weights.length || weights[j] != 0)
+ * @param weights weights array
+ * @param i the index from which to start search; must be < weights.length
+ * @return the smallest index j such that j > i && (j==weights.length || weights[j] != 0)
+ */
+ private static int nextNonzero(final double[] weights, final int i) {
+ int j = i + 1;
+ while(j < weights.length && weights[j] == 0) {
+ j++;
+ }
+ return j;
+ }
+
+ /**
+ * Compute the
+ * <a href="http://en.wikipedia.org/wiki/Local_regression#Weight_function">tricube</a>
+ * weight function
+ *
+ * @param x the argument
+ * @return (1-|x|^3)^3
+ */
+ private static double tricube(final double x) {
+ final double tmp = 1 - x * x * x;
+ return tmp * tmp * tmp;
+ }
+
+ /**
+ * Check that all elements of an array are finite real numbers.
+ *
+ * @param values the values array
+ * @param pattern pattern of the error message
+ * @throws MathException if one of the values is not a finite real number
+ */
+ private static void checkAllFiniteReal(final double[] values, final Localizable pattern)
+ throws MathException {
+ for (int i = 0; i < values.length; i++) {
+ final double x = values[i];
+ if (Double.isInfinite(x) || Double.isNaN(x)) {
+ throw new MathException(pattern, i, x);
+ }
+ }
+ }
+
+ /**
+ * Check that elements of the abscissae array are in a strictly
+ * increasing order.
+ *
+ * @param xval the abscissae array
+ * @throws MathException if the abscissae array
+ * is not in a strictly increasing order
+ */
+ private static void checkStrictlyIncreasing(final double[] xval)
+ throws MathException {
+ for (int i = 0; i < xval.length; ++i) {
+ if (i >= 1 && xval[i - 1] >= xval[i]) {
+ throw new MathException(LocalizedFormats.OUT_OF_ORDER_ABSCISSA_ARRAY,
+ i - 1, xval[i - 1], i, xval[i]);
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/MicrosphereInterpolatingFunction.java b/src/main/java/org/apache/commons/math/analysis/interpolation/MicrosphereInterpolatingFunction.java
new file mode 100644
index 0000000..a710e82
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/MicrosphereInterpolatingFunction.java
@@ -0,0 +1,244 @@
+/*
+ * 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.analysis.interpolation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.math.DimensionMismatchException;
+import org.apache.commons.math.analysis.MultivariateRealFunction;
+import org.apache.commons.math.exception.NoDataException;
+import org.apache.commons.math.linear.ArrayRealVector;
+import org.apache.commons.math.linear.RealVector;
+import org.apache.commons.math.random.UnitSphereRandomVectorGenerator;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Interpolating function that implements the
+ * <a href="http://www.dudziak.com/microsphere.php">Microsphere Projection</a>.
+ *
+ * @version $Revision: 990655 $ $Date: 2010-08-29 23:49:40 +0200 (dim. 29 août 2010) $
+ */
+public class MicrosphereInterpolatingFunction
+ implements MultivariateRealFunction {
+ /**
+ * Space dimension.
+ */
+ private final int dimension;
+ /**
+ * Internal accounting data for the interpolation algorithm.
+ * Each element of the list corresponds to one surface element of
+ * the microsphere.
+ */
+ private final List<MicrosphereSurfaceElement> microsphere;
+ /**
+ * Exponent used in the power law that computes the weights of the
+ * sample data.
+ */
+ private final double brightnessExponent;
+ /**
+ * Sample data.
+ */
+ private final Map<RealVector, Double> samples;
+
+ /**
+ * Class for storing the accounting data needed to perform the
+ * microsphere projection.
+ */
+ private static class MicrosphereSurfaceElement {
+
+ /** Normal vector characterizing a surface element. */
+ private final RealVector normal;
+
+ /** Illumination received from the brightest sample. */
+ private double brightestIllumination;
+
+ /** Brightest sample. */
+ private Map.Entry<RealVector, Double> brightestSample;
+
+ /**
+ * @param n Normal vector characterizing a surface element
+ * of the microsphere.
+ */
+ MicrosphereSurfaceElement(double[] n) {
+ normal = new ArrayRealVector(n);
+ }
+
+ /**
+ * Return the normal vector.
+ * @return the normal vector
+ */
+ RealVector normal() {
+ return normal;
+ }
+
+ /**
+ * Reset "illumination" and "sampleIndex".
+ */
+ void reset() {
+ brightestIllumination = 0;
+ brightestSample = null;
+ }
+
+ /**
+ * Store the illumination and index of the brightest sample.
+ * @param illuminationFromSample illumination received from sample
+ * @param sample current sample illuminating the element
+ */
+ void store(final double illuminationFromSample,
+ final Map.Entry<RealVector, Double> sample) {
+ if (illuminationFromSample > this.brightestIllumination) {
+ this.brightestIllumination = illuminationFromSample;
+ this.brightestSample = sample;
+ }
+ }
+
+ /**
+ * Get the illumination of the element.
+ * @return the illumination.
+ */
+ double illumination() {
+ return brightestIllumination;
+ }
+
+ /**
+ * Get the sample illuminating the element the most.
+ * @return the sample.
+ */
+ Map.Entry<RealVector, Double> sample() {
+ return brightestSample;
+ }
+ }
+
+ /**
+ * @param xval the arguments for the interpolation points.
+ * {@code xval[i][0]} is the first component of interpolation point
+ * {@code i}, {@code xval[i][1]} is the second component, and so on
+ * until {@code xval[i][d-1]}, the last component of that interpolation
+ * point (where {@code dimension} is thus the dimension of the sampled
+ * space).
+ * @param yval the values for the interpolation points
+ * @param brightnessExponent Brightness dimming factor.
+ * @param microsphereElements Number of surface elements of the
+ * microsphere.
+ * @param rand Unit vector generator for creating the microsphere.
+ * @throws DimensionMismatchException if the lengths of {@code yval} and
+ * {@code xval} (equal to {@code n}, the number of interpolation points)
+ * do not match, or the the arrays {@code xval[0]} ... {@code xval[n]},
+ * have lengths different from {@code dimension}.
+ * @throws NoDataException if there are no data (xval null or zero length)
+ */
+ public MicrosphereInterpolatingFunction(double[][] xval,
+ double[] yval,
+ int brightnessExponent,
+ int microsphereElements,
+ UnitSphereRandomVectorGenerator rand)
+ throws DimensionMismatchException, NoDataException {
+ if (xval.length == 0 || xval[0] == null) {
+ throw new NoDataException();
+ }
+
+ if (xval.length != yval.length) {
+ throw new DimensionMismatchException(xval.length, yval.length);
+ }
+
+ dimension = xval[0].length;
+ this.brightnessExponent = brightnessExponent;
+
+ // Copy data samples.
+ samples = new HashMap<RealVector, Double>(yval.length);
+ for (int i = 0; i < xval.length; ++i) {
+ final double[] xvalI = xval[i];
+ if ( xvalI.length != dimension) {
+ throw new DimensionMismatchException(xvalI.length, dimension);
+ }
+
+ samples.put(new ArrayRealVector(xvalI), yval[i]);
+ }
+
+ microsphere = new ArrayList<MicrosphereSurfaceElement>(microsphereElements);
+ // Generate the microsphere, assuming that a fairly large number of
+ // randomly generated normals will represent a sphere.
+ for (int i = 0; i < microsphereElements; i++) {
+ microsphere.add(new MicrosphereSurfaceElement(rand.nextVector()));
+ }
+
+ }
+
+ /**
+ * @param point Interpolation point.
+ * @return the interpolated value.
+ */
+ public double value(double[] point) {
+
+ final RealVector p = new ArrayRealVector(point);
+
+ // Reset.
+ for (MicrosphereSurfaceElement md : microsphere) {
+ md.reset();
+ }
+
+ // Compute contribution of each sample points to the microsphere elements illumination
+ for (Map.Entry<RealVector, Double> sd : samples.entrySet()) {
+
+ // Vector between interpolation point and current sample point.
+ final RealVector diff = sd.getKey().subtract(p);
+ final double diffNorm = diff.getNorm();
+
+ if (FastMath.abs(diffNorm) < FastMath.ulp(1d)) {
+ // No need to interpolate, as the interpolation point is
+ // actually (very close to) one of the sampled points.
+ return sd.getValue();
+ }
+
+ for (MicrosphereSurfaceElement md : microsphere) {
+ final double w = FastMath.pow(diffNorm, -brightnessExponent);
+ md.store(cosAngle(diff, md.normal()) * w, sd);
+ }
+
+ }
+
+ // Interpolation calculation.
+ double value = 0;
+ double totalWeight = 0;
+ for (MicrosphereSurfaceElement md : microsphere) {
+ final double iV = md.illumination();
+ final Map.Entry<RealVector, Double> sd = md.sample();
+ if (sd != null) {
+ value += iV * sd.getValue();
+ totalWeight += iV;
+ }
+ }
+
+ return value / totalWeight;
+
+ }
+
+ /**
+ * Compute the cosine of the angle between 2 vectors.
+ *
+ * @param v Vector.
+ * @param w Vector.
+ * @return cosine of the angle
+ */
+ private double cosAngle(final RealVector v, final RealVector w) {
+ return v.dotProduct(w) / (v.getNorm() * w.getNorm());
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/MicrosphereInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/MicrosphereInterpolator.java
new file mode 100644
index 0000000..c2a4009
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/MicrosphereInterpolator.java
@@ -0,0 +1,118 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.MultivariateRealFunction;
+import org.apache.commons.math.exception.NotPositiveException;
+import org.apache.commons.math.exception.NotStrictlyPositiveException;
+import org.apache.commons.math.random.UnitSphereRandomVectorGenerator;
+
+/**
+ * Interpolator that implements the algorithm described in
+ * <em>William Dudziak</em>'s
+ * <a href="http://www.dudziak.com/microsphere.pdf">MS thesis</a>.
+ * @since 2.1
+ *
+ * @version $Revision: 980944 $ $Date: 2010-07-30 22:31:11 +0200 (ven. 30 juil. 2010) $
+ */
+public class MicrosphereInterpolator
+ implements MultivariateRealInterpolator {
+
+ /**
+ * Default number of surface elements that composes the microsphere.
+ */
+ public static final int DEFAULT_MICROSPHERE_ELEMENTS = 2000;
+
+ /**
+ * Default exponent used the weights calculation.
+ */
+ public static final int DEFAULT_BRIGHTNESS_EXPONENT = 2;
+
+ /**
+ * Number of surface elements of the microsphere.
+ */
+ private int microsphereElements;
+
+ /**
+ * Exponent used in the power law that computes the weights of the
+ * sample data.
+ */
+ private int brightnessExponent;
+
+ /** Create a microsphere interpolator with default settings.
+ * <p>Calling this constructor is equivalent to call {@link
+ * #MicrosphereInterpolator(int, int)
+ * MicrosphereInterpolator(MicrosphereInterpolator.DEFAULT_MICROSPHERE_ELEMENTS,
+ * MicrosphereInterpolator.DEFAULT_BRIGHTNESS_EXPONENT)}.</p>
+ */
+ public MicrosphereInterpolator() {
+ this(DEFAULT_MICROSPHERE_ELEMENTS, DEFAULT_BRIGHTNESS_EXPONENT);
+ }
+
+ /** Create a microsphere interpolator.
+ * @param microsphereElements number of surface elements of the microsphere.
+ * @param brightnessExponent exponent used in the power law that computes the
+ * weights of the sample data.
+ * @throws NotPositiveException if {@code microsphereElements <= 0}
+ * or {@code brightnessExponent < 0}.
+ */
+ public MicrosphereInterpolator(final int microsphereElements,
+ final int brightnessExponent) {
+ setMicropshereElements(microsphereElements);
+ setBrightnessExponent(brightnessExponent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public MultivariateRealFunction interpolate(final double[][] xval,
+ final double[] yval)
+ throws MathException, IllegalArgumentException {
+ final UnitSphereRandomVectorGenerator rand
+ = new UnitSphereRandomVectorGenerator(xval[0].length);
+ return new MicrosphereInterpolatingFunction(xval, yval,
+ brightnessExponent,
+ microsphereElements,
+ rand);
+ }
+
+ /**
+ * Set the brightness exponent.
+ * @param exponent Exponent for computing the distance dimming
+ * factor.
+ * @throws NotPositiveException if {@code exponent < 0}.
+ */
+ public void setBrightnessExponent(final int exponent) {
+ if (exponent < 0) {
+ throw new NotPositiveException(exponent);
+ }
+ brightnessExponent = exponent;
+ }
+
+ /**
+ * Set the number of microsphere elements.
+ * @param elements Number of surface elements of the microsphere.
+ * @throws NotStrictlyPositiveException if {@code elements <= 0}.
+ */
+ public void setMicropshereElements(final int elements) {
+ if (elements <= 0) {
+ throw new NotStrictlyPositiveException(elements);
+ }
+ microsphereElements = elements;
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/MultivariateRealInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/MultivariateRealInterpolator.java
new file mode 100644
index 0000000..ed7690c
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/MultivariateRealInterpolator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.MultivariateRealFunction;
+
+/**
+ * Interface representing a univariate real interpolating function.
+ *
+ * @since 2.1
+ * @version $Revision: 924794 $ $Date: 2010-03-18 15:15:50 +0100 (jeu. 18 mars 2010) $
+ */
+public interface MultivariateRealInterpolator {
+
+ /**
+ * Computes an interpolating function for the data set.
+ *
+ * @param xval the arguments for the interpolation points.
+ * {@code xval[i][0]} is the first component of interpolation point
+ * {@code i}, {@code xval[i][1]} is the second component, and so on
+ * until {@code xval[i][d-1]}, the last component of that interpolation
+ * point (where {@code d} is thus the dimension of the space).
+ * @param yval the values for the interpolation points
+ * @return a function which interpolates the data set
+ * @throws MathException if arguments violate assumptions made by the
+ * interpolation algorithm or some dimension mismatch occurs
+ * @throws IllegalArgumentException if there are no data (xval null or zero length)
+ */
+ MultivariateRealFunction interpolate(double[][] xval, double[] yval)
+ throws MathException, IllegalArgumentException;
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/NevilleInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/NevilleInterpolator.java
new file mode 100644
index 0000000..27e89cd
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/NevilleInterpolator.java
@@ -0,0 +1,54 @@
+/*
+ * 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.analysis.interpolation;
+
+import java.io.Serializable;
+
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.polynomials.PolynomialFunctionLagrangeForm;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/NevillesAlgorithm.html">
+ * Neville's Algorithm</a> for interpolation of real univariate functions. For
+ * reference, see <b>Introduction to Numerical Analysis</b>, ISBN 038795452X,
+ * chapter 2.
+ * <p>
+ * The actual code of Neville's evalution is in PolynomialFunctionLagrangeForm,
+ * this class provides an easy-to-use interface to it.</p>
+ *
+ * @version $Revision: 799857 $ $Date: 2009-08-01 15:07:12 +0200 (sam. 01 août 2009) $
+ * @since 1.2
+ */
+public class NevilleInterpolator implements UnivariateRealInterpolator,
+ Serializable {
+
+ /** serializable version identifier */
+ static final long serialVersionUID = 3003707660147873733L;
+
+ /**
+ * Computes an interpolating function for the data set.
+ *
+ * @param x the interpolating points array
+ * @param y the interpolating values array
+ * @return a function which interpolates the data set
+ * @throws MathException if arguments are invalid
+ */
+ public PolynomialFunctionLagrangeForm interpolate(double x[], double y[])
+ throws MathException {
+ return new PolynomialFunctionLagrangeForm(x, y);
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/SmoothingBicubicSplineInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/SmoothingBicubicSplineInterpolator.java
new file mode 100644
index 0000000..5514433
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/SmoothingBicubicSplineInterpolator.java
@@ -0,0 +1,178 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.DimensionMismatchException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.util.MathUtils;
+import org.apache.commons.math.util.MathUtils.OrderDirection;
+import org.apache.commons.math.analysis.BivariateRealFunction;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+
+/**
+ * Generates a bicubic interpolation function.
+ * Before interpolating, smoothing of the input data is performed using
+ * splines.
+ * See <b>Handbook on splines for the user</b>, ISBN 084939404X,
+ * chapter 2.
+ *
+ * @version $Revision: 1059400 $ $Date: 2011-01-15 20:35:27 +0100 (sam. 15 janv. 2011) $
+ * @since 2.1
+ * @deprecated This class does not perform smoothing; the name is thus misleading.
+ * Please use {@link org.apache.commons.math.analysis.interpolation.BicubicSplineInterpolator}
+ * instead. If smoothing is desired, a tentative implementation is provided in class
+ * {@link org.apache.commons.math.analysis.interpolation.SmoothingPolynomialBicubicSplineInterpolator}.
+ * This class will be removed in math 3.0.
+ */
+@Deprecated
+public class SmoothingBicubicSplineInterpolator
+ implements BivariateRealGridInterpolator {
+ /**
+ * {@inheritDoc}
+ */
+ public BivariateRealFunction interpolate(final double[] xval,
+ final double[] yval,
+ final double[][] zval)
+ throws MathException, IllegalArgumentException {
+ if (xval.length == 0 || yval.length == 0 || zval.length == 0) {
+ throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.NO_DATA);
+ }
+ if (xval.length != zval.length) {
+ throw new DimensionMismatchException(xval.length, zval.length);
+ }
+
+ MathUtils.checkOrder(xval, OrderDirection.INCREASING, true);
+ MathUtils.checkOrder(yval, OrderDirection.INCREASING, true);
+
+ final int xLen = xval.length;
+ final int yLen = yval.length;
+
+ // Samples (first index is y-coordinate, i.e. subarray variable is x)
+ // 0 <= i < xval.length
+ // 0 <= j < yval.length
+ // zX[j][i] = f(xval[i], yval[j])
+ final double[][] zX = new double[yLen][xLen];
+ for (int i = 0; i < xLen; i++) {
+ if (zval[i].length != yLen) {
+ throw new DimensionMismatchException(zval[i].length, yLen);
+ }
+
+ for (int j = 0; j < yLen; j++) {
+ zX[j][i] = zval[i][j];
+ }
+ }
+
+ final SplineInterpolator spInterpolator = new SplineInterpolator();
+
+ // For each line y[j] (0 <= j < yLen), construct a 1D spline with
+ // respect to variable x
+ final PolynomialSplineFunction[] ySplineX = new PolynomialSplineFunction[yLen];
+ for (int j = 0; j < yLen; j++) {
+ ySplineX[j] = spInterpolator.interpolate(xval, zX[j]);
+ }
+
+ // For every knot (xval[i], yval[j]) of the grid, calculate corrected
+ // values zY_1
+ final double[][] zY_1 = new double[xLen][yLen];
+ for (int j = 0; j < yLen; j++) {
+ final PolynomialSplineFunction f = ySplineX[j];
+ for (int i = 0; i < xLen; i++) {
+ zY_1[i][j] = f.value(xval[i]);
+ }
+ }
+
+ // For each line x[i] (0 <= i < xLen), construct a 1D spline with
+ // respect to variable y generated by array zY_1[i]
+ final PolynomialSplineFunction[] xSplineY = new PolynomialSplineFunction[xLen];
+ for (int i = 0; i < xLen; i++) {
+ xSplineY[i] = spInterpolator.interpolate(yval, zY_1[i]);
+ }
+
+ // For every knot (xval[i], yval[j]) of the grid, calculate corrected
+ // values zY_2
+ final double[][] zY_2 = new double[xLen][yLen];
+ for (int i = 0; i < xLen; i++) {
+ final PolynomialSplineFunction f = xSplineY[i];
+ for (int j = 0; j < yLen; j++) {
+ zY_2[i][j] = f.value(yval[j]);
+ }
+ }
+
+ // Partial derivatives with respect to x at the grid knots
+ final double[][] dZdX = new double[xLen][yLen];
+ for (int j = 0; j < yLen; j++) {
+ final UnivariateRealFunction f = ySplineX[j].derivative();
+ for (int i = 0; i < xLen; i++) {
+ dZdX[i][j] = f.value(xval[i]);
+ }
+ }
+
+ // Partial derivatives with respect to y at the grid knots
+ final double[][] dZdY = new double[xLen][yLen];
+ for (int i = 0; i < xLen; i++) {
+ final UnivariateRealFunction f = xSplineY[i].derivative();
+ for (int j = 0; j < yLen; j++) {
+ dZdY[i][j] = f.value(yval[j]);
+ }
+ }
+
+ // Cross partial derivatives
+ final double[][] dZdXdY = new double[xLen][yLen];
+ for (int i = 0; i < xLen ; i++) {
+ final int nI = nextIndex(i, xLen);
+ final int pI = previousIndex(i);
+ for (int j = 0; j < yLen; j++) {
+ final int nJ = nextIndex(j, yLen);
+ final int pJ = previousIndex(j);
+ dZdXdY[i][j] = (zY_2[nI][nJ] - zY_2[nI][pJ] -
+ zY_2[pI][nJ] + zY_2[pI][pJ]) /
+ ((xval[nI] - xval[pI]) * (yval[nJ] - yval[pJ]));
+ }
+ }
+
+ // Create the interpolating splines
+ return new BicubicSplineInterpolatingFunction(xval, yval, zY_2,
+ dZdX, dZdY, dZdXdY);
+ }
+
+ /**
+ * Compute the next index of an array, clipping if necessary.
+ * It is assumed (but not checked) that {@code i} is larger than or equal to 0}.
+ *
+ * @param i Index
+ * @param max Upper limit of the array
+ * @return the next index
+ */
+ private int nextIndex(int i, int max) {
+ final int index = i + 1;
+ return index < max ? index : index - 1;
+ }
+ /**
+ * Compute the previous index of an array, clipping if necessary.
+ * It is assumed (but not checked) that {@code i} is smaller than the size of the array.
+ *
+ * @param i Index
+ * @return the previous index
+ */
+ private int previousIndex(int i) {
+ final int index = i - 1;
+ return index >= 0 ? index : 0;
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/SmoothingPolynomialBicubicSplineInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/SmoothingPolynomialBicubicSplineInterpolator.java
new file mode 100644
index 0000000..406d603
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/SmoothingPolynomialBicubicSplineInterpolator.java
@@ -0,0 +1,143 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.NoDataException;
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.util.MathUtils;
+import org.apache.commons.math.optimization.general.GaussNewtonOptimizer;
+import org.apache.commons.math.optimization.fitting.PolynomialFitter;
+import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
+
+/**
+ * Generates a bicubic interpolation function.
+ * Prior to generating the interpolating function, the input is smoothed using
+ * polynomial fitting.
+ *
+ * @version $Revision: 1003892 $ $Date: 2010-10-02 23:28:56 +0200 (sam. 02 oct. 2010) $
+ * @since 2.2
+ */
+public class SmoothingPolynomialBicubicSplineInterpolator
+ extends BicubicSplineInterpolator {
+
+ /** Fitter for x. */
+ private final PolynomialFitter xFitter;
+
+ /** Fitter for y. */
+ private final PolynomialFitter yFitter;
+
+ /**
+ * Default constructor. The degree of the fitting polynomials is set to 3.
+ */
+ public SmoothingPolynomialBicubicSplineInterpolator() {
+ this(3);
+ }
+
+ /**
+ * @param degree Degree of the polynomial fitting functions.
+ */
+ public SmoothingPolynomialBicubicSplineInterpolator(int degree) {
+ this(degree, degree);
+ }
+
+ /**
+ * @param xDegree Degree of the polynomial fitting functions along the
+ * x-dimension.
+ * @param yDegree Degree of the polynomial fitting functions along the
+ * y-dimension.
+ */
+ public SmoothingPolynomialBicubicSplineInterpolator(int xDegree,
+ int yDegree) {
+ xFitter = new PolynomialFitter(xDegree, new GaussNewtonOptimizer(false));
+ yFitter = new PolynomialFitter(yDegree, new GaussNewtonOptimizer(false));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public BicubicSplineInterpolatingFunction interpolate(final double[] xval,
+ final double[] yval,
+ final double[][] fval)
+ throws MathException {
+ if (xval.length == 0 || yval.length == 0 || fval.length == 0) {
+ throw new NoDataException();
+ }
+ if (xval.length != fval.length) {
+ throw new DimensionMismatchException(xval.length, fval.length);
+ }
+
+ final int xLen = xval.length;
+ final int yLen = yval.length;
+
+ for (int i = 0; i < xLen; i++) {
+ if (fval[i].length != yLen) {
+ throw new DimensionMismatchException(fval[i].length, yLen);
+ }
+ }
+
+ MathUtils.checkOrder(xval);
+ MathUtils.checkOrder(yval);
+
+ // For each line y[j] (0 <= j < yLen), construct a polynomial, with
+ // respect to variable x, fitting array fval[][j]
+ final PolynomialFunction[] yPolyX = new PolynomialFunction[yLen];
+ for (int j = 0; j < yLen; j++) {
+ xFitter.clearObservations();
+ for (int i = 0; i < xLen; i++) {
+ xFitter.addObservedPoint(1, xval[i], fval[i][j]);
+ }
+
+ yPolyX[j] = xFitter.fit();
+ }
+
+ // For every knot (xval[i], yval[j]) of the grid, calculate corrected
+ // values fval_1
+ final double[][] fval_1 = new double[xLen][yLen];
+ for (int j = 0; j < yLen; j++) {
+ final PolynomialFunction f = yPolyX[j];
+ for (int i = 0; i < xLen; i++) {
+ fval_1[i][j] = f.value(xval[i]);
+ }
+ }
+
+ // For each line x[i] (0 <= i < xLen), construct a polynomial, with
+ // respect to variable y, fitting array fval_1[i][]
+ final PolynomialFunction[] xPolyY = new PolynomialFunction[xLen];
+ for (int i = 0; i < xLen; i++) {
+ yFitter.clearObservations();
+ for (int j = 0; j < yLen; j++) {
+ yFitter.addObservedPoint(1, yval[j], fval_1[i][j]);
+ }
+
+ xPolyY[i] = yFitter.fit();
+ }
+
+ // For every knot (xval[i], yval[j]) of the grid, calculate corrected
+ // values fval_2
+ final double[][] fval_2 = new double[xLen][yLen];
+ for (int i = 0; i < xLen; i++) {
+ final PolynomialFunction f = xPolyY[i];
+ for (int j = 0; j < yLen; j++) {
+ fval_2[i][j] = f.value(yval[j]);
+ }
+ }
+
+ return super.interpolate(xval, yval, fval_2);
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/SplineInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/SplineInterpolator.java
new file mode 100644
index 0000000..f25ba83
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/SplineInterpolator.java
@@ -0,0 +1,127 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.exception.NumberIsTooSmallException;
+import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
+import org.apache.commons.math.analysis.polynomials.PolynomialSplineFunction;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Computes a natural (also known as "free", "unclamped") cubic spline interpolation for the data set.
+ * <p>
+ * The {@link #interpolate(double[], double[])} method returns a {@link PolynomialSplineFunction}
+ * consisting of n cubic polynomials, defined over the subintervals determined by the x values,
+ * x[0] < x[i] ... < x[n]. The x values are referred to as "knot points."</p>
+ * <p>
+ * The value of the PolynomialSplineFunction at a point x that is greater than or equal to the smallest
+ * knot point and strictly less than the largest knot point is computed by finding the subinterval to which
+ * x belongs and computing the value of the corresponding polynomial at <code>x - x[i] </code> where
+ * <code>i</code> is the index of the subinterval. See {@link PolynomialSplineFunction} for more details.
+ * </p>
+ * <p>
+ * The interpolating polynomials satisfy: <ol>
+ * <li>The value of the PolynomialSplineFunction at each of the input x values equals the
+ * corresponding y value.</li>
+ * <li>Adjacent polynomials are equal through two derivatives at the knot points (i.e., adjacent polynomials
+ * "match up" at the knot points, as do their first and second derivatives).</li>
+ * </ol></p>
+ * <p>
+ * The cubic spline interpolation algorithm implemented is as described in R.L. Burden, J.D. Faires,
+ * <u>Numerical Analysis</u>, 4th Ed., 1989, PWS-Kent, ISBN 0-53491-585-X, pp 126-131.
+ * </p>
+ *
+ * @version $Revision: 983921 $ $Date: 2010-08-10 12:46:06 +0200 (mar. 10 août 2010) $
+ *
+ */
+public class SplineInterpolator implements UnivariateRealInterpolator {
+
+ /**
+ * Computes an interpolating function for the data set.
+ * @param x the arguments for the interpolation points
+ * @param y the values for the interpolation points
+ * @return a function which interpolates the data set
+ * @throws DimensionMismatchException if {@code x} and {@code y}
+ * have different sizes.
+ * @throws org.apache.commons.math.exception.NonMonotonousSequenceException
+ * if {@code x} is not sorted in strict increasing order.
+ * @throws NumberIsTooSmallException if the size of {@code x} is smaller
+ * than 3.
+ */
+ public PolynomialSplineFunction interpolate(double x[], double y[]) {
+ if (x.length != y.length) {
+ throw new DimensionMismatchException(x.length, y.length);
+ }
+
+ if (x.length < 3) {
+ throw new NumberIsTooSmallException(LocalizedFormats.NUMBER_OF_POINTS,
+ x.length, 3, true);
+ }
+
+ // Number of intervals. The number of data points is n + 1.
+ int n = x.length - 1;
+
+ MathUtils.checkOrder(x);
+
+ // Differences between knot points
+ double h[] = new double[n];
+ for (int i = 0; i < n; i++) {
+ h[i] = x[i + 1] - x[i];
+ }
+
+ double mu[] = new double[n];
+ double z[] = new double[n + 1];
+ mu[0] = 0d;
+ z[0] = 0d;
+ double g = 0;
+ for (int i = 1; i < n; i++) {
+ g = 2d * (x[i+1] - x[i - 1]) - h[i - 1] * mu[i -1];
+ mu[i] = h[i] / g;
+ z[i] = (3d * (y[i + 1] * h[i - 1] - y[i] * (x[i + 1] - x[i - 1])+ y[i - 1] * h[i]) /
+ (h[i - 1] * h[i]) - h[i - 1] * z[i - 1]) / g;
+ }
+
+ // cubic spline coefficients -- b is linear, c quadratic, d is cubic (original y's are constants)
+ double b[] = new double[n];
+ double c[] = new double[n + 1];
+ double d[] = new double[n];
+
+ z[n] = 0d;
+ c[n] = 0d;
+
+ for (int j = n -1; j >=0; j--) {
+ c[j] = z[j] - mu[j] * c[j + 1];
+ b[j] = (y[j + 1] - y[j]) / h[j] - h[j] * (c[j + 1] + 2d * c[j]) / 3d;
+ d[j] = (c[j + 1] - c[j]) / (3d * h[j]);
+ }
+
+ PolynomialFunction polynomials[] = new PolynomialFunction[n];
+ double coefficients[] = new double[4];
+ for (int i = 0; i < n; i++) {
+ coefficients[0] = y[i];
+ coefficients[1] = b[i];
+ coefficients[2] = c[i];
+ coefficients[3] = d[i];
+ polynomials[i] = new PolynomialFunction(coefficients);
+ }
+
+ return new PolynomialSplineFunction(x, polynomials);
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/TricubicSplineInterpolatingFunction.java b/src/main/java/org/apache/commons/math/analysis/interpolation/TricubicSplineInterpolatingFunction.java
new file mode 100644
index 0000000..ea435a3
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/TricubicSplineInterpolatingFunction.java
@@ -0,0 +1,483 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.analysis.TrivariateRealFunction;
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.NoDataException;
+import org.apache.commons.math.exception.OutOfRangeException;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Function that implements the
+ * <a href="http://en.wikipedia.org/wiki/Tricubic_interpolation">
+ * tricubic spline interpolation</a>, as proposed in
+ * <quote>
+ * Tricubic interpolation in three dimensions<br/>
+ * F. Lekien and J. Marsden<br/>
+ * <em>Int. J. Numer. Meth. Engng</em> 2005; <b>63</b>:455-471
+ * </quote>
+ *
+ * @version $Revision$ $Date$
+ * @since 2.2
+ */
+public class TricubicSplineInterpolatingFunction
+ implements TrivariateRealFunction {
+ /**
+ * Matrix to compute the spline coefficients from the function values
+ * and function derivatives values
+ */
+ private static final double[][] AINV = {
+ { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { -3,3,0,0,0,0,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 2,-2,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { -3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,-3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 9,-9,-9,9,0,0,0,0,6,3,-6,-3,0,0,0,0,6,-6,3,-3,0,0,0,0,0,0,0,0,0,0,0,0,4,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { -6,6,6,-6,0,0,0,0,-3,-3,3,3,0,0,0,0,-4,4,-2,2,0,0,0,0,0,0,0,0,0,0,0,0,-2,-2,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 2,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,2,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { -6,6,6,-6,0,0,0,0,-4,-2,4,2,0,0,0,0,-3,3,-3,3,0,0,0,0,0,0,0,0,0,0,0,0,-2,-1,-2,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 4,-4,-4,4,0,0,0,0,2,2,-2,-2,0,0,0,0,2,-2,2,-2,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3,3,0,0,0,0,0,0,-2,-1,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,-2,0,0,0,0,0,0,1,1,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,-1,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-9,-9,9,0,0,0,0,0,0,0,0,0,0,0,0,6,3,-6,-3,0,0,0,0,6,-6,3,-3,0,0,0,0,4,2,2,1,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-6,6,6,-6,0,0,0,0,0,0,0,0,0,0,0,0,-3,-3,3,3,0,0,0,0,-4,4,-2,2,0,0,0,0,-2,-2,-1,-1,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-6,6,6,-6,0,0,0,0,0,0,0,0,0,0,0,0,-4,-2,4,2,0,0,0,0,-3,3,-3,3,0,0,0,0,-2,-1,-2,-1,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,-4,-4,4,0,0,0,0,0,0,0,0,0,0,0,0,2,2,-2,-2,0,0,0,0,2,-2,2,-2,0,0,0,0,1,1,1,1,0,0,0,0 },
+ {-3,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,-3,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 9,-9,0,0,-9,9,0,0,6,3,0,0,-6,-3,0,0,0,0,0,0,0,0,0,0,6,-6,0,0,3,-3,0,0,0,0,0,0,0,0,0,0,4,2,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { -6,6,0,0,6,-6,0,0,-3,-3,0,0,3,3,0,0,0,0,0,0,0,0,0,0,-4,4,0,0,-2,2,0,0,0,0,0,0,0,0,0,0,-2,-2,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,0,0,-1,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-9,0,0,-9,9,0,0,0,0,0,0,0,0,0,0,6,3,0,0,-6,-3,0,0,0,0,0,0,0,0,0,0,6,-6,0,0,3,-3,0,0,4,2,0,0,2,1,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-6,6,0,0,6,-6,0,0,0,0,0,0,0,0,0,0,-3,-3,0,0,3,3,0,0,0,0,0,0,0,0,0,0,-4,4,0,0,-2,2,0,0,-2,-2,0,0,-1,-1,0,0 },
+ { 9,0,-9,0,-9,0,9,0,0,0,0,0,0,0,0,0,6,0,3,0,-6,0,-3,0,6,0,-6,0,3,0,-3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,2,0,2,0,1,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,9,0,-9,0,-9,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,3,0,-6,0,-3,0,6,0,-6,0,3,0,-3,0,0,0,0,0,0,0,0,0,4,0,2,0,2,0,1,0 },
+ { -27,27,27,-27,27,-27,-27,27,-18,-9,18,9,18,9,-18,-9,-18,18,-9,9,18,-18,9,-9,-18,18,18,-18,-9,9,9,-9,-12,-6,-6,-3,12,6,6,3,-12,-6,12,6,-6,-3,6,3,-12,12,-6,6,-6,6,-3,3,-8,-4,-4,-2,-4,-2,-2,-1 },
+ { 18,-18,-18,18,-18,18,18,-18,9,9,-9,-9,-9,-9,9,9,12,-12,6,-6,-12,12,-6,6,12,-12,-12,12,6,-6,-6,6,6,6,3,3,-6,-6,-3,-3,6,6,-6,-6,3,3,-3,-3,8,-8,4,-4,4,-4,2,-2,4,4,2,2,2,2,1,1 },
+ { -6,0,6,0,6,0,-6,0,0,0,0,0,0,0,0,0,-3,0,-3,0,3,0,3,0,-4,0,4,0,-2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,-2,0,-1,0,-1,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,-6,0,6,0,6,0,-6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-3,0,-3,0,3,0,3,0,-4,0,4,0,-2,0,2,0,0,0,0,0,0,0,0,0,-2,0,-2,0,-1,0,-1,0 },
+ { 18,-18,-18,18,-18,18,18,-18,12,6,-12,-6,-12,-6,12,6,9,-9,9,-9,-9,9,-9,9,12,-12,-12,12,6,-6,-6,6,6,3,6,3,-6,-3,-6,-3,8,4,-8,-4,4,2,-4,-2,6,-6,6,-6,3,-3,3,-3,4,2,4,2,2,1,2,1 },
+ { -12,12,12,-12,12,-12,-12,12,-6,-6,6,6,6,6,-6,-6,-6,6,-6,6,6,-6,6,-6,-8,8,8,-8,-4,4,4,-4,-3,-3,-3,-3,3,3,3,3,-4,-4,4,4,-2,-2,2,2,-4,4,-4,4,-2,2,-2,2,-2,-2,-2,-2,-1,-1,-1,-1 },
+ { 2,0,0,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,2,0,0,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { -6,6,0,0,6,-6,0,0,-4,-2,0,0,4,2,0,0,0,0,0,0,0,0,0,0,-3,3,0,0,-3,3,0,0,0,0,0,0,0,0,0,0,-2,-1,0,0,-2,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 4,-4,0,0,-4,4,0,0,2,2,0,0,-2,-2,0,0,0,0,0,0,0,0,0,0,2,-2,0,0,2,-2,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-6,6,0,0,6,-6,0,0,0,0,0,0,0,0,0,0,-4,-2,0,0,4,2,0,0,0,0,0,0,0,0,0,0,-3,3,0,0,-3,3,0,0,-2,-1,0,0,-2,-1,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,-4,0,0,-4,4,0,0,0,0,0,0,0,0,0,0,2,2,0,0,-2,-2,0,0,0,0,0,0,0,0,0,0,2,-2,0,0,2,-2,0,0,1,1,0,0,1,1,0,0 },
+ { -6,0,6,0,6,0,-6,0,0,0,0,0,0,0,0,0,-4,0,-2,0,4,0,2,0,-3,0,3,0,-3,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,0,-1,0,-2,0,-1,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,-6,0,6,0,6,0,-6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-4,0,-2,0,4,0,2,0,-3,0,3,0,-3,0,3,0,0,0,0,0,0,0,0,0,-2,0,-1,0,-2,0,-1,0 },
+ { 18,-18,-18,18,-18,18,18,-18,12,6,-12,-6,-12,-6,12,6,12,-12,6,-6,-12,12,-6,6,9,-9,-9,9,9,-9,-9,9,8,4,4,2,-8,-4,-4,-2,6,3,-6,-3,6,3,-6,-3,6,-6,3,-3,6,-6,3,-3,4,2,2,1,4,2,2,1 },
+ { -12,12,12,-12,12,-12,-12,12,-6,-6,6,6,6,6,-6,-6,-8,8,-4,4,8,-8,4,-4,-6,6,6,-6,-6,6,6,-6,-4,-4,-2,-2,4,4,2,2,-3,-3,3,3,-3,-3,3,3,-4,4,-2,2,-4,4,-2,2,-2,-2,-1,-1,-2,-2,-1,-1 },
+ { 4,0,-4,0,-4,0,4,0,0,0,0,0,0,0,0,0,2,0,2,0,-2,0,-2,0,2,0,-2,0,2,0,-2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,4,0,-4,0,-4,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,-2,0,-2,0,2,0,-2,0,2,0,-2,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,1,0 },
+ { -12,12,12,-12,12,-12,-12,12,-8,-4,8,4,8,4,-8,-4,-6,6,-6,6,6,-6,6,-6,-6,6,6,-6,-6,6,6,-6,-4,-2,-4,-2,4,2,4,2,-4,-2,4,2,-4,-2,4,2,-3,3,-3,3,-3,3,-3,3,-2,-1,-2,-1,-2,-1,-2,-1 },
+ { 8,-8,-8,8,-8,8,8,-8,4,4,-4,-4,-4,-4,4,4,4,-4,4,-4,-4,4,-4,4,4,-4,-4,4,4,-4,-4,4,2,2,2,2,-2,-2,-2,-2,2,2,-2,-2,2,2,-2,-2,2,-2,2,-2,2,-2,2,-2,1,1,1,1,1,1,1,1 }
+ };
+
+ /** Samples x-coordinates */
+ private final double[] xval;
+ /** Samples y-coordinates */
+ private final double[] yval;
+ /** Samples z-coordinates */
+ private final double[] zval;
+ /** Set of cubic splines pacthing the whole data grid */
+ private final TricubicSplineFunction[][][] splines;
+
+ /**
+ * @param x Sample values of the x-coordinate, in increasing order.
+ * @param y Sample values of the y-coordinate, in increasing order.
+ * @param z Sample values of the y-coordinate, in increasing order.
+ * @param f Values of the function on every grid point.
+ * @param dFdX Values of the partial derivative of function with respect
+ * to x on every grid point.
+ * @param dFdY Values of the partial derivative of function with respect
+ * to y on every grid point.
+ * @param dFdZ Values of the partial derivative of function with respect
+ * to z on every grid point.
+ * @param d2FdXdY Values of the cross partial derivative of function on
+ * every grid point.
+ * @param d2FdXdZ Values of the cross partial derivative of function on
+ * every grid point.
+ * @param d2FdYdZ Values of the cross partial derivative of function on
+ * every grid point.
+ * @param d3FdXdYdZ Values of the cross partial derivative of function on
+ * every grid point.
+ * @throws NoDataException if any of the arrays has zero length.
+ * @throws DimensionMismatchException if the various arrays do not contain
+ * the expected number of elements.
+ * @throws IllegalArgumentException if {@code x}, {@code y} or {@code z}
+ * are not strictly increasing.
+ */
+ public TricubicSplineInterpolatingFunction(double[] x,
+ double[] y,
+ double[] z,
+ double[][][] f,
+ double[][][] dFdX,
+ double[][][] dFdY,
+ double[][][] dFdZ,
+ double[][][] d2FdXdY,
+ double[][][] d2FdXdZ,
+ double[][][] d2FdYdZ,
+ double[][][] d3FdXdYdZ) {
+ final int xLen = x.length;
+ final int yLen = y.length;
+ final int zLen = z.length;
+
+ if (xLen == 0 || yLen == 0 || z.length == 0 || f.length == 0 || f[0].length == 0) {
+ throw new NoDataException();
+ }
+ if (xLen != f.length) {
+ throw new DimensionMismatchException(xLen, f.length);
+ }
+ if (xLen != dFdX.length) {
+ throw new DimensionMismatchException(xLen, dFdX.length);
+ }
+ if (xLen != dFdY.length) {
+ throw new DimensionMismatchException(xLen, dFdY.length);
+ }
+ if (xLen != dFdZ.length) {
+ throw new DimensionMismatchException(xLen, dFdZ.length);
+ }
+ if (xLen != d2FdXdY.length) {
+ throw new DimensionMismatchException(xLen, d2FdXdY.length);
+ }
+ if (xLen != d2FdXdZ.length) {
+ throw new DimensionMismatchException(xLen, d2FdXdZ.length);
+ }
+ if (xLen != d2FdYdZ.length) {
+ throw new DimensionMismatchException(xLen, d2FdYdZ.length);
+ }
+ if (xLen != d3FdXdYdZ.length) {
+ throw new DimensionMismatchException(xLen, d3FdXdYdZ.length);
+ }
+
+ MathUtils.checkOrder(x);
+ MathUtils.checkOrder(y);
+ MathUtils.checkOrder(z);
+
+ xval = x.clone();
+ yval = y.clone();
+ zval = z.clone();
+
+ final int lastI = xLen - 1;
+ final int lastJ = yLen - 1;
+ final int lastK = zLen - 1;
+ splines = new TricubicSplineFunction[lastI][lastJ][lastK];
+
+ for (int i = 0; i < lastI; i++) {
+ if (f[i].length != yLen) {
+ throw new DimensionMismatchException(f[i].length, yLen);
+ }
+ if (dFdX[i].length != yLen) {
+ throw new DimensionMismatchException(dFdX[i].length, yLen);
+ }
+ if (dFdY[i].length != yLen) {
+ throw new DimensionMismatchException(dFdY[i].length, yLen);
+ }
+ if (dFdZ[i].length != yLen) {
+ throw new DimensionMismatchException(dFdZ[i].length, yLen);
+ }
+ if (d2FdXdY[i].length != yLen) {
+ throw new DimensionMismatchException(d2FdXdY[i].length, yLen);
+ }
+ if (d2FdXdZ[i].length != yLen) {
+ throw new DimensionMismatchException(d2FdXdZ[i].length, yLen);
+ }
+ if (d2FdYdZ[i].length != yLen) {
+ throw new DimensionMismatchException(d2FdYdZ[i].length, yLen);
+ }
+ if (d3FdXdYdZ[i].length != yLen) {
+ throw new DimensionMismatchException(d3FdXdYdZ[i].length, yLen);
+ }
+
+ final int ip1 = i + 1;
+ for (int j = 0; j < lastJ; j++) {
+ if (f[i][j].length != zLen) {
+ throw new DimensionMismatchException(f[i][j].length, zLen);
+ }
+ if (dFdX[i][j].length != zLen) {
+ throw new DimensionMismatchException(dFdX[i][j].length, zLen);
+ }
+ if (dFdY[i][j].length != zLen) {
+ throw new DimensionMismatchException(dFdY[i][j].length, zLen);
+ }
+ if (dFdZ[i][j].length != zLen) {
+ throw new DimensionMismatchException(dFdZ[i][j].length, zLen);
+ }
+ if (d2FdXdY[i][j].length != zLen) {
+ throw new DimensionMismatchException(d2FdXdY[i][j].length, zLen);
+ }
+ if (d2FdXdZ[i][j].length != zLen) {
+ throw new DimensionMismatchException(d2FdXdZ[i][j].length, zLen);
+ }
+ if (d2FdYdZ[i][j].length != zLen) {
+ throw new DimensionMismatchException(d2FdYdZ[i][j].length, zLen);
+ }
+ if (d3FdXdYdZ[i][j].length != zLen) {
+ throw new DimensionMismatchException(d3FdXdYdZ[i][j].length, zLen);
+ }
+
+ final int jp1 = j + 1;
+ for (int k = 0; k < lastK; k++) {
+ final int kp1 = k + 1;
+
+ final double[] beta = new double[] {
+ f[i][j][k], f[ip1][j][k],
+ f[i][jp1][k], f[ip1][jp1][k],
+ f[i][j][kp1], f[ip1][j][kp1],
+ f[i][jp1][kp1], f[ip1][jp1][kp1],
+
+ dFdX[i][j][k], dFdX[ip1][j][k],
+ dFdX[i][jp1][k], dFdX[ip1][jp1][k],
+ dFdX[i][j][kp1], dFdX[ip1][j][kp1],
+ dFdX[i][jp1][kp1], dFdX[ip1][jp1][kp1],
+
+ dFdY[i][j][k], dFdY[ip1][j][k],
+ dFdY[i][jp1][k], dFdY[ip1][jp1][k],
+ dFdY[i][j][kp1], dFdY[ip1][j][kp1],
+ dFdY[i][jp1][kp1], dFdY[ip1][jp1][kp1],
+
+ dFdZ[i][j][k], dFdZ[ip1][j][k],
+ dFdZ[i][jp1][k], dFdZ[ip1][jp1][k],
+ dFdZ[i][j][kp1], dFdZ[ip1][j][kp1],
+ dFdZ[i][jp1][kp1], dFdZ[ip1][jp1][kp1],
+
+ d2FdXdY[i][j][k], d2FdXdY[ip1][j][k],
+ d2FdXdY[i][jp1][k], d2FdXdY[ip1][jp1][k],
+ d2FdXdY[i][j][kp1], d2FdXdY[ip1][j][kp1],
+ d2FdXdY[i][jp1][kp1], d2FdXdY[ip1][jp1][kp1],
+
+ d2FdXdZ[i][j][k], d2FdXdZ[ip1][j][k],
+ d2FdXdZ[i][jp1][k], d2FdXdZ[ip1][jp1][k],
+ d2FdXdZ[i][j][kp1], d2FdXdZ[ip1][j][kp1],
+ d2FdXdZ[i][jp1][kp1], d2FdXdZ[ip1][jp1][kp1],
+
+ d2FdYdZ[i][j][k], d2FdYdZ[ip1][j][k],
+ d2FdYdZ[i][jp1][k], d2FdYdZ[ip1][jp1][k],
+ d2FdYdZ[i][j][kp1], d2FdYdZ[ip1][j][kp1],
+ d2FdYdZ[i][jp1][kp1], d2FdYdZ[ip1][jp1][kp1],
+
+ d3FdXdYdZ[i][j][k], d3FdXdYdZ[ip1][j][k],
+ d3FdXdYdZ[i][jp1][k], d3FdXdYdZ[ip1][jp1][k],
+ d3FdXdYdZ[i][j][kp1], d3FdXdYdZ[ip1][j][kp1],
+ d3FdXdYdZ[i][jp1][kp1], d3FdXdYdZ[ip1][jp1][kp1],
+ };
+
+ splines[i][j][k] = new TricubicSplineFunction(computeSplineCoefficients(beta));
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public double value(double x, double y, double z) {
+ final int i = searchIndex(x, xval);
+ if (i == -1) {
+ throw new OutOfRangeException(x, xval[0], xval[xval.length - 1]);
+ }
+ final int j = searchIndex(y, yval);
+ if (j == -1) {
+ throw new OutOfRangeException(y, yval[0], yval[yval.length - 1]);
+ }
+ final int k = searchIndex(z, zval);
+ if (k == -1) {
+ throw new OutOfRangeException(z, zval[0], zval[zval.length - 1]);
+ }
+
+ final double xN = (x - xval[i]) / (xval[i + 1] - xval[i]);
+ final double yN = (y - yval[j]) / (yval[j + 1] - yval[j]);
+ final double zN = (z - zval[k]) / (zval[k + 1] - zval[k]);
+
+ return splines[i][j][k].value(xN, yN, zN);
+ }
+
+ /**
+ * @param c Coordinate.
+ * @param val Coordinate samples.
+ * @return the index in {@code val} corresponding to the interval
+ * containing {@code c}, or {@code -1} if {@code c} is out of the
+ * range defined by the end values of {@code val}.
+ */
+ private int searchIndex(double c, double[] val) {
+ if (c < val[0]) {
+ return -1;
+ }
+
+ final int max = val.length;
+ for (int i = 1; i < max; i++) {
+ if (c <= val[i]) {
+ return i - 1;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Compute the spline coefficients from the list of function values and
+ * function partial derivatives values at the four corners of a grid
+ * element. They must be specified in the following order:
+ * <ul>
+ * <li>f(0,0,0)</li>
+ * <li>f(1,0,0)</li>
+ * <li>f(0,1,0)</li>
+ * <li>f(1,1,0)</li>
+ * <li>f(0,0,1)</li>
+ * <li>f(1,0,1)</li>
+ * <li>f(0,1,1)</li>
+ * <li>f(1,1,1)</li>
+ *
+ * <li>f<sub>x</sub>(0,0,0)</li>
+ * <li>... <em>(same order as above)</em></li>
+ * <li>f<sub>x</sub>(1,1,1)</li>
+ *
+ * <li>f<sub>y</sub>(0,0,0)</li>
+ * <li>... <em>(same order as above)</em></li>
+ * <li>f<sub>y</sub>(1,1,1)</li>
+ *
+ * <li>f<sub>z</sub>(0,0,0)</li>
+ * <li>... <em>(same order as above)</em></li>
+ * <li>f<sub>z</sub>(1,1,1)</li>
+ *
+ * <li>f<sub>xy</sub>(0,0,0)</li>
+ * <li>... <em>(same order as above)</em></li>
+ * <li>f<sub>xy</sub>(1,1,1)</li>
+ *
+ * <li>f<sub>xz</sub>(0,0,0)</li>
+ * <li>... <em>(same order as above)</em></li>
+ * <li>f<sub>xz</sub>(1,1,1)</li>
+ *
+ * <li>f<sub>yz</sub>(0,0,0)</li>
+ * <li>... <em>(same order as above)</em></li>
+ * <li>f<sub>yz</sub>(1,1,1)</li>
+ *
+ * <li>f<sub>xyz</sub>(0,0,0)</li>
+ * <li>... <em>(same order as above)</em></li>
+ * <li>f<sub>xyz</sub>(1,1,1)</li>
+ * </ul>
+ * where the subscripts indicate the partial derivative with respect to
+ * the corresponding variable(s).
+ *
+ * @param beta List of function values and function partial derivatives
+ * values.
+ * @return the spline coefficients.
+ */
+ private double[] computeSplineCoefficients(double[] beta) {
+ final int sz = 64;
+ final double[] a = new double[sz];
+
+ for (int i = 0; i < sz; i++) {
+ double result = 0;
+ final double[] row = AINV[i];
+ for (int j = 0; j < sz; j++) {
+ result += row[j] * beta[j];
+ }
+ a[i] = result;
+ }
+
+ return a;
+ }
+}
+
+/**
+ * 3D-spline function.
+ *
+ * @version $Revision$ $Date$
+ */
+class TricubicSplineFunction
+ implements TrivariateRealFunction {
+ /** Number of points. */
+ private static final short N = 4;
+ /** Coefficients */
+ private final double[][][] a = new double[N][N][N];
+
+ /**
+ * @param aV List of spline coefficients.
+ */
+ public TricubicSplineFunction(double[] aV) {
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ for (int k = 0; k < N; k++) {
+ a[i][j][k] = aV[i + N * (j + N * k)];
+ }
+ }
+ }
+ }
+
+ /**
+ * @param x x-coordinate of the interpolation point.
+ * @param y y-coordinate of the interpolation point.
+ * @param z z-coordinate of the interpolation point.
+ * @return the interpolated value.
+ */
+ public double value(double x, double y, double z) {
+ if (x < 0 || x > 1) {
+ throw new OutOfRangeException(x, 0, 1);
+ }
+ if (y < 0 || y > 1) {
+ throw new OutOfRangeException(y, 0, 1);
+ }
+ if (z < 0 || z > 1) {
+ throw new OutOfRangeException(z, 0, 1);
+ }
+
+ final double x2 = x * x;
+ final double x3 = x2 * x;
+ final double[] pX = { 1, x, x2, x3 };
+
+ final double y2 = y * y;
+ final double y3 = y2 * y;
+ final double[] pY = { 1, y, y2, y3 };
+
+ final double z2 = z * z;
+ final double z3 = z2 * z;
+ final double[] pZ = { 1, z, z2, z3 };
+
+ double result = 0;
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ for (int k = 0; k < N; k++) {
+ result += a[i][j][k] * pX[i] * pY[j] * pZ[k];
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/TricubicSplineInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/TricubicSplineInterpolator.java
new file mode 100644
index 0000000..dac7f26
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/TricubicSplineInterpolator.java
@@ -0,0 +1,198 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.exception.DimensionMismatchException;
+import org.apache.commons.math.exception.NoDataException;
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Generates a tricubic interpolating function.
+ *
+ * @version $Revision$ $Date$
+ * @since 2.2
+ */
+public class TricubicSplineInterpolator
+ implements TrivariateRealGridInterpolator {
+ /**
+ * {@inheritDoc}
+ */
+ public TricubicSplineInterpolatingFunction interpolate(final double[] xval,
+ final double[] yval,
+ final double[] zval,
+ final double[][][] fval)
+ throws MathException {
+ if (xval.length == 0 || yval.length == 0 || zval.length == 0 || fval.length == 0) {
+ throw new NoDataException();
+ }
+ if (xval.length != fval.length) {
+ throw new DimensionMismatchException(xval.length, fval.length);
+ }
+
+ MathUtils.checkOrder(xval);
+ MathUtils.checkOrder(yval);
+ MathUtils.checkOrder(zval);
+
+ final int xLen = xval.length;
+ final int yLen = yval.length;
+ final int zLen = zval.length;
+
+ // Samples, re-ordered as (z, x, y) and (y, z, x) tuplets
+ // fvalXY[k][i][j] = f(xval[i], yval[j], zval[k])
+ // fvalZX[j][k][i] = f(xval[i], yval[j], zval[k])
+ final double[][][] fvalXY = new double[zLen][xLen][yLen];
+ final double[][][] fvalZX = new double[yLen][zLen][xLen];
+ for (int i = 0; i < xLen; i++) {
+ if (fval[i].length != yLen) {
+ throw new DimensionMismatchException(fval[i].length, yLen);
+ }
+
+ for (int j = 0; j < yLen; j++) {
+ if (fval[i][j].length != zLen) {
+ throw new DimensionMismatchException(fval[i][j].length, zLen);
+ }
+
+ for (int k = 0; k < zLen; k++) {
+ final double v = fval[i][j][k];
+ fvalXY[k][i][j] = v;
+ fvalZX[j][k][i] = v;
+ }
+ }
+ }
+
+ final BicubicSplineInterpolator bsi = new BicubicSplineInterpolator();
+
+ // For each line x[i] (0 <= i < xLen), construct a 2D spline in y and z
+ final BicubicSplineInterpolatingFunction[] xSplineYZ
+ = new BicubicSplineInterpolatingFunction[xLen];
+ for (int i = 0; i < xLen; i++) {
+ xSplineYZ[i] = bsi.interpolate(yval, zval, fval[i]);
+ }
+
+ // For each line y[j] (0 <= j < yLen), construct a 2D spline in z and x
+ final BicubicSplineInterpolatingFunction[] ySplineZX
+ = new BicubicSplineInterpolatingFunction[yLen];
+ for (int j = 0; j < yLen; j++) {
+ ySplineZX[j] = bsi.interpolate(zval, xval, fvalZX[j]);
+ }
+
+ // For each line z[k] (0 <= k < zLen), construct a 2D spline in x and y
+ final BicubicSplineInterpolatingFunction[] zSplineXY
+ = new BicubicSplineInterpolatingFunction[zLen];
+ for (int k = 0; k < zLen; k++) {
+ zSplineXY[k] = bsi.interpolate(xval, yval, fvalXY[k]);
+ }
+
+ // Partial derivatives wrt x and wrt y
+ final double[][][] dFdX = new double[xLen][yLen][zLen];
+ final double[][][] dFdY = new double[xLen][yLen][zLen];
+ final double[][][] d2FdXdY = new double[xLen][yLen][zLen];
+ for (int k = 0; k < zLen; k++) {
+ final BicubicSplineInterpolatingFunction f = zSplineXY[k];
+ for (int i = 0; i < xLen; i++) {
+ final double x = xval[i];
+ for (int j = 0; j < yLen; j++) {
+ final double y = yval[j];
+ dFdX[i][j][k] = f.partialDerivativeX(x, y);
+ dFdY[i][j][k] = f.partialDerivativeY(x, y);
+ d2FdXdY[i][j][k] = f.partialDerivativeXY(x, y);
+ }
+ }
+ }
+
+ // Partial derivatives wrt y and wrt z
+ final double[][][] dFdZ = new double[xLen][yLen][zLen];
+ final double[][][] d2FdYdZ = new double[xLen][yLen][zLen];
+ for (int i = 0; i < xLen; i++) {
+ final BicubicSplineInterpolatingFunction f = xSplineYZ[i];
+ for (int j = 0; j < yLen; j++) {
+ final double y = yval[j];
+ for (int k = 0; k < zLen; k++) {
+ final double z = zval[k];
+ dFdZ[i][j][k] = f.partialDerivativeY(y, z);
+ d2FdYdZ[i][j][k] = f.partialDerivativeXY(y, z);
+ }
+ }
+ }
+
+ // Partial derivatives wrt x and wrt z
+ final double[][][] d2FdZdX = new double[xLen][yLen][zLen];
+ for (int j = 0; j < yLen; j++) {
+ final BicubicSplineInterpolatingFunction f = ySplineZX[j];
+ for (int k = 0; k < zLen; k++) {
+ final double z = zval[k];
+ for (int i = 0; i < xLen; i++) {
+ final double x = xval[i];
+ d2FdZdX[i][j][k] = f.partialDerivativeXY(z, x);
+ }
+ }
+ }
+
+ // Third partial cross-derivatives
+ final double[][][] d3FdXdYdZ = new double[xLen][yLen][zLen];
+ for (int i = 0; i < xLen ; i++) {
+ final int nI = nextIndex(i, xLen);
+ final int pI = previousIndex(i);
+ for (int j = 0; j < yLen; j++) {
+ final int nJ = nextIndex(j, yLen);
+ final int pJ = previousIndex(j);
+ for (int k = 0; k < zLen; k++) {
+ final int nK = nextIndex(k, zLen);
+ final int pK = previousIndex(k);
+
+ // XXX Not sure about this formula
+ d3FdXdYdZ[i][j][k] = (fval[nI][nJ][nK] - fval[nI][pJ][nK] -
+ fval[pI][nJ][nK] + fval[pI][pJ][nK] -
+ fval[nI][nJ][pK] + fval[nI][pJ][pK] +
+ fval[pI][nJ][pK] - fval[pI][pJ][pK]) /
+ ((xval[nI] - xval[pI]) * (yval[nJ] - yval[pJ]) * (zval[nK] - zval[pK])) ;
+ }
+ }
+ }
+
+ // Create the interpolating splines
+ return new TricubicSplineInterpolatingFunction(xval, yval, zval, fval,
+ dFdX, dFdY, dFdZ,
+ d2FdXdY, d2FdZdX, d2FdYdZ,
+ d3FdXdYdZ);
+ }
+
+ /**
+ * Compute the next index of an array, clipping if necessary.
+ * It is assumed (but not checked) that {@code i} is larger than or equal to 0}.
+ *
+ * @param i Index
+ * @param max Upper limit of the array
+ * @return the next index
+ */
+ private int nextIndex(int i, int max) {
+ final int index = i + 1;
+ return index < max ? index : index - 1;
+ }
+ /**
+ * Compute the previous index of an array, clipping if necessary.
+ * It is assumed (but not checked) that {@code i} is smaller than the size of the array.
+ *
+ * @param i Index
+ * @return the previous index
+ */
+ private int previousIndex(int i) {
+ final int index = i - 1;
+ return index >= 0 ? index : 0;
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/TrivariateRealGridInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/TrivariateRealGridInterpolator.java
new file mode 100644
index 0000000..c42d7aa
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/TrivariateRealGridInterpolator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.TrivariateRealFunction;
+
+/**
+ * Interface representing a trivariate real interpolating function where the
+ * sample points must be specified on a regular grid.
+ *
+ * @version $Revision$ $Date$
+ * @since 2.2
+ */
+public interface TrivariateRealGridInterpolator {
+ /**
+ * Computes an interpolating function for the data set.
+ *
+ * @param xval All the x-coordinates of the interpolation points, sorted
+ * in increasing order.
+ * @param yval All the y-coordinates of the interpolation points, sorted
+ * in increasing order.
+ * @param zval All the z-coordinates of the interpolation points, sorted
+ * in increasing order.
+ * @param fval the values of the interpolation points on all the grid knots:
+ * {@code fval[i][j][k] = f(xval[i], yval[j], zval[k])}.
+ * @return a function that interpolates the data set.
+ * @throws org.apache.commons.math.exception.NoDataException if any of the arrays has zero length.
+ * @throws org.apache.commons.math.exception.DimensionMismatchException if the array lengths are inconsistent.
+ * @throws MathException if arguments violate assumptions made by the
+ * interpolation algorithm.
+ */
+ TrivariateRealFunction interpolate(double[] xval, double[] yval, double[] zval, double[][][] fval)
+ throws MathException;
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/UnivariateRealInterpolator.java b/src/main/java/org/apache/commons/math/analysis/interpolation/UnivariateRealInterpolator.java
new file mode 100644
index 0000000..09f5487
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/UnivariateRealInterpolator.java
@@ -0,0 +1,39 @@
+/*
+ * 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.analysis.interpolation;
+
+import org.apache.commons.math.MathException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+
+/**
+ * Interface representing a univariate real interpolating function.
+ *
+ * @version $Revision: 821626 $ $Date: 2009-10-04 23:57:30 +0200 (dim. 04 oct. 2009) $
+ */
+public interface UnivariateRealInterpolator {
+
+ /**
+ * Computes an interpolating function for the data set.
+ * @param xval the arguments for the interpolation points
+ * @param yval the values for the interpolation points
+ * @return a function which interpolates the data set
+ * @throws MathException if arguments violate assumptions made by the
+ * interpolation algorithm
+ */
+ UnivariateRealFunction interpolate(double xval[], double yval[])
+ throws MathException;
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/interpolation/package.html b/src/main/java/org/apache/commons/math/analysis/interpolation/package.html
new file mode 100644
index 0000000..136c576
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/interpolation/package.html
@@ -0,0 +1,22 @@
+<html>
+<!--
+ 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.
+ -->
+ <!-- $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $ -->
+ <body>
+ Univariate real functions interpolation algorithms.
+ </body>
+</html>
diff --git a/src/main/java/org/apache/commons/math/analysis/package.html b/src/main/java/org/apache/commons/math/analysis/package.html
new file mode 100644
index 0000000..63b64a8
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/package.html
@@ -0,0 +1,33 @@
+<html>
+<!--
+ 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.
+ -->
+ <!-- $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $ -->
+ <body>
+ <p>
+ Parent package for common numerical analysis procedures, including root finding,
+ function interpolation and integration. Note that the optimization (i.e. minimization
+ and maximization) is a huge separate top package, despite it also operate on functions
+ as defined by this top-level package.
+ </p>
+ <p>
+ Functions interfaces are intended to be implemented by user code to represent their
+ domain problems. The algorithms provided by the library will then operate on these
+ function to find their roots, or integrate them, or ... Functions can be multivariate
+ or univariate, real vectorial or matrix valued, and they can be differentiable or not.
+ </p>
+ </body>
+</html>
diff --git a/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunction.java b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunction.java
new file mode 100644
index 0000000..ec528b4
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunction.java
@@ -0,0 +1,350 @@
+/*
+ * 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.analysis.polynomials;
+
+import java.io.Serializable;
+import java.util.Arrays;
+
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.exception.NoDataException;
+import org.apache.commons.math.analysis.DifferentiableUnivariateRealFunction;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Immutable representation of a real polynomial function with real coefficients.
+ * <p>
+ * <a href="http://mathworld.wolfram.com/HornersMethod.html">Horner's Method</a>
+ * is used to evaluate the function.</p>
+ *
+ * @version $Revision: 1042376 $ $Date: 2010-12-05 16:54:55 +0100 (dim. 05 déc. 2010) $
+ */
+public class PolynomialFunction implements DifferentiableUnivariateRealFunction, Serializable {
+
+ /**
+ * Serialization identifier
+ */
+ private static final long serialVersionUID = -7726511984200295583L;
+
+ /**
+ * The coefficients of the polynomial, ordered by degree -- i.e.,
+ * coefficients[0] is the constant term and coefficients[n] is the
+ * coefficient of x^n where n is the degree of the polynomial.
+ */
+ private final double coefficients[];
+
+ /**
+ * Construct a polynomial with the given coefficients. The first element
+ * of the coefficients array is the constant term. Higher degree
+ * coefficients follow in sequence. The degree of the resulting polynomial
+ * is the index of the last non-null element of the array, or 0 if all elements
+ * are null.
+ * <p>
+ * The constructor makes a copy of the input array and assigns the copy to
+ * the coefficients property.</p>
+ *
+ * @param c polynomial coefficients
+ * @throws NullPointerException if c is null
+ * @throws NoDataException if c is empty
+ */
+ public PolynomialFunction(double c[]) {
+ super();
+ int n = c.length;
+ if (n == 0) {
+ throw new NoDataException(LocalizedFormats.EMPTY_POLYNOMIALS_COEFFICIENTS_ARRAY);
+ }
+ while ((n > 1) && (c[n - 1] == 0)) {
+ --n;
+ }
+ this.coefficients = new double[n];
+ System.arraycopy(c, 0, this.coefficients, 0, n);
+ }
+
+ /**
+ * Compute the value of the function for the given argument.
+ * <p>
+ * The value returned is <br>
+ * <code>coefficients[n] * x^n + ... + coefficients[1] * x + coefficients[0]</code>
+ * </p>
+ *
+ * @param x the argument for which the function value should be computed
+ * @return the value of the polynomial at the given point
+ * @see UnivariateRealFunction#value(double)
+ */
+ public double value(double x) {
+ return evaluate(coefficients, x);
+ }
+
+
+ /**
+ * Returns the degree of the polynomial
+ *
+ * @return the degree of the polynomial
+ */
+ public int degree() {
+ return coefficients.length - 1;
+ }
+
+ /**
+ * Returns a copy of the coefficients array.
+ * <p>
+ * Changes made to the returned copy will not affect the coefficients of
+ * the polynomial.</p>
+ *
+ * @return a fresh copy of the coefficients array
+ */
+ public double[] getCoefficients() {
+ return coefficients.clone();
+ }
+
+ /**
+ * Uses Horner's Method to evaluate the polynomial with the given coefficients at
+ * the argument.
+ *
+ * @param coefficients the coefficients of the polynomial to evaluate
+ * @param argument the input value
+ * @return the value of the polynomial
+ * @throws NoDataException if coefficients is empty
+ * @throws NullPointerException if coefficients is null
+ */
+ protected static double evaluate(double[] coefficients, double argument) {
+ int n = coefficients.length;
+ if (n == 0) {
+ throw new NoDataException(LocalizedFormats.EMPTY_POLYNOMIALS_COEFFICIENTS_ARRAY);
+ }
+ double result = coefficients[n - 1];
+ for (int j = n -2; j >=0; j--) {
+ result = argument * result + coefficients[j];
+ }
+ return result;
+ }
+
+ /**
+ * Add a polynomial to the instance.
+ * @param p polynomial to add
+ * @return a new polynomial which is the sum of the instance and p
+ */
+ public PolynomialFunction add(final PolynomialFunction p) {
+
+ // identify the lowest degree polynomial
+ final int lowLength = FastMath.min(coefficients.length, p.coefficients.length);
+ final int highLength = FastMath.max(coefficients.length, p.coefficients.length);
+
+ // build the coefficients array
+ double[] newCoefficients = new double[highLength];
+ for (int i = 0; i < lowLength; ++i) {
+ newCoefficients[i] = coefficients[i] + p.coefficients[i];
+ }
+ System.arraycopy((coefficients.length < p.coefficients.length) ?
+ p.coefficients : coefficients,
+ lowLength,
+ newCoefficients, lowLength,
+ highLength - lowLength);
+
+ return new PolynomialFunction(newCoefficients);
+
+ }
+
+ /**
+ * Subtract a polynomial from the instance.
+ * @param p polynomial to subtract
+ * @return a new polynomial which is the difference the instance minus p
+ */
+ public PolynomialFunction subtract(final PolynomialFunction p) {
+
+ // identify the lowest degree polynomial
+ int lowLength = FastMath.min(coefficients.length, p.coefficients.length);
+ int highLength = FastMath.max(coefficients.length, p.coefficients.length);
+
+ // build the coefficients array
+ double[] newCoefficients = new double[highLength];
+ for (int i = 0; i < lowLength; ++i) {
+ newCoefficients[i] = coefficients[i] - p.coefficients[i];
+ }
+ if (coefficients.length < p.coefficients.length) {
+ for (int i = lowLength; i < highLength; ++i) {
+ newCoefficients[i] = -p.coefficients[i];
+ }
+ } else {
+ System.arraycopy(coefficients, lowLength, newCoefficients, lowLength,
+ highLength - lowLength);
+ }
+
+ return new PolynomialFunction(newCoefficients);
+
+ }
+
+ /**
+ * Negate the instance.
+ * @return a new polynomial
+ */
+ public PolynomialFunction negate() {
+ double[] newCoefficients = new double[coefficients.length];
+ for (int i = 0; i < coefficients.length; ++i) {
+ newCoefficients[i] = -coefficients[i];
+ }
+ return new PolynomialFunction(newCoefficients);
+ }
+
+ /**
+ * Multiply the instance by a polynomial.
+ * @param p polynomial to multiply by
+ * @return a new polynomial
+ */
+ public PolynomialFunction multiply(final PolynomialFunction p) {
+
+ double[] newCoefficients = new double[coefficients.length + p.coefficients.length - 1];
+
+ for (int i = 0; i < newCoefficients.length; ++i) {
+ newCoefficients[i] = 0.0;
+ for (int j = FastMath.max(0, i + 1 - p.coefficients.length);
+ j < FastMath.min(coefficients.length, i + 1);
+ ++j) {
+ newCoefficients[i] += coefficients[j] * p.coefficients[i-j];
+ }
+ }
+
+ return new PolynomialFunction(newCoefficients);
+
+ }
+
+ /**
+ * Returns the coefficients of the derivative of the polynomial with the given coefficients.
+ *
+ * @param coefficients the coefficients of the polynomial to differentiate
+ * @return the coefficients of the derivative or null if coefficients has length 1.
+ * @throws NoDataException if coefficients is empty
+ * @throws NullPointerException if coefficients is null
+ */
+ protected static double[] differentiate(double[] coefficients) {
+ int n = coefficients.length;
+ if (n == 0) {
+ throw new NoDataException(LocalizedFormats.EMPTY_POLYNOMIALS_COEFFICIENTS_ARRAY);
+ }
+ if (n == 1) {
+ return new double[]{0};
+ }
+ double[] result = new double[n - 1];
+ for (int i = n - 1; i > 0; i--) {
+ result[i - 1] = i * coefficients[i];
+ }
+ return result;
+ }
+
+ /**
+ * Returns the derivative as a PolynomialRealFunction
+ *
+ * @return the derivative polynomial
+ */
+ public PolynomialFunction polynomialDerivative() {
+ return new PolynomialFunction(differentiate(coefficients));
+ }
+
+ /**
+ * Returns the derivative as a UnivariateRealFunction
+ *
+ * @return the derivative function
+ */
+ public UnivariateRealFunction derivative() {
+ return polynomialDerivative();
+ }
+
+ /** Returns a string representation of the polynomial.
+
+ * <p>The representation is user oriented. Terms are displayed lowest
+ * degrees first. The multiplications signs, coefficients equals to
+ * one and null terms are not displayed (except if the polynomial is 0,
+ * in which case the 0 constant term is displayed). Addition of terms
+ * with negative coefficients are replaced by subtraction of terms
+ * with positive coefficients except for the first displayed term
+ * (i.e. we display <code>-3</code> for a constant negative polynomial,
+ * but <code>1 - 3 x + x^2</code> if the negative coefficient is not
+ * the first one displayed).</p>
+
+ * @return a string representation of the polynomial
+
+ */
+ @Override
+ public String toString() {
+
+ StringBuilder s = new StringBuilder();
+ if (coefficients[0] == 0.0) {
+ if (coefficients.length == 1) {
+ return "0";
+ }
+ } else {
+ s.append(Double.toString(coefficients[0]));
+ }
+
+ for (int i = 1; i < coefficients.length; ++i) {
+
+ if (coefficients[i] != 0) {
+
+ if (s.length() > 0) {
+ if (coefficients[i] < 0) {
+ s.append(" - ");
+ } else {
+ s.append(" + ");
+ }
+ } else {
+ if (coefficients[i] < 0) {
+ s.append("-");
+ }
+ }
+
+ double absAi = FastMath.abs(coefficients[i]);
+ if ((absAi - 1) != 0) {
+ s.append(Double.toString(absAi));
+ s.append(' ');
+ }
+
+ s.append("x");
+ if (i > 1) {
+ s.append('^');
+ s.append(Integer.toString(i));
+ }
+ }
+
+ }
+
+ return s.toString();
+
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(coefficients);
+ return result;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!(obj instanceof PolynomialFunction))
+ return false;
+ PolynomialFunction other = (PolynomialFunction) obj;
+ if (!Arrays.equals(coefficients, other.coefficients))
+ return false;
+ return true;
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunctionLagrangeForm.java b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunctionLagrangeForm.java
new file mode 100644
index 0000000..b40bf60
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunctionLagrangeForm.java
@@ -0,0 +1,305 @@
+/*
+ * 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.analysis.polynomials;
+
+import org.apache.commons.math.DuplicateSampleAbscissaException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the representation of a real polynomial function in
+ * <a href="http://mathworld.wolfram.com/LagrangeInterpolatingPolynomial.html">
+ * Lagrange Form</a>. For reference, see <b>Introduction to Numerical
+ * Analysis</b>, ISBN 038795452X, chapter 2.
+ * <p>
+ * The approximated function should be smooth enough for Lagrange polynomial
+ * to work well. Otherwise, consider using splines instead.</p>
+ *
+ * @version $Revision: 1073498 $ $Date: 2011-02-22 21:57:26 +0100 (mar. 22 févr. 2011) $
+ * @since 1.2
+ */
+public class PolynomialFunctionLagrangeForm implements UnivariateRealFunction {
+
+ /**
+ * The coefficients of the polynomial, ordered by degree -- i.e.
+ * coefficients[0] is the constant term and coefficients[n] is the
+ * coefficient of x^n where n is the degree of the polynomial.
+ */
+ private double coefficients[];
+
+ /**
+ * Interpolating points (abscissas).
+ */
+ private final double x[];
+
+ /**
+ * Function values at interpolating points.
+ */
+ private final double y[];
+
+ /**
+ * Whether the polynomial coefficients are available.
+ */
+ private boolean coefficientsComputed;
+
+ /**
+ * Construct a Lagrange polynomial with the given abscissas and function
+ * values. The order of interpolating points are not important.
+ * <p>
+ * The constructor makes copy of the input arrays and assigns them.</p>
+ *
+ * @param x interpolating points
+ * @param y function values at interpolating points
+ * @throws IllegalArgumentException if input arrays are not valid
+ */
+ public PolynomialFunctionLagrangeForm(double x[], double y[])
+ throws IllegalArgumentException {
+
+ verifyInterpolationArray(x, y);
+ this.x = new double[x.length];
+ this.y = new double[y.length];
+ System.arraycopy(x, 0, this.x, 0, x.length);
+ System.arraycopy(y, 0, this.y, 0, y.length);
+ coefficientsComputed = false;
+ }
+
+ /** {@inheritDoc} */
+ public double value(double z) throws FunctionEvaluationException {
+ try {
+ return evaluate(x, y, z);
+ } catch (DuplicateSampleAbscissaException e) {
+ throw new FunctionEvaluationException(z, e.getSpecificPattern(), e.getGeneralPattern(), e.getArguments());
+ }
+ }
+
+ /**
+ * Returns the degree of the polynomial.
+ *
+ * @return the degree of the polynomial
+ */
+ public int degree() {
+ return x.length - 1;
+ }
+
+ /**
+ * Returns a copy of the interpolating points array.
+ * <p>
+ * Changes made to the returned copy will not affect the polynomial.</p>
+ *
+ * @return a fresh copy of the interpolating points array
+ */
+ public double[] getInterpolatingPoints() {
+ double[] out = new double[x.length];
+ System.arraycopy(x, 0, out, 0, x.length);
+ return out;
+ }
+
+ /**
+ * Returns a copy of the interpolating values array.
+ * <p>
+ * Changes made to the returned copy will not affect the polynomial.</p>
+ *
+ * @return a fresh copy of the interpolating values array
+ */
+ public double[] getInterpolatingValues() {
+ double[] out = new double[y.length];
+ System.arraycopy(y, 0, out, 0, y.length);
+ return out;
+ }
+
+ /**
+ * Returns a copy of the coefficients array.
+ * <p>
+ * Changes made to the returned copy will not affect the polynomial.</p>
+ * <p>
+ * Note that coefficients computation can be ill-conditioned. Use with caution
+ * and only when it is necessary.</p>
+ *
+ * @return a fresh copy of the coefficients array
+ */
+ public double[] getCoefficients() {
+ if (!coefficientsComputed) {
+ computeCoefficients();
+ }
+ double[] out = new double[coefficients.length];
+ System.arraycopy(coefficients, 0, out, 0, coefficients.length);
+ return out;
+ }
+
+ /**
+ * Evaluate the Lagrange polynomial using
+ * <a href="http://mathworld.wolfram.com/NevillesAlgorithm.html">
+ * Neville's Algorithm</a>. It takes O(N^2) time.
+ * <p>
+ * This function is made public static so that users can call it directly
+ * without instantiating PolynomialFunctionLagrangeForm object.</p>
+ *
+ * @param x the interpolating points array
+ * @param y the interpolating values array
+ * @param z the point at which the function value is to be computed
+ * @return the function value
+ * @throws DuplicateSampleAbscissaException if the sample has duplicate abscissas
+ * @throws IllegalArgumentException if inputs are not valid
+ */
+ public static double evaluate(double x[], double y[], double z) throws
+ DuplicateSampleAbscissaException, IllegalArgumentException {
+
+ verifyInterpolationArray(x, y);
+
+ int nearest = 0;
+ final int n = x.length;
+ final double[] c = new double[n];
+ final double[] d = new double[n];
+ double min_dist = Double.POSITIVE_INFINITY;
+ for (int i = 0; i < n; i++) {
+ // initialize the difference arrays
+ c[i] = y[i];
+ d[i] = y[i];
+ // find out the abscissa closest to z
+ final double dist = FastMath.abs(z - x[i]);
+ if (dist < min_dist) {
+ nearest = i;
+ min_dist = dist;
+ }
+ }
+
+ // initial approximation to the function value at z
+ double value = y[nearest];
+
+ for (int i = 1; i < n; i++) {
+ for (int j = 0; j < n-i; j++) {
+ final double tc = x[j] - z;
+ final double td = x[i+j] - z;
+ final double divider = x[j] - x[i+j];
+ if (divider == 0.0) {
+ // This happens only when two abscissas are identical.
+ throw new DuplicateSampleAbscissaException(x[i], i, i+j);
+ }
+ // update the difference arrays
+ final double w = (c[j+1] - d[j]) / divider;
+ c[j] = tc * w;
+ d[j] = td * w;
+ }
+ // sum up the difference terms to get the final value
+ if (nearest < 0.5*(n-i+1)) {
+ value += c[nearest]; // fork down
+ } else {
+ nearest--;
+ value += d[nearest]; // fork up
+ }
+ }
+
+ return value;
+ }
+
+ /**
+ * Calculate the coefficients of Lagrange polynomial from the
+ * interpolation data. It takes O(N^2) time.
+ * <p>
+ * Note this computation can be ill-conditioned. Use with caution
+ * and only when it is necessary.</p>
+ *
+ * @throws ArithmeticException if any abscissas coincide
+ */
+ protected void computeCoefficients() throws ArithmeticException {
+
+ final int n = degree() + 1;
+ coefficients = new double[n];
+ for (int i = 0; i < n; i++) {
+ coefficients[i] = 0.0;
+ }
+
+ // c[] are the coefficients of P(x) = (x-x[0])(x-x[1])...(x-x[n-1])
+ final double[] c = new double[n+1];
+ c[0] = 1.0;
+ for (int i = 0; i < n; i++) {
+ for (int j = i; j > 0; j--) {
+ c[j] = c[j-1] - c[j] * x[i];
+ }
+ c[0] *= -x[i];
+ c[i+1] = 1;
+ }
+
+ final double[] tc = new double[n];
+ for (int i = 0; i < n; i++) {
+ // d = (x[i]-x[0])...(x[i]-x[i-1])(x[i]-x[i+1])...(x[i]-x[n-1])
+ double d = 1;
+ for (int j = 0; j < n; j++) {
+ if (i != j) {
+ d *= x[i] - x[j];
+ }
+ }
+ if (d == 0.0) {
+ // This happens only when two abscissas are identical.
+ for (int k = 0; k < n; ++k) {
+ if ((i != k) && (x[i] == x[k])) {
+ throw MathRuntimeException.createArithmeticException(
+ LocalizedFormats.IDENTICAL_ABSCISSAS_DIVISION_BY_ZERO,
+ i, k, x[i]);
+ }
+ }
+ }
+ final double t = y[i] / d;
+ // Lagrange polynomial is the sum of n terms, each of which is a
+ // polynomial of degree n-1. tc[] are the coefficients of the i-th
+ // numerator Pi(x) = (x-x[0])...(x-x[i-1])(x-x[i+1])...(x-x[n-1]).
+ tc[n-1] = c[n]; // actually c[n] = 1
+ coefficients[n-1] += t * tc[n-1];
+ for (int j = n-2; j >= 0; j--) {
+ tc[j] = c[j+1] + tc[j+1] * x[i];
+ coefficients[j] += t * tc[j];
+ }
+ }
+
+ coefficientsComputed = true;
+ }
+
+ /**
+ * Verifies that the interpolation arrays are valid.
+ * <p>
+ * The arrays features checked by this method are that both arrays have the
+ * same length and this length is at least 2.
+ * </p>
+ * <p>
+ * The interpolating points must be distinct. However it is not
+ * verified here, it is checked in evaluate() and computeCoefficients().
+ * </p>
+ *
+ * @param x the interpolating points array
+ * @param y the interpolating values array
+ * @throws IllegalArgumentException if not valid
+ * @see #evaluate(double[], double[], double)
+ * @see #computeCoefficients()
+ */
+ public static void verifyInterpolationArray(double x[], double y[])
+ throws IllegalArgumentException {
+
+ if (x.length != y.length) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, x.length, y.length);
+ }
+
+ if (x.length < 2) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.WRONG_NUMBER_OF_POINTS, 2, x.length);
+ }
+
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunctionNewtonForm.java b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunctionNewtonForm.java
new file mode 100644
index 0000000..5ee3224
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialFunctionNewtonForm.java
@@ -0,0 +1,221 @@
+/*
+ * 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.analysis.polynomials;
+
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+
+/**
+ * Implements the representation of a real polynomial function in
+ * Newton Form. For reference, see <b>Elementary Numerical Analysis</b>,
+ * ISBN 0070124477, chapter 2.
+ * <p>
+ * The formula of polynomial in Newton form is
+ * p(x) = a[0] + a[1](x-c[0]) + a[2](x-c[0])(x-c[1]) + ... +
+ * a[n](x-c[0])(x-c[1])...(x-c[n-1])
+ * Note that the length of a[] is one more than the length of c[]</p>
+ *
+ * @version $Revision: 1073498 $ $Date: 2011-02-22 21:57:26 +0100 (mar. 22 févr. 2011) $
+ * @since 1.2
+ */
+public class PolynomialFunctionNewtonForm implements UnivariateRealFunction {
+
+ /**
+ * The coefficients of the polynomial, ordered by degree -- i.e.
+ * coefficients[0] is the constant term and coefficients[n] is the
+ * coefficient of x^n where n is the degree of the polynomial.
+ */
+ private double coefficients[];
+
+ /**
+ * Centers of the Newton polynomial.
+ */
+ private final double c[];
+
+ /**
+ * When all c[i] = 0, a[] becomes normal polynomial coefficients,
+ * i.e. a[i] = coefficients[i].
+ */
+ private final double a[];
+
+ /**
+ * Whether the polynomial coefficients are available.
+ */
+ private boolean coefficientsComputed;
+
+ /**
+ * Construct a Newton polynomial with the given a[] and c[]. The order of
+ * centers are important in that if c[] shuffle, then values of a[] would
+ * completely change, not just a permutation of old a[].
+ * <p>
+ * The constructor makes copy of the input arrays and assigns them.</p>
+ *
+ * @param a the coefficients in Newton form formula
+ * @param c the centers
+ * @throws IllegalArgumentException if input arrays are not valid
+ */
+ public PolynomialFunctionNewtonForm(double a[], double c[])
+ throws IllegalArgumentException {
+
+ verifyInputArray(a, c);
+ this.a = new double[a.length];
+ this.c = new double[c.length];
+ System.arraycopy(a, 0, this.a, 0, a.length);
+ System.arraycopy(c, 0, this.c, 0, c.length);
+ coefficientsComputed = false;
+ }
+
+ /**
+ * Calculate the function value at the given point.
+ *
+ * @param z the point at which the function value is to be computed
+ * @return the function value
+ * @throws FunctionEvaluationException if a runtime error occurs
+ * @see UnivariateRealFunction#value(double)
+ */
+ public double value(double z) throws FunctionEvaluationException {
+ return evaluate(a, c, z);
+ }
+
+ /**
+ * Returns the degree of the polynomial.
+ *
+ * @return the degree of the polynomial
+ */
+ public int degree() {
+ return c.length;
+ }
+
+ /**
+ * Returns a copy of coefficients in Newton form formula.
+ * <p>
+ * Changes made to the returned copy will not affect the polynomial.</p>
+ *
+ * @return a fresh copy of coefficients in Newton form formula
+ */
+ public double[] getNewtonCoefficients() {
+ double[] out = new double[a.length];
+ System.arraycopy(a, 0, out, 0, a.length);
+ return out;
+ }
+
+ /**
+ * Returns a copy of the centers array.
+ * <p>
+ * Changes made to the returned copy will not affect the polynomial.</p>
+ *
+ * @return a fresh copy of the centers array
+ */
+ public double[] getCenters() {
+ double[] out = new double[c.length];
+ System.arraycopy(c, 0, out, 0, c.length);
+ return out;
+ }
+
+ /**
+ * Returns a copy of the coefficients array.
+ * <p>
+ * Changes made to the returned copy will not affect the polynomial.</p>
+ *
+ * @return a fresh copy of the coefficients array
+ */
+ public double[] getCoefficients() {
+ if (!coefficientsComputed) {
+ computeCoefficients();
+ }
+ double[] out = new double[coefficients.length];
+ System.arraycopy(coefficients, 0, out, 0, coefficients.length);
+ return out;
+ }
+
+ /**
+ * Evaluate the Newton polynomial using nested multiplication. It is
+ * also called <a href="http://mathworld.wolfram.com/HornersRule.html">
+ * Horner's Rule</a> and takes O(N) time.
+ *
+ * @param a the coefficients in Newton form formula
+ * @param c the centers
+ * @param z the point at which the function value is to be computed
+ * @return the function value
+ * @throws FunctionEvaluationException if a runtime error occurs
+ * @throws IllegalArgumentException if inputs are not valid
+ */
+ public static double evaluate(double a[], double c[], double z)
+ throws FunctionEvaluationException, IllegalArgumentException {
+
+ verifyInputArray(a, c);
+
+ int n = c.length;
+ double value = a[n];
+ for (int i = n-1; i >= 0; i--) {
+ value = a[i] + (z - c[i]) * value;
+ }
+
+ return value;
+ }
+
+ /**
+ * Calculate the normal polynomial coefficients given the Newton form.
+ * It also uses nested multiplication but takes O(N^2) time.
+ */
+ protected void computeCoefficients() {
+ final int n = degree();
+
+ coefficients = new double[n+1];
+ for (int i = 0; i <= n; i++) {
+ coefficients[i] = 0.0;
+ }
+
+ coefficients[0] = a[n];
+ for (int i = n-1; i >= 0; i--) {
+ for (int j = n-i; j > 0; j--) {
+ coefficients[j] = coefficients[j-1] - c[i] * coefficients[j];
+ }
+ coefficients[0] = a[i] - c[i] * coefficients[0];
+ }
+
+ coefficientsComputed = true;
+ }
+
+ /**
+ * Verifies that the input arrays are valid.
+ * <p>
+ * The centers must be distinct for interpolation purposes, but not
+ * for general use. Thus it is not verified here.</p>
+ *
+ * @param a the coefficients in Newton form formula
+ * @param c the centers
+ * @throws IllegalArgumentException if not valid
+ * @see org.apache.commons.math.analysis.interpolation.DividedDifferenceInterpolator#computeDividedDifference(double[],
+ * double[])
+ */
+ protected static void verifyInputArray(double a[], double c[]) throws
+ IllegalArgumentException {
+
+ if (a.length < 1 || c.length < 1) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.EMPTY_POLYNOMIALS_COEFFICIENTS_ARRAY);
+ }
+ if (a.length != c.length + 1) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.ARRAY_SIZES_SHOULD_HAVE_DIFFERENCE_1,
+ a.length, c.length);
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialSplineFunction.java b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialSplineFunction.java
new file mode 100644
index 0000000..a0e1e01
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialSplineFunction.java
@@ -0,0 +1,224 @@
+/*
+ * 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.analysis.polynomials;
+
+import java.util.Arrays;
+
+import org.apache.commons.math.ArgumentOutsideDomainException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.analysis.DifferentiableUnivariateRealFunction;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+
+/**
+ * Represents a polynomial spline function.
+ * <p>
+ * A <strong>polynomial spline function</strong> consists of a set of
+ * <i>interpolating polynomials</i> and an ascending array of domain
+ * <i>knot points</i>, determining the intervals over which the spline function
+ * is defined by the constituent polynomials. The polynomials are assumed to
+ * have been computed to match the values of another function at the knot
+ * points. The value consistency constraints are not currently enforced by
+ * <code>PolynomialSplineFunction</code> itself, but are assumed to hold among
+ * the polynomials and knot points passed to the constructor.</p>
+ * <p>
+ * N.B.: The polynomials in the <code>polynomials</code> property must be
+ * centered on the knot points to compute the spline function values.
+ * See below.</p>
+ * <p>
+ * The domain of the polynomial spline function is
+ * <code>[smallest knot, largest knot]</code>. Attempts to evaluate the
+ * function at values outside of this range generate IllegalArgumentExceptions.
+ * </p>
+ * <p>
+ * The value of the polynomial spline function for an argument <code>x</code>
+ * is computed as follows:
+ * <ol>
+ * <li>The knot array is searched to find the segment to which <code>x</code>
+ * belongs. If <code>x</code> is less than the smallest knot point or greater
+ * than the largest one, an <code>IllegalArgumentException</code>
+ * is thrown.</li>
+ * <li> Let <code>j</code> be the index of the largest knot point that is less
+ * than or equal to <code>x</code>. The value returned is <br>
+ * <code>polynomials[j](x - knot[j])</code></li></ol></p>
+ *
+ * @version $Revision: 1037327 $ $Date: 2010-11-20 21:57:37 +0100 (sam. 20 nov. 2010) $
+ */
+public class PolynomialSplineFunction
+ implements DifferentiableUnivariateRealFunction {
+
+ /** Spline segment interval delimiters (knots). Size is n+1 for n segments. */
+ private final double knots[];
+
+ /**
+ * The polynomial functions that make up the spline. The first element
+ * determines the value of the spline over the first subinterval, the
+ * second over the second, etc. Spline function values are determined by
+ * evaluating these functions at <code>(x - knot[i])</code> where i is the
+ * knot segment to which x belongs.
+ */
+ private final PolynomialFunction polynomials[];
+
+ /**
+ * Number of spline segments = number of polynomials
+ * = number of partition points - 1
+ */
+ private final int n;
+
+
+ /**
+ * Construct a polynomial spline function with the given segment delimiters
+ * and interpolating polynomials.
+ * <p>
+ * The constructor copies both arrays and assigns the copies to the knots
+ * and polynomials properties, respectively.</p>
+ *
+ * @param knots spline segment interval delimiters
+ * @param polynomials polynomial functions that make up the spline
+ * @throws NullPointerException if either of the input arrays is null
+ * @throws IllegalArgumentException if knots has length less than 2,
+ * <code>polynomials.length != knots.length - 1 </code>, or the knots array
+ * is not strictly increasing.
+ *
+ */
+ public PolynomialSplineFunction(double knots[], PolynomialFunction polynomials[]) {
+ if (knots.length < 2) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.NOT_ENOUGH_POINTS_IN_SPLINE_PARTITION,
+ 2, knots.length);
+ }
+ if (knots.length - 1 != polynomials.length) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.POLYNOMIAL_INTERPOLANTS_MISMATCH_SEGMENTS,
+ polynomials.length, knots.length);
+ }
+ if (!isStrictlyIncreasing(knots)) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.NOT_STRICTLY_INCREASING_KNOT_VALUES);
+ }
+
+ this.n = knots.length -1;
+ this.knots = new double[n + 1];
+ System.arraycopy(knots, 0, this.knots, 0, n + 1);
+ this.polynomials = new PolynomialFunction[n];
+ System.arraycopy(polynomials, 0, this.polynomials, 0, n);
+ }
+
+ /**
+ * Compute the value for the function.
+ * See {@link PolynomialSplineFunction} for details on the algorithm for
+ * computing the value of the function.</p>
+ *
+ * @param v the point for which the function value should be computed
+ * @return the value
+ * @throws ArgumentOutsideDomainException if v is outside of the domain of
+ * of the spline function (less than the smallest knot point or greater
+ * than the largest knot point)
+ */
+ public double value(double v) throws ArgumentOutsideDomainException {
+ if (v < knots[0] || v > knots[n]) {
+ throw new ArgumentOutsideDomainException(v, knots[0], knots[n]);
+ }
+ int i = Arrays.binarySearch(knots, v);
+ if (i < 0) {
+ i = -i - 2;
+ }
+ //This will handle the case where v is the last knot value
+ //There are only n-1 polynomials, so if v is the last knot
+ //then we will use the last polynomial to calculate the value.
+ if ( i >= polynomials.length ) {
+ i--;
+ }
+ return polynomials[i].value(v - knots[i]);
+ }
+
+ /**
+ * Returns the derivative of the polynomial spline function as a UnivariateRealFunction
+ * @return the derivative function
+ */
+ public UnivariateRealFunction derivative() {
+ return polynomialSplineDerivative();
+ }
+
+ /**
+ * Returns the derivative of the polynomial spline function as a PolynomialSplineFunction
+ *
+ * @return the derivative function
+ */
+ public PolynomialSplineFunction polynomialSplineDerivative() {
+ PolynomialFunction derivativePolynomials[] = new PolynomialFunction[n];
+ for (int i = 0; i < n; i++) {
+ derivativePolynomials[i] = polynomials[i].polynomialDerivative();
+ }
+ return new PolynomialSplineFunction(knots, derivativePolynomials);
+ }
+
+ /**
+ * Returns the number of spline segments = the number of polynomials
+ * = the number of knot points - 1.
+ *
+ * @return the number of spline segments
+ */
+ public int getN() {
+ return n;
+ }
+
+ /**
+ * Returns a copy of the interpolating polynomials array.
+ * <p>
+ * Returns a fresh copy of the array. Changes made to the copy will
+ * not affect the polynomials property.</p>
+ *
+ * @return the interpolating polynomials
+ */
+ public PolynomialFunction[] getPolynomials() {
+ PolynomialFunction p[] = new PolynomialFunction[n];
+ System.arraycopy(polynomials, 0, p, 0, n);
+ return p;
+ }
+
+ /**
+ * Returns an array copy of the knot points.
+ * <p>
+ * Returns a fresh copy of the array. Changes made to the copy
+ * will not affect the knots property.</p>
+ *
+ * @return the knot points
+ */
+ public double[] getKnots() {
+ double out[] = new double[n + 1];
+ System.arraycopy(knots, 0, out, 0, n + 1);
+ return out;
+ }
+
+ /**
+ * Determines if the given array is ordered in a strictly increasing
+ * fashion.
+ *
+ * @param x the array to examine.
+ * @return <code>true</code> if the elements in <code>x</code> are ordered
+ * in a stricly increasing manner. <code>false</code>, otherwise.
+ */
+ private static boolean isStrictlyIncreasing(double[] x) {
+ for (int i = 1; i < x.length; ++i) {
+ if (x[i - 1] >= x[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialsUtils.java b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialsUtils.java
new file mode 100644
index 0000000..5e939c7
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/polynomials/PolynomialsUtils.java
@@ -0,0 +1,281 @@
+/*
+ * 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.analysis.polynomials;
+
+import java.util.ArrayList;
+
+import org.apache.commons.math.fraction.BigFraction;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * A collection of static methods that operate on or return polynomials.
+ *
+ * @version $Revision: 990655 $ $Date: 2010-08-29 23:49:40 +0200 (dim. 29 août 2010) $
+ * @since 2.0
+ */
+public class PolynomialsUtils {
+
+ /** Coefficients for Chebyshev polynomials. */
+ private static final ArrayList<BigFraction> CHEBYSHEV_COEFFICIENTS;
+
+ /** Coefficients for Hermite polynomials. */
+ private static final ArrayList<BigFraction> HERMITE_COEFFICIENTS;
+
+ /** Coefficients for Laguerre polynomials. */
+ private static final ArrayList<BigFraction> LAGUERRE_COEFFICIENTS;
+
+ /** Coefficients for Legendre polynomials. */
+ private static final ArrayList<BigFraction> LEGENDRE_COEFFICIENTS;
+
+ static {
+
+ // initialize recurrence for Chebyshev polynomials
+ // T0(X) = 1, T1(X) = 0 + 1 * X
+ CHEBYSHEV_COEFFICIENTS = new ArrayList<BigFraction>();
+ CHEBYSHEV_COEFFICIENTS.add(BigFraction.ONE);
+ CHEBYSHEV_COEFFICIENTS.add(BigFraction.ZERO);
+ CHEBYSHEV_COEFFICIENTS.add(BigFraction.ONE);
+
+ // initialize recurrence for Hermite polynomials
+ // H0(X) = 1, H1(X) = 0 + 2 * X
+ HERMITE_COEFFICIENTS = new ArrayList<BigFraction>();
+ HERMITE_COEFFICIENTS.add(BigFraction.ONE);
+ HERMITE_COEFFICIENTS.add(BigFraction.ZERO);
+ HERMITE_COEFFICIENTS.add(BigFraction.TWO);
+
+ // initialize recurrence for Laguerre polynomials
+ // L0(X) = 1, L1(X) = 1 - 1 * X
+ LAGUERRE_COEFFICIENTS = new ArrayList<BigFraction>();
+ LAGUERRE_COEFFICIENTS.add(BigFraction.ONE);
+ LAGUERRE_COEFFICIENTS.add(BigFraction.ONE);
+ LAGUERRE_COEFFICIENTS.add(BigFraction.MINUS_ONE);
+
+ // initialize recurrence for Legendre polynomials
+ // P0(X) = 1, P1(X) = 0 + 1 * X
+ LEGENDRE_COEFFICIENTS = new ArrayList<BigFraction>();
+ LEGENDRE_COEFFICIENTS.add(BigFraction.ONE);
+ LEGENDRE_COEFFICIENTS.add(BigFraction.ZERO);
+ LEGENDRE_COEFFICIENTS.add(BigFraction.ONE);
+
+ }
+
+ /**
+ * Private constructor, to prevent instantiation.
+ */
+ private PolynomialsUtils() {
+ }
+
+ /**
+ * Create a Chebyshev polynomial of the first kind.
+ * <p><a href="http://mathworld.wolfram.com/ChebyshevPolynomialoftheFirstKind.html">Chebyshev
+ * polynomials of the first kind</a> are orthogonal polynomials.
+ * They can be defined by the following recurrence relations:
+ * <pre>
+ * T<sub>0</sub>(X) = 1
+ * T<sub>1</sub>(X) = X
+ * T<sub>k+1</sub>(X) = 2X T<sub>k</sub>(X) - T<sub>k-1</sub>(X)
+ * </pre></p>
+ * @param degree degree of the polynomial
+ * @return Chebyshev polynomial of specified degree
+ */
+ public static PolynomialFunction createChebyshevPolynomial(final int degree) {
+ return buildPolynomial(degree, CHEBYSHEV_COEFFICIENTS,
+ new RecurrenceCoefficientsGenerator() {
+ private final BigFraction[] coeffs = { BigFraction.ZERO, BigFraction.TWO, BigFraction.ONE };
+ /** {@inheritDoc} */
+ public BigFraction[] generate(int k) {
+ return coeffs;
+ }
+ });
+ }
+
+ /**
+ * Create a Hermite polynomial.
+ * <p><a href="http://mathworld.wolfram.com/HermitePolynomial.html">Hermite
+ * polynomials</a> are orthogonal polynomials.
+ * They can be defined by the following recurrence relations:
+ * <pre>
+ * H<sub>0</sub>(X) = 1
+ * H<sub>1</sub>(X) = 2X
+ * H<sub>k+1</sub>(X) = 2X H<sub>k</sub>(X) - 2k H<sub>k-1</sub>(X)
+ * </pre></p>
+
+ * @param degree degree of the polynomial
+ * @return Hermite polynomial of specified degree
+ */
+ public static PolynomialFunction createHermitePolynomial(final int degree) {
+ return buildPolynomial(degree, HERMITE_COEFFICIENTS,
+ new RecurrenceCoefficientsGenerator() {
+ /** {@inheritDoc} */
+ public BigFraction[] generate(int k) {
+ return new BigFraction[] {
+ BigFraction.ZERO,
+ BigFraction.TWO,
+ new BigFraction(2 * k)};
+ }
+ });
+ }
+
+ /**
+ * Create a Laguerre polynomial.
+ * <p><a href="http://mathworld.wolfram.com/LaguerrePolynomial.html">Laguerre
+ * polynomials</a> are orthogonal polynomials.
+ * They can be defined by the following recurrence relations:
+ * <pre>
+ * L<sub>0</sub>(X) = 1
+ * L<sub>1</sub>(X) = 1 - X
+ * (k+1) L<sub>k+1</sub>(X) = (2k + 1 - X) L<sub>k</sub>(X) - k L<sub>k-1</sub>(X)
+ * </pre></p>
+ * @param degree degree of the polynomial
+ * @return Laguerre polynomial of specified degree
+ */
+ public static PolynomialFunction createLaguerrePolynomial(final int degree) {
+ return buildPolynomial(degree, LAGUERRE_COEFFICIENTS,
+ new RecurrenceCoefficientsGenerator() {
+ /** {@inheritDoc} */
+ public BigFraction[] generate(int k) {
+ final int kP1 = k + 1;
+ return new BigFraction[] {
+ new BigFraction(2 * k + 1, kP1),
+ new BigFraction(-1, kP1),
+ new BigFraction(k, kP1)};
+ }
+ });
+ }
+
+ /**
+ * Create a Legendre polynomial.
+ * <p><a href="http://mathworld.wolfram.com/LegendrePolynomial.html">Legendre
+ * polynomials</a> are orthogonal polynomials.
+ * They can be defined by the following recurrence relations:
+ * <pre>
+ * P<sub>0</sub>(X) = 1
+ * P<sub>1</sub>(X) = X
+ * (k+1) P<sub>k+1</sub>(X) = (2k+1) X P<sub>k</sub>(X) - k P<sub>k-1</sub>(X)
+ * </pre></p>
+ * @param degree degree of the polynomial
+ * @return Legendre polynomial of specified degree
+ */
+ public static PolynomialFunction createLegendrePolynomial(final int degree) {
+ return buildPolynomial(degree, LEGENDRE_COEFFICIENTS,
+ new RecurrenceCoefficientsGenerator() {
+ /** {@inheritDoc} */
+ public BigFraction[] generate(int k) {
+ final int kP1 = k + 1;
+ return new BigFraction[] {
+ BigFraction.ZERO,
+ new BigFraction(k + kP1, kP1),
+ new BigFraction(k, kP1)};
+ }
+ });
+ }
+
+ /** Get the coefficients array for a given degree.
+ * @param degree degree of the polynomial
+ * @param coefficients list where the computed coefficients are stored
+ * @param generator recurrence coefficients generator
+ * @return coefficients array
+ */
+ private static PolynomialFunction buildPolynomial(final int degree,
+ final ArrayList<BigFraction> coefficients,
+ final RecurrenceCoefficientsGenerator generator) {
+
+ final int maxDegree = (int) FastMath.floor(FastMath.sqrt(2 * coefficients.size())) - 1;
+ synchronized (PolynomialsUtils.class) {
+ if (degree > maxDegree) {
+ computeUpToDegree(degree, maxDegree, generator, coefficients);
+ }
+ }
+
+ // coefficient for polynomial 0 is l [0]
+ // coefficients for polynomial 1 are l [1] ... l [2] (degrees 0 ... 1)
+ // coefficients for polynomial 2 are l [3] ... l [5] (degrees 0 ... 2)
+ // coefficients for polynomial 3 are l [6] ... l [9] (degrees 0 ... 3)
+ // coefficients for polynomial 4 are l[10] ... l[14] (degrees 0 ... 4)
+ // coefficients for polynomial 5 are l[15] ... l[20] (degrees 0 ... 5)
+ // coefficients for polynomial 6 are l[21] ... l[27] (degrees 0 ... 6)
+ // ...
+ final int start = degree * (degree + 1) / 2;
+
+ final double[] a = new double[degree + 1];
+ for (int i = 0; i <= degree; ++i) {
+ a[i] = coefficients.get(start + i).doubleValue();
+ }
+
+ // build the polynomial
+ return new PolynomialFunction(a);
+
+ }
+
+ /** Compute polynomial coefficients up to a given degree.
+ * @param degree maximal degree
+ * @param maxDegree current maximal degree
+ * @param generator recurrence coefficients generator
+ * @param coefficients list where the computed coefficients should be appended
+ */
+ private static void computeUpToDegree(final int degree, final int maxDegree,
+ final RecurrenceCoefficientsGenerator generator,
+ final ArrayList<BigFraction> coefficients) {
+
+ int startK = (maxDegree - 1) * maxDegree / 2;
+ for (int k = maxDegree; k < degree; ++k) {
+
+ // start indices of two previous polynomials Pk(X) and Pk-1(X)
+ int startKm1 = startK;
+ startK += k;
+
+ // Pk+1(X) = (a[0] + a[1] X) Pk(X) - a[2] Pk-1(X)
+ BigFraction[] ai = generator.generate(k);
+
+ BigFraction ck = coefficients.get(startK);
+ BigFraction ckm1 = coefficients.get(startKm1);
+
+ // degree 0 coefficient
+ coefficients.add(ck.multiply(ai[0]).subtract(ckm1.multiply(ai[2])));
+
+ // degree 1 to degree k-1 coefficients
+ for (int i = 1; i < k; ++i) {
+ final BigFraction ckPrev = ck;
+ ck = coefficients.get(startK + i);
+ ckm1 = coefficients.get(startKm1 + i);
+ coefficients.add(ck.multiply(ai[0]).add(ckPrev.multiply(ai[1])).subtract(ckm1.multiply(ai[2])));
+ }
+
+ // degree k coefficient
+ final BigFraction ckPrev = ck;
+ ck = coefficients.get(startK + k);
+ coefficients.add(ck.multiply(ai[0]).add(ckPrev.multiply(ai[1])));
+
+ // degree k+1 coefficient
+ coefficients.add(ck.multiply(ai[1]));
+
+ }
+
+ }
+
+ /** Interface for recurrence coefficients generation. */
+ private static interface RecurrenceCoefficientsGenerator {
+ /**
+ * Generate recurrence coefficients.
+ * @param k highest degree of the polynomials used in the recurrence
+ * @return an array of three coefficients such that
+ * P<sub>k+1</sub>(X) = (a[0] + a[1] X) P<sub>k</sub>(X) - a[2] P<sub>k-1</sub>(X)
+ */
+ BigFraction[] generate(int k);
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/polynomials/package.html b/src/main/java/org/apache/commons/math/analysis/polynomials/package.html
new file mode 100644
index 0000000..63ca96a
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/polynomials/package.html
@@ -0,0 +1,23 @@
+<html>
+<!--
+ 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.
+ -->
+ <!-- $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $ -->
+ <body>
+ Univariate real polynomials implementations, seen as differentiable
+ univariate real functions.
+ </body>
+</html>
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/BisectionSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/BisectionSolver.java
new file mode 100644
index 0000000..c9d3a63
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/BisectionSolver.java
@@ -0,0 +1,133 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/Bisection.html">
+ * bisection algorithm</a> for finding zeros of univariate real functions.
+ * <p>
+ * The function should be continuous but not necessarily smooth.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ */
+public class BisectionSolver extends UnivariateRealSolverImpl {
+
+ /**
+ * Construct a solver for the given function.
+ *
+ * @param f function to solve.
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method.
+ */
+ @Deprecated
+ public BisectionSolver(UnivariateRealFunction f) {
+ super(f, 100, 1E-6);
+ }
+
+ /**
+ * Construct a solver.
+ *
+ */
+ public BisectionSolver() {
+ super(100, 1E-6);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(double min, double max, double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(double min, double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f, double min, double max, double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f, double min, double max, double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(maxEval, f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f, double min, double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max);
+ }
+
+ /**
+ * {@inheritDoc}
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f, double min, double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ clearResult();
+ verifyInterval(min,max);
+ double m;
+ double fm;
+ double fmin;
+
+ int i = 0;
+ while (i < maximalIterationCount) {
+ m = UnivariateRealSolverUtils.midpoint(min, max);
+ fmin = f.value(min);
+ fm = f.value(m);
+
+ if (fm * fmin > 0.0) {
+ // max and m bracket the root.
+ min = m;
+ } else {
+ // min and m bracket the root.
+ max = m;
+ }
+
+ if (FastMath.abs(max - min) <= absoluteAccuracy) {
+ m = UnivariateRealSolverUtils.midpoint(min, max);
+ setResult(m, i);
+ return m;
+ }
+ ++i;
+ }
+
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/BrentSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/BrentSolver.java
new file mode 100644
index 0000000..5aa2447
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/BrentSolver.java
@@ -0,0 +1,399 @@
+/*
+ * 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.analysis.solvers;
+
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/BrentsMethod.html">
+ * Brent algorithm</a> for finding zeros of real univariate functions.
+ * <p>
+ * The function should be continuous but not necessarily smooth.</p>
+ *
+ * @version $Revision:670469 $ $Date:2008-06-23 10:01:38 +0200 (lun., 23 juin 2008) $
+ */
+public class BrentSolver extends UnivariateRealSolverImpl {
+
+ /**
+ * Default absolute accuracy
+ * @since 2.1
+ */
+ public static final double DEFAULT_ABSOLUTE_ACCURACY = 1E-6;
+
+ /** Default maximum number of iterations
+ * @since 2.1
+ */
+ public static final int DEFAULT_MAXIMUM_ITERATIONS = 100;
+
+ /** Serializable version identifier */
+ private static final long serialVersionUID = 7694577816772532779L;
+
+ /**
+ * Construct a solver for the given function.
+ *
+ * @param f function to solve.
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method.
+ */
+ @Deprecated
+ public BrentSolver(UnivariateRealFunction f) {
+ super(f, DEFAULT_MAXIMUM_ITERATIONS, DEFAULT_ABSOLUTE_ACCURACY);
+ }
+
+ /**
+ * Construct a solver with default properties.
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public BrentSolver() {
+ super(DEFAULT_MAXIMUM_ITERATIONS, DEFAULT_ABSOLUTE_ACCURACY);
+ }
+
+ /**
+ * Construct a solver with the given absolute accuracy.
+ *
+ * @param absoluteAccuracy lower bound for absolute accuracy of solutions returned by the solver
+ * @since 2.1
+ */
+ public BrentSolver(double absoluteAccuracy) {
+ super(DEFAULT_MAXIMUM_ITERATIONS, absoluteAccuracy);
+ }
+
+ /**
+ * Contstruct a solver with the given maximum iterations and absolute accuracy.
+ *
+ * @param maximumIterations maximum number of iterations
+ * @param absoluteAccuracy lower bound for absolute accuracy of solutions returned by the solver
+ * @since 2.1
+ */
+ public BrentSolver(int maximumIterations, double absoluteAccuracy) {
+ super(maximumIterations, absoluteAccuracy);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(double min, double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(double min, double max, double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a zero in the given interval with an initial guess.
+ * <p>Throws <code>IllegalArgumentException</code> if the values of the
+ * function at the three points have the same sign (note that it is
+ * allowed to have endpoints with the same sign if the initial point has
+ * opposite sign function-wise).</p>
+ *
+ * @param f function to solve.
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @param initial the start value to use (must be set to min if no
+ * initial point is known).
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if initial is not between min and max
+ * (even if it <em>is</em> a root)
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ clearResult();
+ if ((initial < min) || (initial > max)) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.INVALID_INTERVAL_INITIAL_VALUE_PARAMETERS,
+ min, initial, max);
+ }
+
+ // return the initial guess if it is good enough
+ double yInitial = f.value(initial);
+ if (FastMath.abs(yInitial) <= functionValueAccuracy) {
+ setResult(initial, 0);
+ return result;
+ }
+
+ // return the first endpoint if it is good enough
+ double yMin = f.value(min);
+ if (FastMath.abs(yMin) <= functionValueAccuracy) {
+ setResult(min, 0);
+ return result;
+ }
+
+ // reduce interval if min and initial bracket the root
+ if (yInitial * yMin < 0) {
+ return solve(f, min, yMin, initial, yInitial, min, yMin);
+ }
+
+ // return the second endpoint if it is good enough
+ double yMax = f.value(max);
+ if (FastMath.abs(yMax) <= functionValueAccuracy) {
+ setResult(max, 0);
+ return result;
+ }
+
+ // reduce interval if initial and max bracket the root
+ if (yInitial * yMax < 0) {
+ return solve(f, initial, yInitial, max, yMax, initial, yInitial);
+ }
+
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.SAME_SIGN_AT_ENDPOINTS, min, max, yMin, yMax);
+
+ }
+
+ /**
+ * Find a zero in the given interval with an initial guess.
+ * <p>Throws <code>IllegalArgumentException</code> if the values of the
+ * function at the three points have the same sign (note that it is
+ * allowed to have endpoints with the same sign if the initial point has
+ * opposite sign function-wise).</p>
+ *
+ * @param f function to solve.
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @param initial the start value to use (must be set to min if no
+ * initial point is known).
+ * @param maxEval Maximum number of evaluations.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if initial is not between min and max
+ * (even if it <em>is</em> a root)
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a zero in the given interval.
+ * <p>
+ * Requires that the values of the function at the endpoints have opposite
+ * signs. An <code>IllegalArgumentException</code> is thrown if this is not
+ * the case.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min is not less than max or the
+ * signs of the values of the function at the endpoints are not opposites
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ clearResult();
+ verifyInterval(min, max);
+
+ double ret = Double.NaN;
+
+ double yMin = f.value(min);
+ double yMax = f.value(max);
+
+ // Verify bracketing
+ double sign = yMin * yMax;
+ if (sign > 0) {
+ // check if either value is close to a zero
+ if (FastMath.abs(yMin) <= functionValueAccuracy) {
+ setResult(min, 0);
+ ret = min;
+ } else if (FastMath.abs(yMax) <= functionValueAccuracy) {
+ setResult(max, 0);
+ ret = max;
+ } else {
+ // neither value is close to zero and min and max do not bracket root.
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.SAME_SIGN_AT_ENDPOINTS, min, max, yMin, yMax);
+ }
+ } else if (sign < 0){
+ // solve using only the first endpoint as initial guess
+ ret = solve(f, min, yMin, max, yMax, min, yMin);
+ } else {
+ // either min or max is a root
+ if (yMin == 0.0) {
+ ret = min;
+ } else {
+ ret = max;
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * Find a zero in the given interval.
+ * <p>
+ * Requires that the values of the function at the endpoints have opposite
+ * signs. An <code>IllegalArgumentException</code> is thrown if this is not
+ * the case.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @param maxEval Maximum number of evaluations.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min is not less than max or the
+ * signs of the values of the function at the endpoints are not opposites
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max);
+ }
+
+ /**
+ * Find a zero starting search according to the three provided points.
+ * @param f the function to solve
+ * @param x0 old approximation for the root
+ * @param y0 function value at the approximation for the root
+ * @param x1 last calculated approximation for the root
+ * @param y1 function value at the last calculated approximation
+ * for the root
+ * @param x2 bracket point (must be set to x0 if no bracket point is
+ * known, this will force starting with linear interpolation)
+ * @param y2 function value at the bracket point.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ */
+ private double solve(final UnivariateRealFunction f,
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ double delta = x1 - x0;
+ double oldDelta = delta;
+
+ int i = 0;
+ while (i < maximalIterationCount) {
+ if (FastMath.abs(y2) < FastMath.abs(y1)) {
+ // use the bracket point if is better than last approximation
+ x0 = x1;
+ x1 = x2;
+ x2 = x0;
+ y0 = y1;
+ y1 = y2;
+ y2 = y0;
+ }
+ if (FastMath.abs(y1) <= functionValueAccuracy) {
+ // Avoid division by very small values. Assume
+ // the iteration has converged (the problem may
+ // still be ill conditioned)
+ setResult(x1, i);
+ return result;
+ }
+ double dx = x2 - x1;
+ double tolerance =
+ FastMath.max(relativeAccuracy * FastMath.abs(x1), absoluteAccuracy);
+ if (FastMath.abs(dx) <= tolerance) {
+ setResult(x1, i);
+ return result;
+ }
+ if ((FastMath.abs(oldDelta) < tolerance) ||
+ (FastMath.abs(y0) <= FastMath.abs(y1))) {
+ // Force bisection.
+ delta = 0.5 * dx;
+ oldDelta = delta;
+ } else {
+ double r3 = y1 / y0;
+ double p;
+ double p1;
+ // the equality test (x0 == x2) is intentional,
+ // it is part of the original Brent's method,
+ // it should NOT be replaced by proximity test
+ if (x0 == x2) {
+ // Linear interpolation.
+ p = dx * r3;
+ p1 = 1.0 - r3;
+ } else {
+ // Inverse quadratic interpolation.
+ double r1 = y0 / y2;
+ double r2 = y1 / y2;
+ p = r3 * (dx * r1 * (r1 - r2) - (x1 - x0) * (r2 - 1.0));
+ p1 = (r1 - 1.0) * (r2 - 1.0) * (r3 - 1.0);
+ }
+ if (p > 0.0) {
+ p1 = -p1;
+ } else {
+ p = -p;
+ }
+ if (2.0 * p >= 1.5 * dx * p1 - FastMath.abs(tolerance * p1) ||
+ p >= FastMath.abs(0.5 * oldDelta * p1)) {
+ // Inverse quadratic interpolation gives a value
+ // in the wrong direction, or progress is slow.
+ // Fall back to bisection.
+ delta = 0.5 * dx;
+ oldDelta = delta;
+ } else {
+ oldDelta = delta;
+ delta = p / p1;
+ }
+ }
+ // Save old X1, Y1
+ x0 = x1;
+ y0 = y1;
+ // Compute new X1, Y1
+ if (FastMath.abs(delta) > tolerance) {
+ x1 = x1 + delta;
+ } else if (dx > 0.0) {
+ x1 = x1 + 0.5 * tolerance;
+ } else if (dx <= 0.0) {
+ x1 = x1 - 0.5 * tolerance;
+ }
+ y1 = f.value(x1);
+ if ((y1 > 0) == (y2 > 0)) {
+ x2 = x0;
+ y2 = y0;
+ delta = x1 - x0;
+ oldDelta = delta;
+ }
+ i++;
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/LaguerreSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/LaguerreSolver.java
new file mode 100644
index 0000000..e6d8bd8
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/LaguerreSolver.java
@@ -0,0 +1,434 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
+import org.apache.commons.math.complex.Complex;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/LaguerresMethod.html">
+ * Laguerre's Method</a> for root finding of real coefficient polynomials.
+ * For reference, see <b>A First Course in Numerical Analysis</b>,
+ * ISBN 048641454X, chapter 8.
+ * <p>
+ * Laguerre's method is global in the sense that it can start with any initial
+ * approximation and be able to solve all roots from that point.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 1.2
+ */
+public class LaguerreSolver extends UnivariateRealSolverImpl {
+
+ /** polynomial function to solve.
+ * @deprecated as of 2.0 the function is not stored anymore in the instance
+ */
+ @Deprecated
+ private final PolynomialFunction p;
+
+ /**
+ * Construct a solver for the given function.
+ *
+ * @param f function to solve
+ * @throws IllegalArgumentException if function is not polynomial
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method.
+ */
+ @Deprecated
+ public LaguerreSolver(UnivariateRealFunction f) throws IllegalArgumentException {
+ super(f, 100, 1E-6);
+ if (f instanceof PolynomialFunction) {
+ p = (PolynomialFunction) f;
+ } else {
+ throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.FUNCTION_NOT_POLYNOMIAL);
+ }
+ }
+
+ /**
+ * Construct a solver.
+ * @deprecated in 2.2 (to be removed in 3.0)
+ */
+ @Deprecated
+ public LaguerreSolver() {
+ super(100, 1E-6);
+ p = null;
+ }
+
+ /**
+ * Returns a copy of the polynomial function.
+ *
+ * @return a fresh copy of the polynomial function
+ * @deprecated as of 2.0 the function is not stored anymore within the instance.
+ */
+ @Deprecated
+ public PolynomialFunction getPolynomialFunction() {
+ return new PolynomialFunction(p.getCoefficients());
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max)
+ throws ConvergenceException, FunctionEvaluationException {
+ return solve(p, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max, final double initial)
+ throws ConvergenceException, FunctionEvaluationException {
+ return solve(p, min, max, initial);
+ }
+
+ /**
+ * Find a real root in the given interval with initial value.
+ * <p>
+ * Requires bracketing condition.</p>
+ *
+ * @param f function to solve (must be polynomial)
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param initial the start value to use
+ * @param maxEval Maximum number of evaluations.
+ * @return the point at which the function value is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws ConvergenceException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a real root in the given interval with initial value.
+ * <p>
+ * Requires bracketing condition.</p>
+ *
+ * @param f function to solve (must be polynomial)
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param initial the start value to use
+ * @return the point at which the function value is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws ConvergenceException, FunctionEvaluationException {
+
+ // check for zeros before verifying bracketing
+ if (f.value(min) == 0.0) {
+ return min;
+ }
+ if (f.value(max) == 0.0) {
+ return max;
+ }
+ if (f.value(initial) == 0.0) {
+ return initial;
+ }
+
+ verifyBracketing(min, max, f);
+ verifySequence(min, initial, max);
+ if (isBracketing(min, initial, f)) {
+ return solve(f, min, initial);
+ } else {
+ return solve(f, initial, max);
+ }
+
+ }
+
+ /**
+ * Find a real root in the given interval.
+ * <p>
+ * Despite the bracketing condition, the root returned by solve(Complex[],
+ * Complex) may not be a real zero inside [min, max]. For example,
+ * p(x) = x^3 + 1, min = -2, max = 2, initial = 0. We can either try
+ * another initial value, or, as we did here, call solveAll() to obtain
+ * all roots and pick up the one that we're looking for.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param maxEval Maximum number of evaluations.
+ * @return the point at which the function value is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max)
+ throws ConvergenceException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max);
+ }
+
+ /**
+ * Find a real root in the given interval.
+ * <p>
+ * Despite the bracketing condition, the root returned by solve(Complex[],
+ * Complex) may not be a real zero inside [min, max]. For example,
+ * p(x) = x^3 + 1, min = -2, max = 2, initial = 0. We can either try
+ * another initial value, or, as we did here, call solveAll() to obtain
+ * all roots and pick up the one that we're looking for.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @return the point at which the function value is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max)
+ throws ConvergenceException, FunctionEvaluationException {
+
+ // check function type
+ if (!(f instanceof PolynomialFunction)) {
+ throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.FUNCTION_NOT_POLYNOMIAL);
+ }
+
+ // check for zeros before verifying bracketing
+ if (f.value(min) == 0.0) { return min; }
+ if (f.value(max) == 0.0) { return max; }
+ verifyBracketing(min, max, f);
+
+ double coefficients[] = ((PolynomialFunction) f).getCoefficients();
+ Complex c[] = new Complex[coefficients.length];
+ for (int i = 0; i < coefficients.length; i++) {
+ c[i] = new Complex(coefficients[i], 0.0);
+ }
+ Complex initial = new Complex(0.5 * (min + max), 0.0);
+ Complex z = solve(c, initial);
+ if (isRootOK(min, max, z)) {
+ setResult(z.getReal(), iterationCount);
+ return result;
+ }
+
+ // solve all roots and select the one we're seeking
+ Complex[] root = solveAll(c, initial);
+ for (int i = 0; i < root.length; i++) {
+ if (isRootOK(min, max, root[i])) {
+ setResult(root[i].getReal(), iterationCount);
+ return result;
+ }
+ }
+
+ // should never happen
+ throw new ConvergenceException();
+ }
+
+ /**
+ * Returns true iff the given complex root is actually a real zero
+ * in the given interval, within the solver tolerance level.
+ *
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param z the complex root
+ * @return true iff z is the sought-after real zero
+ */
+ protected boolean isRootOK(double min, double max, Complex z) {
+ double tolerance = FastMath.max(relativeAccuracy * z.abs(), absoluteAccuracy);
+ return (isSequence(min, z.getReal(), max)) &&
+ (FastMath.abs(z.getImaginary()) <= tolerance ||
+ z.abs() <= functionValueAccuracy);
+ }
+
+ /**
+ * Find all complex roots for the polynomial with the given coefficients,
+ * starting from the given initial value.
+ *
+ * @param coefficients the polynomial coefficients array
+ * @param initial the start value to use
+ * @return the point at which the function value is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2.
+ */
+ @Deprecated
+ public Complex[] solveAll(double coefficients[], double initial) throws
+ ConvergenceException, FunctionEvaluationException {
+
+ Complex c[] = new Complex[coefficients.length];
+ Complex z = new Complex(initial, 0.0);
+ for (int i = 0; i < c.length; i++) {
+ c[i] = new Complex(coefficients[i], 0.0);
+ }
+ return solveAll(c, z);
+ }
+
+ /**
+ * Find all complex roots for the polynomial with the given coefficients,
+ * starting from the given initial value.
+ *
+ * @param coefficients the polynomial coefficients array
+ * @param initial the start value to use
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2.
+ */
+ @Deprecated
+ public Complex[] solveAll(Complex coefficients[], Complex initial) throws
+ MaxIterationsExceededException, FunctionEvaluationException {
+
+ int n = coefficients.length - 1;
+ int iterationCount = 0;
+ if (n < 1) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.NON_POSITIVE_POLYNOMIAL_DEGREE, n);
+ }
+ Complex c[] = new Complex[n+1]; // coefficients for deflated polynomial
+ for (int i = 0; i <= n; i++) {
+ c[i] = coefficients[i];
+ }
+
+ // solve individual root successively
+ Complex root[] = new Complex[n];
+ for (int i = 0; i < n; i++) {
+ Complex subarray[] = new Complex[n-i+1];
+ System.arraycopy(c, 0, subarray, 0, subarray.length);
+ root[i] = solve(subarray, initial);
+ // polynomial deflation using synthetic division
+ Complex newc = c[n-i];
+ Complex oldc = null;
+ for (int j = n-i-1; j >= 0; j--) {
+ oldc = c[j];
+ c[j] = newc;
+ newc = oldc.add(newc.multiply(root[i]));
+ }
+ iterationCount += this.iterationCount;
+ }
+
+ resultComputed = true;
+ this.iterationCount = iterationCount;
+ return root;
+ }
+
+ /**
+ * Find a complex root for the polynomial with the given coefficients,
+ * starting from the given initial value.
+ *
+ * @param coefficients the polynomial coefficients array
+ * @param initial the start value to use
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2.
+ */
+ @Deprecated
+ public Complex solve(Complex coefficients[], Complex initial) throws
+ MaxIterationsExceededException, FunctionEvaluationException {
+
+ int n = coefficients.length - 1;
+ if (n < 1) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.NON_POSITIVE_POLYNOMIAL_DEGREE, n);
+ }
+ Complex N = new Complex(n, 0.0);
+ Complex N1 = new Complex(n - 1, 0.0);
+
+ int i = 1;
+ Complex pv = null;
+ Complex dv = null;
+ Complex d2v = null;
+ Complex G = null;
+ Complex G2 = null;
+ Complex H = null;
+ Complex delta = null;
+ Complex denominator = null;
+ Complex z = initial;
+ Complex oldz = new Complex(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
+ while (i <= maximalIterationCount) {
+ // Compute pv (polynomial value), dv (derivative value), and
+ // d2v (second derivative value) simultaneously.
+ pv = coefficients[n];
+ dv = Complex.ZERO;
+ d2v = Complex.ZERO;
+ for (int j = n-1; j >= 0; j--) {
+ d2v = dv.add(z.multiply(d2v));
+ dv = pv.add(z.multiply(dv));
+ pv = coefficients[j].add(z.multiply(pv));
+ }
+ d2v = d2v.multiply(new Complex(2.0, 0.0));
+
+ // check for convergence
+ double tolerance = FastMath.max(relativeAccuracy * z.abs(),
+ absoluteAccuracy);
+ if ((z.subtract(oldz)).abs() <= tolerance) {
+ resultComputed = true;
+ iterationCount = i;
+ return z;
+ }
+ if (pv.abs() <= functionValueAccuracy) {
+ resultComputed = true;
+ iterationCount = i;
+ return z;
+ }
+
+ // now pv != 0, calculate the new approximation
+ G = dv.divide(pv);
+ G2 = G.multiply(G);
+ H = G2.subtract(d2v.divide(pv));
+ delta = N1.multiply((N.multiply(H)).subtract(G2));
+ // choose a denominator larger in magnitude
+ Complex deltaSqrt = delta.sqrt();
+ Complex dplus = G.add(deltaSqrt);
+ Complex dminus = G.subtract(deltaSqrt);
+ denominator = dplus.abs() > dminus.abs() ? dplus : dminus;
+ // Perturb z if denominator is zero, for instance,
+ // p(x) = x^3 + 1, z = 0.
+ if (denominator.equals(new Complex(0.0, 0.0))) {
+ z = z.add(new Complex(absoluteAccuracy, absoluteAccuracy));
+ oldz = new Complex(Double.POSITIVE_INFINITY,
+ Double.POSITIVE_INFINITY);
+ } else {
+ oldz = z;
+ z = z.subtract(N.divide(denominator));
+ }
+ i++;
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/MullerSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/MullerSolver.java
new file mode 100644
index 0000000..a6d03bc
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/MullerSolver.java
@@ -0,0 +1,415 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.util.FastMath;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/MullersMethod.html">
+ * Muller's Method</a> for root finding of real univariate functions. For
+ * reference, see <b>Elementary Numerical Analysis</b>, ISBN 0070124477,
+ * chapter 3.
+ * <p>
+ * Muller's method applies to both real and complex functions, but here we
+ * restrict ourselves to real functions. Methods solve() and solve2() find
+ * real zeros, using different ways to bypass complex arithmetics.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 1.2
+ */
+public class MullerSolver extends UnivariateRealSolverImpl {
+
+ /**
+ * Construct a solver for the given function.
+ *
+ * @param f function to solve
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method.
+ */
+ @Deprecated
+ public MullerSolver(UnivariateRealFunction f) {
+ super(f, 100, 1E-6);
+ }
+
+ /**
+ * Construct a solver.
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public MullerSolver() {
+ super(100, 1E-6);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max)
+ throws ConvergenceException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max, final double initial)
+ throws ConvergenceException, FunctionEvaluationException {
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a real root in the given interval with initial value.
+ * <p>
+ * Requires bracketing condition.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param initial the start value to use
+ * @param maxEval Maximum number of evaluations.
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a real root in the given interval with initial value.
+ * <p>
+ * Requires bracketing condition.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param initial the start value to use
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ // check for zeros before verifying bracketing
+ if (f.value(min) == 0.0) { return min; }
+ if (f.value(max) == 0.0) { return max; }
+ if (f.value(initial) == 0.0) { return initial; }
+
+ verifyBracketing(min, max, f);
+ verifySequence(min, initial, max);
+ if (isBracketing(min, initial, f)) {
+ return solve(f, min, initial);
+ } else {
+ return solve(f, initial, max);
+ }
+ }
+
+ /**
+ * Find a real root in the given interval.
+ * <p>
+ * Original Muller's method would have function evaluation at complex point.
+ * Since our f(x) is real, we have to find ways to avoid that. Bracketing
+ * condition is one way to go: by requiring bracketing in every iteration,
+ * the newly computed approximation is guaranteed to be real.</p>
+ * <p>
+ * Normally Muller's method converges quadratically in the vicinity of a
+ * zero, however it may be very slow in regions far away from zeros. For
+ * example, f(x) = exp(x) - 1, min = -50, max = 100. In such case we use
+ * bisection as a safety backup if it performs very poorly.</p>
+ * <p>
+ * The formulas here use divided differences directly.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param maxEval Maximum number of evaluations.
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max);
+ }
+
+ /**
+ * Find a real root in the given interval.
+ * <p>
+ * Original Muller's method would have function evaluation at complex point.
+ * Since our f(x) is real, we have to find ways to avoid that. Bracketing
+ * condition is one way to go: by requiring bracketing in every iteration,
+ * the newly computed approximation is guaranteed to be real.</p>
+ * <p>
+ * Normally Muller's method converges quadratically in the vicinity of a
+ * zero, however it may be very slow in regions far away from zeros. For
+ * example, f(x) = exp(x) - 1, min = -50, max = 100. In such case we use
+ * bisection as a safety backup if it performs very poorly.</p>
+ * <p>
+ * The formulas here use divided differences directly.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ // [x0, x2] is the bracketing interval in each iteration
+ // x1 is the last approximation and an interpolation point in (x0, x2)
+ // x is the new root approximation and new x1 for next round
+ // d01, d12, d012 are divided differences
+
+ double x0 = min;
+ double y0 = f.value(x0);
+ double x2 = max;
+ double y2 = f.value(x2);
+ double x1 = 0.5 * (x0 + x2);
+ double y1 = f.value(x1);
+
+ // check for zeros before verifying bracketing
+ if (y0 == 0.0) {
+ return min;
+ }
+ if (y2 == 0.0) {
+ return max;
+ }
+ verifyBracketing(min, max, f);
+
+ double oldx = Double.POSITIVE_INFINITY;
+ for (int i = 1; i <= maximalIterationCount; ++i) {
+ // Muller's method employs quadratic interpolation through
+ // x0, x1, x2 and x is the zero of the interpolating parabola.
+ // Due to bracketing condition, this parabola must have two
+ // real roots and we choose one in [x0, x2] to be x.
+ final double d01 = (y1 - y0) / (x1 - x0);
+ final double d12 = (y2 - y1) / (x2 - x1);
+ final double d012 = (d12 - d01) / (x2 - x0);
+ final double c1 = d01 + (x1 - x0) * d012;
+ final double delta = c1 * c1 - 4 * y1 * d012;
+ final double xplus = x1 + (-2.0 * y1) / (c1 + FastMath.sqrt(delta));
+ final double xminus = x1 + (-2.0 * y1) / (c1 - FastMath.sqrt(delta));
+ // xplus and xminus are two roots of parabola and at least
+ // one of them should lie in (x0, x2)
+ final double x = isSequence(x0, xplus, x2) ? xplus : xminus;
+ final double y = f.value(x);
+
+ // check for convergence
+ final double tolerance = FastMath.max(relativeAccuracy * FastMath.abs(x), absoluteAccuracy);
+ if (FastMath.abs(x - oldx) <= tolerance) {
+ setResult(x, i);
+ return result;
+ }
+ if (FastMath.abs(y) <= functionValueAccuracy) {
+ setResult(x, i);
+ return result;
+ }
+
+ // Bisect if convergence is too slow. Bisection would waste
+ // our calculation of x, hopefully it won't happen often.
+ // the real number equality test x == x1 is intentional and
+ // completes the proximity tests above it
+ boolean bisect = (x < x1 && (x1 - x0) > 0.95 * (x2 - x0)) ||
+ (x > x1 && (x2 - x1) > 0.95 * (x2 - x0)) ||
+ (x == x1);
+ // prepare the new bracketing interval for next iteration
+ if (!bisect) {
+ x0 = x < x1 ? x0 : x1;
+ y0 = x < x1 ? y0 : y1;
+ x2 = x > x1 ? x2 : x1;
+ y2 = x > x1 ? y2 : y1;
+ x1 = x; y1 = y;
+ oldx = x;
+ } else {
+ double xm = 0.5 * (x0 + x2);
+ double ym = f.value(xm);
+ if (MathUtils.sign(y0) + MathUtils.sign(ym) == 0.0) {
+ x2 = xm; y2 = ym;
+ } else {
+ x0 = xm; y0 = ym;
+ }
+ x1 = 0.5 * (x0 + x2);
+ y1 = f.value(x1);
+ oldx = Double.POSITIVE_INFINITY;
+ }
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+
+ /**
+ * Find a real root in the given interval.
+ * <p>
+ * solve2() differs from solve() in the way it avoids complex operations.
+ * Except for the initial [min, max], solve2() does not require bracketing
+ * condition, e.g. f(x0), f(x1), f(x2) can have the same sign. If complex
+ * number arises in the computation, we simply use its modulus as real
+ * approximation.</p>
+ * <p>
+ * Because the interval may not be bracketing, bisection alternative is
+ * not applicable here. However in practice our treatment usually works
+ * well, especially near real zeros where the imaginary part of complex
+ * approximation is often negligible.</p>
+ * <p>
+ * The formulas here do not use divided differences directly.</p>
+ *
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated replaced by {@link #solve2(UnivariateRealFunction, double, double)}
+ * since 2.0
+ */
+ @Deprecated
+ public double solve2(final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve2(f, min, max);
+ }
+
+ /**
+ * Find a real root in the given interval.
+ * <p>
+ * solve2() differs from solve() in the way it avoids complex operations.
+ * Except for the initial [min, max], solve2() does not require bracketing
+ * condition, e.g. f(x0), f(x1), f(x2) can have the same sign. If complex
+ * number arises in the computation, we simply use its modulus as real
+ * approximation.</p>
+ * <p>
+ * Because the interval may not be bracketing, bisection alternative is
+ * not applicable here. However in practice our treatment usually works
+ * well, especially near real zeros where the imaginary part of complex
+ * approximation is often negligible.</p>
+ * <p>
+ * The formulas here do not use divided differences directly.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve2(final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ // x2 is the last root approximation
+ // x is the new approximation and new x2 for next round
+ // x0 < x1 < x2 does not hold here
+
+ double x0 = min;
+ double y0 = f.value(x0);
+ double x1 = max;
+ double y1 = f.value(x1);
+ double x2 = 0.5 * (x0 + x1);
+ double y2 = f.value(x2);
+
+ // check for zeros before verifying bracketing
+ if (y0 == 0.0) { return min; }
+ if (y1 == 0.0) { return max; }
+ verifyBracketing(min, max, f);
+
+ double oldx = Double.POSITIVE_INFINITY;
+ for (int i = 1; i <= maximalIterationCount; ++i) {
+ // quadratic interpolation through x0, x1, x2
+ final double q = (x2 - x1) / (x1 - x0);
+ final double a = q * (y2 - (1 + q) * y1 + q * y0);
+ final double b = (2 * q + 1) * y2 - (1 + q) * (1 + q) * y1 + q * q * y0;
+ final double c = (1 + q) * y2;
+ final double delta = b * b - 4 * a * c;
+ double x;
+ final double denominator;
+ if (delta >= 0.0) {
+ // choose a denominator larger in magnitude
+ double dplus = b + FastMath.sqrt(delta);
+ double dminus = b - FastMath.sqrt(delta);
+ denominator = FastMath.abs(dplus) > FastMath.abs(dminus) ? dplus : dminus;
+ } else {
+ // take the modulus of (B +/- FastMath.sqrt(delta))
+ denominator = FastMath.sqrt(b * b - delta);
+ }
+ if (denominator != 0) {
+ x = x2 - 2.0 * c * (x2 - x1) / denominator;
+ // perturb x if it exactly coincides with x1 or x2
+ // the equality tests here are intentional
+ while (x == x1 || x == x2) {
+ x += absoluteAccuracy;
+ }
+ } else {
+ // extremely rare case, get a random number to skip it
+ x = min + FastMath.random() * (max - min);
+ oldx = Double.POSITIVE_INFINITY;
+ }
+ final double y = f.value(x);
+
+ // check for convergence
+ final double tolerance = FastMath.max(relativeAccuracy * FastMath.abs(x), absoluteAccuracy);
+ if (FastMath.abs(x - oldx) <= tolerance) {
+ setResult(x, i);
+ return result;
+ }
+ if (FastMath.abs(y) <= functionValueAccuracy) {
+ setResult(x, i);
+ return result;
+ }
+
+ // prepare the next iteration
+ x0 = x1;
+ y0 = y1;
+ x1 = x2;
+ y1 = y2;
+ x2 = x;
+ y2 = y;
+ oldx = x;
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/NewtonSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/NewtonSolver.java
new file mode 100644
index 0000000..a2cffff
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/NewtonSolver.java
@@ -0,0 +1,183 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.DifferentiableUnivariateRealFunction;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Implements <a href="http://mathworld.wolfram.com/NewtonsMethod.html">
+ * Newton's Method</a> for finding zeros of real univariate functions.
+ * <p>
+ * The function should be continuous but not necessarily smooth.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ */
+public class NewtonSolver extends UnivariateRealSolverImpl {
+
+ /**
+ * Construct a solver for the given function.
+ * @param f function to solve.
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method.
+ */
+ @Deprecated
+ public NewtonSolver(DifferentiableUnivariateRealFunction f) {
+ super(f, 100, 1E-6);
+ }
+
+ /**
+ * Construct a solver.
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public NewtonSolver() {
+ super(100, 1E-6);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max, final double startValue)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max, startValue);
+ }
+
+ /**
+ * Find a zero near the midpoint of <code>min</code> and <code>max</code>.
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param maxEval Maximum number of evaluations.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function or derivative
+ * @throws IllegalArgumentException if min is not less than max
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max);
+ }
+
+ /**
+ * Find a zero near the midpoint of <code>min</code> and <code>max</code>.
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function or derivative
+ * @throws IllegalArgumentException if min is not less than max
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max, UnivariateRealSolverUtils.midpoint(min, max));
+ }
+
+ /**
+ * Find a zero near the value <code>startValue</code>.
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval (ignored).
+ * @param max the upper bound for the interval (ignored).
+ * @param startValue the start value to use.
+ * @param maxEval Maximum number of evaluations.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function or derivative
+ * @throws IllegalArgumentException if startValue is not between min and max or
+ * if function is not a {@link DifferentiableUnivariateRealFunction} instance
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max, final double startValue)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max, startValue);
+ }
+
+ /**
+ * Find a zero near the value <code>startValue</code>.
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval (ignored).
+ * @param max the upper bound for the interval (ignored).
+ * @param startValue the start value to use.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function or derivative
+ * @throws IllegalArgumentException if startValue is not between min and max or
+ * if function is not a {@link DifferentiableUnivariateRealFunction} instance
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max, final double startValue)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ try {
+
+ final UnivariateRealFunction derivative =
+ ((DifferentiableUnivariateRealFunction) f).derivative();
+ clearResult();
+ verifySequence(min, startValue, max);
+
+ double x0 = startValue;
+ double x1;
+
+ int i = 0;
+ while (i < maximalIterationCount) {
+
+ x1 = x0 - (f.value(x0) / derivative.value(x0));
+ if (FastMath.abs(x1 - x0) <= absoluteAccuracy) {
+ setResult(x1, i);
+ return x1;
+ }
+
+ x0 = x1;
+ ++i;
+ }
+
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ } catch (ClassCastException cce) {
+ throw MathRuntimeException.createIllegalArgumentException(LocalizedFormats.FUNCTION_NOT_DIFFERENTIABLE);
+ }
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/RiddersSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/RiddersSolver.java
new file mode 100644
index 0000000..4f316c7
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/RiddersSolver.java
@@ -0,0 +1,247 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.util.FastMath;
+import org.apache.commons.math.util.MathUtils;
+
+/**
+ * Implements the <a href="http://mathworld.wolfram.com/RiddersMethod.html">
+ * Ridders' Method</a> for root finding of real univariate functions. For
+ * reference, see C. Ridders, <i>A new algorithm for computing a single root
+ * of a real continuous function </i>, IEEE Transactions on Circuits and
+ * Systems, 26 (1979), 979 - 980.
+ * <p>
+ * The function should be continuous but not necessarily smooth.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @since 1.2
+ */
+public class RiddersSolver extends UnivariateRealSolverImpl {
+
+ /**
+ * Construct a solver for the given function.
+ *
+ * @param f function to solve
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method.
+ */
+ @Deprecated
+ public RiddersSolver(UnivariateRealFunction f) {
+ super(f, 100, 1E-6);
+ }
+
+ /**
+ * Construct a solver.
+ * @deprecated in 2.2
+ */
+ @Deprecated
+ public RiddersSolver() {
+ super(100, 1E-6);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max)
+ throws ConvergenceException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max, final double initial)
+ throws ConvergenceException, FunctionEvaluationException {
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a root in the given interval with initial value.
+ * <p>
+ * Requires bracketing condition.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param initial the start value to use
+ * @param maxEval Maximum number of evaluations.
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a root in the given interval with initial value.
+ * <p>
+ * Requires bracketing condition.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param initial the start value to use
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ // check for zeros before verifying bracketing
+ if (f.value(min) == 0.0) { return min; }
+ if (f.value(max) == 0.0) { return max; }
+ if (f.value(initial) == 0.0) { return initial; }
+
+ verifyBracketing(min, max, f);
+ verifySequence(min, initial, max);
+ if (isBracketing(min, initial, f)) {
+ return solve(f, min, initial);
+ } else {
+ return solve(f, initial, max);
+ }
+ }
+
+ /**
+ * Find a root in the given interval.
+ * <p>
+ * Requires bracketing condition.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param maxEval Maximum number of evaluations.
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max);
+ }
+
+ /**
+ * Find a root in the given interval.
+ * <p>
+ * Requires bracketing condition.</p>
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @return the point at which the function value is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if any parameters are invalid
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ // [x1, x2] is the bracketing interval in each iteration
+ // x3 is the midpoint of [x1, x2]
+ // x is the new root approximation and an endpoint of the new interval
+ double x1 = min;
+ double y1 = f.value(x1);
+ double x2 = max;
+ double y2 = f.value(x2);
+
+ // check for zeros before verifying bracketing
+ if (y1 == 0.0) {
+ return min;
+ }
+ if (y2 == 0.0) {
+ return max;
+ }
+ verifyBracketing(min, max, f);
+
+ int i = 1;
+ double oldx = Double.POSITIVE_INFINITY;
+ while (i <= maximalIterationCount) {
+ // calculate the new root approximation
+ final double x3 = 0.5 * (x1 + x2);
+ final double y3 = f.value(x3);
+ if (FastMath.abs(y3) <= functionValueAccuracy) {
+ setResult(x3, i);
+ return result;
+ }
+ final double delta = 1 - (y1 * y2) / (y3 * y3); // delta > 1 due to bracketing
+ final double correction = (MathUtils.sign(y2) * MathUtils.sign(y3)) *
+ (x3 - x1) / FastMath.sqrt(delta);
+ final double x = x3 - correction; // correction != 0
+ final double y = f.value(x);
+
+ // check for convergence
+ final double tolerance = FastMath.max(relativeAccuracy * FastMath.abs(x), absoluteAccuracy);
+ if (FastMath.abs(x - oldx) <= tolerance) {
+ setResult(x, i);
+ return result;
+ }
+ if (FastMath.abs(y) <= functionValueAccuracy) {
+ setResult(x, i);
+ return result;
+ }
+
+ // prepare the new interval for next iteration
+ // Ridders' method guarantees x1 < x < x2
+ if (correction > 0.0) { // x1 < x < x3
+ if (MathUtils.sign(y1) + MathUtils.sign(y) == 0.0) {
+ x2 = x;
+ y2 = y;
+ } else {
+ x1 = x;
+ x2 = x3;
+ y1 = y;
+ y2 = y3;
+ }
+ } else { // x3 < x < x2
+ if (MathUtils.sign(y2) + MathUtils.sign(y) == 0.0) {
+ x1 = x;
+ y1 = y;
+ } else {
+ x1 = x3;
+ x2 = x;
+ y1 = y3;
+ y2 = y;
+ }
+ }
+ oldx = x;
+ i++;
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/SecantSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/SecantSolver.java
new file mode 100644
index 0000000..325b662
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/SecantSolver.java
@@ -0,0 +1,230 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.MaxIterationsExceededException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.util.FastMath;
+
+
+/**
+ * Implements a modified version of the
+ * <a href="http://mathworld.wolfram.com/SecantMethod.html">secant method</a>
+ * for approximating a zero of a real univariate function.
+ * <p>
+ * The algorithm is modified to maintain bracketing of a root by successive
+ * approximations. Because of forced bracketing, convergence may be slower than
+ * the unrestricted secant algorithm. However, this implementation should in
+ * general outperform the
+ * <a href="http://mathworld.wolfram.com/MethodofFalsePosition.html">
+ * regula falsi method.</a></p>
+ * <p>
+ * The function is assumed to be continuous but not necessarily smooth.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ */
+public class SecantSolver extends UnivariateRealSolverImpl {
+
+ /**
+ * Construct a solver for the given function.
+ * @param f function to solve.
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method.
+ */
+ @Deprecated
+ public SecantSolver(UnivariateRealFunction f) {
+ super(f, 100, 1E-6);
+ }
+
+ /**
+ * Construct a solver.
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public SecantSolver() {
+ super(100, 1E-6);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max)
+ throws ConvergenceException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ public double solve(final double min, final double max, final double initial)
+ throws ConvergenceException, FunctionEvaluationException {
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a zero in the given interval.
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param initial the start value to use (ignored)
+ * @param maxEval Maximum number of evaluations.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min is not less than max or the
+ * signs of the values of the function at the endpoints are not opposites
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max, initial);
+ }
+
+ /**
+ * Find a zero in the given interval.
+ *
+ * @param f the function to solve
+ * @param min the lower bound for the interval
+ * @param max the upper bound for the interval
+ * @param initial the start value to use (ignored)
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min is not less than max or the
+ * signs of the values of the function at the endpoints are not opposites
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max, final double initial)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ return solve(f, min, max);
+ }
+
+ /**
+ * Find a zero in the given interval.
+ * @param f the function to solve
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @param maxEval Maximum number of evaluations.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min is not less than max or the
+ * signs of the values of the function at the endpoints are not opposites
+ */
+ @Override
+ public double solve(int maxEval, final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+ setMaximalIterationCount(maxEval);
+ return solve(f, min, max);
+ }
+
+ /**
+ * Find a zero in the given interval.
+ * @param f the function to solve
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @return the value where the function is zero
+ * @throws MaxIterationsExceededException if the maximum iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min is not less than max or the
+ * signs of the values of the function at the endpoints are not opposites
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ public double solve(final UnivariateRealFunction f,
+ final double min, final double max)
+ throws MaxIterationsExceededException, FunctionEvaluationException {
+
+ clearResult();
+ verifyInterval(min, max);
+
+ // Index 0 is the old approximation for the root.
+ // Index 1 is the last calculated approximation for the root.
+ // Index 2 is a bracket for the root with respect to x0.
+ // OldDelta is the length of the bracketing interval of the last
+ // iteration.
+ double x0 = min;
+ double x1 = max;
+ double y0 = f.value(x0);
+ double y1 = f.value(x1);
+
+ // Verify bracketing
+ if (y0 * y1 >= 0) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.SAME_SIGN_AT_ENDPOINTS, min, max, y0, y1);
+ }
+
+ double x2 = x0;
+ double y2 = y0;
+ double oldDelta = x2 - x1;
+ int i = 0;
+ while (i < maximalIterationCount) {
+ if (FastMath.abs(y2) < FastMath.abs(y1)) {
+ x0 = x1;
+ x1 = x2;
+ x2 = x0;
+ y0 = y1;
+ y1 = y2;
+ y2 = y0;
+ }
+ if (FastMath.abs(y1) <= functionValueAccuracy) {
+ setResult(x1, i);
+ return result;
+ }
+ if (FastMath.abs(oldDelta) <
+ FastMath.max(relativeAccuracy * FastMath.abs(x1), absoluteAccuracy)) {
+ setResult(x1, i);
+ return result;
+ }
+ double delta;
+ if (FastMath.abs(y1) > FastMath.abs(y0)) {
+ // Function value increased in last iteration. Force bisection.
+ delta = 0.5 * oldDelta;
+ } else {
+ delta = (x0 - x1) / (1 - y0 / y1);
+ if (delta / oldDelta > 1) {
+ // New approximation falls outside bracket.
+ // Fall back to bisection.
+ delta = 0.5 * oldDelta;
+ }
+ }
+ x0 = x1;
+ y0 = y1;
+ x1 = x1 + delta;
+ y1 = f.value(x1);
+ if ((y1 > 0) == (y2 > 0)) {
+ // New bracket is (x0,x1).
+ x2 = x0;
+ y2 = y0;
+ }
+ oldDelta = x2 - x1;
+ i++;
+ }
+ throw new MaxIterationsExceededException(maximalIterationCount);
+ }
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolver.java b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolver.java
new file mode 100644
index 0000000..6540f67
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolver.java
@@ -0,0 +1,165 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.ConvergingAlgorithm;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+
+
+/**
+ * Interface for (univariate real) rootfinding algorithms.
+ * <p>
+ * Implementations will search for only one zero in the given interval.</p>
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ */
+public interface UnivariateRealSolver extends ConvergingAlgorithm {
+
+ /**
+ * Set the function value accuracy.
+ * <p>
+ * This is used to determine when an evaluated function value or some other
+ * value which is used as divisor is zero.</p>
+ * <p>
+ * This is a safety guard and it shouldn't be necessary to change this in
+ * general.</p>
+ *
+ * @param accuracy the accuracy.
+ * @throws IllegalArgumentException if the accuracy can't be achieved by
+ * the solver or is otherwise deemed unreasonable.
+ */
+ void setFunctionValueAccuracy(double accuracy);
+
+ /**
+ * Get the actual function value accuracy.
+ * @return the accuracy
+ */
+ double getFunctionValueAccuracy();
+
+ /**
+ * Reset the actual function accuracy to the default.
+ * The default value is provided by the solver implementation.
+ */
+ void resetFunctionValueAccuracy();
+
+ /**
+ * Solve for a zero root in the given interval.
+ * <p>A solver may require that the interval brackets a single zero root.
+ * Solvers that do require bracketing should be able to handle the case
+ * where one of the endpoints is itself a root.</p>
+ *
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @return a value where the function is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise.
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min > max or the endpoints do not
+ * satisfy the requirements specified by the solver
+ * @deprecated replaced by {@link #solve(UnivariateRealFunction, double, double)}
+ * since 2.0
+ */
+ @Deprecated
+ double solve(double min, double max) throws ConvergenceException, FunctionEvaluationException;
+
+ /**
+ * Solve for a zero root in the given interval.
+ * <p>A solver may require that the interval brackets a single zero root.
+ * Solvers that do require bracketing should be able to handle the case
+ * where one of the endpoints is itself a root.</p>
+ *
+ * @param f the function to solve.
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @return a value where the function is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise.
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min > max or the endpoints do not
+ * satisfy the requirements specified by the solver
+ * @since 2.0
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ double solve(UnivariateRealFunction f, double min, double max)
+ throws ConvergenceException, FunctionEvaluationException;
+
+ /**
+ * Solve for a zero in the given interval, start at startValue.
+ * <p>A solver may require that the interval brackets a single zero root.
+ * Solvers that do require bracketing should be able to handle the case
+ * where one of the endpoints is itself a root.</p>
+ *
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @param startValue the start value to use
+ * @return a value where the function is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise.
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min > max or the arguments do not
+ * satisfy the requirements specified by the solver
+ * @deprecated replaced by {@link #solve(UnivariateRealFunction, double, double, double)}
+ * since 2.0
+ */
+ @Deprecated
+ double solve(double min, double max, double startValue)
+ throws ConvergenceException, FunctionEvaluationException, IllegalArgumentException;
+
+ /**
+ * Solve for a zero in the given interval, start at startValue.
+ * <p>A solver may require that the interval brackets a single zero root.
+ * Solvers that do require bracketing should be able to handle the case
+ * where one of the endpoints is itself a root.</p>
+ *
+ * @param f the function to solve.
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @param startValue the start value to use
+ * @return a value where the function is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise.
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min > max or the arguments do not
+ * satisfy the requirements specified by the solver
+ * @since 2.0
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+ @Deprecated
+ double solve(UnivariateRealFunction f, double min, double max, double startValue)
+ throws ConvergenceException, FunctionEvaluationException, IllegalArgumentException;
+
+ /**
+ * Get the result of the last run of the solver.
+ *
+ * @return the last result.
+ * @throws IllegalStateException if there is no result available, either
+ * because no result was yet computed or the last attempt failed.
+ */
+ double getResult();
+
+ /**
+ * Get the result of the last run of the solver.
+ *
+ * @return the value of the function at the last result.
+ * @throws IllegalStateException if there is no result available, either
+ * because no result was yet computed or the last attempt failed.
+ */
+ double getFunctionValue();
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverFactory.java b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverFactory.java
new file mode 100644
index 0000000..46b7234
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverFactory.java
@@ -0,0 +1,90 @@
+/*
+ * 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.analysis.solvers;
+
+/**
+ * Abstract factory class used to create {@link UnivariateRealSolver} instances.
+ * <p>
+ * Solvers implementing the following algorithms are supported:
+ * <ul>
+ * <li>Bisection</li>
+ * <li>Brent's method</li>
+ * <li>Secant method</li>
+ * </ul>
+ * Concrete factories extending this class also specify a default solver, instances of which
+ * are returned by <code>newDefaultSolver()</code>.</p>
+ * <p>
+ * Common usage:<pre>
+ * SolverFactory factory = UnivariateRealSolverFactory.newInstance();</p>
+ *
+ * // create a Brent solver to use
+ * BrentSolver solver = factory.newBrentSolver();
+ * </pre>
+ *
+ * @version $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $
+ */
+public abstract class UnivariateRealSolverFactory {
+ /**
+ * Default constructor.
+ */
+ protected UnivariateRealSolverFactory() {
+ }
+
+ /**
+ * Create a new factory.
+ * @return a new factory.
+ */
+ public static UnivariateRealSolverFactory newInstance() {
+ return new UnivariateRealSolverFactoryImpl();
+ }
+
+ /**
+ * Create a new {@link UnivariateRealSolver}. The
+ * actual solver returned is determined by the underlying factory.
+ * @return the new solver.
+ */
+ public abstract UnivariateRealSolver newDefaultSolver();
+
+ /**
+ * Create a new {@link UnivariateRealSolver}. The
+ * solver is an implementation of the bisection method.
+ * @return the new solver.
+ */
+ public abstract UnivariateRealSolver newBisectionSolver();
+
+ /**
+ * Create a new {@link UnivariateRealSolver}. The
+ * solver is an implementation of the Brent method.
+ * @return the new solver.
+ */
+ public abstract UnivariateRealSolver newBrentSolver();
+
+ /**
+ * Create a new {@link UnivariateRealSolver}. The
+ * solver is an implementation of Newton's Method.
+ * @return the new solver.
+ */
+ public abstract UnivariateRealSolver newNewtonSolver();
+
+ /**
+ * Create a new {@link UnivariateRealSolver}. The
+ * solver is an implementation of the secant method.
+ * @return the new solver.
+ */
+ public abstract UnivariateRealSolver newSecantSolver();
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverFactoryImpl.java b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverFactoryImpl.java
new file mode 100644
index 0000000..cb4c6b2
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverFactoryImpl.java
@@ -0,0 +1,64 @@
+/*
+ * 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.analysis.solvers;
+
+/**
+ * A concrete {@link UnivariateRealSolverFactory}. This is the default solver factory
+ * used by commons-math.
+ * <p>
+ * The default solver returned by this factory is a {@link BrentSolver}.</p>
+ *
+ * @version $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $
+ */
+public class UnivariateRealSolverFactoryImpl extends UnivariateRealSolverFactory {
+
+ /**
+ * Default constructor.
+ */
+ public UnivariateRealSolverFactoryImpl() {
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public UnivariateRealSolver newDefaultSolver() {
+ return newBrentSolver();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public UnivariateRealSolver newBisectionSolver() {
+ return new BisectionSolver();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public UnivariateRealSolver newBrentSolver() {
+ return new BrentSolver();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public UnivariateRealSolver newNewtonSolver() {
+ return new NewtonSolver();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public UnivariateRealSolver newSecantSolver() {
+ return new SecantSolver();
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverImpl.java b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverImpl.java
new file mode 100644
index 0000000..557c767
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverImpl.java
@@ -0,0 +1,304 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.ConvergingAlgorithmImpl;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.exception.NullArgumentException;
+
+/**
+ * Provide a default implementation for several functions useful to generic
+ * solvers.
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ * @deprecated in 2.2 (to be removed in 3.0).
+ */
+@Deprecated
+public abstract class UnivariateRealSolverImpl
+ extends ConvergingAlgorithmImpl implements UnivariateRealSolver {
+
+ /** Maximum error of function. */
+ protected double functionValueAccuracy;
+
+ /** Default maximum error of function. */
+ protected double defaultFunctionValueAccuracy;
+
+ /** Indicates where a root has been computed. */
+ protected boolean resultComputed = false;
+
+ /** The last computed root. */
+ protected double result;
+
+ /** Value of the function at the last computed result. */
+ protected double functionValue;
+
+ /** The function to solve.
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method. */
+ @Deprecated
+ protected UnivariateRealFunction f;
+
+ /**
+ * Construct a solver with given iteration count and accuracy.
+ *
+ * @param f the function to solve.
+ * @param defaultAbsoluteAccuracy maximum absolute error
+ * @param defaultMaximalIterationCount maximum number of iterations
+ * @throws IllegalArgumentException if f is null or the
+ * defaultAbsoluteAccuracy is not valid
+ * @deprecated as of 2.0 the function to solve is passed as an argument
+ * to the {@link #solve(UnivariateRealFunction, double, double)} or
+ * {@link UnivariateRealSolverImpl#solve(UnivariateRealFunction, double, double, double)}
+ * method.
+ */
+ @Deprecated
+ protected UnivariateRealSolverImpl(final UnivariateRealFunction f,
+ final int defaultMaximalIterationCount,
+ final double defaultAbsoluteAccuracy) {
+ super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
+ if (f == null) {
+ throw new NullArgumentException(LocalizedFormats.FUNCTION);
+ }
+ this.f = f;
+ this.defaultFunctionValueAccuracy = 1.0e-15;
+ this.functionValueAccuracy = defaultFunctionValueAccuracy;
+ }
+
+ /**
+ * Construct a solver with given iteration count and accuracy.
+ *
+ * @param defaultAbsoluteAccuracy maximum absolute error
+ * @param defaultMaximalIterationCount maximum number of iterations
+ * @throws IllegalArgumentException if f is null or the
+ * defaultAbsoluteAccuracy is not valid
+ */
+ protected UnivariateRealSolverImpl(final int defaultMaximalIterationCount,
+ final double defaultAbsoluteAccuracy) {
+ super(defaultMaximalIterationCount, defaultAbsoluteAccuracy);
+ this.defaultFunctionValueAccuracy = 1.0e-15;
+ this.functionValueAccuracy = defaultFunctionValueAccuracy;
+ }
+
+ /** Check if a result has been computed.
+ * @exception IllegalStateException if no result has been computed
+ */
+ protected void checkResultComputed() throws IllegalStateException {
+ if (!resultComputed) {
+ throw MathRuntimeException.createIllegalStateException(LocalizedFormats.NO_RESULT_AVAILABLE);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public double getResult() {
+ checkResultComputed();
+ return result;
+ }
+
+ /** {@inheritDoc} */
+ public double getFunctionValue() {
+ checkResultComputed();
+ return functionValue;
+ }
+
+ /** {@inheritDoc} */
+ public void setFunctionValueAccuracy(final double accuracy) {
+ functionValueAccuracy = accuracy;
+ }
+
+ /** {@inheritDoc} */
+ public double getFunctionValueAccuracy() {
+ return functionValueAccuracy;
+ }
+
+ /** {@inheritDoc} */
+ public void resetFunctionValueAccuracy() {
+ functionValueAccuracy = defaultFunctionValueAccuracy;
+ }
+
+ /**
+ * Solve for a zero root in the given interval.
+ * <p>A solver may require that the interval brackets a single zero root.
+ * Solvers that do require bracketing should be able to handle the case
+ * where one of the endpoints is itself a root.</p>
+ *
+ * @param function the function to solve.
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @param maxEval Maximum number of evaluations.
+ * @return a value where the function is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise.
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min > max or the endpoints do not
+ * satisfy the requirements specified by the solver
+ * @since 2.2
+ */
+ public double solve(int maxEval, UnivariateRealFunction function, double min, double max)
+ throws ConvergenceException, FunctionEvaluationException {
+ throw MathRuntimeException.createUnsupportedOperationException(LocalizedFormats.NOT_OVERRIDEN);
+ }
+
+ /**
+ * Solve for a zero in the given interval, start at startValue.
+ * <p>A solver may require that the interval brackets a single zero root.
+ * Solvers that do require bracketing should be able to handle the case
+ * where one of the endpoints is itself a root.</p>
+ *
+ * @param function the function to solve.
+ * @param min the lower bound for the interval.
+ * @param max the upper bound for the interval.
+ * @param startValue the start value to use
+ * @param maxEval Maximum number of evaluations.
+ * @return a value where the function is zero
+ * @throws ConvergenceException if the maximum iteration count is exceeded
+ * or the solver detects convergence problems otherwise.
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if min > max or the arguments do not
+ * satisfy the requirements specified by the solver
+ * @since 2.2
+ */
+ public double solve(int maxEval, UnivariateRealFunction function, double min, double max, double startValue)
+ throws ConvergenceException, FunctionEvaluationException, IllegalArgumentException {
+ throw MathRuntimeException.createUnsupportedOperationException(LocalizedFormats.NOT_OVERRIDEN);
+ }
+
+ /**
+ * Convenience function for implementations.
+ *
+ * @param newResult the result to set
+ * @param iterationCount the iteration count to set
+ */
+ protected final void setResult(final double newResult, final int iterationCount) {
+ this.result = newResult;
+ this.iterationCount = iterationCount;
+ this.resultComputed = true;
+ }
+
+ /**
+ * Convenience function for implementations.
+ *
+ * @param x the result to set
+ * @param fx the result to set
+ * @param iterationCount the iteration count to set
+ */
+ protected final void setResult(final double x, final double fx,
+ final int iterationCount) {
+ this.result = x;
+ this.functionValue = fx;
+ this.iterationCount = iterationCount;
+ this.resultComputed = true;
+ }
+
+ /**
+ * Convenience function for implementations.
+ */
+ protected final void clearResult() {
+ this.iterationCount = 0;
+ this.resultComputed = false;
+ }
+
+ /**
+ * Returns true iff the function takes opposite signs at the endpoints.
+ *
+ * @param lower the lower endpoint
+ * @param upper the upper endpoint
+ * @param function the function
+ * @return true if f(lower) * f(upper) < 0
+ * @throws FunctionEvaluationException if an error occurs evaluating the function at the endpoints
+ */
+ protected boolean isBracketing(final double lower, final double upper,
+ final UnivariateRealFunction function)
+ throws FunctionEvaluationException {
+ final double f1 = function.value(lower);
+ final double f2 = function.value(upper);
+ return (f1 > 0 && f2 < 0) || (f1 < 0 && f2 > 0);
+ }
+
+ /**
+ * Returns true if the arguments form a (strictly) increasing sequence
+ *
+ * @param start first number
+ * @param mid second number
+ * @param end third number
+ * @return true if the arguments form an increasing sequence
+ */
+ protected boolean isSequence(final double start, final double mid, final double end) {
+ return (start < mid) && (mid < end);
+ }
+
+ /**
+ * Verifies that the endpoints specify an interval,
+ * throws IllegalArgumentException if not
+ *
+ * @param lower lower endpoint
+ * @param upper upper endpoint
+ * @throws IllegalArgumentException
+ */
+ protected void verifyInterval(final double lower, final double upper) {
+ if (lower >= upper) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.ENDPOINTS_NOT_AN_INTERVAL,
+ lower, upper);
+ }
+ }
+
+ /**
+ * Verifies that <code>lower < initial < upper</code>
+ * throws IllegalArgumentException if not
+ *
+ * @param lower lower endpoint
+ * @param initial initial value
+ * @param upper upper endpoint
+ * @throws IllegalArgumentException
+ */
+ protected void verifySequence(final double lower, final double initial, final double upper) {
+ if (!isSequence(lower, initial, upper)) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.INVALID_INTERVAL_INITIAL_VALUE_PARAMETERS,
+ lower, initial, upper);
+ }
+ }
+
+ /**
+ * Verifies that the endpoints specify an interval and the function takes
+ * opposite signs at the endpoints, throws IllegalArgumentException if not
+ *
+ * @param lower lower endpoint
+ * @param upper upper endpoint
+ * @param function function
+ * @throws IllegalArgumentException
+ * @throws FunctionEvaluationException if an error occurs evaluating the function at the endpoints
+ */
+ protected void verifyBracketing(final double lower, final double upper,
+ final UnivariateRealFunction function)
+ throws FunctionEvaluationException {
+
+ verifyInterval(lower, upper);
+ if (!isBracketing(lower, upper, function)) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.SAME_SIGN_AT_ENDPOINTS,
+ lower, upper, function.value(lower), function.value(upper));
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java
new file mode 100644
index 0000000..3186d6a
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/UnivariateRealSolverUtils.java
@@ -0,0 +1,240 @@
+/*
+ * 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.analysis.solvers;
+
+import org.apache.commons.math.ConvergenceException;
+import org.apache.commons.math.FunctionEvaluationException;
+import org.apache.commons.math.MathRuntimeException;
+import org.apache.commons.math.analysis.UnivariateRealFunction;
+import org.apache.commons.math.exception.util.LocalizedFormats;
+import org.apache.commons.math.exception.NullArgumentException;
+import org.apache.commons.math.util.FastMath;
+
+/**
+ * Utility routines for {@link UnivariateRealSolver} objects.
+ *
+ * @version $Revision: 1070725 $ $Date: 2011-02-15 02:31:12 +0100 (mar. 15 févr. 2011) $
+ */
+public class UnivariateRealSolverUtils {
+
+ /**
+ * Default constructor.
+ */
+ private UnivariateRealSolverUtils() {
+ super();
+ }
+
+ /**
+ * Convenience method to find a zero of a univariate real function. A default
+ * solver is used.
+ *
+ * @param f the function.
+ * @param x0 the lower bound for the interval.
+ * @param x1 the upper bound for the interval.
+ * @return a value where the function is zero.
+ * @throws ConvergenceException if the iteration count was exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if f is null or the endpoints do not
+ * specify a valid interval
+ */
+ public static double solve(UnivariateRealFunction f, double x0, double x1)
+ throws ConvergenceException, FunctionEvaluationException {
+ setup(f);
+ return LazyHolder.FACTORY.newDefaultSolver().solve(f, x0, x1);
+ }
+
+ /**
+ * Convenience method to find a zero of a univariate real function. A default
+ * solver is used.
+ *
+ * @param f the function
+ * @param x0 the lower bound for the interval
+ * @param x1 the upper bound for the interval
+ * @param absoluteAccuracy the accuracy to be used by the solver
+ * @return a value where the function is zero
+ * @throws ConvergenceException if the iteration count is exceeded
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if f is null, the endpoints do not
+ * specify a valid interval, or the absoluteAccuracy is not valid for the
+ * default solver
+ */
+ public static double solve(UnivariateRealFunction f, double x0, double x1,
+ double absoluteAccuracy) throws ConvergenceException,
+ FunctionEvaluationException {
+
+ setup(f);
+ UnivariateRealSolver solver = LazyHolder.FACTORY.newDefaultSolver();
+ solver.setAbsoluteAccuracy(absoluteAccuracy);
+ return solver.solve(f, x0, x1);
+ }
+
+ /**
+ * This method attempts to find two values a and b satisfying <ul>
+ * <li> <code> lowerBound <= a < initial < b <= upperBound</code> </li>
+ * <li> <code> f(a) * f(b) < 0 </code></li>
+ * </ul>
+ * If f is continuous on <code>[a,b],</code> this means that <code>a</code>
+ * and <code>b</code> bracket a root of f.
+ * <p>
+ * The algorithm starts by setting
+ * <code>a := initial -1; b := initial +1,</code> examines the value of the
+ * function at <code>a</code> and <code>b</code> and keeps moving
+ * the endpoints out by one unit each time through a loop that terminates
+ * when one of the following happens: <ul>
+ * <li> <code> f(a) * f(b) < 0 </code> -- success!</li>
+ * <li> <code> a = lower </code> and <code> b = upper</code>
+ * -- ConvergenceException </li>
+ * <li> <code> Integer.MAX_VALUE</code> iterations elapse
+ * -- ConvergenceException </li>
+ * </ul></p>
+ * <p>
+ * <strong>Note: </strong> this method can take
+ * <code>Integer.MAX_VALUE</code> iterations to throw a
+ * <code>ConvergenceException.</code> Unless you are confident that there
+ * is a root between <code>lowerBound</code> and <code>upperBound</code>
+ * near <code>initial,</code> it is better to use
+ * {@link #bracket(UnivariateRealFunction, double, double, double, int)},
+ * explicitly specifying the maximum number of iterations.</p>
+ *
+ * @param function the function
+ * @param initial initial midpoint of interval being expanded to
+ * bracket a root
+ * @param lowerBound lower bound (a is never lower than this value)
+ * @param upperBound upper bound (b never is greater than this
+ * value)
+ * @return a two element array holding {a, b}
+ * @throws ConvergenceException if a root can not be bracketted
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if function is null, maximumIterations
+ * is not positive, or initial is not between lowerBound and upperBound
+ */
+ public static double[] bracket(UnivariateRealFunction function,
+ double initial, double lowerBound, double upperBound)
+ throws ConvergenceException, FunctionEvaluationException {
+ return bracket( function, initial, lowerBound, upperBound,
+ Integer.MAX_VALUE ) ;
+ }
+
+ /**
+ * This method attempts to find two values a and b satisfying <ul>
+ * <li> <code> lowerBound <= a < initial < b <= upperBound</code> </li>
+ * <li> <code> f(a) * f(b) <= 0 </code> </li>
+ * </ul>
+ * If f is continuous on <code>[a,b],</code> this means that <code>a</code>
+ * and <code>b</code> bracket a root of f.
+ * <p>
+ * The algorithm starts by setting
+ * <code>a := initial -1; b := initial +1,</code> examines the value of the
+ * function at <code>a</code> and <code>b</code> and keeps moving
+ * the endpoints out by one unit each time through a loop that terminates
+ * when one of the following happens: <ul>
+ * <li> <code> f(a) * f(b) <= 0 </code> -- success!</li>
+ * <li> <code> a = lower </code> and <code> b = upper</code>
+ * -- ConvergenceException </li>
+ * <li> <code> maximumIterations</code> iterations elapse
+ * -- ConvergenceException </li></ul></p>
+ *
+ * @param function the function
+ * @param initial initial midpoint of interval being expanded to
+ * bracket a root
+ * @param lowerBound lower bound (a is never lower than this value)
+ * @param upperBound upper bound (b never is greater than this
+ * value)
+ * @param maximumIterations maximum number of iterations to perform
+ * @return a two element array holding {a, b}.
+ * @throws ConvergenceException if the algorithm fails to find a and b
+ * satisfying the desired conditions
+ * @throws FunctionEvaluationException if an error occurs evaluating the function
+ * @throws IllegalArgumentException if function is null, maximumIterations
+ * is not positive, or initial is not between lowerBound and upperBound
+ */
+ public static double[] bracket(UnivariateRealFunction function,
+ double initial, double lowerBound, double upperBound,
+ int maximumIterations) throws ConvergenceException,
+ FunctionEvaluationException {
+
+ if (function == null) {
+ throw new NullArgumentException(LocalizedFormats.FUNCTION);
+ }
+ if (maximumIterations <= 0) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.INVALID_MAX_ITERATIONS, maximumIterations);
+ }
+ if (initial < lowerBound || initial > upperBound || lowerBound >= upperBound) {
+ throw MathRuntimeException.createIllegalArgumentException(
+ LocalizedFormats.INVALID_BRACKETING_PARAMETERS,
+ lowerBound, initial, upperBound);
+ }
+ double a = initial;
+ double b = initial;
+ double fa;
+ double fb;
+ int numIterations = 0 ;
+
+ do {
+ a = FastMath.max(a - 1.0, lowerBound);
+ b = FastMath.min(b + 1.0, upperBound);
+ fa = function.value(a);
+
+ fb = function.value(b);
+ numIterations++ ;
+ } while ((fa * fb > 0.0) && (numIterations < maximumIterations) &&
+ ((a > lowerBound) || (b < upperBound)));
+
+ if (fa * fb > 0.0 ) {
+ throw new ConvergenceException(
+ LocalizedFormats.FAILED_BRACKETING,
+ numIterations, maximumIterations, initial,
+ lowerBound, upperBound, a, b, fa, fb);
+ }
+
+ return new double[]{a, b};
+ }
+
+ /**
+ * Compute the midpoint of two values.
+ *
+ * @param a first value.
+ * @param b second value.
+ * @return the midpoint.
+ */
+ public static double midpoint(double a, double b) {
+ return (a + b) * .5;
+ }
+
+ /**
+ * Checks to see if f is null, throwing IllegalArgumentException if so.
+ * @param f input function
+ * @throws IllegalArgumentException if f is null
+ */
+ private static void setup(UnivariateRealFunction f) {
+ if (f == null) {
+ throw new NullArgumentException(LocalizedFormats.FUNCTION);
+ }
+ }
+
+ // CHECKSTYLE: stop HideUtilityClassConstructor
+ /** Holder for the factory.
+ * <p>We use here the Initialization On Demand Holder Idiom.</p>
+ */
+ private static class LazyHolder {
+ /** Cached solver factory */
+ private static final UnivariateRealSolverFactory FACTORY = UnivariateRealSolverFactory.newInstance();
+ }
+ // CHECKSTYLE: resume HideUtilityClassConstructor
+
+}
diff --git a/src/main/java/org/apache/commons/math/analysis/solvers/package.html b/src/main/java/org/apache/commons/math/analysis/solvers/package.html
new file mode 100644
index 0000000..bbb49d1
--- /dev/null
+++ b/src/main/java/org/apache/commons/math/analysis/solvers/package.html
@@ -0,0 +1,22 @@
+<html>
+<!--
+ 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.
+ -->
+ <!-- $Revision: 811685 $ $Date: 2009-09-05 19:36:48 +0200 (sam. 05 sept. 2009) $ -->
+ <body>
+ Root finding algorithms, for univariate real functions.
+ </body>
+</html>