View Javadoc
1   //******************************************************************************
2   //
3   // File:    ReduceArrays.java
4   // Package: edu.rit.pj.reduction
5   // Unit:    Class edu.rit.pj.reduction.ReduceArrays
6   //
7   // This Java source file is copyright (C) 2007 by Alan Kaminsky. All rights
8   // reserved. For further information, contact the author, Alan Kaminsky, at
9   // ark@cs.rit.edu.
10  //
11  // This Java source file is part of the Parallel Java Library ("PJ"). PJ is free
12  // software; you can redistribute it and/or modify it under the terms of the GNU
13  // General Public License as published by the Free Software Foundation; either
14  // version 3 of the License, or (at your option) any later version.
15  //
16  // PJ is distributed in the hope that it will be useful, but WITHOUT ANY
17  // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18  // A PARTICULAR PURPOSE. See the GNU General Public License for more details.
19  //
20  // Linking this library statically or dynamically with other modules is making a
21  // combined work based on this library. Thus, the terms and conditions of the GNU
22  // General Public License cover the whole combination.
23  //
24  // As a special exception, the copyright holders of this library give you
25  // permission to link this library with independent modules to produce an
26  // executable, regardless of the license terms of these independent modules, and
27  // to copy and distribute the resulting executable under terms of your choice,
28  // provided that you also meet, for each linked independent module, the terms
29  // and conditions of the license of that module. An independent module is a module
30  // which is not derived from or based on this library. If you modify this library,
31  // you may extend this exception to your version of the library, but you are not
32  // obligated to do so. If you do not wish to do so, delete this exception
33  // statement from your version.
34  //
35  // A copy of the GNU General Public License is provided in the file gpl.txt. You
36  // may also obtain a copy of the GNU General Public License on the World Wide
37  // Web at http://www.gnu.org/licenses/gpl.html.
38  //
39  //******************************************************************************
40  package edu.rit.pj.reduction;
41  
42  import edu.rit.util.Range;
43  
44  /**
45   * Class ReduceArrays provides static methods for reduction operations on arrays
46   * and matrices of primitive types and object types.
47   * <P>
48   * <I>Note:</I> The operations in class ReduceArrays are not multiple thread
49   * safe.
50   *
51   * @author Alan Kaminsky
52   * @version 20-Jun-2007
53   */
54  public class ReduceArrays {
55  
56  // Prevent construction.
57      private ReduceArrays() {
58      }
59  
60  // Exported operations.
61      /**
62       * Combine a range of elements from one Boolean array with a range of
63       * elements in another Boolean array. The number of elements combined is the
64       * smaller of <code>srcRange</code>'s length and <code>dstRange</code>'s length.
65       * Either or both of <code>srcRange</code>'s and <code>dstRange</code>'s strides may
66       * be greater than 1.
67       * <P>
68       * For each destination array element <I>D</I> in the destination range and
69       * each corresponding source array element <I>S</I> in the source range,
70       * <I>D</I> is set to <I>D op S</I>.
71       *
72       * @param src Source array.
73       * @param srcRange Range of source elements.
74       * @param dst Destination array.
75       * @param dstRange Range of destination elements.
76       * @param op Binary operation.
77       * @exception NullPointerException (unchecked exception) Thrown if any
78       * argument is null.
79       * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
80       * index in <code>srcRange</code> is outside the bounds of the source array.
81       * Thrown if any index in
82       * <code>dstRange</code> is outside the bounds of the destination array.
83       */
84      public static void reduce(boolean[] src,
85              Range srcRange,
86              boolean[] dst,
87              Range dstRange,
88              BooleanOp op) {
89          int len = Math.min(srcRange.length(), dstRange.length());
90          if (len == 0) {
91              return;
92          }
93          int srcLower = srcRange.lb();
94          int dstLower = dstRange.lb();
95          int srcStride = srcRange.stride();
96          int dstStride = dstRange.stride();
97          int srcUpper = srcLower + (len - 1) * srcStride;
98          int dstUpper = dstLower + (len - 1) * dstStride;
99          if (0 > srcLower || srcUpper >= src.length) {
100             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
101                     + ", srcRange = " + srcRange);
102         }
103         if (0 > dstLower || dstUpper >= dst.length) {
104             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
105                     + ", dstRange = " + dstRange);
106         }
107         if (src != dst || srcLower > dstLower) {
108             for (int i = srcLower, j = dstLower;
109                     i <= srcUpper;
110                     i += srcStride, j += dstStride) {
111                 dst[j] = op.op(dst[j], src[i]);
112             }
113         } else if (srcLower < dstLower) {
114             for (int i = srcUpper, j = dstUpper;
115                     i >= srcLower;
116                     i -= srcStride, j -= dstStride) {
117                 dst[j] = op.op(dst[j], src[i]);
118             }
119         }
120     }
121 
122     /**
123      * Combine a range of elements from one byte array with a range of elements
124      * in another byte array. The number of elements combined is the smaller of
125      * <code>srcRange</code>'s length and <code>dstRange</code>'s length. Either or both
126      * of <code>srcRange</code>'s and <code>dstRange</code>'s strides may be greater
127      * than 1.
128      * <P>
129      * For each destination array element <I>D</I> in the destination range and
130      * each corresponding source array element <I>S</I> in the source range,
131      * <I>D</I> is set to <I>D op S</I>.
132      *
133      * @param src Source array.
134      * @param srcRange Range of source elements.
135      * @param dst Destination array.
136      * @param dstRange Range of destination elements.
137      * @param op Binary operation.
138      * @exception NullPointerException (unchecked exception) Thrown if any
139      * argument is null.
140      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
141      * index in <code>srcRange</code> is outside the bounds of the source array.
142      * Thrown if any index in
143      * <code>dstRange</code> is outside the bounds of the destination array.
144      */
145     public static void reduce(byte[] src,
146             Range srcRange,
147             byte[] dst,
148             Range dstRange,
149             ByteOp op) {
150         int len = Math.min(srcRange.length(), dstRange.length());
151         if (len == 0) {
152             return;
153         }
154         int srcLower = srcRange.lb();
155         int dstLower = dstRange.lb();
156         int srcStride = srcRange.stride();
157         int dstStride = dstRange.stride();
158         int srcUpper = srcLower + (len - 1) * srcStride;
159         int dstUpper = dstLower + (len - 1) * dstStride;
160         if (0 > srcLower || srcUpper >= src.length) {
161             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
162                     + ", srcRange = " + srcRange);
163         }
164         if (0 > dstLower || dstUpper >= dst.length) {
165             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
166                     + ", dstRange = " + dstRange);
167         }
168         if (src != dst || srcLower > dstLower) {
169             for (int i = srcLower, j = dstLower;
170                     i <= srcUpper;
171                     i += srcStride, j += dstStride) {
172                 dst[j] = op.op(dst[j], src[i]);
173             }
174         } else if (srcLower < dstLower) {
175             for (int i = srcUpper, j = dstUpper;
176                     i >= srcLower;
177                     i -= srcStride, j -= dstStride) {
178                 dst[j] = op.op(dst[j], src[i]);
179             }
180         }
181     }
182 
183     /**
184      * Combine a range of elements from one character array with a range of
185      * elements in another character array. The number of elements combined is
186      * the smaller of <code>srcRange</code>'s length and <code>dstRange</code>'s length.
187      * Either or both of <code>srcRange</code>'s and <code>dstRange</code>'s strides may
188      * be greater than 1.
189      * <P>
190      * For each destination array element <I>D</I> in the destination range and
191      * each corresponding source array element <I>S</I> in the source range,
192      * <I>D</I> is set to <I>D op S</I>.
193      *
194      * @param src Source array.
195      * @param srcRange Range of source elements.
196      * @param dst Destination array.
197      * @param dstRange Range of destination elements.
198      * @param op Binary operation.
199      * @exception NullPointerException (unchecked exception) Thrown if any
200      * argument is null.
201      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
202      * index in <code>srcRange</code> is outside the bounds of the source array.
203      * Thrown if any index in
204      * <code>dstRange</code> is outside the bounds of the destination array.
205      */
206     public static void reduce(char[] src,
207             Range srcRange,
208             char[] dst,
209             Range dstRange,
210             CharacterOp op) {
211         int len = Math.min(srcRange.length(), dstRange.length());
212         if (len == 0) {
213             return;
214         }
215         int srcLower = srcRange.lb();
216         int dstLower = dstRange.lb();
217         int srcStride = srcRange.stride();
218         int dstStride = dstRange.stride();
219         int srcUpper = srcLower + (len - 1) * srcStride;
220         int dstUpper = dstLower + (len - 1) * dstStride;
221         if (0 > srcLower || srcUpper >= src.length) {
222             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
223                     + ", srcRange = " + srcRange);
224         }
225         if (0 > dstLower || dstUpper >= dst.length) {
226             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
227                     + ", dstRange = " + dstRange);
228         }
229         if (src != dst || srcLower > dstLower) {
230             for (int i = srcLower, j = dstLower;
231                     i <= srcUpper;
232                     i += srcStride, j += dstStride) {
233                 dst[j] = op.op(dst[j], src[i]);
234             }
235         } else if (srcLower < dstLower) {
236             for (int i = srcUpper, j = dstUpper;
237                     i >= srcLower;
238                     i -= srcStride, j -= dstStride) {
239                 dst[j] = op.op(dst[j], src[i]);
240             }
241         }
242     }
243 
244     /**
245      * Combine a range of elements from one double array with a range of
246      * elements in another double array. The number of elements combined is the
247      * smaller of <code>srcRange</code>'s length and <code>dstRange</code>'s length.
248      * Either or both of <code>srcRange</code>'s and <code>dstRange</code>'s strides may
249      * be greater than 1.
250      * <P>
251      * For each destination array element <I>D</I> in the destination range and
252      * each corresponding source array element <I>S</I> in the source range,
253      * <I>D</I> is set to <I>D op S</I>.
254      *
255      * @param src Source array.
256      * @param srcRange Range of source elements.
257      * @param dst Destination array.
258      * @param dstRange Range of destination elements.
259      * @param op Binary operation.
260      * @exception NullPointerException (unchecked exception) Thrown if any
261      * argument is null.
262      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
263      * index in <code>srcRange</code> is outside the bounds of the source array.
264      * Thrown if any index in
265      * <code>dstRange</code> is outside the bounds of the destination array.
266      */
267     public static void reduce(double[] src,
268             Range srcRange,
269             double[] dst,
270             Range dstRange,
271             DoubleOp op) {
272         int len = Math.min(srcRange.length(), dstRange.length());
273         if (len == 0) {
274             return;
275         }
276         int srcLower = srcRange.lb();
277         int dstLower = dstRange.lb();
278         int srcStride = srcRange.stride();
279         int dstStride = dstRange.stride();
280         int srcUpper = srcLower + (len - 1) * srcStride;
281         int dstUpper = dstLower + (len - 1) * dstStride;
282         if (0 > srcLower || srcUpper >= src.length) {
283             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
284                     + ", srcRange = " + srcRange);
285         }
286         if (0 > dstLower || dstUpper >= dst.length) {
287             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
288                     + ", dstRange = " + dstRange);
289         }
290         if (src != dst || srcLower > dstLower) {
291             for (int i = srcLower, j = dstLower;
292                     i <= srcUpper;
293                     i += srcStride, j += dstStride) {
294                 dst[j] = op.op(dst[j], src[i]);
295             }
296         } else if (srcLower < dstLower) {
297             for (int i = srcUpper, j = dstUpper;
298                     i >= srcLower;
299                     i -= srcStride, j -= dstStride) {
300                 dst[j] = op.op(dst[j], src[i]);
301             }
302         }
303     }
304 
305     /**
306      * Combine a range of elements from one float array with a range of elements
307      * in another float array. The number of elements combined is the smaller of
308      * <code>srcRange</code>'s length and <code>dstRange</code>'s length. Either or both
309      * of <code>srcRange</code>'s and <code>dstRange</code>'s strides may be greater
310      * than 1.
311      * <P>
312      * For each destination array element <I>D</I> in the destination range and
313      * each corresponding source array element <I>S</I> in the source range,
314      * <I>D</I> is set to <I>D op S</I>.
315      *
316      * @param src Source array.
317      * @param srcRange Range of source elements.
318      * @param dst Destination array.
319      * @param dstRange Range of destination elements.
320      * @param op Binary operation.
321      * @exception NullPointerException (unchecked exception) Thrown if any
322      * argument is null.
323      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
324      * index in <code>srcRange</code> is outside the bounds of the source array.
325      * Thrown if any index in
326      * <code>dstRange</code> is outside the bounds of the destination array.
327      */
328     public static void reduce(float[] src,
329             Range srcRange,
330             float[] dst,
331             Range dstRange,
332             FloatOp op) {
333         int len = Math.min(srcRange.length(), dstRange.length());
334         if (len == 0) {
335             return;
336         }
337         int srcLower = srcRange.lb();
338         int dstLower = dstRange.lb();
339         int srcStride = srcRange.stride();
340         int dstStride = dstRange.stride();
341         int srcUpper = srcLower + (len - 1) * srcStride;
342         int dstUpper = dstLower + (len - 1) * dstStride;
343         if (0 > srcLower || srcUpper >= src.length) {
344             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
345                     + ", srcRange = " + srcRange);
346         }
347         if (0 > dstLower || dstUpper >= dst.length) {
348             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
349                     + ", dstRange = " + dstRange);
350         }
351         if (src != dst || srcLower > dstLower) {
352             for (int i = srcLower, j = dstLower;
353                     i <= srcUpper;
354                     i += srcStride, j += dstStride) {
355                 dst[j] = op.op(dst[j], src[i]);
356             }
357         } else if (srcLower < dstLower) {
358             for (int i = srcUpper, j = dstUpper;
359                     i >= srcLower;
360                     i -= srcStride, j -= dstStride) {
361                 dst[j] = op.op(dst[j], src[i]);
362             }
363         }
364     }
365 
366     /**
367      * Combine a range of elements from one integer array with a range of
368      * elements in another integer array. The number of elements combined is the
369      * smaller of <code>srcRange</code>'s length and <code>dstRange</code>'s length.
370      * Either or both of <code>srcRange</code>'s and <code>dstRange</code>'s strides may
371      * be greater than 1.
372      * <P>
373      * For each destination array element <I>D</I> in the destination range and
374      * each corresponding source array element <I>S</I> in the source range,
375      * <I>D</I> is set to <I>D op S</I>.
376      *
377      * @param src Source array.
378      * @param srcRange Range of source elements.
379      * @param dst Destination array.
380      * @param dstRange Range of destination elements.
381      * @param op Binary operation.
382      * @exception NullPointerException (unchecked exception) Thrown if any
383      * argument is null.
384      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
385      * index in <code>srcRange</code> is outside the bounds of the source array.
386      * Thrown if any index in
387      * <code>dstRange</code> is outside the bounds of the destination array.
388      */
389     public static void reduce(int[] src,
390             Range srcRange,
391             int[] dst,
392             Range dstRange,
393             IntegerOp op) {
394         int len = Math.min(srcRange.length(), dstRange.length());
395         if (len == 0) {
396             return;
397         }
398         int srcLower = srcRange.lb();
399         int dstLower = dstRange.lb();
400         int srcStride = srcRange.stride();
401         int dstStride = dstRange.stride();
402         int srcUpper = srcLower + (len - 1) * srcStride;
403         int dstUpper = dstLower + (len - 1) * dstStride;
404         if (0 > srcLower || srcUpper >= src.length) {
405             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
406                     + ", srcRange = " + srcRange);
407         }
408         if (0 > dstLower || dstUpper >= dst.length) {
409             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
410                     + ", dstRange = " + dstRange);
411         }
412         if (src != dst || srcLower > dstLower) {
413             for (int i = srcLower, j = dstLower;
414                     i <= srcUpper;
415                     i += srcStride, j += dstStride) {
416                 dst[j] = op.op(dst[j], src[i]);
417             }
418         } else if (srcLower < dstLower) {
419             for (int i = srcUpper, j = dstUpper;
420                     i >= srcLower;
421                     i -= srcStride, j -= dstStride) {
422                 dst[j] = op.op(dst[j], src[i]);
423             }
424         }
425     }
426 
427     /**
428      * Combine a range of elements from one long array with a range of elements
429      * in another long array. The number of elements combined is the smaller of
430      * <code>srcRange</code>'s length and <code>dstRange</code>'s length. Either or both
431      * of <code>srcRange</code>'s and <code>dstRange</code>'s strides may be greater
432      * than 1.
433      * <P>
434      * For each destination array element <I>D</I> in the destination range and
435      * each corresponding source array element <I>S</I> in the source range,
436      * <I>D</I> is set to <I>D op S</I>.
437      *
438      * @param src Source array.
439      * @param srcRange Range of source elements.
440      * @param dst Destination array.
441      * @param dstRange Range of destination elements.
442      * @param op Binary operation.
443      * @exception NullPointerException (unchecked exception) Thrown if any
444      * argument is null.
445      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
446      * index in <code>srcRange</code> is outside the bounds of the source array.
447      * Thrown if any index in
448      * <code>dstRange</code> is outside the bounds of the destination array.
449      */
450     public static void reduce(long[] src,
451             Range srcRange,
452             long[] dst,
453             Range dstRange,
454             LongOp op) {
455         int len = Math.min(srcRange.length(), dstRange.length());
456         if (len == 0) {
457             return;
458         }
459         int srcLower = srcRange.lb();
460         int dstLower = dstRange.lb();
461         int srcStride = srcRange.stride();
462         int dstStride = dstRange.stride();
463         int srcUpper = srcLower + (len - 1) * srcStride;
464         int dstUpper = dstLower + (len - 1) * dstStride;
465         if (0 > srcLower || srcUpper >= src.length) {
466             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
467                     + ", srcRange = " + srcRange);
468         }
469         if (0 > dstLower || dstUpper >= dst.length) {
470             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
471                     + ", dstRange = " + dstRange);
472         }
473         if (src != dst || srcLower > dstLower) {
474             for (int i = srcLower, j = dstLower;
475                     i <= srcUpper;
476                     i += srcStride, j += dstStride) {
477                 dst[j] = op.op(dst[j], src[i]);
478             }
479         } else if (srcLower < dstLower) {
480             for (int i = srcUpper, j = dstUpper;
481                     i >= srcLower;
482                     i -= srcStride, j -= dstStride) {
483                 dst[j] = op.op(dst[j], src[i]);
484             }
485         }
486     }
487 
488     /**
489      * Combine a range of elements from one short array with a range of elements
490      * in another short array. The number of elements combined is the smaller of
491      * <code>srcRange</code>'s length and <code>dstRange</code>'s length. Either or both
492      * of <code>srcRange</code>'s and <code>dstRange</code>'s strides may be greater
493      * than 1.
494      * <P>
495      * For each destination array element <I>D</I> in the destination range and
496      * each corresponding source array element <I>S</I> in the source range,
497      * <I>D</I> is set to <I>D op S</I>.
498      *
499      * @param src Source array.
500      * @param srcRange Range of source elements.
501      * @param dst Destination array.
502      * @param dstRange Range of destination elements.
503      * @param op Binary operation.
504      * @exception NullPointerException (unchecked exception) Thrown if any
505      * argument is null.
506      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
507      * index in <code>srcRange</code> is outside the bounds of the source array.
508      * Thrown if any index in
509      * <code>dstRange</code> is outside the bounds of the destination array.
510      */
511     public static void reduce(short[] src,
512             Range srcRange,
513             short[] dst,
514             Range dstRange,
515             ShortOp op) {
516         int len = Math.min(srcRange.length(), dstRange.length());
517         if (len == 0) {
518             return;
519         }
520         int srcLower = srcRange.lb();
521         int dstLower = dstRange.lb();
522         int srcStride = srcRange.stride();
523         int dstStride = dstRange.stride();
524         int srcUpper = srcLower + (len - 1) * srcStride;
525         int dstUpper = dstLower + (len - 1) * dstStride;
526         if (0 > srcLower || srcUpper >= src.length) {
527             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
528                     + ", srcRange = " + srcRange);
529         }
530         if (0 > dstLower || dstUpper >= dst.length) {
531             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
532                     + ", dstRange = " + dstRange);
533         }
534         if (src != dst || srcLower > dstLower) {
535             for (int i = srcLower, j = dstLower;
536                     i <= srcUpper;
537                     i += srcStride, j += dstStride) {
538                 dst[j] = op.op(dst[j], src[i]);
539             }
540         } else if (srcLower < dstLower) {
541             for (int i = srcUpper, j = dstUpper;
542                     i >= srcLower;
543                     i -= srcStride, j -= dstStride) {
544                 dst[j] = op.op(dst[j], src[i]);
545             }
546         }
547     }
548 
549     /**
550      * Combine a range of elements from one object array with a range of
551      * elements in another object array. The number of elements combined is the
552      * smaller of <code>srcRange</code>'s length and <code>dstRange</code>'s length.
553      * Either or both of <code>srcRange</code>'s and <code>dstRange</code>'s strides may
554      * be greater than 1.
555      * <P>
556      * For each destination array element <I>D</I> in the destination range and
557      * each corresponding source array element <I>S</I> in the source range,
558      * <I>D</I> is set to <I>D op S</I>.
559      *
560      * @param <ST> Data type that extends the destination matrix element data type.
561      * @param <DT> Destination array element data type.
562      * @param src Source array.
563      * @param srcRange Range of source elements.
564      * @param dst Destination array.
565      * @param dstRange Range of destination elements.
566      * @param op Binary operation.
567      * @exception NullPointerException (unchecked exception) Thrown if any
568      * argument is null.
569      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
570      * index in <code>srcRange</code> is outside the bounds of the source array.
571      * Thrown if any index in
572      * <code>dstRange</code> is outside the bounds of the destination array.
573      */
574     public static <DT, ST extends DT> void reduce(ST[] src,
575             Range srcRange,
576             DT[] dst,
577             Range dstRange,
578             ObjectOp<DT> op) {
579         int len = Math.min(srcRange.length(), dstRange.length());
580         if (len == 0) {
581             return;
582         }
583         int srcLower = srcRange.lb();
584         int dstLower = dstRange.lb();
585         int srcStride = srcRange.stride();
586         int dstStride = dstRange.stride();
587         int srcUpper = srcLower + (len - 1) * srcStride;
588         int dstUpper = dstLower + (len - 1) * dstStride;
589         if (0 > srcLower || srcUpper >= src.length) {
590             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src indexes = 0.." + (src.length - 1)
591                     + ", srcRange = " + srcRange);
592         }
593         if (0 > dstLower || dstUpper >= dst.length) {
594             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst indexes = 0.." + (dst.length - 1)
595                     + ", dstRange = " + dstRange);
596         }
597         if (src != dst || srcLower > dstLower) {
598             for (int i = srcLower, j = dstLower;
599                     i <= srcUpper;
600                     i += srcStride, j += dstStride) {
601                 dst[j] = op.op(dst[j], src[i]);
602             }
603         } else if (srcLower < dstLower) {
604             for (int i = srcUpper, j = dstUpper;
605                     i >= srcLower;
606                     i -= srcStride, j -= dstStride) {
607                 dst[j] = op.op(dst[j], src[i]);
608             }
609         }
610     }
611 
612     /**
613      * Combine a range of elements from one Boolean matrix with a range of
614      * elements in another Boolean matrix. The number of rows combined is the
615      * smaller of <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s
616      * length. Within each row, the number of columns combined is the smaller of
617      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
618      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
619      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
620      * that the source matrix is fully allocated; each row in the source matrix
621      * is the same length; the destination matrix is fully allocated; and each
622      * row in the destination matrix is the same length.
623      * <P>
624      * For each destination matrix element <I>D</I> in the destination row and
625      * column ranges and each corresponding source matrix element <I>S</I> in
626      * the source row and column ranges, <I>D</I> is set to <I>D op S</I>.
627      *
628      * @param src Source matrix.
629      * @param srcRowRange Range of source rows.
630      * @param srcColRange Range of source columns.
631      * @param dst Destination matrix.
632      * @param dstRowRange Range of destination rows.
633      * @param dstColRange Range of destination columns.
634      * @param op Binary operation.
635      * @exception NullPointerException (unchecked exception) Thrown if any
636      * argument is null.
637      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
638      * index in <code>srcRowRange</code> is outside the row bounds of the source
639      * matrix. Thrown if any index in
640      * <code>srcColRange</code> is outside the column bounds of the source matrix.
641      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
642      * the destination matrix. Thrown if any index in
643      * <code>dstColRange</code> is outside the column bounds of the destination
644      * matrix.
645      */
646     public static void reduce(boolean[][] src,
647             Range srcRowRange,
648             Range srcColRange,
649             boolean[][] dst,
650             Range dstRowRange,
651             Range dstColRange,
652             BooleanOp op) {
653         int len = Math.min(srcRowRange.length(), dstRowRange.length());
654         if (len == 0) {
655             return;
656         }
657         int srcRowLower = srcRowRange.lb();
658         int dstRowLower = dstRowRange.lb();
659         int srcRowStride = srcRowRange.stride();
660         int dstRowStride = dstRowRange.stride();
661         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
662         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
663         if (0 > srcRowLower || srcRowUpper >= src.length) {
664             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
665                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
666         }
667         if (0 > dstRowLower || dstRowUpper >= dst.length) {
668             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
669                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
670         }
671         if (src != dst || srcRowLower > dstRowLower) {
672             for (int i = srcRowLower, j = dstRowLower;
673                     i <= srcRowUpper;
674                     i += srcRowStride, j += dstRowStride) {
675                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
676             }
677         } else if (srcRowLower < dstRowLower) {
678             for (int i = srcRowUpper, j = dstRowUpper;
679                     i >= srcRowLower;
680                     i -= srcRowStride, j -= dstRowStride) {
681                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
682             }
683         }
684     }
685 
686     /**
687      * Combine a range of elements from one byte matrix with a range of elements
688      * in another byte matrix. The number of rows combined is the smaller of
689      * <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s length. Within
690      * each row, the number of columns combined is the smaller of
691      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
692      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
693      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
694      * that the source matrix is fully allocated; each row in the source matrix
695      * is the same length; the destination matrix is fully allocated; and each
696      * row in the destination matrix is the same length.
697      * <P>
698      * For each destination matrix element <I>D</I> in the destination row and
699      * column ranges and each corresponding source matrix element <I>S</I> in
700      * the source row and column ranges, <I>D</I> is set to <I>D op S</I>.
701      *
702      * @param src Source matrix.
703      * @param srcRowRange Range of source rows.
704      * @param srcColRange Range of source columns.
705      * @param dst Destination matrix.
706      * @param dstRowRange Range of destination rows.
707      * @param dstColRange Range of destination columns.
708      * @param op Binary operation.
709      * @exception NullPointerException (unchecked exception) Thrown if any
710      * argument is null.
711      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
712      * index in <code>srcRowRange</code> is outside the row bounds of the source
713      * matrix. Thrown if any index in
714      * <code>srcColRange</code> is outside the column bounds of the source matrix.
715      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
716      * the destination matrix. Thrown if any index in
717      * <code>dstColRange</code> is outside the column bounds of the destination
718      * matrix.
719      */
720     public static void reduce(byte[][] src,
721             Range srcRowRange,
722             Range srcColRange,
723             byte[][] dst,
724             Range dstRowRange,
725             Range dstColRange,
726             ByteOp op) {
727         int len = Math.min(srcRowRange.length(), dstRowRange.length());
728         if (len == 0) {
729             return;
730         }
731         int srcRowLower = srcRowRange.lb();
732         int dstRowLower = dstRowRange.lb();
733         int srcRowStride = srcRowRange.stride();
734         int dstRowStride = dstRowRange.stride();
735         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
736         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
737         if (0 > srcRowLower || srcRowUpper >= src.length) {
738             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
739                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
740         }
741         if (0 > dstRowLower || dstRowUpper >= dst.length) {
742             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
743                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
744         }
745         if (src != dst || srcRowLower > dstRowLower) {
746             for (int i = srcRowLower, j = dstRowLower;
747                     i <= srcRowUpper;
748                     i += srcRowStride, j += dstRowStride) {
749                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
750             }
751         } else if (srcRowLower < dstRowLower) {
752             for (int i = srcRowUpper, j = dstRowUpper;
753                     i >= srcRowLower;
754                     i -= srcRowStride, j -= dstRowStride) {
755                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
756             }
757         }
758     }
759 
760     /**
761      * Combine a range of elements from one character matrix with a range of
762      * elements in another character matrix. The number of rows combined is the
763      * smaller of <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s
764      * length. Within each row, the number of columns combined is the smaller of
765      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
766      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
767      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
768      * that the source matrix is fully allocated; each row in the source matrix
769      * is the same length; the destination matrix is fully allocated; and each
770      * row in the destination matrix is the same length.
771      * <P>
772      * For each destination matrix element <I>D</I> in the destination row and
773      * column ranges and each corresponding source matrix element <I>S</I> in
774      * the source row and column ranges, <I>D</I> is set to <I>D op S</I>.
775      *
776      * @param src Source matrix.
777      * @param srcRowRange Range of source rows.
778      * @param srcColRange Range of source columns.
779      * @param dst Destination matrix.
780      * @param dstRowRange Range of destination rows.
781      * @param dstColRange Range of destination columns.
782      * @param op Binary operation.
783      * @exception NullPointerException (unchecked exception) Thrown if any
784      * argument is null.
785      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
786      * index in <code>srcRowRange</code> is outside the row bounds of the source
787      * matrix. Thrown if any index in
788      * <code>srcColRange</code> is outside the column bounds of the source matrix.
789      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
790      * the destination matrix. Thrown if any index in
791      * <code>dstColRange</code> is outside the column bounds of the destination
792      * matrix.
793      */
794     public static void reduce(char[][] src,
795             Range srcRowRange,
796             Range srcColRange,
797             char[][] dst,
798             Range dstRowRange,
799             Range dstColRange,
800             CharacterOp op) {
801         int len = Math.min(srcRowRange.length(), dstRowRange.length());
802         if (len == 0) {
803             return;
804         }
805         int srcRowLower = srcRowRange.lb();
806         int dstRowLower = dstRowRange.lb();
807         int srcRowStride = srcRowRange.stride();
808         int dstRowStride = dstRowRange.stride();
809         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
810         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
811         if (0 > srcRowLower || srcRowUpper >= src.length) {
812             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
813                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
814         }
815         if (0 > dstRowLower || dstRowUpper >= dst.length) {
816             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
817                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
818         }
819         if (src != dst || srcRowLower > dstRowLower) {
820             for (int i = srcRowLower, j = dstRowLower;
821                     i <= srcRowUpper;
822                     i += srcRowStride, j += dstRowStride) {
823                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
824             }
825         } else if (srcRowLower < dstRowLower) {
826             for (int i = srcRowUpper, j = dstRowUpper;
827                     i >= srcRowLower;
828                     i -= srcRowStride, j -= dstRowStride) {
829                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
830             }
831         }
832     }
833 
834     /**
835      * Combine a range of elements from one double matrix with a range of
836      * elements in another double matrix. The number of rows combined is the
837      * smaller of <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s
838      * length. Within each row, the number of columns combined is the smaller of
839      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
840      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
841      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
842      * that the source matrix is fully allocated; each row in the source matrix
843      * is the same length; the destination matrix is fully allocated; and each
844      * row in the destination matrix is the same length.
845      *
846      * @param src Source matrix.
847      * @param srcRowRange Range of source rows.
848      * @param srcColRange Range of source columns.
849      * @param dst Destination matrix.
850      * @param dstRowRange Range of destination rows.
851      * @param dstColRange Range of destination columns.
852      * @param op Binary operation.
853      * @exception NullPointerException (unchecked exception) Thrown if any
854      * argument is null.
855      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
856      * index in <code>srcRowRange</code> is outside the row bounds of the source
857      * matrix. Thrown if any index in
858      * <code>srcColRange</code> is outside the column bounds of the source matrix.
859      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
860      * the destination matrix. Thrown if any index in
861      * <code>dstColRange</code> is outside the column bounds of the destination
862      * matrix.
863      */
864     public static void reduce(double[][] src,
865             Range srcRowRange,
866             Range srcColRange,
867             double[][] dst,
868             Range dstRowRange,
869             Range dstColRange,
870             DoubleOp op) {
871         int len = Math.min(srcRowRange.length(), dstRowRange.length());
872         if (len == 0) {
873             return;
874         }
875         int srcRowLower = srcRowRange.lb();
876         int dstRowLower = dstRowRange.lb();
877         int srcRowStride = srcRowRange.stride();
878         int dstRowStride = dstRowRange.stride();
879         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
880         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
881         if (0 > srcRowLower || srcRowUpper >= src.length) {
882             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
883                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
884         }
885         if (0 > dstRowLower || dstRowUpper >= dst.length) {
886             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
887                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
888         }
889         if (src != dst || srcRowLower > dstRowLower) {
890             for (int i = srcRowLower, j = dstRowLower;
891                     i <= srcRowUpper;
892                     i += srcRowStride, j += dstRowStride) {
893                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
894             }
895         } else if (srcRowLower < dstRowLower) {
896             for (int i = srcRowUpper, j = dstRowUpper;
897                     i >= srcRowLower;
898                     i -= srcRowStride, j -= dstRowStride) {
899                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
900             }
901         }
902     }
903 
904     /**
905      * Combine a range of elements from one float matrix with a range of
906      * elements in another float matrix. The number of rows combined is the
907      * smaller of <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s
908      * length. Within each row, the number of columns combined is the smaller of
909      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
910      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
911      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
912      * that the source matrix is fully allocated; each row in the source matrix
913      * is the same length; the destination matrix is fully allocated; and each
914      * row in the destination matrix is the same length.
915      * <P>
916      * For each destination matrix element <I>D</I> in the destination row and
917      * column ranges and each corresponding source matrix element <I>S</I> in
918      * the source row and column ranges, <I>D</I> is set to <I>D op S</I>.
919      *
920      * @param src Source matrix.
921      * @param srcRowRange Range of source rows.
922      * @param srcColRange Range of source columns.
923      * @param dst Destination matrix.
924      * @param dstRowRange Range of destination rows.
925      * @param dstColRange Range of destination columns.
926      * @param op Binary operation.
927      * @exception NullPointerException (unchecked exception) Thrown if any
928      * argument is null.
929      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
930      * index in <code>srcRowRange</code> is outside the row bounds of the source
931      * matrix. Thrown if any index in
932      * <code>srcColRange</code> is outside the column bounds of the source matrix.
933      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
934      * the destination matrix. Thrown if any index in
935      * <code>dstColRange</code> is outside the column bounds of the destination
936      * matrix.
937      */
938     public static void reduce(float[][] src,
939             Range srcRowRange,
940             Range srcColRange,
941             float[][] dst,
942             Range dstRowRange,
943             Range dstColRange,
944             FloatOp op) {
945         int len = Math.min(srcRowRange.length(), dstRowRange.length());
946         if (len == 0) {
947             return;
948         }
949         int srcRowLower = srcRowRange.lb();
950         int dstRowLower = dstRowRange.lb();
951         int srcRowStride = srcRowRange.stride();
952         int dstRowStride = dstRowRange.stride();
953         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
954         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
955         if (0 > srcRowLower || srcRowUpper >= src.length) {
956             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
957                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
958         }
959         if (0 > dstRowLower || dstRowUpper >= dst.length) {
960             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
961                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
962         }
963         if (src != dst || srcRowLower > dstRowLower) {
964             for (int i = srcRowLower, j = dstRowLower;
965                     i <= srcRowUpper;
966                     i += srcRowStride, j += dstRowStride) {
967                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
968             }
969         } else if (srcRowLower < dstRowLower) {
970             for (int i = srcRowUpper, j = dstRowUpper;
971                     i >= srcRowLower;
972                     i -= srcRowStride, j -= dstRowStride) {
973                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
974             }
975         }
976     }
977 
978     /**
979      * Combine a range of elements from one integer matrix with a range of
980      * elements in another integer matrix. The number of rows combined is the
981      * smaller of <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s
982      * length. Within each row, the number of columns combined is the smaller of
983      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
984      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
985      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
986      * that the source matrix is fully allocated; each row in the source matrix
987      * is the same length; the destination matrix is fully allocated; and each
988      * row in the destination matrix is the same length.
989      * <P>
990      * For each destination matrix element <I>D</I> in the destination row and
991      * column ranges and each corresponding source matrix element <I>S</I> in
992      * the source row and column ranges, <I>D</I> is set to <I>D op S</I>.
993      *
994      * @param src Source matrix.
995      * @param srcRowRange Range of source rows.
996      * @param srcColRange Range of source columns.
997      * @param dst Destination matrix.
998      * @param dstRowRange Range of destination rows.
999      * @param dstColRange Range of destination columns.
1000      * @param op Binary operation.
1001      * @exception NullPointerException (unchecked exception) Thrown if any
1002      * argument is null.
1003      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
1004      * index in <code>srcRowRange</code> is outside the row bounds of the source
1005      * matrix. Thrown if any index in
1006      * <code>srcColRange</code> is outside the column bounds of the source matrix.
1007      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
1008      * the destination matrix. Thrown if any index in
1009      * <code>dstColRange</code> is outside the column bounds of the destination
1010      * matrix.
1011      */
1012     public static void reduce(int[][] src,
1013             Range srcRowRange,
1014             Range srcColRange,
1015             int[][] dst,
1016             Range dstRowRange,
1017             Range dstColRange,
1018             IntegerOp op) {
1019         int len = Math.min(srcRowRange.length(), dstRowRange.length());
1020         if (len == 0) {
1021             return;
1022         }
1023         int srcRowLower = srcRowRange.lb();
1024         int dstRowLower = dstRowRange.lb();
1025         int srcRowStride = srcRowRange.stride();
1026         int dstRowStride = dstRowRange.stride();
1027         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
1028         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
1029         if (0 > srcRowLower || srcRowUpper >= src.length) {
1030             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
1031                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
1032         }
1033         if (0 > dstRowLower || dstRowUpper >= dst.length) {
1034             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
1035                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
1036         }
1037         if (src != dst || srcRowLower > dstRowLower) {
1038             for (int i = srcRowLower, j = dstRowLower;
1039                     i <= srcRowUpper;
1040                     i += srcRowStride, j += dstRowStride) {
1041                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
1042             }
1043         } else if (srcRowLower < dstRowLower) {
1044             for (int i = srcRowUpper, j = dstRowUpper;
1045                     i >= srcRowLower;
1046                     i -= srcRowStride, j -= dstRowStride) {
1047                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
1048             }
1049         }
1050     }
1051 
1052     /**
1053      * Combine a range of elements from one long matrix with a range of elements
1054      * in another long matrix. The number of rows combined is the smaller of
1055      * <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s length. Within
1056      * each row, the number of columns combined is the smaller of
1057      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
1058      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
1059      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
1060      * that the source matrix is fully allocated; each row in the source matrix
1061      * is the same length; the destination matrix is fully allocated; and each
1062      * row in the destination matrix is the same length.
1063      * <P>
1064      * For each destination matrix element <I>D</I> in the destination row and
1065      * column ranges and each corresponding source matrix element <I>S</I> in
1066      * the source row and column ranges, <I>D</I> is set to <I>D op S</I>.
1067      *
1068      * @param src Source matrix.
1069      * @param srcRowRange Range of source rows.
1070      * @param srcColRange Range of source columns.
1071      * @param dst Destination matrix.
1072      * @param dstRowRange Range of destination rows.
1073      * @param dstColRange Range of destination columns.
1074      * @param op Binary operation.
1075      * @exception NullPointerException (unchecked exception) Thrown if any
1076      * argument is null.
1077      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
1078      * index in <code>srcRowRange</code> is outside the row bounds of the source
1079      * matrix. Thrown if any index in
1080      * <code>srcColRange</code> is outside the column bounds of the source matrix.
1081      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
1082      * the destination matrix. Thrown if any index in
1083      * <code>dstColRange</code> is outside the column bounds of the destination
1084      * matrix.
1085      */
1086     public static void reduce(long[][] src,
1087             Range srcRowRange,
1088             Range srcColRange,
1089             long[][] dst,
1090             Range dstRowRange,
1091             Range dstColRange,
1092             LongOp op) {
1093         int len = Math.min(srcRowRange.length(), dstRowRange.length());
1094         if (len == 0) {
1095             return;
1096         }
1097         int srcRowLower = srcRowRange.lb();
1098         int dstRowLower = dstRowRange.lb();
1099         int srcRowStride = srcRowRange.stride();
1100         int dstRowStride = dstRowRange.stride();
1101         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
1102         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
1103         if (0 > srcRowLower || srcRowUpper >= src.length) {
1104             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
1105                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
1106         }
1107         if (0 > dstRowLower || dstRowUpper >= dst.length) {
1108             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
1109                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
1110         }
1111         if (src != dst || srcRowLower > dstRowLower) {
1112             for (int i = srcRowLower, j = dstRowLower;
1113                     i <= srcRowUpper;
1114                     i += srcRowStride, j += dstRowStride) {
1115                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
1116             }
1117         } else if (srcRowLower < dstRowLower) {
1118             for (int i = srcRowUpper, j = dstRowUpper;
1119                     i >= srcRowLower;
1120                     i -= srcRowStride, j -= dstRowStride) {
1121                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
1122             }
1123         }
1124     }
1125 
1126     /**
1127      * Combine a range of elements from one short matrix with a range of
1128      * elements in another short matrix. The number of rows combined is the
1129      * smaller of <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s
1130      * length. Within each row, the number of columns combined is the smaller of
1131      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
1132      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
1133      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
1134      * that the source matrix is fully allocated; each row in the source matrix
1135      * is the same length; the destination matrix is fully allocated; and each
1136      * row in the destination matrix is the same length.
1137      * <P>
1138      * For each destination matrix element <I>D</I> in the destination row and
1139      * column ranges and each corresponding source matrix element <I>S</I> in
1140      * the source row and column ranges, <I>D</I> is set to <I>D op S</I>.
1141      *
1142      * @param src Source matrix.
1143      * @param srcRowRange Range of source rows.
1144      * @param srcColRange Range of source columns.
1145      * @param dst Destination matrix.
1146      * @param dstRowRange Range of destination rows.
1147      * @param dstColRange Range of destination columns.
1148      * @param op Binary operation.
1149      * @exception NullPointerException (unchecked exception) Thrown if any
1150      * argument is null.
1151      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
1152      * index in <code>srcRowRange</code> is outside the row bounds of the source
1153      * matrix. Thrown if any index in
1154      * <code>srcColRange</code> is outside the column bounds of the source matrix.
1155      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
1156      * the destination matrix. Thrown if any index in
1157      * <code>dstColRange</code> is outside the column bounds of the destination
1158      * matrix.
1159      */
1160     public static void reduce(short[][] src,
1161             Range srcRowRange,
1162             Range srcColRange,
1163             short[][] dst,
1164             Range dstRowRange,
1165             Range dstColRange,
1166             ShortOp op) {
1167         int len = Math.min(srcRowRange.length(), dstRowRange.length());
1168         if (len == 0) {
1169             return;
1170         }
1171         int srcRowLower = srcRowRange.lb();
1172         int dstRowLower = dstRowRange.lb();
1173         int srcRowStride = srcRowRange.stride();
1174         int dstRowStride = dstRowRange.stride();
1175         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
1176         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
1177         if (0 > srcRowLower || srcRowUpper >= src.length) {
1178             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
1179                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
1180         }
1181         if (0 > dstRowLower || dstRowUpper >= dst.length) {
1182             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
1183                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
1184         }
1185         if (src != dst || srcRowLower > dstRowLower) {
1186             for (int i = srcRowLower, j = dstRowLower;
1187                     i <= srcRowUpper;
1188                     i += srcRowStride, j += dstRowStride) {
1189                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
1190             }
1191         } else if (srcRowLower < dstRowLower) {
1192             for (int i = srcRowUpper, j = dstRowUpper;
1193                     i >= srcRowLower;
1194                     i -= srcRowStride, j -= dstRowStride) {
1195                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
1196             }
1197         }
1198     }
1199 
1200     /**
1201      * Combine a range of elements from one object matrix with a range of
1202      * elements in another object matrix. The number of rows combined is the
1203      * smaller of <code>srcRowRange</code>'s length and <code>dstRowRange</code>'s
1204      * length. Within each row, the number of columns combined is the smaller of
1205      * <code>srcColRange</code>'s length and <code>dstColRange</code>'s length. Any of
1206      * <code>srcRowRange</code>'s, <code>srcColRange</code>'s, <code>dstRowRange</code>'s,
1207      * and <code>dstColRange</code>'s strides may be greater than 1. It is assumed
1208      * that the source matrix is fully allocated; each row in the source matrix
1209      * is the same length; the destination matrix is fully allocated; and each
1210      * row in the destination matrix is the same length.
1211      * <P>
1212      * For each destination matrix element <I>D</I> in the destination row and
1213      * column ranges and each corresponding source matrix element <I>S</I> in
1214      * the source row and column ranges, <I>D</I> is set to <I>D op S</I>.
1215      *
1216      * @param <ST> Data type that extends the destination matrix element data type.
1217      * @param <DT> Destination matrix element data type.
1218      * @param src Source matrix.
1219      * @param srcRowRange Range of source rows.
1220      * @param srcColRange Range of source columns.
1221      * @param dst Destination matrix.
1222      * @param dstRowRange Range of destination rows.
1223      * @param dstColRange Range of destination columns.
1224      * @param op Binary operation.
1225      * @exception NullPointerException (unchecked exception) Thrown if any
1226      * argument is null.
1227      * @exception IndexOutOfBoundsException (unchecked exception) Thrown if any
1228      * index in <code>srcRowRange</code> is outside the row bounds of the source
1229      * matrix. Thrown if any index in
1230      * <code>srcColRange</code> is outside the column bounds of the source matrix.
1231      * Thrown if any index in <code>dstRowRange</code> is outside the row bounds of
1232      * the destination matrix. Thrown if any index in
1233      * <code>dstColRange</code> is outside the column bounds of the destination
1234      * matrix.
1235      */
1236     public static <DT, ST extends DT> void reduce(ST[][] src,
1237             Range srcRowRange,
1238             Range srcColRange,
1239             DT[][] dst,
1240             Range dstRowRange,
1241             Range dstColRange,
1242             ObjectOp<DT> op) {
1243         int len = Math.min(srcRowRange.length(), dstRowRange.length());
1244         if (len == 0) {
1245             return;
1246         }
1247         int srcRowLower = srcRowRange.lb();
1248         int dstRowLower = dstRowRange.lb();
1249         int srcRowStride = srcRowRange.stride();
1250         int dstRowStride = dstRowRange.stride();
1251         int srcRowUpper = srcRowLower + (len - 1) * srcRowStride;
1252         int dstRowUpper = dstRowLower + (len - 1) * dstRowStride;
1253         if (0 > srcRowLower || srcRowUpper >= src.length) {
1254             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): src row indexes = 0.."
1255                     + (src.length - 1) + ", srcRowRange = " + srcRowRange);
1256         }
1257         if (0 > dstRowLower || dstRowUpper >= dst.length) {
1258             throw new IndexOutOfBoundsException("ReduceArrays.reduce(): dst row indexes = 0.."
1259                     + (dst.length - 1) + ", dstRowRange = " + dstRowRange);
1260         }
1261         if (src != dst || srcRowLower > dstRowLower) {
1262             for (int i = srcRowLower, j = dstRowLower;
1263                     i <= srcRowUpper;
1264                     i += srcRowStride, j += dstRowStride) {
1265                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
1266             }
1267         } else if (srcRowLower < dstRowLower) {
1268             for (int i = srcRowUpper, j = dstRowUpper;
1269                     i >= srcRowLower;
1270                     i -= srcRowStride, j -= dstRowStride) {
1271                 reduce(src[i], srcColRange, dst[j], dstColRange, op);
1272             }
1273         }
1274     }
1275 
1276 }