    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
    018    package org.apache.commons.math3.analysis.function;
    019
    020    import java.util.Arrays;
    021    import org.apache.commons.math3.analysis.UnivariateFunction;
    022    import org.apache.commons.math3.exception.DimensionMismatchException;
    023    import org.apache.commons.math3.exception.NullArgumentException;
    024    import org.apache.commons.math3.exception.NoDataException;
    025    import org.apache.commons.math3.util.MathArrays;
    026
    027    /**
    028     * <a href="http://en.wikipedia.org/wiki/Step_function">
    029     *  Step function</a>.
    030     *
    031     * @since 3.0
    032     * @version $Id: StepFunction.java 1379218 2012-08-30 23:18:57Z erans $
    033     */
    034    public class StepFunction implements UnivariateFunction {
    035        /** Abscissae. */
    036        private final double[] abscissa;
    037        /** Ordinates. */
    038        private final double[] ordinate;
    039
    040        /**
    041         * Builds a step function from a list of arguments and the corresponding
    042         * values. Specifically, returns the function h(x) defined by <pre><code>
    043         * h(x) = y[0] for all x < x[1]
    044         *        y[1] for x[1] <= x < x[2]
    045         *        ...
    046         *        y[y.length - 1] for x >= x[x.length - 1]
    047         * </code></pre>
    048         * The value of {@code x[0]} is ignored, but it must be strictly less than
    049         * {@code x[1]}.
    050         *
    051         * @param x Domain values where the function changes value.
    052         * @param y Values of the function.
    053         * @throws org.apache.commons.math3.exception.NonMonotonicSequenceException
    054         * if the {@code x} array is not sorted in strictly increasing order.
    055         * @throws NullArgumentException if {@code x} or {@code y} are {@code null}.
    056         * @throws NoDataException if {@code x} or {@code y} are zero-length.
    057         * @throws DimensionMismatchException if {@code x} and {@code y} do not
    058         * have the same length.
    059         */
    060        public StepFunction(double[] x,
    061                            double[] y)
    062            throws NullArgumentException,
    063                   NoDataException,
    064                   DimensionMismatchException {
    065            if (x == null ||
    066                y == null) {
    067                throw new NullArgumentException();
    068            }
    069            if (x.length == 0 ||
    070                y.length == 0) {
    071                throw new NoDataException();
    072            }
    073            if (y.length != x.length) {
    074                throw new DimensionMismatchException(y.length, x.length);
    075            }
    076            MathArrays.checkOrder(x);
    077
    078            abscissa = MathArrays.copyOf(x);
    079            ordinate = MathArrays.copyOf(y);
    080        }
    081
    082        /** {@inheritDoc} */
    083        public double value(double x) {
    084            int index = Arrays.binarySearch(abscissa, x);
    085            double fx = 0;
    086
    087            if (index < -1) {
    088                // "x" is between "abscissa[-index-2]" and "abscissa[-index-1]".
    089                fx = ordinate[-index-2];
    090            } else if (index >= 0) {
    091                // "x" is exactly "abscissa[index]".
    092                fx = ordinate[index];
    093            } else {
    094                // Otherwise, "x" is smaller than the first value in "abscissa"
    095                // (hence the returned value should be "ordinate[0]").
    096                fx = ordinate[0];
    097            }
    098
    099            return fx;
    100        }
    101    }