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    package org.apache.commons.math3.transform;
018    
019    import java.util.Arrays;
020    
021    import org.apache.commons.math3.complex.Complex;
022    import org.apache.commons.math3.exception.DimensionMismatchException;
023    import org.apache.commons.math3.exception.MathIllegalArgumentException;
024    import org.apache.commons.math3.exception.util.LocalizedFormats;
025    
026    /**
027     * Useful functions for the implementation of various transforms.
028     *
029     * @version $Id: TransformUtils.java 1385310 2012-09-16 16:32:10Z tn $
030     * @since 3.0
031     */
032    public class TransformUtils {
033        /**
034         * Table of the powers of 2 to facilitate binary search lookup.
035         *
036         * @see #exactLog2(int)
037         */
038        private static final int[] POWERS_OF_TWO = {
039            0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020,
040            0x00000040, 0x00000080, 0x00000100, 0x00000200, 0x00000400, 0x00000800,
041            0x00001000, 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000,
042            0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000,
043            0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
044            0x40000000
045        };
046    
047        /** Private constructor. */
048        private TransformUtils() {
049            super();
050        }
051    
052        /**
053         * Multiply every component in the given real array by the
054         * given real number. The change is made in place.
055         *
056         * @param f the real array to be scaled
057         * @param d the real scaling coefficient
058         * @return a reference to the scaled array
059         */
060        public static double[] scaleArray(double[] f, double d) {
061    
062            for (int i = 0; i < f.length; i++) {
063                f[i] *= d;
064            }
065            return f;
066        }
067    
068        /**
069         * Multiply every component in the given complex array by the
070         * given real number. The change is made in place.
071         *
072         * @param f the complex array to be scaled
073         * @param d the real scaling coefficient
074         * @return a reference to the scaled array
075         */
076        public static Complex[] scaleArray(Complex[] f, double d) {
077    
078            for (int i = 0; i < f.length; i++) {
079                f[i] = new Complex(d * f[i].getReal(), d * f[i].getImaginary());
080            }
081            return f;
082        }
083    
084    
085        /**
086         * Builds a new two dimensional array of {@code double} filled with the real
087         * and imaginary parts of the specified {@link Complex} numbers. In the
088         * returned array {@code dataRI}, the data is laid out as follows
089         * <ul>
090         * <li>{@code dataRI[0][i] = dataC[i].getReal()},</li>
091         * <li>{@code dataRI[1][i] = dataC[i].getImaginary()}.</li>
092         * </ul>
093         *
094         * @param dataC the array of {@link Complex} data to be transformed
095         * @return a two dimensional array filled with the real and imaginary parts
096         *   of the specified complex input
097         */
098        public static double[][] createRealImaginaryArray(final Complex[] dataC) {
099            final double[][] dataRI = new double[2][dataC.length];
100            final double[] dataR = dataRI[0];
101            final double[] dataI = dataRI[1];
102            for (int i = 0; i < dataC.length; i++) {
103                final Complex c = dataC[i];
104                dataR[i] = c.getReal();
105                dataI[i] = c.getImaginary();
106            }
107            return dataRI;
108        }
109    
110        /**
111         * Builds a new array of {@link Complex} from the specified two dimensional
112         * array of real and imaginary parts. In the returned array {@code dataC},
113         * the data is laid out as follows
114         * <ul>
115         * <li>{@code dataC[i].getReal() = dataRI[0][i]},</li>
116         * <li>{@code dataC[i].getImaginary() = dataRI[1][i]}.</li>
117         * </ul>
118         *
119         * @param dataRI the array of real and imaginary parts to be transformed
120         * @return an array of {@link Complex} with specified real and imaginary parts.
121         * @throws DimensionMismatchException if the number of rows of the specified
122         *   array is not two, or the array is not rectangular
123         */
124        public static Complex[] createComplexArray(final double[][] dataRI)
125            throws DimensionMismatchException{
126    
127            if (dataRI.length != 2) {
128                throw new DimensionMismatchException(dataRI.length, 2);
129            }
130            final double[] dataR = dataRI[0];
131            final double[] dataI = dataRI[1];
132            if (dataR.length != dataI.length) {
133                throw new DimensionMismatchException(dataI.length, dataR.length);
134            }
135    
136            final int n = dataR.length;
137            final Complex[] c = new Complex[n];
138            for (int i = 0; i < n; i++) {
139                c[i] = new Complex(dataR[i], dataI[i]);
140            }
141            return c;
142        }
143    
144    
145        /**
146         * Returns the base-2 logarithm of the specified {@code int}. Throws an
147         * exception if {@code n} is not a power of two.
148         *
149         * @param n the {@code int} whose base-2 logarithm is to be evaluated
150         * @return the base-2 logarithm of {@code n}
151         * @throws MathIllegalArgumentException if {@code n} is not a power of two
152         */
153        public static int exactLog2(final int n)
154            throws MathIllegalArgumentException {
155    
156            int index = Arrays.binarySearch(TransformUtils.POWERS_OF_TWO, n);
157            if (index < 0) {
158                throw new MathIllegalArgumentException(
159                        LocalizedFormats.NOT_POWER_OF_TWO_CONSIDER_PADDING,
160                        Integer.valueOf(n));
161            }
162            return index;
163        }
164    }