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  package org.apache.commons.math4.transform;
18  
19  import java.util.function.DoubleUnaryOperator;
20  
21  import org.apache.commons.numbers.complex.Complex;
22  
23  /**
24   * Useful functions for the implementation of various transforms.
25   * Class is package-private (for internal use only).
26   */
27  final class TransformUtils {
28      /** Number of array slots: 1 for "real" parts 1 for "imaginary" parts. */
29      private static final int NUM_PARTS = 2;
30  
31      /** Utility class. */
32      private TransformUtils() {}
33  
34      /**
35       * Multiply every component in the given real array by the
36       * given real number. The change is made in place.
37       *
38       * @param f Array to be scaled.
39       * @param d Scaling coefficient.
40       * @return a reference to the scaled array.
41       */
42      static double[] scaleInPlace(double[] f, double d) {
43          for (int i = 0; i < f.length; i++) {
44              f[i] *= d;
45          }
46          return f;
47      }
48  
49      /**
50       * Multiply every component in the given complex array by the
51       * given real number. The change is made in place.
52       *
53       * @param f Array to be scaled.
54       * @param d Scaling coefficient.
55       * @return the scaled array.
56       */
57      static Complex[] scaleInPlace(Complex[] f, double d) {
58          for (int i = 0; i < f.length; i++) {
59              f[i] = Complex.ofCartesian(d * f[i].getReal(), d * f[i].getImaginary());
60          }
61          return f;
62      }
63  
64  
65      /**
66       * Builds a new two dimensional array of {@code double} filled with the real
67       * and imaginary parts of the specified {@link Complex} numbers. In the
68       * returned array {@code dataRI}, the data is laid out as follows
69       * <ul>
70       * <li>{@code dataRI[0][i] = dataC[i].getReal()},</li>
71       * <li>{@code dataRI[1][i] = dataC[i].getImaginary()}.</li>
72       * </ul>
73       *
74       * @param dataC Array of {@link Complex} data to be transformed.
75       * @return a two dimensional array filled with the real and imaginary parts
76       * of the specified complex input.
77       */
78      static double[][] createRealImaginary(final Complex[] dataC) {
79          final double[][] dataRI = new double[2][dataC.length];
80          final double[] dataR = dataRI[0];
81          final double[] dataI = dataRI[1];
82          for (int i = 0; i < dataC.length; i++) {
83              final Complex c = dataC[i];
84              dataR[i] = c.getReal();
85              dataI[i] = c.getImaginary();
86          }
87          return dataRI;
88      }
89  
90      /**
91       * Builds a new array of {@link Complex} from the specified two dimensional
92       * array of real and imaginary parts. In the returned array {@code dataC},
93       * the data is laid out as follows
94       * <ul>
95       * <li>{@code dataC[i].getReal() = dataRI[0][i]},</li>
96       * <li>{@code dataC[i].getImaginary() = dataRI[1][i]}.</li>
97       * </ul>
98       *
99       * @param dataRI Array of real and imaginary parts to be transformed.
100      * @return a {@link Complex} array.
101      * @throws IllegalArgumentException if the number of rows of the specified
102      * array is not two, or the array is not rectangular.
103      */
104     static Complex[] createComplex(final double[][] dataRI) {
105         if (dataRI.length != NUM_PARTS) {
106             throw new TransformException(TransformException.SIZE_MISMATCH,
107                                          dataRI.length, NUM_PARTS);
108         }
109         final double[] dataR = dataRI[0];
110         final double[] dataI = dataRI[1];
111         if (dataR.length != dataI.length) {
112             throw new TransformException(TransformException.SIZE_MISMATCH,
113                                          dataI.length, dataR.length);
114         }
115 
116         final int n = dataR.length;
117         final Complex[] c = new Complex[n];
118         for (int i = 0; i < n; i++) {
119             c[i] = Complex.ofCartesian(dataR[i], dataI[i]);
120         }
121         return c;
122     }
123 
124     /**
125      * Samples the specified univariate real function on the specified interval.
126      * <p>
127      * The interval is divided equally into {@code n} sections and sample points
128      * are taken from {@code min} to {@code max - (max - min) / n}; therefore
129      * {@code f} is not sampled at the upper bound {@code max}.</p>
130      *
131      * @param f Function to be sampled
132      * @param min Lower bound of the interval (included).
133      * @param max Upper bound of the interval (excluded).
134      * @param n Number of sample points.
135      * @return the array of samples.
136      * @throws IllegalArgumentException if the lower bound {@code min} is
137      * greater than, or equal to the upper bound {@code max}, if the number
138      * of sample points {@code n} is negative.
139      */
140     static double[] sample(DoubleUnaryOperator f,
141                            double min,
142                            double max,
143                            int n) {
144         if (n <= 0) {
145             throw new TransformException(TransformException.NOT_STRICTLY_POSITIVE,
146                                          Integer.valueOf(n));
147         }
148         if (min >= max) {
149             throw new TransformException(TransformException.TOO_LARGE, min, max);
150         }
151 
152         final double[] s = new double[n];
153         final double h = (max - min) / n;
154         for (int i = 0; i < n; i++) {
155             s[i] = f.applyAsDouble(min + i * h);
156         }
157         return s;
158     }
159 }