Clover icon

jalviewX

  1. Project Clover database Wed Oct 31 2018 15:13:58 GMT
  2. Package jalview.math

File SparseMatrix.java

 

Coverage histogram

../../img/srcFileCovDistChart9.png
12% of files have more coverage

Code metrics

32
58
10
1
239
143
27
0.47
5.8
10
2.7

Classes

Class Line # Actions
SparseMatrix 33 58 27 18
0.8282%
 

Contributing tests

This file is covered by 11 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.math;
22   
23    import jalview.ext.android.SparseDoubleArray;
24   
25    /**
26    * A variant of Matrix intended for use for sparse (mostly zero) matrices. This
27    * class uses a SparseDoubleArray to hold each row of the matrix. The sparse
28    * array only stores non-zero values. This gives a smaller memory footprint, and
29    * fewer matrix calculation operations, for mostly zero matrices.
30    *
31    * @author gmcarstairs
32    */
 
33    public class SparseMatrix extends Matrix
34    {
35    /*
36    * we choose columns for the sparse arrays as this allows
37    * optimisation of the preMultiply() method used in PCA.run()
38    */
39    SparseDoubleArray[] sparseColumns;
40   
41    /**
42    * Constructor given data in [row][column] order
43    *
44    * @param v
45    */
 
46  22 toggle public SparseMatrix(double[][] v)
47    {
48  22 rows = v.length;
49  22 if (rows > 0)
50    {
51  22 cols = v[0].length;
52    }
53  22 sparseColumns = new SparseDoubleArray[cols];
54   
55    /*
56    * transpose v[row][col] into [col][row] order
57    */
58  107 for (int col = 0; col < cols; col++)
59    {
60  85 SparseDoubleArray sparseColumn = new SparseDoubleArray();
61  85 sparseColumns[col] = sparseColumn;
62  522 for (int row = 0; row < rows; row++)
63    {
64  437 double value = v[row][col];
65  437 if (value != 0d)
66    {
67  184 sparseColumn.put(row, value);
68    }
69    }
70    }
71    }
72   
73    /**
74    * Answers the value at row i, column j
75    */
 
76  7019 toggle @Override
77    public double getValue(int i, int j)
78    {
79  7019 return sparseColumns[j].get(i);
80    }
81   
82    /**
83    * Sets the value at row i, column j to val
84    */
 
85  870 toggle @Override
86    public void setValue(int i, int j, double val)
87    {
88  870 if (val == 0d)
89    {
90  385 sparseColumns[j].delete(i);
91    }
92    else
93    {
94  485 sparseColumns[j].put(i, val);
95    }
96    }
97   
 
98  0 toggle @Override
99    public double[] getColumn(int i)
100    {
101  0 double[] col = new double[height()];
102   
103  0 SparseDoubleArray vals = sparseColumns[i];
104  0 for (int nonZero = 0; nonZero < vals.size(); nonZero++)
105    {
106  0 col[vals.keyAt(nonZero)] = vals.valueAt(nonZero);
107    }
108  0 return col;
109    }
110   
 
111  0 toggle @Override
112    public MatrixI copy()
113    {
114  0 double[][] vals = new double[height()][width()];
115  0 for (int i = 0; i < height(); i++)
116    {
117  0 vals[i] = getRow(i);
118    }
119  0 return new SparseMatrix(vals);
120    }
121   
 
122  1 toggle @Override
123    public MatrixI transpose()
124    {
125  1 double[][] out = new double[cols][rows];
126   
127    /*
128    * for each column...
129    */
130  4 for (int i = 0; i < cols; i++)
131    {
132    /*
133    * put non-zero values into the corresponding row
134    * of the transposed matrix
135    */
136  3 SparseDoubleArray vals = sparseColumns[i];
137  7 for (int nonZero = 0; nonZero < vals.size(); nonZero++)
138    {
139  4 out[i][vals.keyAt(nonZero)] = vals.valueAt(nonZero);
140    }
141    }
142   
143  1 return new SparseMatrix(out);
144    }
145   
146    /**
147    * Answers a new matrix which is the product in.this. If the product contains
148    * less than 20% non-zero values, it is returned as a SparseMatrix, else as a
149    * Matrix.
150    * <p>
151    * This method is optimised for the sparse arrays which store column values
152    * for a SparseMatrix. Note that postMultiply is not so optimised. That would
153    * require redundantly also storing sparse arrays for the rows, which has not
154    * been done. Currently only preMultiply is used in Jalview.
155    */
 
156  12 toggle @Override
157    public MatrixI preMultiply(MatrixI in)
158    {
159  12 if (in.width() != rows)
160    {
161  2 throw new IllegalArgumentException("Can't pre-multiply " + this.rows
162    + " rows by " + in.width() + " columns");
163    }
164  10 double[][] tmp = new double[in.height()][this.cols];
165   
166  10 long count = 0L;
167  34 for (int i = 0; i < in.height(); i++)
168    {
169  98 for (int j = 0; j < this.cols; j++)
170    {
171    /*
172    * result[i][j] is the vector product of
173    * in.row[i] and this.column[j]
174    * we only need to use non-zero values from the column
175    */
176  74 SparseDoubleArray vals = sparseColumns[j];
177  74 boolean added = false;
178  161 for (int nonZero = 0; nonZero < vals.size(); nonZero++)
179    {
180  87 int myRow = vals.keyAt(nonZero);
181  87 double myValue = vals.valueAt(nonZero);
182  87 tmp[i][j] += (in.getValue(i, myRow) * myValue);
183  87 added = true;
184    }
185  74 if (added && tmp[i][j] != 0d)
186    {
187  41 count++; // non-zero entry in product
188    }
189    }
190    }
191   
192    /*
193    * heuristic rule - if product is more than 80% zero
194    * then construct a SparseMatrix, else a Matrix
195    */
196  10 if (count * 5 < in.height() * cols)
197    {
198  1 return new SparseMatrix(tmp);
199    }
200    else
201    {
202  9 return new Matrix(tmp);
203    }
204    }
205   
 
206  146 toggle @Override
207    protected double divideValue(int i, int j, double divisor)
208    {
209  146 if (divisor == 0d)
210    {
211  0 return getValue(i, j);
212    }
213  146 double v = sparseColumns[j].divide(i, divisor);
214  146 return v;
215    }
216   
 
217  1432 toggle @Override
218    protected double addValue(int i, int j, double addend)
219    {
220  1432 double v = sparseColumns[j].add(i, addend);
221  1432 return v;
222    }
223   
224    /**
225    * Returns the fraction of the whole matrix size that is actually modelled in
226    * sparse arrays (normally, the non-zero values)
227    *
228    * @return
229    */
 
230  1 toggle public float getFillRatio()
231    {
232  1 long count = 0L;
233  1 for (SparseDoubleArray col : sparseColumns)
234    {
235  5 count += col.size();
236    }
237  1 return count / (float) (height() * width());
238    }
239    }