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