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}