View Javadoc
1   /*
2    * The baseCode project
3    * 
4    * Copyright (c) 2006 University of British Columbia
5    * 
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *       http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   *
18   */
19  package ubic.basecode.dataStructure.matrix;
20  
21  import java.util.List;
22  
23  import no.uib.cipr.matrix.DenseMatrix;
24  import no.uib.cipr.matrix.sparse.FlexCompRowMatrix;
25  import no.uib.cipr.matrix.sparse.SparseVector;
26  import cern.colt.list.DoubleArrayList;
27  import cern.colt.matrix.DoubleMatrix1D;
28  
29  /**
30   * Supports sparse matrices (where sparse means most values are zero, not that they are missing).
31   * 
32   * @author xwan
33   * @see no.uib.cipr.matrix.sparse.FlexCompRowMatrix for how this is implemented under the hood.
34   * 
35   */
36  public class CompressedSparseDoubleMatrix<R, C> extends DoubleMatrix<R, C> {
37  
38      private static final long serialVersionUID = 5771918031750038719L;
39  
40      /*
41       * FlexCompRowMatrix isn't serializable, so either is this in any useful way, despite claim.
42       */
43      private transient FlexCompRowMatrix matrix;
44  
45      /**
46       * @param mat
47       */
48      public CompressedSparseDoubleMatrix( double[][] mat ) {
49          super();
50          matrix = new FlexCompRowMatrix( new DenseMatrix( mat ) );
51          matrix.compact();
52      }
53  
54      /**
55       * @param rows int
56       * @param cols int
57       */
58      public CompressedSparseDoubleMatrix( int rows, int cols ) {
59          super();
60          matrix = new FlexCompRowMatrix( rows, cols );
61          matrix.compact();
62      }
63  
64      /**
65       * @return double[][]
66       */
67      @Override
68      public double[][] asArray() {
69          double[][] result = new double[rows()][];
70          for ( int i = 0; i < rows(); i++ ) {
71              result[i] = getRow( i );
72          }
73          return result;
74      }
75  
76      /**
77       * @return
78       */
79      public int cardinality() {
80          int total = 0;
81          for ( int i = 0; i < matrix.numRows(); i++ ) {
82              total = total + matrix.getRow( i ).getUsed();
83          }
84  
85          return total;
86      }
87  
88      /**
89       * @return
90       */
91      @Override
92      public int columns() {
93          return matrix.numColumns();
94      }
95  
96      /*
97       * (non-Javadoc)
98       * 
99       * @see ubic.basecode.dataStructure.matrix.DoubleMatrixNamed#copy()
100      */
101     @Override
102     public DoubleMatrix<R, C> copy() {
103         DoubleMatrix<R, C> returnval = new CompressedSparseDoubleMatrix<R, C>( this.rows(), this.columns() );
104 
105         for ( int i = 0; i < this.rows(); i++ ) {
106             returnval.setRowName( this.getRowName( i ), i );
107             for ( int j = 0; j < this.columns(); j++ ) {
108                 if ( i == 0 ) {
109                     returnval.setColumnName( this.getColName( j ), j );
110                 }
111                 returnval.set( i, j, this.get( i, j ) );
112             }
113         }
114         return returnval;
115 
116     }
117 
118     /**
119      * @param row
120      * @param column
121      * @return
122      */
123     @Override
124     public double get( int row, int column ) {
125         return matrix.get( row, column );
126     }
127 
128     /*
129      * (non-Javadoc)
130      * 
131      * @see ubic.basecode.dataStructure.matrix.NamedPrimitiveMatrix#getColObj(int)
132      */
133     @Override
134     public Double[] getColObj( int col ) {
135         Double[] result = new Double[rows()];
136         for ( int i = 0; i < rows(); i++ ) {
137             result[i] = new Double( get( i, col ) );
138         }
139         return result;
140     }
141 
142     @Override
143     public DoubleMatrix<R, C> getColRange( int startCol, int endCol ) {
144         super.checkColRange( startCol, endCol );
145 
146         DoubleMatrix<R, C> returnval = new CompressedSparseDoubleMatrix<R, C>( this.rows(), 1 + endCol - startCol );
147         int k = 0;
148         for ( int i = startCol; i <= endCol; i++ ) {
149             C colName = this.getColName( i );
150             if ( colName != null ) {
151                 returnval.setColumnName( colName, i );
152             }
153             for ( int j = 0, m = this.rows(); j < m; j++ ) {
154                 if ( i == startCol ) {
155                     R rowName = this.getRowName( j );
156                     returnval.setRowName( rowName, j );
157                 }
158                 returnval.set( j, k, this.get( j, i ) );
159             }
160             k++;
161         }
162         return returnval;
163     }
164 
165     /*
166      * (non-Javadoc)
167      * 
168      * @see basecode.dataStructure.matrix.DoubleMatrixNamed#getColumn(int)
169      */
170     @Override
171     public double[] getColumn( int col ) {
172         double[] result = new double[rows()];
173         for ( int i = 0; i < rows(); i++ ) {
174             result[i] = get( i, col );
175         }
176         return result;
177     }
178 
179     @Override
180     public Double getObject( int row, int col ) {
181         return new Double( get( row, col ) );
182     }
183 
184     /**
185      * Return a reference to a specific row.
186      * 
187      * @param row int
188      * @return double[]
189      */
190     @Override
191     public double[] getRow( int row ) {
192         SparseVector vector = this.matrix.getRow( row );
193         double[] data = vector.getData();
194         int[] indices = vector.getIndex();
195         double[] values = new double[columns()];
196         assert data.length == indices.length;
197         for ( int j = 0; j < data.length; j++ ) {
198             if ( indices[j] == 0 && j > 0 ) break;
199             values[indices[j]] = data[j];
200         }
201         return values;
202     }
203 
204     /*
205      * (non-Javadoc)
206      * 
207      * @see basecode.dataStructure.matrix.AbstractNamedDoubleMatrix#getRowArrayList(int)
208      */
209     @Override
210     public DoubleArrayList getRowArrayList( int i ) {
211         return new DoubleArrayList( getRow( i ) );
212     }
213 
214     /**
215      * @param s String
216      * @return double[]
217      */
218     @Override
219     public double[] getRowByName( R s ) {
220         return getRow( getRowIndexByName( s ) );
221     }
222 
223     @Override
224     public Double[] getRowObj( int row ) {
225         Double[] result = new Double[columns()];
226         double[] values = getRow( row );
227         for ( int i = 0; i < columns(); i++ ) {
228             result[i] = new Double( values[i] );
229         }
230         return result;
231     }
232 
233     /*
234      * (non-Javadoc)
235      * 
236      * @see ubic.basecode.dataStructure.matrix.Matrix2D#getRowRange(int, int)
237      */
238     @Override
239     public DoubleMatrix<R, C> getRowRange( int startRow, int endRow ) {
240         super.checkRowRange( startRow, endRow );
241 
242         DoubleMatrix<R, C> returnval = new CompressedSparseDoubleMatrix<R, C>( endRow + 1 - startRow, this.columns() );
243         int k = 0;
244         for ( int i = startRow; i <= endRow; i++ ) {
245             R rowName = this.getRowName( i );
246             if ( rowName != null ) {
247                 returnval.setRowName( rowName, i );
248             }
249             for ( int j = 0, m = this.columns(); j < m; j++ ) {
250                 if ( i == 0 ) {
251                     C colName = this.getColName( j );
252                     returnval.setColumnName( colName, j );
253                 }
254                 returnval.set( k, j, this.get( i, j ) );
255             }
256             k++;
257         }
258         return returnval;
259     }
260 
261     @Override
262     public boolean isMissing( int i, int j ) {
263         return Double.isNaN( get( i, j ) );
264     }
265 
266     @Override
267     public int rows() {
268         return matrix.numRows();
269     }
270 
271     /**
272      * @param row
273      * @param column
274      * @param value
275      */
276     @Override
277     public void set( int row, int column, Double value ) {
278         matrix.set( row, column, value );
279     }
280 
281     /**
282      * @return
283      */
284     @Override
285     public int size() {
286         return matrix.numColumns() * matrix.numRows();
287     }
288 
289     /*
290      * (non-Javadoc)
291      * 
292      * @see ubic.basecode.dataStructure.matrix.DoubleMatrix#subsetColumns(java.util.List)
293      */
294     @Override
295     public DoubleMatrix<R, C> subsetColumns( List<C> columns ) {
296 
297         DoubleMatrix<R, C> returnval = new DenseDoubleMatrix<R, C>( this.rows(), columns.size() );
298         returnval.setRowNames( this.getRowNames() );
299         for ( int i = 0; i < this.rows(); i++ ) {
300             int currentColumn = 0;
301             for ( C c : columns ) {
302                 int j = this.getColIndexByName( c );
303 
304                 returnval.set( i, currentColumn, this.get( i, j ) );
305 
306                 if ( i == 0 ) {
307                     returnval.setColumnName( c, currentColumn );
308                 }
309 
310                 currentColumn++;
311 
312             }
313 
314         }
315         return returnval;
316     }
317 
318     @Override
319     public DoubleMatrix<R, C> subsetRows( List<R> rowNames ) {
320         DoubleMatrix<R, C> returnval = new CompressedSparseDoubleMatrix<R, C>( rowNames.size(), this.columns() );
321 
322         int currentRow = 0;
323         for ( R rowName : rowNames ) {
324 
325             if ( !this.containsRowName( rowName ) ) continue;
326 
327             int i = this.getRowIndexByName( rowName );
328             returnval.setRowName( rowName, currentRow );
329             for ( int j = 0; j < this.columns(); j++ ) {
330                 if ( currentRow == 0 ) {
331                     returnval.setColumnName( this.getColName( j ), j );
332                 }
333                 returnval.set( currentRow, j, this.get( i, j ) );
334             }
335             currentRow++;
336         }
337         if ( !returnval.getRowNames().containsAll( rowNames ) ) {
338             throw new IllegalArgumentException( "Invalid rows to select, some are not in the original matrix" );
339         }
340         return returnval;
341     }
342 
343     @Override
344     public DoubleMatrix<C, R> transpose() {
345         throw new UnsupportedOperationException();
346     }
347 
348     /**
349      * 
350      */
351     public void trimToSize() {
352 
353     }
354 
355     /**
356      * @param column
357      * @return
358      */
359     @Override
360     public DoubleMatrix1D viewColumn( int column ) {
361         double[] oneColumn = new double[this.rows()];
362         for ( int i = 0; i < matrix.numRows(); i++ )
363             oneColumn[i] = this.get( i, column );
364         return new DenseDoubleMatrix1D( oneColumn );
365     }
366 
367     /**
368      * @param row
369      * @return
370      */
371     @Override
372     public DoubleMatrix1D viewRow( int row ) {
373         return new DenseDoubleMatrix1D( getRow( row ) );
374     }
375 
376 }