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.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   * Abstract implementation of Matrix2D.
42   *
43   * @param <E> type of this abstract 2D matrix
44   * @author  Michael Heuer
45   */
46  abstract class AbstractMatrix2D<E>
47      implements Matrix2D<E>
48  {
49      /** Number of rows. */
50      protected long rows;
51  
52      /** Number of columns. */
53      protected long columns;
54  
55      /** Row of the first element. */
56      protected long rowZero;
57  
58      /** Column of the first element. */
59      protected long columnZero;
60  
61      /** Number of rows between two elements. */
62      protected long rowStride;
63  
64      /** Number of columns between two elements. */
65      protected long columnStride;
66  
67      /** True if this instance is a view. */
68      protected boolean isView;
69  
70  
71      /**
72       * Protected no-arg constructor, to support serialization.
73       */
74      protected AbstractMatrix2D()
75      {
76          // empty
77      }
78  
79      /**
80       * Create a new abstract 2D matrix with the specified number of
81       * rows and columns.
82       *
83       * @param rows rows, must be <code>&gt;= 0</code>
84       * @param columns columns, must be <code>&gt;= 0</code>
85       * @throws IllegalArgumentException if either <code>rows</code> or
86       *    <code>columns</code> is negative
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      * Create a new abstract 2D matrix with the specified parameters.
110      *
111      * @param rows rows, must be <code>&gt;= 0</code>
112      * @param columns columns, must be <code>&gt;= 0</code>
113      * @param rowZero row of the first element
114      * @param columnZero column of the first element
115      * @param rowStride number of rows between two elements
116      * @param columnStride number of columns between two elements
117      * @param isView true if this instance is a view
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     /** {@inheritDoc} */
147     public long size()
148     {
149         return (rows * columns);
150     }
151 
152     /** {@inheritDoc} */
153     public long rows()
154     {
155         return rows;
156     }
157 
158     /** {@inheritDoc} */
159     public long columns()
160     {
161         return columns;
162     }
163 
164     /** {@inheritDoc} */
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     /** {@inheritDoc} */
179     public boolean isEmpty()
180     {
181         return (0 == cardinality());
182     }
183 
184     /** {@inheritDoc} */
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     /** {@inheritDoc} */
200     public Iterator<E> iterator()
201     {
202         return new ObjectMatrix2DIterator();
203     }
204 
205     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
252     public void setQuick(final long row, final long column, final E e)
253     {
254         throw new UnsupportedOperationException();
255     }
256 
257     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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      * Create a new view.
413      *
414      * @return a new view
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      * Self-modifying version of <code>viewDice()</code>.
431      *
432      * @return modified version of <code>this</cod>
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     /** {@inheritDoc} */
455     public Matrix2D<E> viewDice()
456     {
457         return view().vDice();
458     }
459 
460     /**
461      * Self-modifying version of <code>viewRowFlip()</code>.
462      *
463      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
478     public Matrix2D<E> viewRowFlip()
479     {
480         return view().vRowFlip();
481     }
482 
483     /**
484      * Self-modifying version of <code>viewColumnFlip()</code>.
485      *
486      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
501     public Matrix2D<E> viewColumnFlip()
502     {
503         return view().vColumnFlip();
504     }
505 
506     /**
507      * Self-modifying version of <code>viewPart(long, long, long, long)</code>.
508      *
509      * @param row row
510      * @param column column
511      * @param height height
512      * @param width width
513      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
559     public Matrix2D<E> viewSelection(final long[] rows, final long[] columns)
560     {
561         return null;
562     }
563 
564     /** {@inheritDoc} */
565     public Matrix2D<E> viewSelection(final UnaryPredicate<Matrix1D<E>> predicate)
566     {
567         return null;
568     }
569 
570     /** {@inheritDoc} */
571     public Matrix2D<E> viewSelection(final BitMatrix2D mask)
572     {
573         return null;
574     }
575 
576     /**
577      * Self-modifying version of <code>viewStrides(long, long)</code>.
578      *
579      * @param rowStride row stride
580      * @param columnStride column stride
581      * @return modified version of <code>this</code>
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     /** {@inheritDoc} */
602     public Matrix2D<E> viewStrides(final long rowStride, final long columnStride)
603     {
604         return view().vStrides(rowStride, columnStride);
605     }
606 
607     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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     /** {@inheritDoc} */
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      * Return the row of the first element.
709      *
710      * @return the row of the first element
711      */
712     protected long rowZero()
713     {
714         return rowZero;
715     }
716 
717     /**
718      * Return the column of the first element.
719      *
720      * @return the column of this first element
721      */
722     protected long columnZero()
723     {
724         return columnZero;
725     }
726 
727     /**
728      * Return the number of rows between two elements.
729      *
730      * @return the number of rows between two elements
731      */
732     protected long rowStride()
733     {
734         return rowStride;
735     }
736 
737     /**
738      * Return the number of columns between two elements.
739      *
740      * @return the number of columns between two elements
741      */
742     protected long columnStride()
743     {
744         return columnStride;
745     }
746 
747     /**
748      * Return true if this instance is a view.
749      *
750      * @return true if this instance is a view
751      */
752     protected boolean isView()
753     {
754         return isView;
755     }
756 
757     /** {@inheritDoc} */
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      * Matrix2D iterator.
786      */
787     private class ObjectMatrix2DIterator
788         implements Iterator<E>
789     {
790         /** Row. */
791         private long row = 0L;
792 
793         /** Column. */
794         private long column = 0L;
795 
796 
797         /** {@inheritDoc} */
798         public boolean hasNext()
799         {
800             return ((row < rows) && (column < columns));
801         }
802 
803         /** {@inheritDoc} */
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         /** {@inheritDoc} */
826         public void remove()
827         {
828             throw new UnsupportedOperationException();
829         }
830     }
831 }