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 }