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