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 018package org.apache.commons.math4.legacy.core; 019 020import java.lang.reflect.Array; 021import java.util.Arrays; 022import java.util.Iterator; 023import java.util.TreeSet; 024 025import org.apache.commons.numbers.core.Precision; 026import org.apache.commons.math4.legacy.exception.DimensionMismatchException; 027import org.apache.commons.math4.legacy.exception.MathArithmeticException; 028import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException; 029import org.apache.commons.math4.legacy.exception.MathInternalError; 030import org.apache.commons.math4.legacy.exception.NoDataException; 031import org.apache.commons.math4.legacy.exception.NonMonotonicSequenceException; 032import org.apache.commons.math4.legacy.exception.NotANumberException; 033import org.apache.commons.math4.legacy.exception.NotPositiveException; 034import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; 035import org.apache.commons.math4.legacy.exception.NullArgumentException; 036import org.apache.commons.math4.legacy.exception.NumberIsTooLargeException; 037import org.apache.commons.math4.legacy.exception.NotFiniteNumberException; 038import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; 039import org.apache.commons.math4.core.jdkmath.JdkMath; 040 041/** 042 * Arrays utilities. 043 * 044 * @since 3.0 045 */ 046public final class MathArrays { 047 048 /** 049 * Private constructor. 050 */ 051 private MathArrays() {} 052 053 /** 054 * Real-valued function that operate on an array or a part of it. 055 * @since 3.1 056 */ 057 public interface Function { 058 /** 059 * Operates on an entire array. 060 * 061 * @param array Array to operate on. 062 * @return the result of the operation. 063 */ 064 double evaluate(double[] array); 065 /** 066 * @param array Array to operate on. 067 * @param startIndex Index of the first element to take into account. 068 * @param numElements Number of elements to take into account. 069 * @return the result of the operation. 070 */ 071 double evaluate(double[] array, 072 int startIndex, 073 int numElements); 074 } 075 076 /** 077 * Create a copy of an array scaled by a value. 078 * 079 * @param arr Array to scale. 080 * @param val Scalar. 081 * @return scaled copy of array with each entry multiplied by val. 082 * @since 3.2 083 */ 084 public static double[] scale(double val, final double[] arr) { 085 double[] newArr = new double[arr.length]; 086 for (int i = 0; i < arr.length; i++) { 087 newArr[i] = arr[i] * val; 088 } 089 return newArr; 090 } 091 092 /** 093 * <p>Multiply each element of an array by a value.</p> 094 * 095 * <p>The array is modified in place (no copy is created).</p> 096 * 097 * @param arr Array to scale 098 * @param val Scalar 099 * @since 3.2 100 */ 101 public static void scaleInPlace(double val, final double[] arr) { 102 for (int i = 0; i < arr.length; i++) { 103 arr[i] *= val; 104 } 105 } 106 107 /** 108 * Creates an array whose contents will be the element-by-element 109 * addition of the arguments. 110 * 111 * @param a First term of the addition. 112 * @param b Second term of the addition. 113 * @return a new array {@code r} where {@code r[i] = a[i] + b[i]}. 114 * @throws DimensionMismatchException if the array lengths differ. 115 * @since 3.1 116 */ 117 public static double[] ebeAdd(double[] a, double[] b) { 118 checkEqualLength(a, b); 119 120 final double[] result = a.clone(); 121 for (int i = 0; i < a.length; i++) { 122 result[i] += b[i]; 123 } 124 return result; 125 } 126 /** 127 * Creates an array whose contents will be the element-by-element 128 * subtraction of the second argument from the first. 129 * 130 * @param a First term. 131 * @param b Element to be subtracted. 132 * @return a new array {@code r} where {@code r[i] = a[i] - b[i]}. 133 * @throws DimensionMismatchException if the array lengths differ. 134 * @since 3.1 135 */ 136 public static double[] ebeSubtract(double[] a, double[] b) { 137 checkEqualLength(a, b); 138 139 final double[] result = a.clone(); 140 for (int i = 0; i < a.length; i++) { 141 result[i] -= b[i]; 142 } 143 return result; 144 } 145 /** 146 * Creates an array whose contents will be the element-by-element 147 * multiplication of the arguments. 148 * 149 * @param a First factor of the multiplication. 150 * @param b Second factor of the multiplication. 151 * @return a new array {@code r} where {@code r[i] = a[i] * b[i]}. 152 * @throws DimensionMismatchException if the array lengths differ. 153 * @since 3.1 154 */ 155 public static double[] ebeMultiply(double[] a, double[] b) { 156 checkEqualLength(a, b); 157 158 final double[] result = a.clone(); 159 for (int i = 0; i < a.length; i++) { 160 result[i] *= b[i]; 161 } 162 return result; 163 } 164 /** 165 * Creates an array whose contents will be the element-by-element 166 * division of the first argument by the second. 167 * 168 * @param a Numerator of the division. 169 * @param b Denominator of the division. 170 * @return a new array {@code r} where {@code r[i] = a[i] / b[i]}. 171 * @throws DimensionMismatchException if the array lengths differ. 172 * @since 3.1 173 */ 174 public static double[] ebeDivide(double[] a, double[] b) { 175 checkEqualLength(a, b); 176 177 final double[] result = a.clone(); 178 for (int i = 0; i < a.length; i++) { 179 result[i] /= b[i]; 180 } 181 return result; 182 } 183 184 /** 185 * Calculates the L<sub>1</sub> (sum of abs) distance between two points. 186 * 187 * @param p1 the first point 188 * @param p2 the second point 189 * @return the L<sub>1</sub> distance between the two points 190 * @throws DimensionMismatchException if the array lengths differ. 191 */ 192 public static double distance1(double[] p1, double[] p2) { 193 checkEqualLength(p1, p2); 194 double sum = 0; 195 for (int i = 0; i < p1.length; i++) { 196 sum += JdkMath.abs(p1[i] - p2[i]); 197 } 198 return sum; 199 } 200 201 /** 202 * Calculates the L<sub>1</sub> (sum of abs) distance between two points. 203 * 204 * @param p1 the first point 205 * @param p2 the second point 206 * @return the L<sub>1</sub> distance between the two points 207 * @throws DimensionMismatchException if the array lengths differ. 208 */ 209 public static int distance1(int[] p1, int[] p2) { 210 checkEqualLength(p1, p2); 211 int sum = 0; 212 for (int i = 0; i < p1.length; i++) { 213 sum += JdkMath.abs(p1[i] - p2[i]); 214 } 215 return sum; 216 } 217 218 /** 219 * Calculates the L<sub>2</sub> (Euclidean) distance between two points. 220 * 221 * @param p1 the first point 222 * @param p2 the second point 223 * @return the L<sub>2</sub> distance between the two points 224 * @throws DimensionMismatchException if the array lengths differ. 225 */ 226 public static double distance(double[] p1, double[] p2) { 227 checkEqualLength(p1, p2); 228 double sum = 0; 229 for (int i = 0; i < p1.length; i++) { 230 final double dp = p1[i] - p2[i]; 231 sum += dp * dp; 232 } 233 return JdkMath.sqrt(sum); 234 } 235 236 /** 237 * Calculates the L<sub>2</sub> (Euclidean) distance between two points. 238 * 239 * @param p1 the first point 240 * @param p2 the second point 241 * @return the L<sub>2</sub> distance between the two points 242 * @throws DimensionMismatchException if the array lengths differ. 243 */ 244 public static double distance(int[] p1, int[] p2) { 245 checkEqualLength(p1, p2); 246 double sum = 0; 247 for (int i = 0; i < p1.length; i++) { 248 final double dp = (double) p1[i] - p2[i]; 249 sum += dp * dp; 250 } 251 return JdkMath.sqrt(sum); 252 } 253 254 /** 255 * Calculates the L<sub>∞</sub> (max of abs) distance between two points. 256 * 257 * @param p1 the first point 258 * @param p2 the second point 259 * @return the L<sub>∞</sub> distance between the two points 260 * @throws DimensionMismatchException if the array lengths differ. 261 */ 262 public static double distanceInf(double[] p1, double[] p2) { 263 checkEqualLength(p1, p2); 264 double max = 0; 265 for (int i = 0; i < p1.length; i++) { 266 max = JdkMath.max(max, JdkMath.abs(p1[i] - p2[i])); 267 } 268 return max; 269 } 270 271 /** 272 * Calculates the L<sub>∞</sub> (max of abs) distance between two points. 273 * 274 * @param p1 the first point 275 * @param p2 the second point 276 * @return the L<sub>∞</sub> distance between the two points 277 * @throws DimensionMismatchException if the array lengths differ. 278 */ 279 public static int distanceInf(int[] p1, int[] p2) { 280 checkEqualLength(p1, p2); 281 int max = 0; 282 for (int i = 0; i < p1.length; i++) { 283 max = JdkMath.max(max, JdkMath.abs(p1[i] - p2[i])); 284 } 285 return max; 286 } 287 288 /** 289 * Specification of ordering direction. 290 */ 291 public enum OrderDirection { 292 /** Constant for increasing direction. */ 293 INCREASING, 294 /** Constant for decreasing direction. */ 295 DECREASING 296 } 297 298 /** 299 * Check that an array is monotonically increasing or decreasing. 300 * 301 * @param <T> the type of the elements in the specified array 302 * @param val Values. 303 * @param dir Ordering direction. 304 * @param strict Whether the order should be strict. 305 * @return {@code true} if sorted, {@code false} otherwise. 306 */ 307 public static <T extends Comparable<? super T>> boolean isMonotonic(T[] val, 308 OrderDirection dir, 309 boolean strict) { 310 T previous = val[0]; 311 final int max = val.length; 312 for (int i = 1; i < max; i++) { 313 final int comp; 314 switch (dir) { 315 case INCREASING: 316 comp = previous.compareTo(val[i]); 317 if (strict) { 318 if (comp >= 0) { 319 return false; 320 } 321 } else { 322 if (comp > 0) { 323 return false; 324 } 325 } 326 break; 327 case DECREASING: 328 comp = val[i].compareTo(previous); 329 if (strict) { 330 if (comp >= 0) { 331 return false; 332 } 333 } else { 334 if (comp > 0) { 335 return false; 336 } 337 } 338 break; 339 default: 340 // Should never happen. 341 throw new MathInternalError(); 342 } 343 344 previous = val[i]; 345 } 346 return true; 347 } 348 349 /** 350 * Check that an array is monotonically increasing or decreasing. 351 * 352 * @param val Values. 353 * @param dir Ordering direction. 354 * @param strict Whether the order should be strict. 355 * @return {@code true} if sorted, {@code false} otherwise. 356 */ 357 public static boolean isMonotonic(double[] val, OrderDirection dir, boolean strict) { 358 return checkOrder(val, dir, strict, false); 359 } 360 361 /** 362 * Check that both arrays have the same length. 363 * 364 * @param a Array. 365 * @param b Array. 366 * @param abort Whether to throw an exception if the check fails. 367 * @return {@code true} if the arrays have the same length. 368 * @throws DimensionMismatchException if the lengths differ and 369 * {@code abort} is {@code true}. 370 * @since 3.6 371 */ 372 public static boolean checkEqualLength(double[] a, 373 double[] b, 374 boolean abort) { 375 if (a.length == b.length) { 376 return true; 377 } else { 378 if (abort) { 379 throw new DimensionMismatchException(a.length, b.length); 380 } 381 return false; 382 } 383 } 384 385 /** 386 * Check that both arrays have the same length. 387 * 388 * @param a Array. 389 * @param b Array. 390 * @throws DimensionMismatchException if the lengths differ. 391 * @since 3.6 392 */ 393 public static void checkEqualLength(double[] a, 394 double[] b) { 395 checkEqualLength(a, b, true); 396 } 397 398 399 /** 400 * Check that both arrays have the same length. 401 * 402 * @param a Array. 403 * @param b Array. 404 * @param abort Whether to throw an exception if the check fails. 405 * @return {@code true} if the arrays have the same length. 406 * @throws DimensionMismatchException if the lengths differ and 407 * {@code abort} is {@code true}. 408 * @since 3.6 409 */ 410 public static boolean checkEqualLength(int[] a, 411 int[] b, 412 boolean abort) { 413 if (a.length == b.length) { 414 return true; 415 } else { 416 if (abort) { 417 throw new DimensionMismatchException(a.length, b.length); 418 } 419 return false; 420 } 421 } 422 423 /** 424 * Check that both arrays have the same length. 425 * 426 * @param a Array. 427 * @param b Array. 428 * @throws DimensionMismatchException if the lengths differ. 429 * @since 3.6 430 */ 431 public static void checkEqualLength(int[] a, 432 int[] b) { 433 checkEqualLength(a, b, true); 434 } 435 436 /** 437 * Check that the given array is sorted. 438 * 439 * @param val Values. 440 * @param dir Ordering direction. 441 * @param strict Whether the order should be strict. 442 * @param abort Whether to throw an exception if the check fails. 443 * @return {@code true} if the array is sorted. 444 * @throws NonMonotonicSequenceException if the array is not sorted 445 * and {@code abort} is {@code true}. 446 */ 447 public static boolean checkOrder(double[] val, OrderDirection dir, 448 boolean strict, boolean abort) { 449 double previous = val[0]; 450 final int max = val.length; 451 452 int index; 453 ITEM: 454 for (index = 1; index < max; index++) { 455 switch (dir) { 456 case INCREASING: 457 if (strict) { 458 if (val[index] <= previous) { 459 break ITEM; 460 } 461 } else { 462 if (val[index] < previous) { 463 break ITEM; 464 } 465 } 466 break; 467 case DECREASING: 468 if (strict) { 469 if (val[index] >= previous) { 470 break ITEM; 471 } 472 } else { 473 if (val[index] > previous) { 474 break ITEM; 475 } 476 } 477 break; 478 default: 479 // Should never happen. 480 throw new MathInternalError(); 481 } 482 483 previous = val[index]; 484 } 485 486 if (index == max) { 487 // Loop completed. 488 return true; 489 } 490 491 // Loop early exit means wrong ordering. 492 if (abort) { 493 throw new NonMonotonicSequenceException(val[index], 494 previous, 495 index, 496 dir == OrderDirection.INCREASING, 497 strict); 498 } else { 499 return false; 500 } 501 } 502 503 /** 504 * Check that the given array is sorted. 505 * 506 * @param val Values. 507 * @param dir Ordering direction. 508 * @param strict Whether the order should be strict. 509 * @throws NonMonotonicSequenceException if the array is not sorted. 510 * @since 2.2 511 */ 512 public static void checkOrder(double[] val, OrderDirection dir, boolean strict) { 513 checkOrder(val, dir, strict, true); 514 } 515 516 /** 517 * Check that the given array is sorted in strictly increasing order. 518 * 519 * @param val Values. 520 * @throws NonMonotonicSequenceException if the array is not sorted. 521 * @since 2.2 522 */ 523 public static void checkOrder(double[] val) { 524 checkOrder(val, OrderDirection.INCREASING, true); 525 } 526 527 /** 528 * Throws DimensionMismatchException if the input array is not rectangular. 529 * 530 * @param in array to be tested 531 * @throws NullArgumentException if input array is null 532 * @throws DimensionMismatchException if input array is not rectangular 533 * @since 3.1 534 */ 535 public static void checkRectangular(final long[][] in) { 536 NullArgumentException.check(in); 537 for (int i = 1; i < in.length; i++) { 538 if (in[i].length != in[0].length) { 539 throw new DimensionMismatchException( 540 LocalizedFormats.DIFFERENT_ROWS_LENGTHS, 541 in[i].length, in[0].length); 542 } 543 } 544 } 545 546 /** 547 * Check that all entries of the input array are strictly positive. 548 * 549 * @param in Array to be tested 550 * @throws NotStrictlyPositiveException if any entries of the array are not 551 * strictly positive. 552 * @since 3.1 553 */ 554 public static void checkPositive(final double[] in) { 555 for (double x : in) { 556 if (x <= 0) { 557 throw new NotStrictlyPositiveException(x); 558 } 559 } 560 } 561 562 /** 563 * Check that no entry of the input array is {@code NaN}. 564 * 565 * @param in Array to be tested. 566 * @throws NotANumberException if an entry is {@code NaN}. 567 * @since 3.4 568 */ 569 public static void checkNotNaN(final double[] in) { 570 for (double x : in) { 571 if (Double.isNaN(x)) { 572 throw new NotANumberException(); 573 } 574 } 575 } 576 577 /** 578 * Check that all the elements are real numbers. 579 * 580 * @param val Arguments. 581 * @throws NotFiniteNumberException if any values of the array is not a 582 * finite real number. 583 */ 584 public static void checkFinite(final double[] val) { 585 for (double x : val) { 586 if (!Double.isFinite(x)) { 587 throw new NotFiniteNumberException(x); 588 } 589 } 590 } 591 592 /** 593 * Check that all entries of the input array are >= 0. 594 * 595 * @param in Array to be tested 596 * @throws NotPositiveException if any array entries are less than 0. 597 * @since 3.1 598 */ 599 public static void checkNonNegative(final long[] in) { 600 for (long i : in) { 601 if (i < 0) { 602 throw new NotPositiveException(i); 603 } 604 } 605 } 606 607 /** 608 * Check all entries of the input array are >= 0. 609 * 610 * @param in Array to be tested 611 * @throws NotPositiveException if any array entries are less than 0. 612 * @since 3.1 613 */ 614 public static void checkNonNegative(final long[][] in) { 615 for (int i = 0; i < in.length; i++) { 616 for (int j = 0; j < in[i].length; j++) { 617 if (in[i][j] < 0) { 618 throw new NotPositiveException(in[i][j]); 619 } 620 } 621 } 622 } 623 624 /** 625 * Returns true iff both arguments are null or have same dimensions and all 626 * their elements are equal as defined by 627 * {@link Precision#equals(float,float)}. 628 * 629 * @param x first array 630 * @param y second array 631 * @return true if the values are both null or have same dimension 632 * and equal elements. 633 */ 634 public static boolean equals(float[] x, float[] y) { 635 if (x == null || y == null) { 636 return (x == null) == (y == null); 637 } 638 if (x.length != y.length) { 639 return false; 640 } 641 for (int i = 0; i < x.length; ++i) { 642 if (!Precision.equals(x[i], y[i])) { 643 return false; 644 } 645 } 646 return true; 647 } 648 649 /** 650 * Returns true iff both arguments are null or have same dimensions and all 651 * their elements are equal as defined by 652 * {@link Precision#equalsIncludingNaN(double,double) this method}. 653 * 654 * @param x first array 655 * @param y second array 656 * @return true if the values are both null or have same dimension and 657 * equal elements 658 * @since 2.2 659 */ 660 public static boolean equalsIncludingNaN(float[] x, float[] y) { 661 if (x == null || y == null) { 662 return (x == null) == (y == null); 663 } 664 if (x.length != y.length) { 665 return false; 666 } 667 for (int i = 0; i < x.length; ++i) { 668 if (!Precision.equalsIncludingNaN(x[i], y[i])) { 669 return false; 670 } 671 } 672 return true; 673 } 674 675 /** 676 * Returns {@code true} iff both arguments are {@code null} or have same 677 * dimensions and all their elements are equal as defined by 678 * {@link Precision#equals(double,double)}. 679 * 680 * @param x First array. 681 * @param y Second array. 682 * @return {@code true} if the values are both {@code null} or have same 683 * dimension and equal elements. 684 */ 685 public static boolean equals(double[] x, double[] y) { 686 if (x == null || y == null) { 687 return (x == null) == (y == null); 688 } 689 if (x.length != y.length) { 690 return false; 691 } 692 for (int i = 0; i < x.length; ++i) { 693 if (!Precision.equals(x[i], y[i])) { 694 return false; 695 } 696 } 697 return true; 698 } 699 700 /** 701 * Returns {@code true} iff both arguments are {@code null} or have same 702 * dimensions and all their elements are equal as defined by 703 * {@link Precision#equalsIncludingNaN(double,double) this method}. 704 * 705 * @param x First array. 706 * @param y Second array. 707 * @return {@code true} if the values are both {@code null} or have same 708 * dimension and equal elements. 709 * @since 2.2 710 */ 711 public static boolean equalsIncludingNaN(double[] x, double[] y) { 712 if (x == null || y == null) { 713 return (x == null) == (y == null); 714 } 715 if (x.length != y.length) { 716 return false; 717 } 718 for (int i = 0; i < x.length; ++i) { 719 if (!Precision.equalsIncludingNaN(x[i], y[i])) { 720 return false; 721 } 722 } 723 return true; 724 } 725 726 /** 727 * Normalizes an array to make it sum to a specified value. 728 * Returns the result of the transformation 729 * <pre> 730 * x |-> x * normalizedSum / sum 731 * </pre> 732 * applied to each non-NaN element x of the input array, where sum is the 733 * sum of the non-NaN entries in the input array. 734 * <p> 735 * Throws IllegalArgumentException if {@code normalizedSum} is infinite 736 * or NaN and ArithmeticException if the input array contains any infinite elements 737 * or sums to 0. 738 * <p> 739 * Ignores (i.e., copies unchanged to the output array) NaNs in the input array. 740 * 741 * @param values Input array to be normalized 742 * @param normalizedSum Target sum for the normalized array 743 * @return the normalized array. 744 * @throws MathArithmeticException if the input array contains infinite 745 * elements or sums to zero. 746 * @throws MathIllegalArgumentException if the target sum is infinite or {@code NaN}. 747 * @since 2.1 748 */ 749 public static double[] normalizeArray(double[] values, double normalizedSum) { 750 if (Double.isInfinite(normalizedSum)) { 751 throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_INFINITE); 752 } 753 if (Double.isNaN(normalizedSum)) { 754 throw new MathIllegalArgumentException(LocalizedFormats.NORMALIZE_NAN); 755 } 756 double sum = 0d; 757 final int len = values.length; 758 double[] out = new double[len]; 759 for (int i = 0; i < len; i++) { 760 if (Double.isInfinite(values[i])) { 761 throw new MathIllegalArgumentException(LocalizedFormats.INFINITE_ARRAY_ELEMENT, values[i], i); 762 } 763 if (!Double.isNaN(values[i])) { 764 sum += values[i]; 765 } 766 } 767 if (sum == 0) { 768 throw new MathArithmeticException(LocalizedFormats.ARRAY_SUMS_TO_ZERO); 769 } 770 final double scale = normalizedSum / sum; 771 for (int i = 0; i < len; i++) { 772 if (Double.isNaN(values[i])) { 773 out[i] = Double.NaN; 774 } else { 775 out[i] = values[i] * scale; 776 } 777 } 778 return out; 779 } 780 781 /** Build an array of elements. 782 * <p> 783 * Arrays are filled with field.getZero() 784 * 785 * @param <T> the type of the field elements 786 * @param field field to which array elements belong 787 * @param length of the array 788 * @return a new array 789 * @since 3.2 790 */ 791 public static <T> T[] buildArray(final Field<T> field, final int length) { 792 @SuppressWarnings("unchecked") // OK because field must be correct class 793 T[] array = (T[]) Array.newInstance(field.getRuntimeClass(), length); 794 Arrays.fill(array, field.getZero()); 795 return array; 796 } 797 798 /** Build a double dimension array of elements. 799 * <p> 800 * Arrays are filled with field.getZero() 801 * 802 * @param <T> the type of the field elements 803 * @param field field to which array elements belong 804 * @param rows number of rows in the array 805 * @param columns number of columns (may be negative to build partial 806 * arrays in the same way <code>new Field[rows][]</code> works) 807 * @return a new array 808 * @since 3.2 809 */ 810 @SuppressWarnings("unchecked") 811 public static <T> T[][] buildArray(final Field<T> field, final int rows, final int columns) { 812 final T[][] array; 813 if (columns < 0) { 814 T[] dummyRow = buildArray(field, 0); 815 array = (T[][]) Array.newInstance(dummyRow.getClass(), rows); 816 } else { 817 array = (T[][]) Array.newInstance(field.getRuntimeClass(), 818 rows, columns); 819 for (int i = 0; i < rows; ++i) { 820 Arrays.fill(array[i], field.getZero()); 821 } 822 } 823 return array; 824 } 825 826 /** 827 * Calculates the <a href="http://en.wikipedia.org/wiki/Convolution"> 828 * convolution</a> between two sequences. 829 * <p> 830 * The solution is obtained via straightforward computation of the 831 * convolution sum (and not via FFT). Whenever the computation needs 832 * an element that would be located at an index outside the input arrays, 833 * the value is assumed to be zero. 834 * 835 * @param x First sequence. 836 * Typically, this sequence will represent an input signal to a system. 837 * @param h Second sequence. 838 * Typically, this sequence will represent the impulse response of the system. 839 * @return the convolution of {@code x} and {@code h}. 840 * This array's length will be {@code x.length + h.length - 1}. 841 * @throws NullArgumentException if either {@code x} or {@code h} is {@code null}. 842 * @throws NoDataException if either {@code x} or {@code h} is empty. 843 * 844 * @since 3.3 845 */ 846 public static double[] convolve(double[] x, double[] h) { 847 NullArgumentException.check(x); 848 NullArgumentException.check(h); 849 850 final int xLen = x.length; 851 final int hLen = h.length; 852 853 if (xLen == 0 || hLen == 0) { 854 throw new NoDataException(); 855 } 856 857 // initialize the output array 858 final int totalLength = xLen + hLen - 1; 859 final double[] y = new double[totalLength]; 860 861 // straightforward implementation of the convolution sum 862 for (int n = 0; n < totalLength; n++) { 863 double yn = 0; 864 int k = JdkMath.max(0, n + 1 - xLen); 865 int j = n - k; 866 while (k < hLen && j >= 0) { 867 yn += x[j--] * h[k++]; 868 } 869 y[n] = yn; 870 } 871 872 return y; 873 } 874 875 /** 876 * Returns an array representing the natural number {@code n}. 877 * 878 * @param n Natural number. 879 * @return an array whose entries are the numbers 0, 1, ..., {@code n}-1. 880 * If {@code n == 0}, the returned array is empty. 881 */ 882 public static int[] natural(int n) { 883 return sequence(n, 0, 1); 884 } 885 /** 886 * Returns an array of {@code size} integers starting at {@code start}, 887 * skipping {@code stride} numbers. 888 * 889 * @param size Natural number. 890 * @param start Natural number. 891 * @param stride Natural number. 892 * @return an array whose entries are the numbers 893 * {@code start, start + stride, ..., start + (size - 1) * stride}. 894 * If {@code size == 0}, the returned array is empty. 895 * 896 * @since 3.4 897 */ 898 public static int[] sequence(int size, 899 int start, 900 int stride) { 901 final int[] a = new int[size]; 902 for (int i = 0; i < size; i++) { 903 a[i] = start + i * stride; 904 } 905 return a; 906 } 907 /** 908 * This method is used 909 * to verify that the input parameters designate a subarray of positive length. 910 * <ul> 911 * <li>returns <code>true</code> iff the parameters designate a subarray of 912 * positive length</li> 913 * <li>throws <code>MathIllegalArgumentException</code> if the array is null or 914 * or the indices are invalid</li> 915 * <li>returns <code>false</code> if the array is non-null, but 916 * <code>length</code> is 0.</li> 917 * </ul> 918 * 919 * @param values the input array 920 * @param begin index of the first array element to include 921 * @param length the number of elements to include 922 * @return true if the parameters are valid and designate a subarray of positive length 923 * @throws MathIllegalArgumentException if the indices are invalid or the array is null 924 * @since 3.3 925 */ 926 public static boolean verifyValues(final double[] values, final int begin, final int length) { 927 return verifyValues(values, begin, length, false); 928 } 929 930 /** 931 * This method is used 932 * to verify that the input parameters designate a subarray of positive length. 933 * <ul> 934 * <li>returns <code>true</code> iff the parameters designate a subarray of 935 * non-negative length</li> 936 * <li>throws <code>IllegalArgumentException</code> if the array is null or 937 * or the indices are invalid</li> 938 * <li>returns <code>false</code> if the array is non-null, but 939 * <code>length</code> is 0 unless <code>allowEmpty</code> is <code>true</code></li> 940 * </ul> 941 * 942 * @param values the input array 943 * @param begin index of the first array element to include 944 * @param length the number of elements to include 945 * @param allowEmpty if <code>true</code> then zero length arrays are allowed 946 * @return true if the parameters are valid 947 * @throws MathIllegalArgumentException if the indices are invalid or the array is null 948 * @since 3.3 949 */ 950 public static boolean verifyValues(final double[] values, final int begin, 951 final int length, final boolean allowEmpty) { 952 953 if (values == null) { 954 throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); 955 } 956 957 if (begin < 0) { 958 throw new NotPositiveException(LocalizedFormats.START_POSITION, Integer.valueOf(begin)); 959 } 960 961 if (length < 0) { 962 throw new NotPositiveException(LocalizedFormats.LENGTH, Integer.valueOf(length)); 963 } 964 965 if (begin + length > values.length) { 966 throw new NumberIsTooLargeException(LocalizedFormats.SUBARRAY_ENDS_AFTER_ARRAY_END, 967 Integer.valueOf(begin + length), Integer.valueOf(values.length), true); 968 } 969 970 return !(length == 0 && !allowEmpty); 971 } 972 973 /** 974 * This method is used 975 * to verify that the begin and length parameters designate a subarray of positive length 976 * and the weights are all non-negative, non-NaN, finite, and not all zero. 977 * <ul> 978 * <li>returns <code>true</code> iff the parameters designate a subarray of 979 * positive length and the weights array contains legitimate values.</li> 980 * <li>throws <code>IllegalArgumentException</code> if any of the following are true: 981 * <ul><li>the values array is null</li> 982 * <li>the weights array is null</li> 983 * <li>the weights array does not have the same length as the values array</li> 984 * <li>the weights array contains one or more infinite values</li> 985 * <li>the weights array contains one or more NaN values</li> 986 * <li>the weights array contains negative values</li> 987 * <li>the weights array does not contain at least one non-zero value (applies when length is non zero)</li> 988 * <li>the start and length arguments do not determine a valid array</li></ul> 989 * </li> 990 * <li>returns <code>false</code> if the array is non-null, but 991 * <code>length</code> is 0.</li> 992 * </ul> 993 * 994 * @param values the input array 995 * @param weights the weights array 996 * @param begin index of the first array element to include 997 * @param length the number of elements to include 998 * @return true if the parameters are valid and designate a subarray of positive length 999 * @throws MathIllegalArgumentException if the indices are invalid or the array is null 1000 * @since 3.3 1001 */ 1002 public static boolean verifyValues( 1003 final double[] values, 1004 final double[] weights, 1005 final int begin, 1006 final int length) { 1007 return verifyValues(values, weights, begin, length, false); 1008 } 1009 1010 /** 1011 * This method is used 1012 * to verify that the begin and length parameters designate a subarray of positive length 1013 * and the weights are all non-negative, non-NaN, finite, and not all zero. 1014 * <ul> 1015 * <li>returns <code>true</code> iff the parameters designate a subarray of 1016 * non-negative length and the weights array contains legitimate values.</li> 1017 * <li>throws <code>MathIllegalArgumentException</code> if any of the following are true: 1018 * <ul><li>the values array is null</li> 1019 * <li>the weights array is null</li> 1020 * <li>the weights array does not have the same length as the values array</li> 1021 * <li>the weights array contains one or more infinite values</li> 1022 * <li>the weights array contains one or more NaN values</li> 1023 * <li>the weights array contains negative values</li> 1024 * <li>the weights array does not contain at least one non-zero value (applies when length is non zero)</li> 1025 * <li>the start and length arguments do not determine a valid array</li></ul> 1026 * </li> 1027 * <li>returns <code>false</code> if the array is non-null, but 1028 * <code>length</code> is 0 unless <code>allowEmpty</code> is <code>true</code>.</li> 1029 * </ul> 1030 * 1031 * @param values the input array. 1032 * @param weights the weights array. 1033 * @param begin index of the first array element to include. 1034 * @param length the number of elements to include. 1035 * @param allowEmpty if {@code true} than allow zero length arrays to pass. 1036 * @return {@code true} if the parameters are valid. 1037 * @throws NullArgumentException if either of the arrays are null 1038 * @throws MathIllegalArgumentException if the array indices are not valid, 1039 * the weights array contains NaN, infinite or negative elements, or there 1040 * are no positive weights. 1041 * @since 3.3 1042 */ 1043 public static boolean verifyValues(final double[] values, final double[] weights, 1044 final int begin, final int length, final boolean allowEmpty) { 1045 1046 if (weights == null || values == null) { 1047 throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); 1048 } 1049 1050 checkEqualLength(weights, values); 1051 1052 if (length != 0) { 1053 boolean containsPositiveWeight = false; 1054 for (int i = begin; i < begin + length; i++) { 1055 final double weight = weights[i]; 1056 if (Double.isNaN(weight)) { 1057 throw new MathIllegalArgumentException(LocalizedFormats.NAN_ELEMENT_AT_INDEX, Integer.valueOf(i)); 1058 } 1059 if (Double.isInfinite(weight)) { 1060 throw new MathIllegalArgumentException(LocalizedFormats.INFINITE_ARRAY_ELEMENT, 1061 Double.valueOf(weight), Integer.valueOf(i)); 1062 } 1063 if (weight < 0) { 1064 throw new MathIllegalArgumentException(LocalizedFormats.NEGATIVE_ELEMENT_AT_INDEX, 1065 Integer.valueOf(i), Double.valueOf(weight)); 1066 } 1067 if (!containsPositiveWeight && weight > 0.0) { 1068 containsPositiveWeight = true; 1069 } 1070 } 1071 1072 if (!containsPositiveWeight) { 1073 throw new MathIllegalArgumentException(LocalizedFormats.WEIGHT_AT_LEAST_ONE_NON_ZERO); 1074 } 1075 } 1076 1077 return verifyValues(values, begin, length, allowEmpty); 1078 } 1079 1080 /** 1081 * Concatenates a sequence of arrays. The return array consists of the 1082 * entries of the input arrays concatenated in the order they appear in 1083 * the argument list. Null arrays cause NullPointerExceptions; zero 1084 * length arrays are allowed (contributing nothing to the output array). 1085 * 1086 * @param x list of double[] arrays to concatenate 1087 * @return a new array consisting of the entries of the argument arrays 1088 * @throws NullPointerException if any of the arrays are null 1089 * @since 3.6 1090 */ 1091 public static double[] concatenate(double[]... x) { 1092 int combinedLength = 0; 1093 for (double[] a : x) { 1094 combinedLength += a.length; 1095 } 1096 int offset = 0; 1097 int curLength = 0; 1098 final double[] combined = new double[combinedLength]; 1099 for (int i = 0; i < x.length; i++) { 1100 curLength = x[i].length; 1101 System.arraycopy(x[i], 0, combined, offset, curLength); 1102 offset += curLength; 1103 } 1104 return combined; 1105 } 1106 1107 /** 1108 * Returns an array consisting of the unique values in {@code data}. 1109 * The return array is sorted in descending order. Empty arrays 1110 * are allowed, but null arrays result in NullPointerException. 1111 * Infinities are allowed. NaN values are allowed with maximum 1112 * sort order - i.e., if there are NaN values in {@code data}, 1113 * {@code Double.NaN} will be the first element of the output array, 1114 * even if the array also contains {@code Double.POSITIVE_INFINITY}. 1115 * 1116 * @param data array to scan 1117 * @return descending list of values included in the input array 1118 * @throws NullPointerException if data is null 1119 * @since 3.6 1120 */ 1121 public static double[] unique(double[] data) { 1122 TreeSet<Double> values = new TreeSet<>(); 1123 for (int i = 0; i < data.length; i++) { 1124 values.add(data[i]); 1125 } 1126 final int count = values.size(); 1127 final double[] out = new double[count]; 1128 Iterator<Double> iterator = values.descendingIterator(); 1129 int i = 0; 1130 while (iterator.hasNext()) { 1131 out[i++] = iterator.next(); 1132 } 1133 return out; 1134 } 1135}