1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.dishevelled.matrix.impl;
25
26 import java.util.Iterator;
27 import java.util.NoSuchElementException;
28
29 import org.dishevelled.functor.UnaryFunction;
30 import org.dishevelled.functor.UnaryPredicate;
31 import org.dishevelled.functor.UnaryProcedure;
32 import org.dishevelled.functor.BinaryFunction;
33 import org.dishevelled.functor.QuaternaryPredicate;
34 import org.dishevelled.functor.QuaternaryProcedure;
35
36 import org.dishevelled.matrix.BitMatrix3D;
37 import org.dishevelled.matrix.Matrix2D;
38 import org.dishevelled.matrix.Matrix3D;
39
40
41
42
43
44
45
46 abstract class AbstractMatrix3D<E>
47 implements Matrix3D<E>
48 {
49
50 protected long slices;
51
52
53 protected long rows;
54
55
56 protected long columns;
57
58
59 protected long sliceZero;
60
61
62 protected long rowZero;
63
64
65 protected long columnZero;
66
67
68 protected long sliceStride;
69
70
71 protected long rowStride;
72
73
74 protected long columnStride;
75
76
77 protected boolean isView;
78
79
80
81
82
83 protected AbstractMatrix3D()
84 {
85
86 }
87
88
89
90
91
92
93
94
95
96
97
98 protected AbstractMatrix3D(final long slices,
99 final long rows,
100 final long columns)
101 {
102
103 this.slices = slices;
104 this.rows = rows;
105 this.columns = columns;
106 this.sliceZero = 0L;
107 this.rowZero = 0L;
108 this.columnZero = 0L;
109 this.sliceStride = rows * columns;
110 this.rowStride = columns;
111 this.columnStride = 1L;
112 this.isView = false;
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 protected AbstractMatrix3D(final long slices,
130 final long rows,
131 final long columns,
132 final long sliceZero,
133 final long rowZero,
134 final long columnZero,
135 final long sliceStride,
136 final long rowStride,
137 final long columnStride,
138 final boolean isView)
139 {
140 this.slices = slices;
141 this.rows = rows;
142 this.columns = columns;
143 this.sliceZero = sliceZero;
144 this.rowZero = rowZero;
145 this.columnZero = columnZero;
146 this.sliceStride = sliceStride;
147 this.rowStride = rowStride;
148 this.columnStride = columnStride;
149 this.isView = isView;
150 }
151
152
153
154 public long size()
155 {
156 return (slices * rows * columns);
157 }
158
159
160 public long slices()
161 {
162 return slices;
163 }
164
165
166 public long rows()
167 {
168 return rows;
169 }
170
171
172 public long columns()
173 {
174 return columns;
175 }
176
177
178 public long cardinality()
179 {
180 long cardinality = 0;
181 for (E e : this)
182 {
183 if (e != null)
184 {
185 cardinality++;
186 }
187 }
188 return cardinality;
189 }
190
191
192 public boolean isEmpty()
193 {
194 return (0 == cardinality());
195 }
196
197
198 public void clear()
199 {
200 forEach(new QuaternaryProcedure<Long, Long, Long, E>()
201 {
202 public void run(final Long slice, final Long row, final Long column, final E e)
203 {
204 if (e != null)
205 {
206 set(slice, row, column, null);
207 }
208 }
209 });
210 }
211
212
213 public Iterator<E> iterator()
214 {
215 return new ObjectMatrix3DIterator();
216 }
217
218
219 public E get(final long slice, final long row, final long column)
220 {
221 if (slice < 0)
222 {
223 throw new IndexOutOfBoundsException(slice + "< 0");
224 }
225 if (row < 0)
226 {
227 throw new IndexOutOfBoundsException(row + "< 0");
228 }
229 if (column < 0)
230 {
231 throw new IndexOutOfBoundsException(column + "< 0");
232 }
233 if (slice >= slices)
234 {
235 throw new IndexOutOfBoundsException(slice + " >= " + slices);
236 }
237 if (row >= rows)
238 {
239 throw new IndexOutOfBoundsException(row + " >= " + rows);
240 }
241 if (column >= columns)
242 {
243 throw new IndexOutOfBoundsException(column + " >= " + columns);
244 }
245
246 return getQuick(slice, row, column);
247 }
248
249
250 public void set(final long slice, final long row, final long column, final E e)
251 {
252 if (slice < 0)
253 {
254 throw new IndexOutOfBoundsException(slice + "< 0");
255 }
256 if (row < 0)
257 {
258 throw new IndexOutOfBoundsException(row + "< 0");
259 }
260 if (column < 0)
261 {
262 throw new IndexOutOfBoundsException(column + "< 0");
263 }
264 if (slice >= slices)
265 {
266 throw new IndexOutOfBoundsException(slice + " >= " + slices);
267 }
268 if (row >= rows)
269 {
270 throw new IndexOutOfBoundsException(row + " >= " + rows);
271 }
272 if (column >= columns)
273 {
274 throw new IndexOutOfBoundsException(column + " >= " + columns);
275 }
276
277 setQuick(slice, row, column, e);
278 }
279
280
281 public void setQuick(final long slice, final long row, final long column, final E e)
282 {
283 throw new UnsupportedOperationException();
284 }
285
286
287 public Matrix3D<E> assign(final E e)
288 {
289 forEach(new QuaternaryProcedure<Long, Long, Long, E>()
290 {
291 public void run(final Long slice, final Long row, final Long column, final E ignore)
292 {
293 setQuick(slice, row, column, e);
294 }
295 });
296
297 return this;
298 }
299
300
301 public Matrix3D<E> assign(final UnaryFunction<E, E> function)
302 {
303 if (function == null)
304 {
305 throw new IllegalArgumentException("function must not be null");
306 }
307
308 forEach(new QuaternaryProcedure<Long, Long, Long, E>()
309 {
310 public void run(final Long slice, final Long row, final Long column, final E e)
311 {
312 setQuick(slice, row, column, function.evaluate(e));
313 }
314 });
315
316 return this;
317 }
318
319
320 public Matrix3D<E> assign(final Matrix3D<? extends E> other)
321 {
322 if (other == null)
323 {
324 throw new IllegalArgumentException("other must not be null");
325 }
326 if ((size() != other.size())
327 || (slices != other.slices())
328 || (rows != other.rows())
329 || (columns != other.columns()))
330 {
331 throw new IllegalArgumentException("other must have the same dimensions as this");
332 }
333
334 forEach(new QuaternaryProcedure<Long, Long, Long, E>()
335 {
336 public void run(final Long slice, final Long row, final Long column, final E e)
337 {
338 setQuick(slice, row, column, other.getQuick(slice, row, column));
339 }
340 });
341
342 return this;
343 }
344
345
346 public Matrix3D<E> assign(final Matrix3D<? extends E> other,
347 final BinaryFunction<E, E, E> function)
348 {
349 if (other == null)
350 {
351 throw new IllegalArgumentException("other must not be null");
352 }
353 if ((size() != other.size())
354 || (slices != other.slices())
355 || (rows != other.rows())
356 || (columns != other.columns()))
357 {
358 throw new IllegalArgumentException("other must have the same dimensions as this");
359 }
360 if (function == null)
361 {
362 throw new IllegalArgumentException("function must not be null");
363 }
364
365 forEach(new QuaternaryProcedure<Long, Long, Long, E>()
366 {
367 public void run(final Long slice, final Long row, final Long column, final E e)
368 {
369 E result = function.evaluate(e, other.getQuick(slice, row, column));
370 setQuick(slice, row, column, result);
371 }
372 });
373
374 return this;
375 }
376
377
378 public E aggregate(final BinaryFunction<E, E, E> aggr, final UnaryFunction<E, E> function)
379 {
380 if (aggr == null)
381 {
382 throw new IllegalArgumentException("aggr must not be null");
383 }
384 if (function == null)
385 {
386 throw new IllegalArgumentException("function must not be null");
387 }
388 if (size() == 0)
389 {
390 return null;
391 }
392 E a = function.evaluate(getQuick(slices - 1L, rows - 1L, columns - 1L));
393 long skip = 1L;
394 for (long slice = slices; --slice >= 0;)
395 {
396 for (long row = rows; --row >= 0;)
397 {
398 for (long column = (columns - skip); --column >= 0;)
399 {
400 a = aggr.evaluate(a, function.evaluate(getQuick(slice, row, column)));
401 }
402 skip = 0L;
403 }
404 }
405 return a;
406 }
407
408
409 public E aggregate(final Matrix3D<? extends E> other,
410 final BinaryFunction<E, E, E> aggr,
411 final BinaryFunction<E, E, E> function)
412 {
413 if (other == null)
414 {
415 throw new IllegalArgumentException("other must not be null");
416 }
417 if ((size() != other.size())
418 || (slices != other.slices())
419 || (rows != other.rows())
420 || (columns != other.columns()))
421 {
422 throw new IllegalArgumentException("other must have the same dimensions as this");
423 }
424 if (aggr == null)
425 {
426 throw new IllegalArgumentException("aggr must not be null");
427 }
428 if (function == null)
429 {
430 throw new IllegalArgumentException("function must not be null");
431 }
432 if (size() == 0)
433 {
434 return null;
435 }
436 long lastSlice = (slices - 1L);
437 long lastRow = (rows - 1L);
438 long lastColumn = (columns - 1L);
439 E a = function.evaluate(getQuick(lastSlice, lastRow, lastColumn),
440 other.getQuick(lastSlice, lastRow, lastColumn));
441 long skip = 1L;
442 for (long slice = slices; --slice >= 0;)
443 {
444 for (long row = rows; --row >= 0;)
445 {
446 for (long column = (columns - skip); --column >= 0;)
447 {
448 a = aggr.evaluate(a, function.evaluate(getQuick(slice, row, column),
449 other.getQuick(slice, row, column)));
450 }
451 skip = 0L;
452 }
453 }
454 return a;
455 }
456
457
458
459
460
461
462 protected AbstractMatrix3D<E> view()
463 {
464 try
465 {
466 AbstractMatrix3D<E> m = (AbstractMatrix3D<E>) clone();
467 return m;
468 }
469 catch (CloneNotSupportedException e)
470 {
471 throw new RuntimeException(e);
472 }
473 }
474
475
476
477
478
479
480
481
482
483 protected AbstractMatrix3D<E> vDice(final int axis0, final int axis1, final int axis2)
484 {
485 long[] shape = new long[3];
486 shape[0] = slices;
487 shape[1] = rows;
488 shape[2] = columns;
489
490 slices = shape[axis0];
491 rows = shape[axis1];
492 columns = shape[axis2];
493
494 long[] strides = new long[3];
495 strides[0] = sliceStride;
496 strides[1] = rowStride;
497 strides[2] = columnStride;
498
499 sliceStride = strides[axis0];
500 rowStride = strides[axis1];
501 columnStride = strides[axis2];
502 isView = true;
503
504 return this;
505 }
506
507
508 public Matrix3D<E> viewDice(final int axis0, final int axis1, final int axis2)
509 {
510 return view().vDice(axis0, axis1, axis2);
511 }
512
513
514
515
516
517
518 protected AbstractMatrix3D<E> vSliceFlip()
519 {
520 if (slices > 0)
521 {
522 sliceZero += (slices - 1) * sliceStride;
523 sliceStride = -sliceStride;
524 isView = true;
525 }
526 return this;
527 }
528
529
530 public Matrix3D<E> viewSliceFlip()
531 {
532 return view().vSliceFlip();
533 }
534
535
536
537
538
539
540 protected AbstractMatrix3D<E> vRowFlip()
541 {
542 if (rows > 0)
543 {
544 rowZero += (rows - 1) * rowStride;
545 rowStride = -rowStride;
546 isView = true;
547 }
548
549 return this;
550 }
551
552
553 public Matrix3D<E> viewRowFlip()
554 {
555 return view().vRowFlip();
556 }
557
558
559
560
561
562
563 protected AbstractMatrix3D<E> vColumnFlip()
564 {
565 if (columns > 0)
566 {
567 columnZero += (columns - 1) * columnStride;
568 columnStride = -columnStride;
569 isView = true;
570 }
571
572 return this;
573 }
574
575
576 public Matrix3D<E> viewColumnFlip()
577 {
578 return view().vColumnFlip();
579 }
580
581
582
583
584
585
586
587
588
589
590
591
592 protected AbstractMatrix3D<E> vPart(final long slice, final long row, final long column,
593 final long depth, final long height, final long width)
594 {
595 sliceZero += sliceStride * slice;
596 rowZero += rowStride * row;
597 columnZero += columnStride * column;
598
599 slices = depth;
600 rows = height;
601 columns = width;
602
603 isView = true;
604
605 return this;
606 }
607
608
609 public Matrix3D<E> viewPart(final long slice, final long row, final long column,
610 final long depth, final long height, final long width)
611 {
612 return view().vPart(slice, row, column, depth, height, width);
613 }
614
615
616 public Matrix3D<E> viewSelection(final long[] sliceIndices,
617 final long[] rowIndices,
618 final long[] columnIndices)
619 {
620 return null;
621 }
622
623
624 public Matrix3D<E> viewSelection(final UnaryPredicate<Matrix2D<E>> predicate)
625 {
626 return null;
627 }
628
629
630 public Matrix3D<E> viewSelection(final BitMatrix3D mask)
631 {
632 return null;
633 }
634
635
636
637
638
639
640
641
642
643 protected AbstractMatrix3D<E> vStrides(final long sliceStride,
644 final long rowStride,
645 final long columnStride)
646 {
647 this.sliceStride *= sliceStride;
648 this.rowStride *= rowStride;
649 this.columnStride *= columnStride;
650
651 if (slices != 0)
652 {
653 this.slices = (((this.slices - 1L) / sliceStride) + 1L);
654 }
655 if (rows != 0)
656 {
657 this.rows = (((this.rows - 1L) / rowStride) + 1L);
658 }
659 if (columns != 0)
660 {
661 this.columns = (((this.columns - 1L) / columnStride) + 1L);
662 }
663 isView = true;
664
665 return this;
666 }
667
668
669 public Matrix3D<E> viewStrides(final long sliceStride,
670 final long rowStride,
671 final long columnStride)
672 {
673 return view().vStrides(sliceStride, rowStride, columnStride);
674 }
675
676
677 public void forEach(final UnaryProcedure<? super E> procedure)
678 {
679 if (procedure == null)
680 {
681 throw new IllegalArgumentException("procedure must not be null");
682 }
683 for (long slice = 0; slice < slices; slice++)
684 {
685 for (long row = 0; row < rows; row++)
686 {
687 for (long column = 0; column < columns; column++)
688 {
689 E e = getQuick(slice, row, column);
690 procedure.run(e);
691 }
692 }
693 }
694 }
695
696
697 public void forEach(final UnaryPredicate<? super E> predicate,
698 final UnaryProcedure<? super E> procedure)
699 {
700 if (predicate == null)
701 {
702 throw new IllegalArgumentException("predicate must not be null");
703 }
704 if (procedure == null)
705 {
706 throw new IllegalArgumentException("procedure must not be null");
707 }
708 for (long slice = 0; slice < slices; slice++)
709 {
710 for (long row = 0; row < rows; row++)
711 {
712 for (long column = 0; column < columns; column++)
713 {
714 E e = getQuick(slice, row, column);
715 if (predicate.test(e))
716 {
717 procedure.run(e);
718 }
719 }
720 }
721 }
722 }
723
724
725 public void forEachNonNull(final UnaryProcedure<? super E> procedure)
726 {
727 if (procedure == null)
728 {
729 throw new IllegalArgumentException("procedure must not be null");
730 }
731 forEach(new UnaryPredicate<E>()
732 {
733 public boolean test(final E e)
734 {
735 return (e != null);
736 }
737 }, procedure);
738 }
739
740
741 public void forEach(final QuaternaryProcedure<Long, Long, Long, ? super E> procedure)
742 {
743 if (procedure == null)
744 {
745 throw new IllegalArgumentException("procedure must not be null");
746 }
747 for (long slice = 0; slice < slices; slice++)
748 {
749 for (long row = 0; row < rows; row++)
750 {
751 for (long column = 0; column < columns; column++)
752 {
753 E e = getQuick(slice, row, column);
754 procedure.run(slice, row, column, e);
755 }
756 }
757 }
758 }
759
760
761 public void forEach(final QuaternaryPredicate<Long, Long, Long, ? super E> predicate,
762 final QuaternaryProcedure<Long, Long, Long, ? super E> procedure)
763 {
764 if (predicate == null)
765 {
766 throw new IllegalArgumentException("predicate must not be null");
767 }
768 if (procedure == null)
769 {
770 throw new IllegalArgumentException("procedure must not be null");
771 }
772 for (long slice = 0; slice < slices; slice++)
773 {
774 for (long row = 0; row < rows; row++)
775 {
776 for (long column = 0; column < columns; column++)
777 {
778 E e = getQuick(slice, row, column);
779 if (predicate.test(slice, row, column, e))
780 {
781 procedure.run(slice, row, column, e);
782 }
783 }
784 }
785 }
786 }
787
788
789
790
791
792
793 protected long sliceZero()
794 {
795 return sliceZero;
796 }
797
798
799
800
801
802
803 protected long rowZero()
804 {
805 return rowZero;
806 }
807
808
809
810
811
812
813 protected long columnZero()
814 {
815 return columnZero;
816 }
817
818
819
820
821
822
823 protected long sliceStride()
824 {
825 return sliceStride;
826 }
827
828
829
830
831
832
833 protected long rowStride()
834 {
835 return rowStride;
836 }
837
838
839
840
841
842
843 protected long columnStride()
844 {
845 return columnStride;
846 }
847
848
849
850
851
852
853 protected boolean isView()
854 {
855 return isView;
856 }
857
858
859
860
861 private class ObjectMatrix3DIterator
862 implements Iterator<E>
863 {
864
865 private long slice = 0L;
866
867
868 private long row = 0L;
869
870
871 private long column = 0L;
872
873
874
875 public boolean hasNext()
876 {
877 return ((slice < slices) && (row < rows) && (column < columns));
878 }
879
880
881 public E next()
882 {
883 if ((slice < slices) && (row < rows) && (column < columns))
884 {
885 E e = getQuick(slice, row, column);
886
887 column++;
888 if (column == columns)
889 {
890 column = 0L;
891 row++;
892 if (row == rows)
893 {
894 row = 0L;
895 slice++;
896 }
897 }
898
899 return e;
900 }
901 else
902 {
903 throw new NoSuchElementException("slice=" + slice + " row=" + row + " column=" + column);
904 }
905 }
906
907
908 public void remove()
909 {
910 throw new UnsupportedOperationException();
911 }
912 }
913 }