View Javadoc

1   /*
2   
3       dsh-matrix  long-addressable bit and typed object matrix implementations.
4       Copyright (c) 2004-2013 held jointly by the individual authors.
5   
6       This library is free software; you can redistribute it and/or modify it
7       under the terms of the GNU Lesser General Public License as published
8       by the Free Software Foundation; either version 3 of the License, or (at
9       your option) any later version.
10  
11      This library is distributed in the hope that it will be useful, but WITHOUT
12      ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13      FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14      License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public License
17      along with this library;  if not, write to the Free Software Foundation,
18      Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
19  
20      > http://www.fsf.org/licensing/licenses/lgpl.html
21      > http://www.opensource.org/licenses/lgpl-license.php
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   * Abstract implementation of Matrix3D.
42   *
43   * @param <E> type of this abstract 3D matrix
44   * @author  Michael Heuer
45   */
46  abstract class AbstractMatrix3D<E>
47      implements Matrix3D<E>
48  {
49      /** Number of slices. */
50      protected long slices;
51  
52      /** Number of rows. */
53      protected long rows;
54  
55      /** Number of columns. */
56      protected long columns;
57  
58      /** Slice of the first element. */
59      protected long sliceZero;
60  
61      /** Row of the first element. */
62      protected long rowZero;
63  
64      /** Column of the first element. */
65      protected long columnZero;
66  
67      /** Number of slices between elements. */
68      protected long sliceStride;
69  
70      /** Number of rows between elements. */
71      protected long rowStride;
72  
73      /** Number of columns between elements. */
74      protected long columnStride;
75  
76      /** True if this instance is a view. */
77      protected boolean isView;
78  
79  
80      /**
81       * Protected no-arg constructor, to support serialization.
82       */
83      protected AbstractMatrix3D()
84      {
85          // empty
86      }
87  
88      /**
89       * Create a new abstract 3D matrix with the specified number of
90       * slices, rows, and columns.
91       *
92       * @param slices slices, must be <code>&gt;= 0</code>
93       * @param rows rows, must be <code>&gt;= 0</code>
94       * @param columns columns, must be <code>&gt;= 0</code>
95       * @throws IllegalArgumentException if any of <code>slices</code>,
96       *    <code>rows</code>, or <code>columns</code> are negative
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      * Create a new abstract 3D matrix with the specified parameters.
117      *
118      * @param slices slices, must be <code>&gt;= 0</code>
119      * @param rows rows, must be <code>&gt;= 0</code>
120      * @param columns columns, must be <code>&gt;= 0</code>
121      * @param sliceZero slice of the first element
122      * @param rowZero row of the first element
123      * @param columnZero column of the first element
124      * @param sliceStride number of slices between two elements
125      * @param rowStride number of rows between two elements
126      * @param columnStride number of columns between two elements
127      * @param isView true if this instance is a view
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     /** {@inheritDoc} */
154     public long size()
155     {
156         return (slices * rows * columns);
157     }
158 
159     /** {@inheritDoc} */
160     public long slices()
161     {
162         return slices;
163     }
164 
165     /** {@inheritDoc} */
166     public long rows()
167     {
168         return rows;
169     }
170 
171     /** {@inheritDoc} */
172     public long columns()
173     {
174         return columns;
175     }
176 
177     /** {@inheritDoc} */
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     /** {@inheritDoc} */
192     public boolean isEmpty()
193     {
194         return (0 == cardinality());
195     }
196 
197     /** {@inheritDoc} */
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     /** {@inheritDoc} */
213     public Iterator<E> iterator()
214     {
215         return new ObjectMatrix3DIterator();
216     }
217 
218     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
281     public void setQuick(final long slice, final long row, final long column, final E e)
282     {
283         throw new UnsupportedOperationException();
284     }
285 
286     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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      * Create a new view.
459      *
460      * @return a new view
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      * Self-modifying version of <code>viewDice(int, int, int)</code>.
477      *
478      * @param axis0 first axis
479      * @param axis1 second axis
480      * @param axis2 third axis
481      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
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      * Self-modifying version of <code>viewSliceFlip()</code>.
515      *
516      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
530     public Matrix3D<E> viewSliceFlip()
531     {
532         return view().vSliceFlip();
533     }
534 
535     /**
536      * Self-modifying version of <code>viewRowFlip()</code>.
537      *
538      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
553     public Matrix3D<E> viewRowFlip()
554     {
555         return view().vRowFlip();
556     }
557 
558     /**
559      * Self-modifying version of <code>viewColumnFlip()</code>.
560      *
561      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
576     public Matrix3D<E> viewColumnFlip()
577     {
578         return view().vColumnFlip();
579     }
580 
581     /**
582      * Self-modifying version of <code>viewPart(long, long, long, long, long, long)</code>.
583      *
584      * @param slice slice
585      * @param row row
586      * @param column column
587      * @param depth depth
588      * @param height height
589      * @param width width
590      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
616     public Matrix3D<E> viewSelection(final long[] sliceIndices,
617                                            final long[] rowIndices,
618                                            final long[] columnIndices)
619     {
620         return null;
621     }
622 
623     /** {@inheritDoc} */
624     public Matrix3D<E> viewSelection(final UnaryPredicate<Matrix2D<E>> predicate)
625     {
626         return null;
627     }
628 
629     /** {@inheritDoc} */
630     public Matrix3D<E> viewSelection(final BitMatrix3D mask)
631     {
632         return null;
633     }
634 
635     /**
636      * Self-modifying version of <code>viewStrides(long, long, long)</code>.
637      *
638      * @param sliceStride slice stride
639      * @param rowStride row stride
640      * @param columnStride column stride
641      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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      * Return the slice of the first element.
790      *
791      * @return the slice of the first element
792      */
793     protected long sliceZero()
794     {
795         return sliceZero;
796     }
797 
798     /**
799      * Return the row of the first element.
800      *
801      * @return the row of the first element
802      */
803     protected long rowZero()
804     {
805         return rowZero;
806     }
807 
808     /**
809      * Return the column of the first element.
810      *
811      * @return the column of this first element
812      */
813     protected long columnZero()
814     {
815         return columnZero;
816     }
817 
818     /**
819      * Return the number of slices between two elements.
820      *
821      * @return the number of slices between two elements
822      */
823     protected long sliceStride()
824     {
825         return sliceStride;
826     }
827 
828     /**
829      * Return the number of rows between two elements.
830      *
831      * @return the number of rows between two elements
832      */
833     protected long rowStride()
834     {
835         return rowStride;
836     }
837 
838     /**
839      * Return the number of columns between two elements.
840      *
841      * @return the number of columns between two elements
842      */
843     protected long columnStride()
844     {
845         return columnStride;
846     }
847 
848     /**
849      * Return true if this instance is a view.
850      *
851      * @return true if this instance is a view
852      */
853     protected boolean isView()
854     {
855         return isView;
856     }
857 
858     /**
859      * Matrix3D iterator.
860      */
861     private class ObjectMatrix3DIterator
862         implements Iterator<E>
863     {
864         /** Slice. */
865         private long slice = 0L;
866 
867         /** Row. */
868         private long row = 0L;
869 
870         /** Column. */
871         private long column = 0L;
872 
873 
874         /** {@inheritDoc} */
875         public boolean hasNext()
876         {
877             return ((slice < slices) && (row < rows) && (column < columns));
878         }
879 
880         /** {@inheritDoc} */
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         /** {@inheritDoc} */
908         public void remove()
909         {
910             throw new UnsupportedOperationException();
911         }
912     }
913 }