root / tmp / org.txm.analec.rcp / src / JamaPlus / SparseMatrix.java @ 671
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 | } |