View Javadoc
1   /*
2    * Copyright (C) 2012 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.algebra;
17  
18  import java.util.Arrays;
19  
20  /**
21   * Class containing utility methods for common operations with arrays of values.
22   */
23  @SuppressWarnings("DuplicatedCode")
24  public class ArrayUtils {
25  
26      /**
27       * Constructor.
28       */
29      private ArrayUtils() {
30      }
31  
32      /**
33       * Internal method that multiplied by scalar provided input array without
34       * comparing length of input array and result array.
35       *
36       * @param inputArray Array to be multiplied.
37       * @param scalar     Scalar used for multiplication.
38       * @param result     Array where result is stored.
39       * @see #multiplyByScalar(double[], double, double[])
40       */
41      private static void internalMultiplyByScalar(
42              final double[] inputArray, final double scalar, final double[] result) {
43          for (var i = 0; i < inputArray.length; ++i) {
44              result[i] = scalar * inputArray[i];
45          }
46      }
47  
48      /**
49       * Multiplies values in provided input array by provided scalar value
50       * and stores the result in provided result array.
51       *
52       * @param inputArray Array to be multiplied.
53       * @param scalar     Scalar used for multiplication.
54       * @param result     Array where result is stored.
55       * @throws IllegalArgumentException Thrown if inputArray length and result
56       *                                  array length are not equal.
57       */
58      public static void multiplyByScalar(final double[] inputArray, final double scalar, final double[] result) {
59          if (inputArray.length != result.length) {
60              throw new IllegalArgumentException();
61          }
62          internalMultiplyByScalar(inputArray, scalar, result);
63      }
64  
65      /**
66       * Multiplies values in provided array by provided scalar value and returns
67       * the result in a new array.
68       *
69       * @param inputArray Array to be multiplied.
70       * @param scalar     Scalar used for multiplication.
71       * @return Result obtained after multiplying input array by provided scalar
72       * value.
73       */
74      public static double[] multiplyByScalarAndReturnNew(final double[] inputArray, final double scalar) {
75          final var result = new double[inputArray.length];
76          internalMultiplyByScalar(inputArray, scalar, result);
77          return result;
78      }
79  
80      /**
81       * Sums provided operands arrays and stores the result in provided result
82       * array (i.e. result = firstOperand + secondOperand). Summation is done in
83       * an element by element basis.
84       * Provided array result must be initialized.
85       * All arrays must have the same length.
86       * This method does not check array lengths.
87       *
88       * @param firstOperand  First operand.
89       * @param secondOperand Second operand.
90       * @param result        Result of summation.
91       */
92      private static void internalSum(final double[] firstOperand, final double[] secondOperand, final double[] result) {
93          for (var i = 0; i < firstOperand.length; i++) {
94              result[i] = firstOperand[i] + secondOperand[i];
95          }
96      }
97  
98      /**
99       * Sums provided operands arrays and stores the result in provided result
100      * array (i.e. result = firstOperand + secondOperand). Summation is done
101      * in an element by element basis.
102      * Provided array result must be initialized.
103      * All arrays must have the same length.
104      *
105      * @param firstOperand  First operand.
106      * @param secondOperand Second operand.
107      * @param result        Result of summation.
108      * @throws IllegalArgumentException Raised if not all arrays have the same
109      *                                  length.
110      */
111     public static void sum(final double[] firstOperand, final double[] secondOperand, final double[] result) {
112         if (firstOperand.length != secondOperand.length || firstOperand.length != result.length) {
113             throw new IllegalArgumentException();
114         }
115         internalSum(firstOperand, secondOperand, result);
116     }
117 
118     /**
119      * Sums provided operands and returns the result as a new array instance.
120      * Summation is done in an element by element basis.
121      *
122      * @param firstOperand  First operand.
123      * @param secondOperand Second operand.
124      * @return Sum of first and second operands.
125      * @throws IllegalArgumentException Raised if first and second operands
126      *                                  arrays don't have the same length.
127      */
128     public static double[] sumAndReturnNew(final double[] firstOperand, final double[] secondOperand) {
129         if (firstOperand.length != secondOperand.length) {
130             throw new IllegalArgumentException();
131         }
132 
133         final var result = new double[firstOperand.length];
134         internalSum(firstOperand, secondOperand, result);
135         return result;
136     }
137 
138     /**
139      * Subtracts provided operands arrays and stores the result in provided
140      * result array (i.e. result = firstOperand - secondOperand). Subtraction is
141      * done in an element by element basis.
142      * Provided array result must be initialized.
143      * All arrays must have the same length.
144      * This method does not check array lengths.
145      *
146      * @param firstOperand  First operand.
147      * @param secondOperand Second operand.
148      * @param result        Result of subtraction.
149      */
150     private static void internalSubtract(
151             final double[] firstOperand, final double[] secondOperand, final double[] result) {
152         for (var i = 0; i < firstOperand.length; i++) {
153             result[i] = firstOperand[i] - secondOperand[i];
154         }
155     }
156 
157     /**
158      * Subtracts provided operands arrays and stores the result in provided
159      * result array (i.e. result = firstOperand - secondOperand). Subtraction is
160      * done in an element by element basis.
161      * Provided array result must be initialized.
162      * All arrays must have the same length.
163      *
164      * @param firstOperand  First operand.
165      * @param secondOperand Second operand.
166      * @param result        Result of subtraction.
167      * @throws IllegalArgumentException Raised if not all arrays have the same
168      *                                  length.
169      */
170     public static void subtract(final double[] firstOperand, final double[] secondOperand, final double[] result) {
171         if (firstOperand.length != secondOperand.length || firstOperand.length != result.length) {
172             throw new IllegalArgumentException();
173         }
174         internalSubtract(firstOperand, secondOperand, result);
175     }
176 
177     /**
178      * Subtracts provided operands and returns the result as a new array
179      * instance.
180      * Subtraction is done in an element by element basis.
181      *
182      * @param firstOperand  First operand
183      * @param secondOperand Second operand
184      * @return Subtraction of first and second operands
185      * @throws IllegalArgumentException Raised if first and second operands
186      *                                  arrays don't have the same length
187      */
188     public static double[] subtractAndReturnNew(final double[] firstOperand, final double[] secondOperand) {
189         if (firstOperand.length != secondOperand.length) {
190             throw new IllegalArgumentException();
191         }
192 
193         final var result = new double[firstOperand.length];
194         internalSubtract(firstOperand, secondOperand, result);
195         return result;
196     }
197 
198     /**
199      * Computes the dot product of provided arrays as the sum of the product
200      * of the elements of both arrays.
201      *
202      * @param firstOperand  First operand.
203      * @param secondOperand Second operand.
204      * @return Dot product.
205      * @throws IllegalArgumentException Raised if first and second operands
206      *                                  arrays don't have the same length.
207      */
208     public static double dotProduct(final double[] firstOperand, final double[] secondOperand) {
209         if (firstOperand.length != secondOperand.length) {
210             throw new IllegalArgumentException("both operands must have same length");
211         }
212 
213         var result = 0.0;
214         for (var i = 0; i < firstOperand.length; i++) {
215             result += firstOperand[i] * secondOperand[i];
216         }
217         return result;
218     }
219 
220     /**
221      * Computes the dot product of provided arrays as the sum of the product of
222      * the elements of both arrays.
223      *
224      * @param firstOperand   first operand.
225      * @param secondOperand  second operand.
226      * @param jacobianFirst  matrix where jacobian of first operand will be
227      *                       stored. Must be a column matrix having the same number of rows as the
228      *                       first operand length.
229      * @param jacobianSecond matrix where jacobian of second operand will be
230      *                       stored. Must be a column matrix having the same number of rows as the
231      *                       second operand length.
232      * @return dot product.
233      * @throws IllegalArgumentException if first and second operands don't have
234      *                                  the same length or if jacobian matrices are not column vectors having
235      *                                  the same length as their respective operands.
236      */
237     public static double dotProduct(final double[] firstOperand, final double[] secondOperand,
238                                     final Matrix jacobianFirst, final Matrix jacobianSecond) {
239         if (jacobianFirst != null
240                 && (jacobianFirst.getRows() != 1 || jacobianFirst.getColumns() != firstOperand.length)) {
241             throw new IllegalArgumentException("jacobian first must be a row vector having the same number of "
242                     + "columns as first operand length");
243         }
244         if (jacobianSecond != null
245                 && (jacobianSecond.getRows() != 1 || jacobianSecond.getColumns() != secondOperand.length)) {
246             throw new IllegalArgumentException("jacobian second must be a row vector having the same number of "
247                     + "columns as second operand length");
248         }
249 
250         if (jacobianFirst != null) {
251             jacobianFirst.setSubmatrix(0, 0, 0,
252                     firstOperand.length - 1, firstOperand);
253         }
254         if (jacobianSecond != null) {
255             jacobianSecond.setSubmatrix(0, 0, 0,
256                     secondOperand.length - 1, secondOperand);
257         }
258 
259         return dotProduct(firstOperand, secondOperand);
260     }
261 
262     /**
263      * Computes the angle between two vectors.
264      * The angle is defined between 0 and PI.
265      *
266      * @param firstOperand  first operand.
267      * @param secondOperand second operand.
268      * @return angle between arrays.
269      * @throws IllegalArgumentException if first and second operands don't have
270      *                                  the same length.
271      */
272     public static double angle(final double[] firstOperand, final double[] secondOperand) {
273         final var norm1 = Utils.normF(firstOperand);
274         final var norm2 = Utils.normF(secondOperand);
275         return Math.acos(Math.min(dotProduct(firstOperand, secondOperand) / norm1 / norm2, 1.0));
276     }
277 
278     //The same for Complex arrays
279 
280     /**
281      * Internal method that multiplied by scalar provided input array without
282      * comparing length of input array and result array.
283      *
284      * @param inputArray Array to be multiplied.
285      * @param scalar     Scalar used for multiplication.
286      * @param result     Array where result is stored.
287      * @see #multiplyByScalar(double[], double, double[])
288      */
289     private static void internalMultiplyByScalar(final Complex[] inputArray, final double scalar,
290                                                  final Complex[] result) {
291         for (var i = 0; i < inputArray.length; ++i) {
292             result[i].setReal(inputArray[i].getReal() * scalar);
293             result[i].setImaginary(inputArray[i].getImaginary() * scalar);
294         }
295     }
296 
297     /**
298      * Multiplies values in provided input array by provided scalar value
299      * and stores the result in provided result array.
300      *
301      * @param inputArray Array to be multiplied.
302      * @param scalar     Scalar used for multiplication.
303      * @param result     Array where result is stored.
304      * @throws IllegalArgumentException Thrown if inputArray length and result
305      *                                  array length are not equal.
306      */
307     public static void multiplyByScalar(final Complex[] inputArray, final double scalar, final Complex[] result) {
308         if (inputArray.length != result.length) {
309             throw new IllegalArgumentException();
310         }
311         internalMultiplyByScalar(inputArray, scalar, result);
312     }
313 
314     /**
315      * Multiplies values in provided array by provided scalar value and returns
316      * the result in a new array.
317      *
318      * @param inputArray Array to be multiplied.
319      * @param scalar     Scalar used for multiplication.
320      * @return Result obtained after multiplying input array by provided scalar
321      * value.
322      */
323     public static Complex[] multiplyByScalarAndReturnNew(final Complex[] inputArray, final double scalar) {
324         final var result = new Complex[inputArray.length];
325         // instantiate Complex instances in result array containing values of
326         // provided array multiplied by scalar value
327         for (var i = 0; i < inputArray.length; i++) {
328             result[i] = new Complex(inputArray[i].getReal() * scalar,
329                     inputArray[i].getImaginary() * scalar);
330         }
331         return result;
332     }
333 
334     /**
335      * Sums provided operands arrays and stores the result in provided result
336      * array (i.e. result = firstOperand + secondOperand). Summation is done in
337      * an element by element basis.
338      * Provided array result must be initialized.
339      * All arrays must have the same length.
340      * This method does not check array lengths.
341      *
342      * @param firstOperand  First operand.
343      * @param secondOperand Second operand.
344      * @param result        Result of summation.
345      */
346     private static void internalSum(final Complex[] firstOperand, final Complex[] secondOperand,
347                                     final Complex[] result) {
348         for (var i = 0; i < firstOperand.length; i++) {
349             result[i].setReal(firstOperand[i].getReal() + secondOperand[i].getReal());
350             result[i].setImaginary(firstOperand[i].getImaginary() + secondOperand[i].getImaginary());
351         }
352     }
353 
354     /**
355      * Sums provided operands arrays and stores the result in provided result
356      * array (i.e. result = firstOperand + secondOperand). Summation is done
357      * in an element by element basis.
358      * Provided array result must be initialized.
359      * All arrays must have the same length.
360      *
361      * @param firstOperand  First operand.
362      * @param secondOperand Second operand.
363      * @param result        Result of summation.
364      * @throws IllegalArgumentException Raised if not all arrays have the same
365      *                                  length.
366      */
367     public static void sum(
368             final Complex[] firstOperand, final Complex[] secondOperand, final Complex[] result) {
369         if (firstOperand.length != secondOperand.length || firstOperand.length != result.length) {
370             throw new IllegalArgumentException();
371         }
372         internalSum(firstOperand, secondOperand, result);
373     }
374 
375     /**
376      * Sums provided operands and returns the result as a new array instance.
377      * Summation is done in an element by element basis
378      *
379      * @param firstOperand  First operand
380      * @param secondOperand Second operand
381      * @return Sum of first and second operands
382      * @throws IllegalArgumentException Raised if first and second operands
383      *                                  arrays don't have the same length
384      */
385     public static Complex[] sumAndReturnNew(final Complex[] firstOperand, final Complex[] secondOperand) {
386         if (firstOperand.length != secondOperand.length) {
387             throw new IllegalArgumentException();
388         }
389 
390         final var result = new Complex[firstOperand.length];
391         // initialize each element of result matrix
392         for (var i = 0; i < firstOperand.length; i++)
393             result[i] = firstOperand[i].addAndReturnNew(secondOperand[i]);
394         return result;
395     }
396 
397     /**
398      * Subtracts provided operands arrays and stores the result in provided
399      * result array (i.e. result = firstOperand - secondOperand). Subtraction is
400      * done in an element by element basis
401      * Provided array result must be initialized.
402      * All arrays must have the same length
403      * This method does not check array lengths
404      *
405      * @param firstOperand  First operand
406      * @param secondOperand Second operand
407      * @param result        Result of subtraction
408      */
409     private static void internalSubtract(
410             final Complex[] firstOperand, final Complex[] secondOperand, final Complex[] result) {
411         for (var i = 0; i < firstOperand.length; i++) {
412             result[i].setReal(firstOperand[i].getReal() - secondOperand[i].getReal());
413             result[i].setImaginary(firstOperand[i].getImaginary() - secondOperand[i].getImaginary());
414         }
415     }
416 
417     /**
418      * Subtracts provided operands arrays and stores the result in provided
419      * result array (i.e. result = firstOperand - secondOperand). Subtraction is
420      * done in an element by element basis
421      * Provided array result must be initialized.
422      * All arrays must have the same length
423      *
424      * @param firstOperand  First operand
425      * @param secondOperand Second operand
426      * @param result        Result of subtraction
427      * @throws IllegalArgumentException Raised if not all arrays have the same
428      *                                  length
429      */
430     public static void subtract(final Complex[] firstOperand, final Complex[] secondOperand, final Complex[] result) {
431         if (firstOperand.length != secondOperand.length || firstOperand.length != result.length) {
432             throw new IllegalArgumentException();
433         }
434         internalSubtract(firstOperand, secondOperand, result);
435     }
436 
437     /**
438      * Subtracts provided operands and returns the result as a new array
439      * instance.
440      * Subtraction is done in an element by element basis
441      *
442      * @param firstOperand  First operand
443      * @param secondOperand Second operand
444      * @return Subtraction of first and second operands
445      * @throws IllegalArgumentException Raised if first and second operands
446      *                                  arrays don't have the same length
447      */
448     public static Complex[] subtractAndReturnNew(final Complex[] firstOperand, final Complex[] secondOperand) {
449         if (firstOperand.length != secondOperand.length) {
450             throw new IllegalArgumentException();
451         }
452 
453         final var result = new Complex[firstOperand.length];
454         // initialize each element of result matrix
455         for (int i = 0; i < firstOperand.length; i++) {
456             result[i] = firstOperand[i].subtractAndReturnNew(secondOperand[i]);
457         }
458         return result;
459     }
460 
461     /**
462      * Computes the dot product of provided arrays as the sum of the product
463      * of the elements of both arrays
464      *
465      * @param firstOperand  First operand
466      * @param secondOperand Second operand
467      * @return Dot product
468      * @throws IllegalArgumentException Raised if first and second operands
469      *                                  arrays don't have the same length
470      */
471     public static Complex dotProduct(final Complex[] firstOperand, final Complex[] secondOperand) {
472         if (firstOperand.length != secondOperand.length) {
473             throw new IllegalArgumentException();
474         }
475 
476         final var result = new Complex(0.0);
477         for (var i = 0; i < firstOperand.length; i++) {
478             result.add(firstOperand[i].multiplyAndReturnNew(secondOperand[i]));
479         }
480         return result;
481     }
482 
483     /**
484      * Normalizes provided array and computes corresponding jacobian.
485      *
486      * @param v        array to be normalized.
487      * @param result   array where result of normalized array will be stored.
488      * @param jacobian matrix where jacobian will be stored.
489      * @throws IllegalArgumentException if provided arrays don't have the same
490      *                                  length or if provided jacobian is not NxN, where N is length of arrays.
491      */
492     public static void normalize(final double[] v, final double[] result, final Matrix jacobian) {
493         final var s = v.length;
494 
495         if (s != result.length) {
496             throw new IllegalArgumentException("both arrays must have the same length");
497         }
498 
499         if (jacobian != null && (jacobian.getRows() != s || jacobian.getColumns() != s)) {
500             throw new IllegalArgumentException("provided jacobian is not NxN where N is length of v");
501         }
502 
503         final var n2 = dotProduct(v, v);
504         final var n = Math.sqrt(n2);
505 
506         if (jacobian != null) {
507             try {
508                 final var n3 = n * n2;
509 
510                 // VN_v = (n2*eye(s) - v*v') / n3
511                 Matrix.identity(jacobian);
512                 jacobian.multiplyByScalar(n2);
513                 jacobian.subtract(Matrix.newFromArray(v, true)
514                         .multiplyAndReturnNew(Matrix.newFromArray(v, false)));
515                 if (n3 != 0.0) {
516                     jacobian.multiplyByScalar(1.0 / n3);
517                 } else {
518                     jacobian.initialize(Double.MAX_VALUE);
519                 }
520             } catch (final WrongSizeException ignore) {
521                 // never thrown
522             }
523         }
524 
525         if (n != 0.0) {
526             internalMultiplyByScalar(v, 1.0 / n, result);
527         } else {
528             Arrays.fill(result, Double.MAX_VALUE);
529         }
530     }
531 
532     /**
533      * Normalizes provided array and computes corresponding jacobian.
534      *
535      * @param v        array to be normalized.
536      * @param jacobian matrix where jacobian will be stored.
537      * @return a new array instance containing normalized array.
538      * @throws IllegalArgumentException if provided jacobian is not NxN, where N
539      *                                  is length of arrays.
540      */
541     public static double[] normalizeAndReturnNew(final double[] v, final Matrix jacobian) {
542         final var result = new double[v.length];
543         normalize(v, result, jacobian);
544         return result;
545     }
546 
547     /**
548      * Normalizes provided array, updates its values and computes corresponding
549      * jacobian.
550      *
551      * @param v        array to be normalized and updated.
552      * @param jacobian matrix where jacobian will be stored.
553      * @throws IllegalArgumentException if provided jacobian is not NxN, where N
554      *                                  is length of arrays.
555      */
556     public static void normalize(final double[] v, final Matrix jacobian) {
557         normalize(v, v, jacobian);
558     }
559 
560     /**
561      * Normalizes provided array.
562      *
563      * @param v      array to be normalized.
564      * @param result array where result of normalized array will be stored.
565      * @throws IllegalArgumentException if provided arrays don't have the same
566      *                                  length.
567      */
568     public static void normalize(final double[] v, final double[] result) {
569         normalize(v, result, null);
570     }
571 
572     /**
573      * Normalizes provided array.
574      *
575      * @param v array to be normalized.
576      * @return a new array instance containing normalized array.
577      */
578     public static double[] normalizeAndReturnNew(final double[] v) {
579         return normalizeAndReturnNew(v, null);
580     }
581 
582     /**
583      * Normalizes provided array and updates its values.
584      *
585      * @param v array to be normalized and updated.
586      */
587     public static void normalize(final double[] v) {
588         normalize(v, (Matrix) null);
589     }
590 
591     /**
592      * Reverses the order of elements in the array.
593      *
594      * @param v      array to be reversed.
595      * @param result instance where results will be stored.
596      * @throws IllegalArgumentException if provided arrays don't have the same
597      *                                  length.
598      */
599     public static void reverse(final double[] v, final double[] result) {
600 
601         final var length = v.length;
602 
603         if (result.length != length) {
604             throw new IllegalArgumentException();
605         }
606 
607         final var halfLength = length / 2;
608         double tmp;
609         for (int i = 0, j = length - 1; i < halfLength; i++, j--) {
610             tmp = v[i];
611             result[i] = v[j];
612             result[j] = tmp;
613         }
614 
615         if (length % 2 != 0) {
616             // if length is odd, copy central value
617             result[halfLength] = v[halfLength];
618         }
619     }
620 
621     /**
622      * Reverses provided array. This method updates provided array to contain
623      * its reversed values.
624      *
625      * @param v array to be reversed.
626      */
627     public static void reverse(final double[] v) {
628         reverse(v, v);
629     }
630 
631     /**
632      * Returns a new array containing provided array having its elements in
633      * reversed order.
634      *
635      * @param v array to be reversed.
636      * @return a new instance containing reversed array.
637      */
638     public static double[] reverseAndReturnNew(final double[] v) {
639         final var result = new double[v.length];
640         reverse(v, result);
641         return result;
642     }
643 
644     /**
645      * Reverses the order of elements in the array.
646      *
647      * @param v      array to be reversed.
648      * @param result instance where results will be stored.
649      * @throws IllegalArgumentException if provided arrays don't have the same
650      *                                  length.
651      */
652     public static void reverse(final Complex[] v, final Complex[] result) {
653 
654         final var length = v.length;
655 
656         if (result.length != length) {
657             throw new IllegalArgumentException();
658         }
659 
660         final var halfLength = length / 2;
661         Complex tmp;
662         if (v != result) {
663             // for different instances, copy values
664             for (int i = 0, j = length - 1; i < halfLength; i++, j--) {
665                 tmp = new Complex(v[i]);
666                 result[i] = new Complex(v[j]);
667                 result[j] = tmp;
668             }
669 
670             if (length % 2 != 0) {
671                 // if length is odd, copy central value
672                 result[halfLength] = new Complex(v[halfLength]);
673             }
674         } else {
675             // for same instances, rearrange values
676             for (int i = 0, j = length - 1; i < halfLength; i++, j--) {
677                 tmp = v[i];
678                 result[i] = v[j];
679                 result[j] = tmp;
680             }
681 
682             if (length % 2 != 0) {
683                 // if length is odd, copy central value
684                 result[halfLength] = v[halfLength];
685             }
686         }
687     }
688 
689     /**
690      * Reverses provided array. This method updates provided array to contain
691      * its reversed values.
692      *
693      * @param v array to be reversed.
694      */
695     public static void reverse(final Complex[] v) {
696         reverse(v, v);
697     }
698 
699     /**
700      * Returns a new array containing provided array having its elements in
701      * reversed order.
702      *
703      * @param v array to be reversed.
704      * @return a new instance containing reversed array.
705      */
706     public static Complex[] reverseAndReturnNew(final Complex[] v) {
707         final var result = new Complex[v.length];
708         reverse(v, result);
709         return result;
710     }
711 
712     /**
713      * Computes the squared root of each element of provided array and sets the
714      * result into provided result array.
715      *
716      * @param v      input array to compute the squared root of each element.
717      * @param result array where results will be stored.
718      * @throws IllegalArgumentException if provided arrays don't have the same
719      *                                  length.
720      */
721     public static void sqrt(final double[] v, final double[] result) {
722         final var length = v.length;
723 
724         if (result.length != length) {
725             throw new IllegalArgumentException();
726         }
727 
728         for (int i = 0; i < length; i++) {
729             result[i] = Math.sqrt(v[i]);
730         }
731     }
732 
733     /**
734      * Computes the squared root of each element of provided array and returns
735      * the result as a new array.
736      *
737      * @param v input array to compute the squared root of each element.
738      * @return a new array containing the squared root of each element of input
739      * array.
740      */
741     public static double[] sqrtAndReturnNew(final double[] v) {
742         final var result = new double[v.length];
743         sqrt(v, result);
744         return result;
745     }
746 
747     /**
748      * Updates provided array by setting on each element its squared root.
749      *
750      * @param v input array to be updated with its squared root elements.
751      */
752     public static void sqrt(final double[] v) {
753         sqrt(v, v);
754     }
755 
756     /**
757      * Finds the minimum value into provided array.
758      *
759      * @param v   array where minimum must be found.
760      * @param pos position where minimum was found. Position will be stored at
761      *            position zero of the array, if provided.
762      * @return minimum value.
763      */
764     public static double min(final double[] v, final int[] pos) {
765         final var length = v.length;
766         var min = Double.MAX_VALUE;
767         var foundPos = -1;
768         for (int i = 0; i < length; i++) {
769             if (v[i] < min) {
770                 min = v[i];
771                 foundPos = i;
772             }
773         }
774 
775         if (pos != null && pos.length > 0) {
776             pos[0] = foundPos;
777         }
778 
779         return min;
780     }
781 
782     /**
783      * Finds the minimum value into provided array.
784      *
785      * @param v array where minimum must be found.
786      * @return minimum value.
787      */
788     public static double min(final double[] v) {
789         return min(v, null);
790     }
791 
792     /**
793      * Finds the maximum value into provided array.
794      *
795      * @param v   array where maximum must be found.
796      * @param pos position where maximum was found. Position will be stored at
797      *            position zero of the array, if provided.
798      * @return maximum value.
799      */
800     public static double max(final double[] v, final int[] pos) {
801         final var length = v.length;
802         var max = -Double.MAX_VALUE;
803         var foundPos = -1;
804         for (int i = 0; i < length; i++) {
805             if (v[i] > max) {
806                 max = v[i];
807                 foundPos = i;
808             }
809         }
810 
811         if (pos != null && pos.length > 0) {
812             pos[0] = foundPos;
813         }
814 
815         return max;
816     }
817 
818     /**
819      * Finds the maximum value into provided array.
820      *
821      * @param v array where maximum must be found.
822      * @return maximum value.
823      */
824     public static double max(final double[] v) {
825         return max(v, null);
826     }
827 
828     /**
829      * Finds the minimum and maximum values into provided array and finds their
830      * positions.
831      *
832      * @param v      array where minimum and maximum must be found.
833      * @param result array of length 2 containing found minimum and maximum
834      *               values at positions 0 and 1 respectively.
835      * @param pos    array of length 2 containing positions where minimum and
836      *               maximum where found in v array. Position 0 will contain minimum position,
837      *               position 1 will contain maximum position.
838      * @throws IllegalArgumentException if provided result or pos array don't
839      *                                  have length 2.
840      */
841     public static void minMax(final double[] v, final double[] result, final int[] pos) {
842         if (result.length != 2) {
843             throw new IllegalArgumentException("result must have length 2");
844         }
845         if (pos != null && pos.length != 2) {
846             throw new IllegalArgumentException("pos must have length 2");
847         }
848 
849         final var length = v.length;
850         var min = Double.MAX_VALUE;
851         var max = -Double.MAX_VALUE;
852         var minPos = -1;
853         var maxPos = -1;
854         for (int i = 0; i < length; i++) {
855             if (v[i] < min) {
856                 min = v[i];
857                 minPos = i;
858             }
859             if (v[i] > max) {
860                 max = v[i];
861                 maxPos = i;
862             }
863         }
864 
865         result[0] = min;
866         result[1] = max;
867         if (pos != null) {
868             pos[0] = minPos;
869             pos[1] = maxPos;
870         }
871     }
872 }