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 }