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.io.IOException;
27  import java.io.Serializable;
28  import java.io.ObjectInputStream;
29  import java.io.ObjectOutputStream;
30  
31  import java.util.Map;
32  import java.util.HashMap;
33  
34  import org.dishevelled.functor.UnaryProcedure;
35  
36  import org.dishevelled.matrix.Matrix2D;
37  
38  /**
39   * Sparse implementation of Matrix3D based on
40   * a hash map whose keys are <code>Long</code>s.
41   *
42   * <p>The cardinality of this sparse object matrix is limited
43   * by the <code>HashMap</code> underlying this implementation
44   * to something less than <code>Integer.MAX_VALUE</code>.  The
45   * addressable size, on the other hand, is limited to
46   * <code>(slices * rows * columns) &lt; Long.MAX_VALUE</code>.</p>
47   *
48   * @param <E> type for this sparse 3D matrix
49   * @author  Michael Heuer
50   */
51  public class SparseMatrix3D<E>
52      extends AbstractMatrix3D<E>
53      implements Serializable
54  {
55      /** Map of elements keyed by a <code>Long</code> index. */
56      private Map<Long, E> elements;
57  
58      /** Default load factor. */
59      private static final float DEFAULT_LOAD_FACTOR = 0.75f;
60  
61  
62      /**
63       * Private no-arg constructor, to support serialization.
64       */
65      private SparseMatrix3D()
66      {
67          elements = null;
68      }
69  
70      /**
71       * Create a new sparse 3D matrix with the specified number
72       * of slices, rows, and columns.
73       *
74       * @param slices slices, must be <code>&gt;= 0</code>
75       * @param rows rows, must be <code>&gt;= 0</code>
76       * @param columns columns, must be <code>&gt;= 0</code>
77       * @throws IllegalArgumentException if any of <code>slices</code>,
78       *    <code>rows</code>, or <code>columns</code> is negative
79       */
80      public SparseMatrix3D(final long slices, final long rows, final long columns)
81      {
82          this(slices, rows, columns,
83               (int) Math.min(Integer.MAX_VALUE, ((slices * rows * columns) / DEFAULT_LOAD_FACTOR)),
84               DEFAULT_LOAD_FACTOR);
85      }
86  
87      /**
88       * Create a new sparse 3D matrix with the specified number
89       * of slices, rows, and columns, initial capacity, and load factor.
90       *
91       * @param slices slices, must be <code>&gt;= 0</code>
92       * @param rows rows, must be <code>&gt;= 0</code>
93       * @param columns columns, must be <code>&gt;= 0</code>
94       * @param initialCapacity initial capacity, must be <code>&gt;= 0</code>
95       * @param loadFactor load factor, must be <code>&gt; 0</code>
96       */
97      public SparseMatrix3D(final long slices,
98                                  final long rows,
99                                  final long columns,
100                                 final int initialCapacity,
101                                 final float loadFactor)
102     {
103         super(slices, rows, columns);
104         elements = new HashMap<Long, E>(initialCapacity, loadFactor);
105     }
106 
107     /**
108      * Create a new instance of SparseMatrix3D with the specified
109      * number of slices, rows, and columns and map of elements.  Used
110      * exclusively by the <code>clone()</code> method.
111      *
112      * @param slices slices, must be <code>&gt;= 0</code>
113      * @param rows rows, must be <code>&gt;= 0</code>
114      * @param columns columns, must be <code>&gt;= 0</code>
115      * @param sliceZero slice of the first element
116      * @param rowZero row of the first element
117      * @param columnZero column of the first element
118      * @param sliceStride number of slices between two elements
119      * @param rowStride number of rows between two elements
120      * @param columnStride number of columns between two elements
121      * @param isView true if this instance is a view
122      * @param elements map of elements
123      */
124     protected SparseMatrix3D(final long slices,
125                              final long rows,
126                              final long columns,
127                              final long sliceZero,
128                              final long rowZero,
129                              final long columnZero,
130                              final long sliceStride,
131                              final long rowStride,
132                              final long columnStride,
133                              final boolean isView,
134                              final Map<Long, E> elements)
135     {
136         super(slices, rows, columns,
137               sliceZero, rowZero, columnZero,
138               sliceStride, rowStride, columnStride, isView);
139         this.elements = elements;
140     }
141 
142 
143     /** {@inheritDoc} */
144     public Object clone()
145     {
146         return new SparseMatrix3D<E>(slices, rows, columns,
147                                            sliceZero, rowZero, columnZero,
148                                            sliceStride, rowStride, columnStride,
149                                            isView, elements);
150     }
151 
152     /** {@inheritDoc} */
153     public E getQuick(final long slice, final long row, final long column)
154     {
155         long index = sliceZero + (slice * sliceStride)
156             + rowZero + (row * rowStride)
157             + columnZero + (column * columnStride);
158         return elements.get(index);
159     }
160 
161     /** {@inheritDoc} */
162     public void setQuick(final long slice, final long row, final long column, final E e)
163     {
164         long index = sliceZero + (slice * sliceStride)
165             + rowZero + (row * rowStride)
166             + columnZero + (column * columnStride);
167         if (e == null)
168         {
169             elements.remove(index);
170         }
171         else
172         {
173             elements.put(index, e);
174         }
175     }
176 
177     /**
178      * {@inheritDoc}
179      *
180      * Overridden for performance.
181      */
182     public void clear()
183     {
184         if (isView)
185         {
186             super.clear();
187         }
188         else
189         {
190             elements.clear();
191         }
192     }
193 
194     /**
195      * {@inheritDoc}
196      *
197      * Overridden for performance.
198      */
199     public void forEachNonNull(final UnaryProcedure<? super E> procedure)
200     {
201         if (isView)
202         {
203             super.forEachNonNull(procedure);
204         }
205         else
206         {
207             if (procedure == null)
208             {
209                 throw new IllegalArgumentException("procedure must not be null");
210             }
211 
212             for (E e : elements.values())
213             {
214                 procedure.run(e);
215             }
216         }
217     }
218 
219     /** {@inheritDoc} */
220     public Matrix2D<E> viewSlice(final long slice)
221     {
222         return new SliceView(slice);
223     }
224 
225     /** {@inheritDoc} */
226     public Matrix2D<E> viewRow(final long row)
227     {
228         return new RowView(row);
229     }
230 
231     /** {@inheritDoc} */
232     public Matrix2D<E> viewColumn(final long column)
233     {
234         return new ColumnView(column);
235     }
236 
237     /**
238      * Return a reference to the map backing this sparse 3D matrix.
239      *
240      * @return a reference to the map backing this sparse 3D matrix
241      */
242     protected Map<Long, E> elements()
243     {
244         return elements;
245     }
246 
247     /**
248      * Write this 3D matrix to the specified object output stream.
249      *
250      * @see java.io.ObjectOutputStream
251      * @param out object output stream
252      * @throws IOException if an IO error occurs
253      */
254     private void writeObject(final ObjectOutputStream out)
255         throws IOException
256     {
257         out.writeLong(slices);
258         out.writeLong(rows);
259         out.writeLong(columns);
260         out.writeLong(sliceZero);
261         out.writeLong(rowZero);
262         out.writeLong(columnZero);
263         out.writeLong(sliceStride);
264         out.writeLong(rowStride);
265         out.writeLong(columnStride);
266         out.writeBoolean(isView);
267         out.writeObject(elements);
268     }
269 
270     /**
271      * Read this 3D matrix in from the specified object input stream.
272      *
273      * @see java.io.ObjectInputStream
274      * @param in object input stream
275      * @throws IOException if an IO error occurs
276      * @throws ClassNotFoundException if a classloading error occurs
277      */
278     private void readObject(final ObjectInputStream in)
279         throws IOException, ClassNotFoundException
280     {
281         super.slices = in.readLong();
282         super.rows = in.readLong();
283         super.columns = in.readLong();
284         super.sliceZero = in.readLong();
285         super.rowZero = in.readLong();
286         super.columnZero = in.readLong();
287         super.sliceStride = in.readLong();
288         super.rowStride = in.readLong();
289         super.columnStride = in.readLong();
290         super.isView = in.readBoolean();
291         this.elements = (Map<Long, E>) in.readObject();
292     }
293 
294     /** {@inheritDoc} */
295     public String toString()
296     {
297         StringBuffer sb = new StringBuffer(super.toString());
298         sb.append("\n   slices=");
299         sb.append(slices);
300         sb.append("   rows=");
301         sb.append(rows);
302         sb.append("   columns=");
303         sb.append(columns);
304         sb.append("   sliceZero=");
305         sb.append(sliceZero);
306         sb.append("   rowZero=");
307         sb.append(rowZero);
308         sb.append("   columnZero=");
309         sb.append(columnZero);
310         sb.append("   sliceStride=");
311         sb.append(sliceStride);
312         sb.append("   rowStride=");
313         sb.append(rowStride);
314         sb.append("   columnStride=");
315         sb.append(columnStride);
316         sb.append("\n   elements=");
317         sb.append(elements.toString());
318         sb.append("\n");
319         return sb.toString();
320     }
321 
322     /**
323      * Slice view.
324      */
325     private class SliceView
326         extends SparseMatrix2D<E>
327     {
328 
329         /**
330          * Create a new slice view with the specified slice.
331          *
332          * @param slice slice to view
333          */
334         SliceView(final long slice)
335         {
336             super(SparseMatrix3D.this.rows,
337                   SparseMatrix3D.this.columns,
338                   SparseMatrix3D.this.rowZero,
339                   SparseMatrix3D.this.columnZero
340                       + (slice * SparseMatrix3D.this.sliceStride)
341                       + SparseMatrix3D.this.sliceZero,
342                   SparseMatrix3D.this.rowStride,
343                   SparseMatrix3D.this.columnStride,
344                   true,
345                   SparseMatrix3D.this.elements);
346         }
347     }
348 
349     /**
350      * Row view.
351      */
352     private class RowView
353         extends SparseMatrix2D<E>
354     {
355 
356         /**
357          * Create a new row view with the specified row.
358          *
359          * @param row row to view
360          */
361         RowView(final long row)
362         {
363             super(SparseMatrix3D.this.slices,
364                   SparseMatrix3D.this.columns,
365                   SparseMatrix3D.this.sliceZero,
366                   SparseMatrix3D.this.columnZero
367                       + (row * SparseMatrix3D.this.rowStride)
368                       + SparseMatrix3D.this.rowZero,
369                   SparseMatrix3D.this.sliceStride,
370                   SparseMatrix3D.this.columnStride,
371                   true,
372                   SparseMatrix3D.this.elements);
373         }
374     }
375 
376     /**
377      * Column view.
378      */
379     private class ColumnView
380         extends SparseMatrix2D<E>
381     {
382 
383         /**
384          * Create a new column view with the specified column.
385          *
386          * @param column column to view
387          */
388         ColumnView(final long column)
389         {
390             super(SparseMatrix3D.this.slices,
391                   SparseMatrix3D.this.rows,
392                   SparseMatrix3D.this.sliceZero,
393                   SparseMatrix3D.this.rowZero
394                       + (column * SparseMatrix3D.this.columnStride)
395                       + SparseMatrix3D.this.columnZero,
396                   SparseMatrix3D.this.sliceStride,
397                   SparseMatrix3D.this.rowStride,
398                   true,
399                   SparseMatrix3D.this.elements);
400         }
401     }
402 }