001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.nabla.numerical;
018    
019    import java.io.Serializable;
020    
021    import org.apache.commons.nabla.core.UnivariateDifferentiator;
022    
023    /** This class represents a differentiation scheme based on finite differences.
024     * <p>The differences are based on regularly distributed points around the
025     * central test point according to a given h step.
026     * For example a four points scheme would use a linear combination of points
027     * <code>f(x-2h)</code>, <code>f(x-h)</code>, <code>f(x+h)</code> and
028     * <code>f(x+2h)</code> to compute the first derivative <code>f'(x)</code>
029     * (note that <code>f(x)</code> by itself is not used for the evaluation of
030     * <code>f'(x)</code>, but is used to compute the value of the function
031     * <code>f(x)</code).</p>
032     * <p>The computed differential is only an approximation. The error depends on
033     * the value of the high order derivatives of the function which were not
034     * canceled by the linear combination, the number of points and the step size.
035     * For example the four points scheme cancels the
036     * <code>f<sup>(2)</sup></code>, <code>f<sup>(3)</sup></code> and
037     * <code>f<sup>(4)</sup></code> high order derivatives but not the
038     * <code>f<sup>(5)</sup></code> and higher order terms. The theoretical error
039     * model for this scheme is <code>-2h<sup>4</sup>/5 f<sup>(5)</sup>(x) +
040     * O(h<sup>6</sup>)</code>. This model doesn't take into account numerical
041     * cancellation which occur when the steps are too small.</p>
042     * <p>The general expression of the theoretical error model is
043     * <code>A f<sup>(k)</sup> + O(h<sup>k+1</sup>)</code> where <code>A</code>
044     * is the value returned by {@link #getSignedErrorScaleFactor()} and
045     * <code>k</code> is the value returned by {@link #getOrderFirstNonCanceled()}.</p>
046     */
047    public abstract class FiniteDifferencesDifferentiator
048        implements UnivariateDifferentiator, Serializable {
049    
050        /** Serializable UID. */
051        private static final long serialVersionUID = 3971239681079110480L;
052    
053        /** Step size. */
054        private final double stepSize;
055    
056        /** Error scale factor. */
057        private final double factor;
058    
059        /** Order of the first non-canceled derivative. */
060        private final int order;
061    
062        /** Simple constructor.
063         * @param stepSize step stepSize
064         * @param factor error scale factor
065         * @param order order of the first non-canceled derivative
066         */
067        protected FiniteDifferencesDifferentiator(final double stepSize,
068                                                  final double factor,
069                                                  final int order) {
070            this.stepSize = stepSize;
071            this.factor   = factor;
072            this.order    = order;
073        }
074    
075        /** Get the signed error scale factor for the finite differences scheme.
076         * <p>The error scale factor is the value of the h-dependent
077         * factor of the first non-canceled high order differential of the function.
078         * For example since the error model for the four points scheme is
079         * <code>-2h<sup>4</sup>/5 f<sup>(5)</sup>(x) + O(h<sup>6</sup>)</code>,
080         * the signed error scale factor is <code>-2h<sup>4</sup>/5</code>.</p>
081         * @return error signed scale factor
082         * @see #getOrderFirstNonCanceled()
083         */
084        public double getSignedErrorScaleFactor() {
085            return factor;
086        }
087    
088        /** Get the order of the first non-canceled derivative.
089         * <p>The error model of the scheme depends on the first non-canceled
090         * high order differential of the function. For example since the error
091         * model for the four points scheme is <code>-2h<sup>4</sup>/5
092         * f<sup>(5)</sup>(x) + O(h<sup>6</sup>)</code>, the order of the first
093         * non-canceled derivative is 5.
094         * @return order of the first non-canceled derivative
095         * @see #getSignedErrorScaleFactor()
096         */
097        public int getOrderFirstNonCanceled() {
098            return order;
099        }
100    
101        /** Get the step size.
102         * @return step size
103         */
104        protected double getStepSize() {
105            return stepSize;
106        }
107    
108    }