001/*
002 A library for mathematical operations on arrays of doubles.
003
004 This file was automatically generated with a preprocessor, so that
005 similar array operations are supported on ints, longs, floats, and doubles.
006
007 Copyright (c) 1998-2013 The Regents of the University of California.
008 All rights reserved.
009
010 Permission is hereby granted, without written agreement and without
011 license or royalty fees, to use, copy, modify, and distribute this
012 software and its documentation for any purpose, provided that the above
013 copyright notice and the following two paragraphs appear in all copies
014 of this software.
015
016 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
017 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
018 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
019 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
020 SUCH DAMAGE.
021
022 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
023 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
024 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
025 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
026 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
027 ENHANCEMENTS, OR MODIFICATIONS.
028
029 PT_COPYRIGHT_VERSION_2
030 COPYRIGHTENDKEY
031
032 */
033package ptolemy.math;
034
035///////////////////////////////////////////////////////////////////
036//// DoubleArrayMath
037
038/**
039 This class provides a library for mathematical operations on double arrays.
040 unless explicitly noted otherwise, all array arguments are assumed to be
041 non-null. If a null array is passed to a method, a NullPointerException
042 will be thrown in the method or called methods.
043 @author Albert Chen, William Wu, Edward A. Lee, Jeff Tsay
044 @version $Id$
045 @since Ptolemy II 0.3
046 @Pt.ProposedRating Yellow (ctsay)
047 @Pt.AcceptedRating Yellow (ctsay)
048 */
049public class DoubleArrayMath {
050    // Protected constructor prevents construction of this class.
051    protected DoubleArrayMath() {
052    }
053
054    ///////////////////////////////////////////////////////////////////
055    ////                         public methods                    ////
056
057    /** Return a new array that is the formed by adding z to each element
058     *  of the input array.
059     */
060    public static final double[] add(double[] array, final double z) {
061        int length = array.length;
062        double[] returnValue = new double[length];
063
064        for (int i = 0; i < length; i++) {
065            returnValue[i] = array[i] + z;
066        }
067
068        return returnValue;
069    }
070
071    /** Return a new array that is the element-by-element sum of the two
072     *  input arrays.
073     *  If the lengths of both arrays are 0, return a new array of length 0.
074     *  If the two arrays do not have the same length, throw an
075     *  IllegalArgumentException.
076     */
077    public static final double[] add(final double[] array1,
078            final double[] array2) {
079        int length = _commonLength(array1, array2, "DoubleArrayMath.add");
080        double[] returnValue = new double[length];
081
082        for (int i = 0; i < length; i++) {
083            returnValue[i] = array1[i] + array2[i];
084        }
085
086        return returnValue;
087    }
088
089    /** Return a new array that is a copy of the array argument.
090     *  @param array An array of ints.
091     *  @return A new array of ints.
092     */
093    public static final double[] allocCopy(final double[] array) {
094        int elements = array.length;
095        double[] newArray = new double[elements];
096        System.arraycopy(array, 0, newArray, 0, elements);
097        return newArray;
098    }
099
100    /** Return a new array that is the result of appending array2 to the end
101     *  of array1. This method simply calls
102     *  append(array1, 0, array1.length, array2, 0, array2.length)
103     */
104    public static final double[] append(final double[] array1,
105            final double[] array2) {
106        return append(array1, 0, array1.length, array2, 0, array2.length);
107    }
108
109    /** Return a new array that is the result of appending length2
110     *  elements of array2, starting from the array2[idx2] to length1
111     *  elements of array1, starting from array1[idx1].  Appending
112     *  empty arrays is supported. In that case, the corresponding idx
113     *  may be any number. Allow System.arraycopy() to throw array
114     *  access exceptions if idx .. idx + length - 1 are not all valid
115     *  array indices, for both of the arrays.
116     *
117     *  @param array1 The first array of doubles.
118     *  @param idx1 The starting index for array1.
119     *  @param length1 The number of elements of array1 to use.
120     *  @param array2 The second array of doubles, which is appended.
121     *  @param idx2 The starting index for array2.
122     *  @param length2 The number of elements of array2 to append.
123     *  @return A new array of doubles.
124     */
125    public static final double[] append(final double[] array1, final int idx1,
126            final int length1, final double[] array2, final int idx2,
127            final int length2) {
128        double[] returnValue = new double[length1 + length2];
129
130        if (length1 > 0) {
131            System.arraycopy(array1, idx1, returnValue, 0, length1);
132        }
133
134        if (length2 > 0) {
135            System.arraycopy(array2, idx2, returnValue, length1, length2);
136        }
137
138        return returnValue;
139    }
140
141    /** Return a new array that is formed by applying an instance of a
142     *  DoubleBinaryOperation to each element in the input array
143     *  and z, using the array elements as the left operands and z
144     *  as the right operand in all cases. (op.operate(array[i], z)).
145     *  If the length of the array is 0, return a new array of length 0.
146     */
147    public static final double[] applyBinaryOperation(DoubleBinaryOperation op,
148            final double[] array, final double z) {
149        int length = array.length;
150        double[] returnValue = new double[length];
151
152        for (int i = 0; i < length; i++) {
153            returnValue[i] = op.operate(array[i], z);
154        }
155
156        return returnValue;
157    }
158
159    /** Return a new array that is formed by applying an instance of a
160     *  DoubleBinaryOperation to each element in the input array,
161     *  using z as the left operand in all cases and the array elements
162     *  as the right operands (op.operate(z, array[i])).
163     *  If the length of the array is 0, return a new array of length 0.
164     */
165    public static final double[] applyBinaryOperation(DoubleBinaryOperation op,
166            final double z, final double[] array) {
167        int length = array.length;
168        double[] returnValue = new double[length];
169
170        for (int i = 0; i < length; i++) {
171            returnValue[i] = op.operate(array[i], z);
172        }
173
174        return returnValue;
175    }
176
177    /** Return a new array that is formed by applying an instance of a
178     *  DoubleBinaryOperation to the two arrays, element by element,
179     *  using the elements of the first array as the left operands and the
180     *  elements of the second array as the right operands.
181     *  (op.operate(array[i], array2[i])).
182     *  If the lengths of both arrays are 0, return a new array of length 0.
183     *  If the two arrays do not have the same length, throw an
184     *  IllegalArgumentException.
185     */
186    public static final double[] applyBinaryOperation(DoubleBinaryOperation op,
187            final double[] array1, final double[] array2) {
188        int length = _commonLength(array1, array2,
189                "DoubleArrayMath.applyBinaryOperation");
190        double[] returnValue = new double[length];
191
192        for (int i = 0; i < length; i++) {
193            returnValue[i] = op.operate(array1[i], array2[i]);
194        }
195
196        return returnValue;
197    }
198
199    /** Return a new array that is formed by applying an instance of a
200     *  DoubleUnaryOperation to each element in the input array
201     *  (op.operate(array[i])).
202     *  If the length of the array is 0, return a new array of length 0.
203     */
204    public static final double[] applyUnaryOperation(
205            final DoubleUnaryOperation op, final double[] array) {
206        int length = array.length;
207        double[] returnValue = new double[length];
208
209        for (int i = 0; i < length; i++) {
210            returnValue[i] = op.operate(array[i]);
211        }
212
213        return returnValue;
214    }
215
216    // no need for an element-by-element division, use divide(array,
217    // 1.0 / z) instead
218
219    /** Return a new array that is the element-by-element division of
220     *  the first array by the second array (array1[i] / array2[i]).
221     *  If the lengths of both arrays are 0, return a new array of length 0.
222     *  If the two arrays do not have the same length, throw an
223     *  IllegalArgumentException.
224     *  @param array1 The first array of doubles.
225     *  @param array2 The second array of doubles.
226     *  @return A new array of doubles.
227     */
228    public static final double[] divideElements(final double[] array1,
229            final double[] array2) {
230        int length = _commonLength(array1, array2,
231                "DoubleArrayMath.divideElements");
232        double[] returnValue = new double[length];
233
234        for (int i = 0; i < length; i++) {
235            returnValue[i] = array1[i] / array2[i];
236        }
237
238        return returnValue;
239    }
240
241    /** Return a new array that is the element-by-element division of
242     *  the first array by the given value.
243     *  @param array The array of double numbers.
244     *  @param num The double scalar.
245     *  @return A new array of double numbers.
246     */
247    public static final double[] divide(double[] array, double num) {
248        double[] returnValue = new double[array.length];
249
250        for (int i = 0; i < array.length; i++) {
251            returnValue[i] = array[i] / num;
252        }
253
254        return returnValue;
255    }
256
257    /** Return the dot product of the two arrays.
258     *  If the lengths of the array are both 0, return 0.0.
259     *  If the two arrays do not have the same length, throw an
260     *  IllegalArgumentException.
261     */
262    public static final double dotProduct(final double[] array1,
263            final double[] array2) {
264        int length = _commonLength(array1, array2,
265                "DoubleArrayMath.dotProduct");
266
267        double sum = 0.0;
268
269        for (int i = 0; i < length; i++) {
270            sum += array1[i] * array2[i];
271        }
272
273        return sum;
274    }
275
276    /** Return the L2-norm of the array, that is, the square root of
277     *  the sum of the squares of the elements.
278     */
279    public static final double l2norm(final double[] array) {
280        return Math.sqrt(sumOfSquares(array));
281    }
282
283    /** Return a new array that is a copy of the argument except that
284     *  the elements are limited to lie within the specified range.
285     *  If any value is infinite, then it is replaced by either the
286     *  top or the bottom, depending on its sign.  If any element of
287     *  the array is NaN, then the corresponding element in the new
288     *  array will also be NaN. To leave either the bottom or the top
289     *  unconstrained, specify Double.NEGATIVE_INFINITY or
290     *  Double.POSITIVE_INFINITY.  <p>If the length of the array is 0,
291     *  return a new array of length 0.
292     *
293     *  @param array An array of doubles.
294     *  @param bottom The bottom limit.
295     *  @param top The top limit.
296     *  @return A new array with values in the range [bottom, top].
297     */
298    public static final double[] limit(final double[] array,
299            final double bottom, final double top) {
300        double[] returnValue = new double[array.length];
301
302        for (int i = 0; i < array.length; i++) {
303            if (array[i] > top || array[i] == Double.POSITIVE_INFINITY) {
304                returnValue[i] = top;
305            } else if (array[i] < bottom
306                    || array[i] == Double.NEGATIVE_INFINITY) {
307                returnValue[i] = bottom;
308            } else {
309                returnValue[i] = array[i];
310            }
311        }
312
313        return returnValue;
314    }
315
316    /** Return a new array that is the formed by the modulo of each element
317     *  of the input array and z (array[i] % z).
318     */
319    public static final double[] modulo(double[] array, double z) {
320        int length = array.length;
321        double[] returnValue = new double[length];
322
323        for (int i = 0; i < length; i++) {
324            returnValue[i] = array[i] % z;
325        }
326
327        return returnValue;
328    }
329
330    /** Return a new array that is the element-by-element multiplication of
331     *  the two input arrays.
332     *  If the lengths of both arrays are 0, return a new array of length 0.
333     *  If the two arrays do not have the same length, throw an
334     *  IllegalArgumentException.
335     */
336    public static final double[] multiply(final double[] array1,
337            final double[] array2) {
338        int length = _commonLength(array1, array2, "DoubleArrayMath.multiply");
339        double[] returnValue = new double[length];
340
341        for (int i = 0; i < length; i++) {
342            returnValue[i] = array1[i] * array2[i];
343        }
344
345        return returnValue;
346    }
347
348    /** Return a new array that is constructed from the argument by
349     *  multiplying each element in the array by the second argument, which is
350     *  a double.
351     *  If the sizes of the array is 0, return a new array of size 0.
352     *  @param array An array of doubles.
353     *  @param factor A double.
354     *  @return A new array of doubles.
355     */
356    public static final double[] multiply(double[] array, double factor) {
357        int length = array.length;
358        double[] returnValue = new double[length];
359
360        for (int i = 0; i < length; i++) {
361            returnValue[i] = array[i] * factor;
362        }
363
364        return returnValue;
365    }
366
367    /** Return a new array that is the formed by the additive inverse of each
368     *  element of the input array (-array[i]).
369     */
370    public static final double[] negative(final double[] array) {
371        int length = array.length;
372        double[] returnValue = new double[length];
373
374        for (int i = 0; i < length; i++) {
375            returnValue[i] = -array[i];
376        }
377
378        return returnValue;
379    }
380
381    /** Return a new array that is formed by scaling the array so that
382     *  it has a L2-norm of 1.
383     */
384    public static final double[] normalize(final double[] array) {
385        return scale(array, 1.0 / l2norm(array));
386    }
387
388    /** Return a new array of doubles that is formed by padding the
389     *  middle of the array with 0's. If either the length of the
390     *  input array is odd, the sample with index ceil(L/2) will be
391     *  repeated in the output array, where L is the length of the input array.
392     *  If the length of the input and output arrays are equal, return
393     *  a copy of the input array.
394     *  This method is useful for preparing data for an IFFT.
395     *  @param array An array of doubles.
396     *  @param newLength The desired length of the returned array.
397     *  @return A new array of doubles.
398     */
399    public static final double[] padMiddle(final double[] array,
400            final int newLength) {
401        int length = array.length;
402
403        int entriesNeeded = newLength - length;
404
405        if (entriesNeeded < 0) {
406            throw new IllegalArgumentException("ptolemy.math."
407                    + "DoubleArrayMath.padMiddle() : newLength must be "
408                    + ">= length of array.");
409        } else if (entriesNeeded == 0) {
410            return resize(array, newLength); // allocates a new array
411        }
412
413        double halfLength = length * 0.5;
414        int halfLengthFloor = (int) Math.floor(halfLength);
415        int halfLengthCeil = (int) Math.ceil(halfLength);
416        double[] returnValue = new double[newLength];
417
418        System.arraycopy(array, 0, returnValue, 0, halfLengthCeil);
419
420        System.arraycopy(array, halfLengthFloor, returnValue,
421                newLength - halfLengthCeil, halfLengthCeil);
422
423        return returnValue;
424    }
425
426    /** Return a new array of length newLength that is formed by
427     *  either truncating or padding the input array.
428     *  This method simply calls :
429     *  resize(array, newLength, 0)
430     *  @param array An array of doubles.
431     *  @param newLength The desired length of the output array.
432     *  @return A new array of doubles of length newLength.
433     */
434    public static final double[] resize(final double[] array,
435            final int newLength) {
436        return resize(array, newLength, 0);
437    }
438
439    /** Return a new array of length newLength that is formed by
440     *  either truncating or padding the input array.
441     *  Elements from the input array are copied to the output array,
442     *  starting from array[startIdx] until one of the following conditions
443     *  is met :
444     *  <ol>
445     *  <li> The input array has no more elements to copy.
446     *  <li> The output array has been completely filled.
447     *  </ol>
448     *  startIdx must index a valid entry in array unless the input array
449     *  is of zero length or the output array is of zero length.
450     *  If case 1) is met, the remainder of the output array is filled with
451     *  zero's, implicitly by Java (padding).
452     *  @param array An array of doubles.
453     *  @param newLength The desired length of the output array.
454     *  @param startIdx The starting index for the input array.
455     *  @return A new array of doubles of length newLength.
456     */
457    public static final double[] resize(double[] array, final int newLength,
458            final int startIdx) {
459        double[] returnValue = new double[newLength];
460        int copySize = Math.min(newLength, array.length - startIdx);
461
462        if (startIdx >= array.length && copySize > 0) {
463            throw new IllegalArgumentException("resize():  the start index '"
464                    + startIdx + "' is greater than equal to the array length '"
465                    + array.length + "' and the number of items to be copied '"
466                    + copySize + "' is greater than zero.");
467        }
468
469        if (copySize > 0) {
470            System.arraycopy(array, startIdx, returnValue, 0, copySize);
471        }
472
473        return returnValue;
474    }
475
476    /** Return a new array of doubles produced by scaling the input
477     *  array elements by scaleFactor.
478     *  If the length of the array is 0, return a new array of length 0.
479     */
480    public static final double[] scale(double[] array, double scaleFactor) {
481        double[] returnValue = new double[array.length];
482
483        for (int i = 0; i < array.length; i++) {
484            returnValue[i] = scaleFactor * array[i];
485        }
486
487        return returnValue;
488    }
489
490    /** Return a new array that is the element-by-element difference of the
491     *  two input arrays, i.e. the first array minus the second array
492     *  (array1[i] - array2[i]).
493     *  If the lengths of both arrays are 0, return a new array of length 0.
494     */
495    public static final double[] subtract(final double[] array1,
496            final double[] array2) {
497        int length = _commonLength(array1, array2, "DoubleArrayMath.subtract");
498        double[] returnValue = new double[length];
499
500        for (int i = 0; i < length; i++) {
501            returnValue[i] = array1[i] - array2[i];
502        }
503
504        return returnValue;
505    }
506
507    /** Return the sum of the elements in the array.
508     *  Return 0.0 if the length of the array is 0.
509     */
510    public static final double sum(double[] array) {
511        double sum = 0.0;
512
513        for (double element : array) {
514            sum += element;
515        }
516
517        return sum;
518    }
519
520    /** Return the sum of the squares of all of the elements in the array.
521     *  This is equivalent to the square of the L2-norm of the array.
522     *  Return 0.0 if the length of the array is 0.
523     */
524    public static final double sumOfSquares(double[] array) {
525        double sum = 0.0;
526
527        for (double element : array) {
528            sum += element * element;
529        }
530
531        return sum;
532    }
533
534    /** Return a new array that is formed by converting the doubles in
535     *  the argument array to complex numbers. Each complex number has
536     *  real part equal to the value in the argument array and a zero
537     *  imaginary part.
538     *
539     *  @param array An array of double.
540     *  @return A new array of complex numbers.
541     */
542    public static final Complex[] toComplexArray(final double[] array) {
543        int length = array.length;
544        Complex[] returnValue = new Complex[length];
545
546        for (int i = 0; i < length; i++) {
547            returnValue[i] = new Complex(array[i], 0.0);
548        }
549
550        return returnValue;
551    }
552
553    /** Return a new array that is formed by converting the doubles in
554     *  the argument array to doubles.  If the length of the argument
555     *  array is 0, return a new array of length 0.
556     *  @param array An array of double.
557     *  @return A new array of doubles.
558     */
559    public static final float[] toFloatArray(final double[] array) {
560        int length = array.length;
561        float[] returnValue = new float[length];
562
563        for (int i = 0; i < length; i++) {
564            returnValue[i] = (float) array[i];
565        }
566
567        return returnValue;
568    }
569
570    /** Return a new array that is formed by converting the doubles in
571     *  the argument array to integers.  If the length of the argument
572     *  array is 0, return a new array of length 0.
573     *  @param array An array of double.
574     *  @return A new array of integers.
575     */
576    public static final int[] toIntegerArray(final double[] array) {
577        int length = array.length;
578        int[] returnValue = new int[length];
579
580        for (int i = 0; i < length; i++) {
581            returnValue[i] = (int) array[i];
582        }
583
584        return returnValue;
585    }
586
587    /** Return a new array that is formed by converting the doubles in
588     *  the argument array to longs.  If the length of the argument
589     *  array is 0, return a new array of length 0.
590     *
591     *  @param array An array of double.
592     *  @return A new array of longs.
593     */
594    public static final long[] toLongArray(final double[] array) {
595        int length = array.length;
596        long[] returnValue = new long[length];
597
598        for (int i = 0; i < length; i++) {
599            returnValue[i] = (long) array[i];
600        }
601
602        return returnValue;
603    }
604
605    /** Return a new String representing the array, formatted as
606     *  in Java array initializers.
607     */
608    public static final String toString(final double[] array) {
609        return toString(array, ", ", "{", "}");
610    }
611
612    /** Return a new String representing the array, formatted as
613     *  specified by the ArrayStringFormat argument.
614     *  To get a String in the Ptolemy expression language format,
615     *  call this method with ArrayStringFormat.exprASFormat as the
616     *  format argument.
617     */
618    public static final String toString(final double[] array,
619            String elementDelimiter, String vectorBegin, String vectorEnd) {
620        int length = array.length;
621        StringBuffer sb = new StringBuffer();
622
623        sb.append(vectorBegin);
624
625        for (int i = 0; i < length; i++) {
626            sb.append(Double.toString(array[i]));
627
628            if (i < length - 1) {
629                sb.append(elementDelimiter);
630            }
631        }
632
633        sb.append(vectorEnd);
634
635        return new String(sb);
636    }
637
638    /** Return true if all the distances between corresponding elements
639     *  <i>array1</i> and <i>array2</i> are all less than or equal to
640     *  the corresponding elements in <i>maxError</i>. If both arrays
641     *  are empty, return true. If <i>maxError</i> is negative, return false.
642     *
643     *  @param array1 The first array.
644     *  @param array2 The second array.
645     *  @param maxError The threshold for the magnitude of the difference.
646     *  @return True if all the distances between corresponding elements
647     *  <i>array1</i> and <i>array2</i> are all less than or equal to
648     *  the corresponding elements in <i>maxError</i>.
649     *  @exception IllegalArgumentException If the arrays are not of the same
650     *   length.
651     */
652    public static final boolean within(final double[] array1,
653            final double[] array2, double maxError) {
654        int length = _commonLength(array1, array2, "DoubleArrayMath.within");
655
656        for (int i = 0; i < length; i++) {
657            if (array1[i] > array2[i] + maxError
658                    || array1[i] < array2[i] - maxError) {
659                return false;
660            }
661        }
662
663        return true;
664    }
665
666    /** Return true if all the distances between corresponding elements
667     *  <i>array1</i> and <i>array2</i> are all less than or equal to
668     *  the corresponding elements in <i>maxError</i>. If both arrays
669     *  are empty, return true. If any element of <i>maxError</i> is negative,
670     *  return false.
671     *
672     *  @param array1 The first array.
673     *  @param array2 The second array.
674     *  @param maxError The array of thresholds for the magnitudes of
675     *   the difference.
676     *  @return True if all the distances between corresponding elements
677     *  <i>array1</i> and <i>array2</i> are all less than or equal to
678     *  the corresponding elements in <i>maxError</i>.
679     *  @exception IllegalArgumentException If the arrays are not of the same
680     *   length.
681     */
682    public static final boolean within(final double[] array1,
683            final double[] array2, double[] maxError) {
684        int length = _commonLength(array1, array2, "DoubleArrayMath.within");
685
686        for (int i = 0; i < length; i++) {
687            if (array1[i] > array2[i] + maxError[i]
688                    || array1[i] < array2[i] - maxError[i]) {
689                return false;
690            }
691        }
692
693        return true;
694    }
695
696    ///////////////////////////////////////////////////////////////////
697    ////                         protected methods                 ////
698
699    /** Throw an exception if the two arrays are not of the same length,
700     *  or if either array is null. An exception is NOT thrown if both
701     *  arrays are of length 0. If no exception is thrown, return the common
702     *  length of the arrays.
703     *  @param array1 The first array of doubles.
704     *  @param array2 The second array of doubles.
705     *  @param methodName A String representing the method name of the caller,
706     *  without parentheses.
707     *  @return The common length of both arrays.
708     */
709    protected static final int _commonLength(final double[] array1,
710            final double[] array2, String methodName) {
711        if (array1 == null) {
712            throw new IllegalArgumentException("ptolemy.math." + methodName
713                    + "() : first input array is null.");
714        }
715
716        if (array2 == null) {
717            throw new IllegalArgumentException("ptolemy.math." + methodName
718                    + "() : second input array is null.");
719        }
720
721        if (array1.length != array2.length) {
722            throw new IllegalArgumentException("ptolemy.math." + methodName
723                    + "() : input arrays must have the same length, "
724                    + "but the first array has length " + array1.length
725                    + " and the second array has length " + array2.length
726                    + ".");
727        }
728
729        return array1.length;
730    }
731}