root / tmp / org.txm.analec.rcp / src / JamaPlus / SparseMatrix.java @ 2029
Historique | Voir | Annoter | Télécharger (7,7 ko)
1 | 481 | mdecorde | /*
|
---|---|---|---|
2 | 481 | mdecorde | * To change this template, choose Tools | Templates
|
3 | 481 | mdecorde | * and open the template in the editor.
|
4 | 481 | mdecorde | */
|
5 | 481 | mdecorde | package JamaPlus; |
6 | 481 | mdecorde | |
7 | 481 | mdecorde | import JamaPlus.SparseSVD.SparseSVDException; |
8 | 481 | mdecorde | import java.util.*; |
9 | 481 | mdecorde | import java.util.logging.Level; |
10 | 481 | mdecorde | import java.util.logging.Logger; |
11 | 481 | mdecorde | |
12 | 481 | mdecorde | /**
|
13 | 481 | mdecorde | *
|
14 | 481 | mdecorde | * @author Bernard
|
15 | 481 | mdecorde | */
|
16 | 481 | mdecorde | public class SparseMatrix { |
17 | 481 | mdecorde | private int m, n, nnz; |
18 | 481 | mdecorde | private int[] colpts, rowinds; |
19 | 481 | mdecorde | private double[] vals; |
20 | 481 | mdecorde | private double[] tempRow; // stockage temporaire pour certains calculs (opb) |
21 | 481 | mdecorde | |
22 | 481 | mdecorde | public SparseMatrix(int m, int n) { // null matrix |
23 | 481 | mdecorde | this.m = m;
|
24 | 481 | mdecorde | this.n = n;
|
25 | 481 | mdecorde | nnz = 0;
|
26 | 481 | mdecorde | colpts = new int[n+1]; |
27 | 481 | mdecorde | rowinds = new int[0]; |
28 | 481 | mdecorde | vals = new double[0]; |
29 | 481 | mdecorde | } |
30 | 481 | mdecorde | |
31 | 481 | mdecorde | private static class Triple implements Comparable<Triple> { |
32 | 481 | mdecorde | int row;
|
33 | 481 | mdecorde | int col;
|
34 | 481 | mdecorde | double val;
|
35 | 481 | mdecorde | |
36 | 481 | mdecorde | private Triple(int row, int col, double val) { |
37 | 481 | mdecorde | this.row = row;
|
38 | 481 | mdecorde | this.col = col;
|
39 | 481 | mdecorde | this.val = val;
|
40 | 481 | mdecorde | } |
41 | 481 | mdecorde | private Triple(int row, int col) { |
42 | 481 | mdecorde | this.row = row;
|
43 | 481 | mdecorde | this.col = col;
|
44 | 481 | mdecorde | } |
45 | 481 | mdecorde | public int compareTo(Triple t) { |
46 | 481 | mdecorde | int res = col - t.col;
|
47 | 481 | mdecorde | if(res==0) res = row - t.row; |
48 | 481 | mdecorde | return res;
|
49 | 481 | mdecorde | } |
50 | 481 | mdecorde | } |
51 | 481 | mdecorde | |
52 | 481 | mdecorde | public SparseMatrix(int m, int n, ArrayList<Integer> rows, ArrayList<Integer> cols, |
53 | 481 | mdecorde | ArrayList<Double> values) { |
54 | 481 | mdecorde | this.m = m;
|
55 | 481 | mdecorde | this.n = n;
|
56 | 481 | mdecorde | nnz = rows.size(); |
57 | 481 | mdecorde | if (nnz!=cols.size()||nnz!=rows.size())
|
58 | 481 | mdecorde | throw new ArrayIndexOutOfBoundsException( |
59 | 481 | mdecorde | "Size of lines, cols and values don't agree");
|
60 | 481 | mdecorde | colpts = new int[n+1]; |
61 | 481 | mdecorde | rowinds = new int[nnz]; |
62 | 481 | mdecorde | vals = new double[nnz]; |
63 | 481 | mdecorde | Triple[] triples = new Triple[nnz]; |
64 | 481 | mdecorde | for(int i=0; i<nnz; i++) |
65 | 481 | mdecorde | triples[i] = new Triple(rows.get(i), cols.get(i), values.get(i));
|
66 | 481 | mdecorde | Arrays.sort(triples);
|
67 | 481 | mdecorde | colpts[0] = 0; |
68 | 481 | mdecorde | int c = 0; |
69 | 481 | mdecorde | for(int i=0; i<nnz; i++) { |
70 | 481 | mdecorde | if(i>0 && triples[i].row == triples[i-1].row && triples[i].col == triples[i-1].col) |
71 | 481 | mdecorde | throw new ArrayIndexOutOfBoundsException( |
72 | 481 | mdecorde | "Two values with same row and column numbers");
|
73 | 481 | mdecorde | while(c<triples[i].col) colpts[++c] = i;
|
74 | 481 | mdecorde | rowinds[i] = triples[i].row; |
75 | 481 | mdecorde | vals[i] = triples[i].val; |
76 | 481 | mdecorde | } |
77 | 481 | mdecorde | while(c<n) colpts[++c] = nnz;
|
78 | 481 | mdecorde | } |
79 | 481 | mdecorde | |
80 | 481 | mdecorde | public SparseMatrix(int m, int n, ArrayList<Integer> rows, ArrayList<Integer> cols, |
81 | 481 | mdecorde | double value) {
|
82 | 481 | mdecorde | this.m = m;
|
83 | 481 | mdecorde | this.n = n;
|
84 | 481 | mdecorde | nnz = rows.size(); |
85 | 481 | mdecorde | if (nnz!=cols.size()||nnz!=rows.size())
|
86 | 481 | mdecorde | throw new ArrayIndexOutOfBoundsException( |
87 | 481 | mdecorde | "Size of lines, cols and values don't agree");
|
88 | 481 | mdecorde | colpts = new int[n+1]; |
89 | 481 | mdecorde | rowinds = new int[nnz]; |
90 | 481 | mdecorde | vals = new double[nnz]; |
91 | 481 | mdecorde | Triple[] triples = new Triple[nnz]; |
92 | 481 | mdecorde | for(int i=0; i<nnz; i++) |
93 | 481 | mdecorde | triples[i] = new Triple(rows.get(i), cols.get(i));
|
94 | 481 | mdecorde | Arrays.sort(triples);
|
95 | 481 | mdecorde | colpts[0] = 0; |
96 | 481 | mdecorde | int c = 0; |
97 | 481 | mdecorde | for(int i=0; i<nnz; i++) { |
98 | 481 | mdecorde | if(i>0 && triples[i].row == triples[i-1].row && triples[i].col == triples[i-1].col) |
99 | 481 | mdecorde | throw new ArrayIndexOutOfBoundsException( |
100 | 481 | mdecorde | "Two values with same row and column numbers");
|
101 | 481 | mdecorde | while(c<triples[i].col) colpts[++c] = i;
|
102 | 481 | mdecorde | rowinds[i] = triples[i].row; |
103 | 481 | mdecorde | vals[i] = value; |
104 | 481 | mdecorde | } |
105 | 481 | mdecorde | while(c<n) colpts[++c] = nnz;
|
106 | 481 | mdecorde | } |
107 | 481 | mdecorde | |
108 | 481 | mdecorde | private SparseMatrix(int m, int n, int nnz, int[] colpts, int[] rowinds, double[] vals) { |
109 | 481 | mdecorde | this.m = m;
|
110 | 481 | mdecorde | this.n = n;
|
111 | 481 | mdecorde | this.nnz = nnz;
|
112 | 481 | mdecorde | this.colpts = colpts;
|
113 | 481 | mdecorde | this.rowinds = rowinds;
|
114 | 481 | mdecorde | this.vals = vals;
|
115 | 481 | mdecorde | } |
116 | 481 | mdecorde | |
117 | 481 | mdecorde | public SparseMatrix(Matrix mat) { // convert a dense matrix |
118 | 481 | mdecorde | m = mat.getRowDimension(); |
119 | 481 | mdecorde | n = mat.getColumnDimension(); |
120 | 481 | mdecorde | long nbval = mat.getNumberNonZeroValues();
|
121 | 481 | mdecorde | if (nbval>Integer.MAX_VALUE) throw new ArrayIndexOutOfBoundsException( |
122 | 481 | mdecorde | "Number of non-zero values exceeds 32 bits integer");
|
123 | 481 | mdecorde | nnz = (int) nbval;
|
124 | 481 | mdecorde | colpts = new int[n+1]; |
125 | 481 | mdecorde | rowinds = new int[nnz]; |
126 | 481 | mdecorde | vals = new double[nnz]; |
127 | 481 | mdecorde | int nval = 0; |
128 | 481 | mdecorde | for (int j = 0; j<n; j++) { |
129 | 481 | mdecorde | colpts[j] = nval; |
130 | 481 | mdecorde | for (int i = 0; i<m; i++) if (mat.get(i, j)!=0) { |
131 | 481 | mdecorde | rowinds[nval] = i; |
132 | 481 | mdecorde | vals[nval++] = mat.get(i, j); |
133 | 481 | mdecorde | } |
134 | 481 | mdecorde | } |
135 | 481 | mdecorde | colpts[n] = nnz; |
136 | 481 | mdecorde | } |
137 | 481 | mdecorde | |
138 | 481 | mdecorde | public SparseMatrix copy() {
|
139 | 481 | mdecorde | int[] colpts1 = new int[n+1]; |
140 | 481 | mdecorde | int[] rowinds1 = new int[nnz]; |
141 | 481 | mdecorde | double[] vals1 = new double[nnz]; |
142 | 481 | mdecorde | System.arraycopy(colpts, 0, colpts1, 0, n+1); |
143 | 481 | mdecorde | System.arraycopy(rowinds, 0, rowinds1, 0, nnz); |
144 | 481 | mdecorde | System.arraycopy(vals, 0, vals1, 0, nnz); |
145 | 481 | mdecorde | return new SparseMatrix(m, n, nnz, colpts1, rowinds1, vals1); |
146 | 481 | mdecorde | } |
147 | 481 | mdecorde | |
148 | 481 | mdecorde | public int getRowDimension() { |
149 | 481 | mdecorde | return m;
|
150 | 481 | mdecorde | } |
151 | 481 | mdecorde | |
152 | 481 | mdecorde | public int getColumnDimension() { |
153 | 481 | mdecorde | return n;
|
154 | 481 | mdecorde | } |
155 | 481 | mdecorde | |
156 | 481 | mdecorde | public double get(int i, int j) { |
157 | 481 | mdecorde | try {
|
158 | 481 | mdecorde | for (int nval = colpts[j]; nval<colpts[j+1]; nval++) |
159 | 481 | mdecorde | if (rowinds[nval]==i) return vals[nval]; |
160 | 481 | mdecorde | return 0; |
161 | 481 | mdecorde | } catch (ArrayIndexOutOfBoundsException ex) { |
162 | 481 | mdecorde | throw new ArrayIndexOutOfBoundsException("Sparse matrix : " |
163 | 481 | mdecorde | +ex.getLocalizedMessage()); |
164 | 481 | mdecorde | } |
165 | 481 | mdecorde | } |
166 | 481 | mdecorde | |
167 | 481 | mdecorde | public SparseMatrix transpose() {
|
168 | 481 | mdecorde | int[] colpts1 = new int[m+1]; |
169 | 481 | mdecorde | int[] rowinds1 = new int[nnz]; |
170 | 481 | mdecorde | double[] vals1 = new double[nnz]; |
171 | 481 | mdecorde | for (int v = 0; v<nnz; v++) colpts1[rowinds[v]]++; // nnz in each row |
172 | 481 | mdecorde | colpts1[m] = nnz-colpts1[m-1];
|
173 | 481 | mdecorde | for (int r = m-1; r>0; r--) |
174 | 481 | mdecorde | colpts1[r] = colpts1[r+1]-colpts1[r-1]; // starting point of the previous row |
175 | 481 | mdecorde | colpts1[0] = 0; |
176 | 481 | mdecorde | int i = 0; |
177 | 481 | mdecorde | for (int c = 0; c<n; c++) while (i<colpts[c+1]) { |
178 | 481 | mdecorde | int j = colpts1[rowinds[i]+1]++; // j : index of the value in the new vectors |
179 | 481 | mdecorde | rowinds1[j] = c; |
180 | 481 | mdecorde | vals1[j] = vals[i++]; |
181 | 481 | mdecorde | } |
182 | 481 | mdecorde | return new SparseMatrix(n, m, nnz, colpts1, rowinds1, vals1); |
183 | 481 | mdecorde | } |
184 | 481 | mdecorde | |
185 | 481 | mdecorde | public void nulColumnSuppression() { |
186 | 481 | mdecorde | ArrayList<Integer> colpts1 = new ArrayList<Integer>(); |
187 | 481 | mdecorde | colpts1.add(0);
|
188 | 481 | mdecorde | for (int i = 0; i<n; i++) if (colpts[i+1]>colpts[i]) |
189 | 481 | mdecorde | colpts1.add(colpts[i+1]);
|
190 | 481 | mdecorde | n = colpts1.size()-1;
|
191 | 481 | mdecorde | colpts = new int[n+1]; |
192 | 481 | mdecorde | for (int i = 0; i<=n; i++) colpts[i] = colpts1.get(i); |
193 | 481 | mdecorde | } |
194 | 481 | mdecorde | |
195 | 481 | mdecorde | public double elementSum() { |
196 | 481 | mdecorde | double s = 0; |
197 | 481 | mdecorde | for (int i = 0; i<nnz; i++) s += vals[i]; |
198 | 481 | mdecorde | |
199 | 481 | mdecorde | return s;
|
200 | 481 | mdecorde | } |
201 | 481 | mdecorde | |
202 | 481 | mdecorde | public Matrix lineSum() {
|
203 | 481 | mdecorde | double[] S = new double[m]; |
204 | 481 | mdecorde | for (int i = 0; i<nnz; i++) S[rowinds[i]] += vals[i]; |
205 | 481 | mdecorde | |
206 | 481 | mdecorde | return new Matrix(S, m); |
207 | 481 | mdecorde | } |
208 | 481 | mdecorde | |
209 | 481 | mdecorde | public Matrix columnSum() {
|
210 | 481 | mdecorde | double[] S = new double[n]; |
211 | 481 | mdecorde | for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++) |
212 | 481 | mdecorde | S[i] += vals[j]; |
213 | 481 | mdecorde | |
214 | 481 | mdecorde | return new Matrix(S, 1); |
215 | 481 | mdecorde | } |
216 | 481 | mdecorde | |
217 | 481 | mdecorde | public SparseMatrix timesEquals(double s) { |
218 | 481 | mdecorde | for (int i = 0; i<nnz; i++) { |
219 | 481 | mdecorde | vals[i] *= s; |
220 | 481 | mdecorde | } |
221 | 481 | mdecorde | return this; |
222 | 481 | mdecorde | } |
223 | 481 | mdecorde | |
224 | 481 | mdecorde | public SparseMatrix firstColumnTimesEqual(Matrix B) {
|
225 | 481 | mdecorde | double[][] A = B.getArray(); |
226 | 481 | mdecorde | for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++) |
227 | 481 | mdecorde | vals[j] *= A[rowinds[j]][0];
|
228 | 481 | mdecorde | return this; |
229 | 481 | mdecorde | } |
230 | 481 | mdecorde | |
231 | 481 | mdecorde | public SparseMatrix firstLineTimesEqual(Matrix B) {
|
232 | 481 | mdecorde | double[][] A = B.getArray(); |
233 | 481 | mdecorde | for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++) |
234 | 481 | mdecorde | vals[j] *= A[0][i];
|
235 | 481 | mdecorde | return this; |
236 | 481 | mdecorde | } |
237 | 481 | mdecorde | |
238 | 481 | mdecorde | public void opa(double x[], double y[]) { |
239 | 481 | mdecorde | // Computes y = Ax (x et y : length n)
|
240 | 481 | mdecorde | Arrays.fill(y, 0); |
241 | 481 | mdecorde | for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++) |
242 | 481 | mdecorde | y[rowinds[j]] += vals[j]*x[i]; |
243 | 481 | mdecorde | } |
244 | 481 | mdecorde | |
245 | 481 | mdecorde | public void opb(double x[], double y[]) { |
246 | 481 | mdecorde | // Computes y = A'Ax (x et y : length n)
|
247 | 481 | mdecorde | if (tempRow==null) tempRow = new double[m]; |
248 | 481 | mdecorde | else Arrays.fill(tempRow, 0); |
249 | 481 | mdecorde | Arrays.fill(y, 0); |
250 | 481 | mdecorde | for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++) |
251 | 481 | mdecorde | tempRow[rowinds[j]] += vals[j]*x[i]; |
252 | 481 | mdecorde | for (int i = 0; i<n; i++) for (int j = colpts[i]; j<colpts[i+1]; j++) |
253 | 481 | mdecorde | y[i] += vals[j]*tempRow[rowinds[j]]; |
254 | 481 | mdecorde | } |
255 | 481 | mdecorde | |
256 | 481 | mdecorde | public SparseSVD svd(int dim) throws SparseSVD.SparseSVDException { |
257 | 481 | mdecorde | return new SparseSVD(this, dim); |
258 | 481 | mdecorde | } |
259 | 481 | mdecorde | |
260 | 481 | mdecorde | /** Analyse factorielle de correspondances
|
261 | 481 | mdecorde | @return Analyse factorielle de correspondances
|
262 | 481 | mdecorde | @see Analyse factorielle de correspondances
|
263 | 481 | mdecorde | */
|
264 | 481 | mdecorde | public SparseAFC afc() {
|
265 | 481 | mdecorde | try {
|
266 | 481 | mdecorde | return new SparseAFC(this); |
267 | 481 | mdecorde | } catch (SparseSVDException ex) {
|
268 | 481 | mdecorde | return null; |
269 | 481 | mdecorde | } |
270 | 481 | mdecorde | } |
271 | 481 | mdecorde | } |