View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math4.legacy.analysis.function;
19  
20  import java.util.Arrays;
21  
22  import org.apache.commons.math4.legacy.analysis.UnivariateFunction;
23  import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
24  import org.apache.commons.math4.legacy.exception.NoDataException;
25  import org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException;
26  import org.apache.commons.math4.legacy.exception.NullArgumentException;
27  import org.apache.commons.math4.legacy.core.MathArrays;
28  
29  /**
30   * <a href="http://en.wikipedia.org/wiki/Step_function">
31   *  Step function</a>.
32   *
33   * @since 3.0
34   */
35  public class StepFunction implements UnivariateFunction {
36      /** Abscissae. */
37      private final double[] abscissa;
38      /** Ordinates. */
39      private final double[] ordinate;
40  
41      /**
42       * Builds a step function from a list of arguments and the corresponding
43       * values. Specifically, returns the function h(x) defined by <pre><code>
44       * h(x) = y[0] for all x &lt; x[1]
45       *        y[1] for x[1] &le; x &lt; x[2]
46       *        ...
47       *        y[y.length - 1] for x &ge; x[x.length - 1]
48       * </code></pre>
49       * The value of {@code x[0]} is ignored, but it must be strictly less than
50       * {@code x[1]}.
51       *
52       * @param x Domain values where the function changes value.
53       * @param y Values of the function.
54       * @throws NonMonotonicSequenceException
55       * if the {@code x} array is not sorted in strictly increasing order.
56       * @throws NullArgumentException if {@code x} or {@code y} are {@code null}.
57       * @throws NoDataException if {@code x} or {@code y} are zero-length.
58       * @throws DimensionMismatchException if {@code x} and {@code y} do not
59       * have the same length.
60       */
61      public StepFunction(double[] x,
62                          double[] y)
63          throws NullArgumentException, NoDataException,
64                 DimensionMismatchException, NonMonotonicSequenceException {
65          if (x == null ||
66              y == null) {
67              throw new NullArgumentException();
68          }
69          if (x.length == 0 ||
70              y.length == 0) {
71              throw new NoDataException();
72          }
73          if (y.length != x.length) {
74              throw new DimensionMismatchException(y.length, x.length);
75          }
76          MathArrays.checkOrder(x);
77  
78          abscissa = Arrays.copyOf(x, x.length);
79          ordinate = Arrays.copyOf(y, y.length);
80      }
81  
82      /** {@inheritDoc} */
83      @Override
84      public double value(double x) {
85          int index = Arrays.binarySearch(abscissa, x);
86          double fx = 0;
87  
88          if (index < -1) {
89              // "x" is between "abscissa[-index-2]" and "abscissa[-index-1]".
90              fx = ordinate[-index-2];
91          } else if (index >= 0) {
92              // "x" is exactly "abscissa[index]".
93              fx = ordinate[index];
94          } else {
95              // Otherwise, "x" is smaller than the first value in "abscissa"
96              // (hence the returned value should be "ordinate[0]").
97              fx = ordinate[0];
98          }
99  
100         return fx;
101     }
102 }