Statistiques
| Révision :

root / tmp / org.txm.analec.rcp / src / JamaPlus / Matrix.java @ 2094

Historique | Voir | Annoter | Télécharger (33,16 ko)

1
package JamaPlus;
2

    
3
import java.text.NumberFormat;
4
import java.text.DecimalFormat;
5
import java.text.DecimalFormatSymbols;
6
import java.util.Locale;
7
import java.io.PrintWriter;
8
import java.io.BufferedReader;
9
import java.io.StreamTokenizer;
10
import JamaPlus.util.*;
11
import java.util.ArrayList;
12

    
13
/**
14
Jama = Java Matrix class.
15
<P>
16
The Java Matrix Class provides the fundamental operations of numerical
17
linear algebra.  Various constructors create Matrices from two dimensional
18
arrays of double precision floating point numbers.  Various "gets" and
19
"sets" provide access to submatrices and matrix elements.  Several methods 
20
implement basic matrix arithmetic, including matrix addition and
21
multiplication, matrix norms, and element-by-element array operations.
22
Methods for reading and printing matrices are also included.  All the
23
operations in this version of the Matrix Class involve real matrices.
24
Complex matrices may be handled in a future version.
25
<P>
26
Five fundamental matrix decompositions, which consist of pairs or triples
27
of matrices, permutation vectors, and the like, produce results in five
28
decomposition classes.  These decompositions are accessed by the Matrix
29
class to compute solutions of simultaneous linear equations, determinants,
30
inverses and other matrix functions.  The five decompositions are:
31
<P><UL>
32
<LI>Cholesky Decomposition of symmetric, positive definite matrices.
33
<LI>LU Decomposition of rectangular matrices.
34
<LI>QR Decomposition of rectangular matrices.
35
<LI>Singular Value Decomposition of rectangular matrices.
36
<LI>Eigenvalue Decomposition of both symmetric and nonsymmetric square matrices.
37
</UL>
38
<DL>
39
<DT><B>Example of use:</B></DT>
40
<P>
41
<DD>Solve a linear system A x = b and compute the residual norm, ||b - A x||.
42
<P><PRE>
43
double[][] vals = {{1.,2.,3},{4.,5.,6.},{7.,8.,10.}};
44
Matrix A = new Matrix(vals);
45
Matrix b = Matrix.random(3,1);
46
Matrix x = A.solve(b);
47
Matrix r = A.times(x).minus(b);
48
double rnorm = r.normInf();
49
</PRE></DD>
50
</DL>
51

52
@author The MathWorks, Inc. and the National Institute of Standards and Technology.
53
@version 5 August 1998
54
 */
55
public class Matrix implements Cloneable, java.io.Serializable {
56

    
57
  /* ------------------------
58
  Class variables
59
   * ------------------------ */
60
  /** Array for internal storage of elements.
61
  @serial internal array storage.
62
   */
63
  private double[][] A;
64
  /** Row and column dimensions.
65
  @serial row dimension.
66
  @serial column dimension.
67
   */
68
  private int m, n;
69

    
70
  /* ------------------------
71
  Constructors
72
   * ------------------------ */
73
  /** Construct an m-by-n matrix of zeros. 
74
  @param m    Number of rows.
75
  @param n    Number of colums.
76
   */
77
  public Matrix(int m, int n) {
78
    this.m = m;
79
    this.n = n;
80
    A = new double[m][n];
81
  }
82

    
83
  /** Construct an m-by-n constant matrix.
84
  @param m    Number of rows.
85
  @param n    Number of colums.
86
  @param s    Fill the matrix with this scalar value.
87
   */
88
  public Matrix(int m, int n, double s) {
89
    this.m = m;
90
    this.n = n;
91
    A = new double[m][n];
92
    for (int i = 0; i < m; i++) {
93
      for (int j = 0; j < n; j++) {
94
        A[i][j] = s;
95
      }
96
    }
97
  }
98

    
99
  /** Construct a matrix from a 2-D array.
100
  @param A    Two-dimensional array of doubles.
101
  @exception  IllegalArgumentException All rows must have the same length
102
  @see        #constructWithCopy
103
   */
104
  public Matrix(double[][] A) {
105
    m = A.length;
106
    n = A[0].length;
107
    for (int i = 0; i < m; i++) {
108
      if (A[i].length != n) {
109
        throw new IllegalArgumentException("All rows must have the same length.");
110
      }
111
    }
112
    this.A = A;
113
  }
114

    
115
  /** Construct a matrix quickly without checking arguments.
116
  @param A    Two-dimensional array of doubles.
117
  @param m    Number of rows.
118
  @param n    Number of colums.
119
   */
120
  public Matrix(double[][] A, int m, int n) {
121
    this.A = A;
122
    this.m = m;
123
    this.n = n;
124
  }
125

    
126
  /** Construct a matrix from a one-dimensional packed array
127
  @param vals One-dimensional array of doubles, packed by columns (ala Fortran).
128
  @param m    Number of rows.
129
  @exception  IllegalArgumentException Array length must be a multiple of m.
130
   */
131
  public Matrix(double vals[], int m) {
132
    this.m = m;
133
    n = (m != 0 ? vals.length / m : 0);
134
    if (m * n != vals.length) {
135
      throw new IllegalArgumentException("Array length must be a multiple of m.");
136
    }
137
    A = new double[m][n];
138
    for (int i = 0; i < m; i++) {
139
      for (int j = 0; j < n; j++) {
140
        A[i][j] = vals[i + j * m];
141
      }
142
    }
143
  }
144

    
145
  /* ------------------------
146
  Public Methods
147
   * ------------------------ */
148
  /** Construct a matrix from a copy of a 2-D array.
149
  @param A    Two-dimensional array of doubles.
150
  @exception  IllegalArgumentException All rows must have the same length
151
   */
152
  public static Matrix constructWithCopy(double[][] A) {
153
    int m = A.length;
154
    int n = A[0].length;
155
    Matrix X = new Matrix(m, n);
156
    double[][] C = X.getArray();
157
    for (int i = 0; i < m; i++) {
158
      if (A[i].length != n) {
159
        throw new IllegalArgumentException("All rows must have the same length.");
160
      }
161
      for (int j = 0; j < n; j++) {
162
        C[i][j] = A[i][j];
163
      }
164
    }
165
    return X;
166
  }
167

    
168
  /** Make a deep copy of a matrix
169
   */
170
  public Matrix copy() {
171
    Matrix X = new Matrix(m, n);
172
    double[][] C = X.getArray();
173
    for (int i = 0; i < m; i++) {
174
      System.arraycopy(A[i], 0, C[i], 0, n);
175
    }
176
    return X;
177
  }
178

    
179
  /** Clone the Matrix object.
180
   */
181
  public Object clone() {
182
    return this.copy();
183
  }
184

    
185
  /** Access the internal two-dimensional array.
186
  @return     Pointer to the two-dimensional array of matrix elements.
187
   */
188
  public double[][] getArray() {
189
    return A;
190
  }
191

    
192
  /** Copy the internal two-dimensional array.
193
  @return     Two-dimensional array copy of matrix elements.
194
   */
195
  public double[][] getArrayCopy() {
196
    double[][] C = new double[m][n];
197
    for (int i = 0; i < m; i++) {
198
      System.arraycopy(A[i], 0, C[i], 0, n);
199
    }
200
    return C;
201
  }
202

    
203
  /** Make a one-dimensional column packed copy of the internal array.
204
  @return     Matrix elements packed in a one-dimensional array by columns.
205
   */
206
  public double[] getColumnPackedCopy() {
207
    double[] vals = new double[m * n];
208
    for (int i = 0; i < m; i++) {
209
      for (int j = 0; j < n; j++) {
210
        vals[i + j * m] = A[i][j];
211
      }
212
    }
213
    return vals;
214
  }
215

    
216
  /** Make a one-dimensional row packed copy of the internal array.
217
  @return     Matrix elements packed in a one-dimensional array by rows.
218
   */
219
  public double[] getRowPackedCopy() {
220
    double[] vals = new double[m * n];
221
    for (int i = 0; i < m; i++) {
222
      for (int j = 0; j < n; j++) {
223
        vals[i * n + j] = A[i][j];
224
      }
225
    }
226
    return vals;
227
  }
228

    
229
  /** Get row dimension.
230
  @return     m, the number of rows.
231
   */
232
  public int getRowDimension() {
233
    return m;
234
  }
235

    
236
  /** Get column dimension.
237
  @return     n, the number of columns.
238
   */
239
  public int getColumnDimension() {
240
    return n;
241
  }
242

    
243
  /** Get a single element.
244
  @param i    Row index.
245
  @param j    Column index.
246
  @return     A(i,j)
247
  @exception  ArrayIndexOutOfBoundsException
248
   */
249
  public double get(int i, int j) {
250
    return A[i][j];
251
  }
252

    
253
  /** Get a submatrix.
254
  @param i0   Initial row index
255
  @param i1   Final row index
256
  @param j0   Initial column index
257
  @param j1   Final column index
258
  @return     A(i0:i1,j0:j1)
259
  @exception  ArrayIndexOutOfBoundsException Submatrix indices
260
   */
261
  public Matrix getMatrix(int i0, int i1, int j0, int j1) {
262
    Matrix X = new Matrix(i1 - i0 + 1, j1 - j0 + 1);
263
    double[][] B = X.getArray();
264
    try {
265
      for (int i = i0; i <= i1; i++) {
266
        for (int j = j0; j <= j1; j++) {
267
          B[i - i0][j - j0] = A[i][j];
268
        }
269
      }
270
    } catch (ArrayIndexOutOfBoundsException e) {
271
      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
272
    }
273
    return X;
274
  }
275

    
276
  /** Get a submatrix.
277
  @param r    Array of row indices.
278
  @param c    Array of column indices.
279
  @return     A(r(:),c(:))
280
  @exception  ArrayIndexOutOfBoundsException Submatrix indices
281
   */
282
  public Matrix getMatrix(int[] r, int[] c) {
283
    Matrix X = new Matrix(r.length, c.length);
284
    double[][] B = X.getArray();
285
    try {
286
      for (int i = 0; i < r.length; i++) {
287
        for (int j = 0; j < c.length; j++) {
288
          B[i][j] = A[r[i]][c[j]];
289
        }
290
      }
291
    } catch (ArrayIndexOutOfBoundsException e) {
292
      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
293
    }
294
    return X;
295
  }
296

    
297
  /** Get a submatrix.
298
  @param i0   Initial row index
299
  @param i1   Final row index
300
  @param c    Array of column indices.
301
  @return     A(i0:i1,c(:))
302
  @exception  ArrayIndexOutOfBoundsException Submatrix indices
303
   */
304
  public Matrix getMatrix(int i0, int i1, int[] c) {
305
    Matrix X = new Matrix(i1 - i0 + 1, c.length);
306
    double[][] B = X.getArray();
307
    try {
308
      for (int i = i0; i <= i1; i++) {
309
        for (int j = 0; j < c.length; j++) {
310
          B[i - i0][j] = A[i][c[j]];
311
        }
312
      }
313
    } catch (ArrayIndexOutOfBoundsException e) {
314
      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
315
    }
316
    return X;
317
  }
318

    
319
  /** Get a submatrix.
320
  @param r    Array of row indices.
321
  @param i0   Initial column index
322
  @param i1   Final column index
323
  @return     A(r(:),j0:j1)
324
  @exception  ArrayIndexOutOfBoundsException Submatrix indices
325
   */
326
  public Matrix getMatrix(int[] r, int j0, int j1) {
327
    Matrix X = new Matrix(r.length, j1 - j0 + 1);
328
    double[][] B = X.getArray();
329
    try {
330
      for (int i = 0; i < r.length; i++) {
331
        for (int j = j0; j <= j1; j++) {
332
          B[i][j - j0] = A[r[i]][j];
333
        }
334
      }
335
    } catch (ArrayIndexOutOfBoundsException e) {
336
      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
337
    }
338
    return X;
339
  }
340

    
341
  /** Set a single element.
342
  @param i    Row index.
343
  @param j    Column index.
344
  @param s    A(i,j).
345
  @exception  ArrayIndexOutOfBoundsException
346
   */
347
  public void set(int i, int j, double s) {
348
    A[i][j] = s;
349
  }
350

    
351
  /** Set a submatrix.
352
  @param i0   Initial row index
353
  @param i1   Final row index
354
  @param j0   Initial column index
355
  @param j1   Final column index
356
  @param X    A(i0:i1,j0:j1)
357
  @exception  ArrayIndexOutOfBoundsException Submatrix indices
358
   */
359
  public void setMatrix(int i0, int i1, int j0, int j1, Matrix X) {
360
    try {
361
      for (int i = i0; i <= i1; i++) {
362
        for (int j = j0; j <= j1; j++) {
363
          A[i][j] = X.get(i - i0, j - j0);
364
        }
365
      }
366
    } catch (ArrayIndexOutOfBoundsException e) {
367
      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
368
    }
369
  }
370

    
371
  /** Set a submatrix.
372
  @param r    Array of row indices.
373
  @param c    Array of column indices.
374
  @param X    A(r(:),c(:))
375
  @exception  ArrayIndexOutOfBoundsException Submatrix indices
376
   */
377
  public void setMatrix(int[] r, int[] c, Matrix X) {
378
    try {
379
      for (int i = 0; i < r.length; i++) {
380
        for (int j = 0; j < c.length; j++) {
381
          A[r[i]][c[j]] = X.get(i, j);
382
        }
383
      }
384
    } catch (ArrayIndexOutOfBoundsException e) {
385
      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
386
    }
387
  }
388

    
389
  /** Set a submatrix.
390
  @param r    Array of row indices.
391
  @param j0   Initial column index
392
  @param j1   Final column index
393
  @param X    A(r(:),j0:j1)
394
  @exception  ArrayIndexOutOfBoundsException Submatrix indices
395
   */
396
  public void setMatrix(int[] r, int j0, int j1, Matrix X) {
397
    try {
398
      for (int i = 0; i < r.length; i++) {
399
        for (int j = j0; j <= j1; j++) {
400
          A[r[i]][j] = X.get(i, j - j0);
401
        }
402
      }
403
    } catch (ArrayIndexOutOfBoundsException e) {
404
      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
405
    }
406
  }
407

    
408
  /** Set a submatrix.
409
  @param i0   Initial row index
410
  @param i1   Final row index
411
  @param c    Array of column indices.
412
  @param X    A(i0:i1,c(:))
413
  @exception  ArrayIndexOutOfBoundsException Submatrix indices
414
   */
415
  public void setMatrix(int i0, int i1, int[] c, Matrix X) {
416
    try {
417
      for (int i = i0; i <= i1; i++) {
418
        for (int j = 0; j < c.length; j++) {
419
          A[i][c[j]] = X.get(i - i0, j);
420
        }
421
      }
422
    } catch (ArrayIndexOutOfBoundsException e) {
423
      throw new ArrayIndexOutOfBoundsException("Submatrix indices");
424
    }
425
  }
426

    
427
  /** Matrix transpose.
428
  @return    A'
429
   */
430
  public Matrix transpose() {
431
    Matrix X = new Matrix(n, m);
432
    double[][] C = X.getArray();
433
    for (int i = 0; i < m; i++) {
434
      for (int j = 0; j < n; j++) {
435
        C[j][i] = A[i][j];
436
      }
437
    }
438
    return X;
439
  }
440

    
441
  /** One norm
442
  @return    maximum column sum.
443
   */
444
  public double norm1() {
445
    double f = 0;
446
    for (int j = 0; j < n; j++) {
447
      double s = 0;
448
      for (int i = 0; i < m; i++) {
449
        s += Math.abs(A[i][j]);
450
      }
451
      f = Math.max(f, s);
452
    }
453
    return f;
454
  }
455

    
456
  /** Two norm
457
  @return    maximum singular value.
458
   */
459
  public double norm2() {
460
    return (new SingularValueDecomposition(this).norm2());
461
  }
462

    
463
  /** Infinity norm
464
  @return    maximum row sum.
465
   */
466
  public double normInf() {
467
    double f = 0;
468
    for (int i = 0; i < m; i++) {
469
      double s = 0;
470
      for (int j = 0; j < n; j++) {
471
        s += Math.abs(A[i][j]);
472
      }
473
      f = Math.max(f, s);
474
    }
475
    return f;
476
  }
477

    
478
  /** Frobenius norm
479
  @return    sqrt of sum of squares of all elements.
480
   */
481
  public double normF() {
482
    double f = 0;
483
    for (int i = 0; i < m; i++) {
484
      for (int j = 0; j < n; j++) {
485
        f = Math.hypot(f, A[i][j]);
486
      }
487
    }
488
    return f;
489
  }
490

    
491
  /**  Unary minus
492
  @return    -A
493
   */
494
  public Matrix uminus() {
495
    Matrix X = new Matrix(m, n);
496
    double[][] C = X.getArray();
497
    for (int i = 0; i < m; i++) {
498
      for (int j = 0; j < n; j++) {
499
        C[i][j] = -A[i][j];
500
      }
501
    }
502
    return X;
503
  }
504

    
505
  /** C = A + B
506
  @param B    another matrix
507
  @return     A + B
508
   */
509
  public Matrix plus(Matrix B) {
510
    checkMatrixDimensions(B);
511
    Matrix X = new Matrix(m, n);
512
    double[][] C = X.getArray();
513
    for (int i = 0; i < m; i++) {
514
      for (int j = 0; j < n; j++) {
515
        C[i][j] = A[i][j] + B.A[i][j];
516
      }
517
    }
518
    return X;
519
  }
520

    
521
  /** A = A + B
522
  @param B    another matrix
523
  @return     A + B
524
   */
525
  public Matrix plusEquals(Matrix B) {
526
    checkMatrixDimensions(B);
527
    for (int i = 0; i < m; i++) {
528
      for (int j = 0; j < n; j++) {
529
        A[i][j] = A[i][j] + B.A[i][j];
530
      }
531
    }
532
    return this;
533
  }
534

    
535
  /** C = A - B
536
  @param B    another matrix
537
  @return     A - B
538
   */
539
  public Matrix minus(Matrix B) {
540
    checkMatrixDimensions(B);
541
    Matrix X = new Matrix(m, n);
542
    double[][] C = X.getArray();
543
    for (int i = 0; i < m; i++) {
544
      for (int j = 0; j < n; j++) {
545
        C[i][j] = A[i][j] - B.A[i][j];
546
      }
547
    }
548
    return X;
549
  }
550

    
551
  /** A = A - B
552
  @param B    another matrix
553
  @return     A - B
554
   */
555
  public Matrix minusEquals(Matrix B) {
556
    checkMatrixDimensions(B);
557
    for (int i = 0; i < m; i++) {
558
      for (int j = 0; j < n; j++) {
559
        A[i][j] = A[i][j] - B.A[i][j];
560
      }
561
    }
562
    return this;
563
  }
564

    
565
  /** Element-by-element multiplication, C = A.*B
566
  @param B    another matrix
567
  @return     A.*B
568
   */
569
  public Matrix arrayTimes(Matrix B) {
570
    checkMatrixDimensions(B);
571
    Matrix X = new Matrix(m, n);
572
    double[][] C = X.getArray();
573
    for (int i = 0; i < m; i++) {
574
      for (int j = 0; j < n; j++) {
575
        C[i][j] = A[i][j] * B.A[i][j];
576
      }
577
    }
578
    return X;
579
  }
580

    
581
  /** Element-by-element multiplication in place, A = A.*B
582
  @param B    another matrix
583
  @return     A.*B
584
   */
585
  public Matrix arrayTimesEquals(Matrix B) {
586
    checkMatrixDimensions(B);
587
    for (int i = 0; i < m; i++) {
588
      for (int j = 0; j < n; j++) {
589
        A[i][j] = A[i][j] * B.A[i][j];
590
      }
591
    }
592
    return this;
593
  }
594

    
595
  /** Element-by-element right division, C = A./B
596
  @param B    another matrix
597
  @return     A./B
598
   */
599
  public Matrix arrayRightDivide(Matrix B) {
600
    checkMatrixDimensions(B);
601
    Matrix X = new Matrix(m, n);
602
    double[][] C = X.getArray();
603
    for (int i = 0; i < m; i++) {
604
      for (int j = 0; j < n; j++) {
605
        C[i][j] = A[i][j] / B.A[i][j];
606
      }
607
    }
608
    return X;
609
  }
610

    
611
  /** Element-by-element right division in place, A = A./B
612
  @param B    another matrix
613
  @return     A./B
614
   */
615
  public Matrix arrayRightDivideEquals(Matrix B) {
616
    checkMatrixDimensions(B);
617
    for (int i = 0; i < m; i++) {
618
      for (int j = 0; j < n; j++) {
619
        A[i][j] = A[i][j] / B.A[i][j];
620
      }
621
    }
622
    return this;
623
  }
624

    
625
  /** Element-by-element left division, C = A.\B
626
  @param B    another matrix
627
  @return     A.\B
628
   */
629
  public Matrix arrayLeftDivide(Matrix B) {
630
    checkMatrixDimensions(B);
631
    Matrix X = new Matrix(m, n);
632
    double[][] C = X.getArray();
633
    for (int i = 0; i < m; i++) {
634
      for (int j = 0; j < n; j++) {
635
        C[i][j] = B.A[i][j] / A[i][j];
636
      }
637
    }
638
    return X;
639
  }
640

    
641
  /** Element-by-element left division in place, A = A.\B
642
  @param B    another matrix
643
  @return     A.\B
644
   */
645
  public Matrix arrayLeftDivideEquals(Matrix B) {
646
    checkMatrixDimensions(B);
647
    for (int i = 0; i < m; i++) {
648
      for (int j = 0; j < n; j++) {
649
        A[i][j] = B.A[i][j] / A[i][j];
650
      }
651
    }
652
    return this;
653
  }
654

    
655
  /** Multiply a matrix by a scalar, C = s*A
656
  @param s    scalar
657
  @return     s*A
658
   */
659
  public Matrix times(double s) {
660
    Matrix X = new Matrix(m, n);
661
    double[][] C = X.getArray();
662
    for (int i = 0; i < m; i++) {
663
      for (int j = 0; j < n; j++) {
664
        C[i][j] = s * A[i][j];
665
      }
666
    }
667
    return X;
668
  }
669

    
670
  /** Multiply a matrix by a scalar in place, A = s*A
671
  @param s    scalar
672
  @return     replace A by s*A
673
   */
674
  public Matrix timesEquals(double s) {
675
    for (int i = 0; i < m; i++) {
676
      for (int j = 0; j < n; j++) {
677
        A[i][j] = s * A[i][j];
678
      }
679
    }
680
    return this;
681
  }
682

    
683
  /** Linear algebraic matrix multiplication, A * B
684
  @param B    another matrix
685
  @return     Matrix product, A * B
686
  @exception  IllegalArgumentException Matrix inner dimensions must agree.
687
   */
688
  public Matrix times(Matrix B) {
689
    if (B.m != n) {
690
      throw new IllegalArgumentException("Matrix inner dimensions must agree.");
691
    }
692
    Matrix X = new Matrix(m, B.n);
693
    double[][] C = X.getArray();
694
    double[] Bcolj = new double[n];
695
    for (int j = 0; j < B.n; j++) {
696
      for (int k = 0; k < n; k++) {
697
        Bcolj[k] = B.A[k][j];
698
      }
699
      for (int i = 0; i < m; i++) {
700
        double[] Arowi = A[i];
701
        double s = 0;
702
        for (int k = 0; k < n; k++) {
703
          s += Arowi[k] * Bcolj[k];
704
        }
705
        C[i][j] = s;
706
      }
707
    }
708
    return X;
709
  }
710

    
711
  /** LU Decomposition
712
  @return     LUDecomposition
713
  @see LUDecomposition
714
   */
715
  public LUDecomposition lu() {
716
    return new LUDecomposition(this);
717
  }
718

    
719
  /** QR Decomposition
720
  @return     QRDecomposition
721
  @see QRDecomposition
722
   */
723
  public QRDecomposition qr() {
724
    return new QRDecomposition(this);
725
  }
726

    
727
  /** Cholesky Decomposition
728
  @return     CholeskyDecomposition
729
  @see CholeskyDecomposition
730
   */
731
  public CholeskyDecomposition chol() {
732
    return new CholeskyDecomposition(this);
733
  }
734

    
735
  /** Singular Value Decomposition
736
  @return     SingularValueDecomposition
737
  @see SingularValueDecomposition
738
   */
739
  public SingularValueDecomposition svd() {
740
    return new SingularValueDecomposition(this);
741
  }
742

    
743
  /** Eigenvalue Decomposition
744
  @return     EigenvalueDecomposition
745
  @see EigenvalueDecomposition
746
   */
747
  public EigenvalueDecomposition eig() {
748
    return new EigenvalueDecomposition(this);
749
  }
750

    
751
  /** Solve A*X = B
752
  @param B    right hand side
753
  @return     solution if A is square, least squares solution otherwise
754
   */
755
  public Matrix solve(Matrix B) {
756
    return (m == n ? (new LUDecomposition(this)).solve(B) : (new QRDecomposition(this)).solve(B));
757
  }
758

    
759
  /** Solve X*A = B, which is also A'*X' = B'
760
  @param B    right hand side
761
  @return     solution if A is square, least squares solution otherwise.
762
   */
763
  public Matrix solveTranspose(Matrix B) {
764
    return transpose().solve(B.transpose());
765
  }
766

    
767
  /** Matrix inverse or pseudoinverse
768
  @return     inverse(A) if A is square, pseudoinverse otherwise.
769
   */
770
  public Matrix inverse() {
771
    return solve(identity(m, m));
772
  }
773

    
774
  /** Matrix determinant
775
  @return     determinant
776
   */
777
  public double det() {
778
    return new LUDecomposition(this).det();
779
  }
780

    
781
  /** Matrix rank
782
  @return     effective numerical rank, obtained from SVD.
783
   */
784
  public int rank() {
785
    return new SingularValueDecomposition(this).rank();
786
  }
787

    
788
  /** Matrix condition (2 norm)
789
  @return     ratio of largest to smallest singular value.
790
   */
791
  public double cond() {
792
    return new SingularValueDecomposition(this).cond();
793
  }
794

    
795
  /** Matrix trace.
796
  @return     sum of the diagonal elements.
797
   */
798
  public double trace() {
799
    double t = 0;
800
    for (int i = 0; i < Math.min(m, n); i++) {
801
      t += A[i][i];
802
    }
803
    return t;
804
  }
805

    
806
  /** Generate matrix with random elements
807
  @param m    Number of rows.
808
  @param n    Number of colums.
809
  @return     An m-by-n matrix with uniformly distributed random elements.
810
   */
811
  public static Matrix random(int m, int n) {
812
    Matrix A = new Matrix(m, n);
813
    double[][] X = A.getArray();
814
    for (int i = 0; i < m; i++) {
815
      for (int j = 0; j < n; j++) {
816
        X[i][j] = Math.random();
817
      }
818
    }
819
    return A;
820
  }
821

    
822
  /** Generate identity matrix
823
  @param m    Number of rows.
824
  @param n    Number of colums.
825
  @return     An m-by-n matrix with ones on the diagonal and zeros elsewhere.
826
   */
827
  public static Matrix identity(int m, int n) {
828
    Matrix A = new Matrix(m, n);
829
    double[][] X = A.getArray();
830
    for (int i = 0; i < m; i++) {
831
      for (int j = 0; j < n; j++) {
832
        X[i][j] = (i == j ? 1.0 : 0.0);
833
      }
834
    }
835
    return A;
836
  }
837

    
838
  /** Print the matrix to stdout.   Line the elements up in columns
839
   * with a Fortran-like 'Fw.d' style format.
840
  @param w    Column width.
841
  @param d    Number of digits after the decimal.
842
   */
843
  public void print(int w, int d) {
844
    print(new PrintWriter(System.out, true), w, d);
845
  }
846

    
847
  /** Print the matrix to the output stream.   Line the elements up in
848
   * columns with a Fortran-like 'Fw.d' style format.
849
  @param output Output stream.
850
  @param w      Column width.
851
  @param d      Number of digits after the decimal.
852
   */
853
  public void print(PrintWriter output, int w, int d) {
854
    DecimalFormat format = new DecimalFormat();
855
    format.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
856
    format.setMinimumIntegerDigits(1);
857
    format.setMaximumFractionDigits(d);
858
    format.setMinimumFractionDigits(d);
859
    format.setGroupingUsed(false);
860
    print(output, format, w + 2);
861
  }
862

    
863
  /** Print the matrix to stdout.  Line the elements up in columns.
864
   * Use the format object, and right justify within columns of width
865
   * characters.
866
   * Note that is the matrix is to be read back in, you probably will want
867
   * to use a NumberFormat that is set to US Locale.
868
  @param format A  Formatting object for individual elements.
869
  @param width     Field width for each column.
870
  @see java.text.DecimalFormat#setDecimalFormatSymbols
871
   */
872
  public void print(NumberFormat format, int width) {
873
    print(new PrintWriter(System.out, true), format, width);
874
  }
875

    
876
  // DecimalFormat is a little disappointing coming from Fortran or C's printf.
877
  // Since it doesn't pad on the left, the elements will come out different
878
  // widths.  Consequently, we'll pass the desired column width in as an
879
  // argument and do the extra padding ourselves.
880
  /** Print the matrix to the output stream.  Line the elements up in columns.
881
   * Use the format object, and right justify within columns of width
882
   * characters.
883
   * Note that is the matrix is to be read back in, you probably will want
884
   * to use a NumberFormat that is set to US Locale.
885
  @param output the output stream.
886
  @param format A formatting object to format the matrix elements 
887
  @param width  Column width.
888
  @see java.text.DecimalFormat#setDecimalFormatSymbols
889
   */
890
  public void print(PrintWriter output, NumberFormat format, int width) {
891
    output.println();  // start on new line.
892
    for (int i = 0; i < m; i++) {
893
      for (int j = 0; j < n; j++) {
894
        String s = format.format(A[i][j]); // format the number
895
        int padding = Math.max(1, width - s.length()); // At _least_ 1 space
896
        for (int k = 0; k < padding; k++) {
897
          output.print(' ');
898
        }
899
        output.print(s);
900
      }
901
      output.println();
902
    }
903
    output.println();   // end with blank line.
904
  }
905

    
906
  /** Read a matrix from a stream.  The format is the same the print method,
907
   * so printed matrices can be read back in (provided they were printed using
908
   * US Locale).  Elements are separated by
909
   * whitespace, all the elements for each row appear on a single line,
910
   * the last row is followed by a blank line.
911
  @param input the input stream.
912
   */
913
  @SuppressWarnings("unchecked")
914
  public static Matrix read(BufferedReader input) throws java.io.IOException {
915
    StreamTokenizer tokenizer = new StreamTokenizer(input);
916

    
917
    // Although StreamTokenizer will parse numbers, it doesn't recognize
918
    // scientific notation (E or D); however, Double.valueOf does.
919
    // The strategy here is to disable StreamTokenizer's number parsing.
920
    // We'll only get whitespace delimited words, EOL's and EOF's.
921
    // These words should all be numbers, for Double.valueOf to parse.
922

    
923
    tokenizer.resetSyntax();
924
    tokenizer.wordChars(0, 255);
925
    tokenizer.whitespaceChars(0, ' ');
926
    tokenizer.eolIsSignificant(true);
927
    java.util.Vector v = new java.util.Vector();
928

    
929
    // Ignore initial empty lines
930
    while (tokenizer.nextToken() == StreamTokenizer.TT_EOL);
931
    if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
932
      throw new java.io.IOException("Unexpected EOF on matrix read.");
933
    }
934
    do {
935
      v.addElement(Double.valueOf(tokenizer.sval)); // Read & store 1st row.
936
    } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
937

    
938
    int n = v.size();  // Now we've got the number of columns!
939
    double row[] = new double[n];
940
    for (int j = 0; j < n; j++) // extract the elements of the 1st row.
941
    {
942
      row[j] = ((Double) v.elementAt(j)).doubleValue();
943
    }
944
    v.removeAllElements();
945
    v.addElement(row);  // Start storing rows instead of columns.
946
    while (tokenizer.nextToken() == StreamTokenizer.TT_WORD) {
947
      // While non-empty lines
948
      v.addElement(row = new double[n]);
949
      int j = 0;
950
      do {
951
        if (j >= n) {
952
          throw new java.io.IOException("Row " + v.size() + " is too long.");
953
        }
954
        row[j++] = Double.valueOf(tokenizer.sval).doubleValue();
955
      } while (tokenizer.nextToken() == StreamTokenizer.TT_WORD);
956
      if (j < n) {
957
        throw new java.io.IOException("Row " + v.size() + " is too short.");
958
      }
959
    }
960
    int m = v.size();  // Now we've got the number of rows.
961
    double[][] A = new double[m][];
962
    v.copyInto(A);  // copy the rows out of the vector
963
    return new Matrix(A);
964
  }
965

    
966

    
967
  /* ------------------------
968
  Private Methods
969
   * ------------------------ */
970
  /** Check if size(A) == size(B) **/
971
  private void checkMatrixDimensions(Matrix B) {
972
    if (B.m != m || B.n != n) {
973
      throw new IllegalArgumentException("Matrix dimensions must agree.");
974
    }
975
  }
976

    
977
  /* ---------------------------------
978
  Quelques méthodes supplémentaires
979
   * ---------------------------------*/
980
  private void checkLineDimension(Matrix B) {
981
    if (B.m != m) {
982
      throw new IllegalArgumentException("Matrix line dimension must agree.");
983
    }
984
  }
985

    
986
  private void checkColumnDimension(Matrix B) {
987
    if (B.n != n) {
988
      throw new IllegalArgumentException("Matrix column dimension must agree.");
989
    }
990
  }
991

    
992
  public long getNumberNonZeroValues() {
993
    long nnz = 0;
994
    for (int i = 0; i < m; i++) {
995
      for (int j = 0; j < n; j++) {
996
        if (A[i][j] != 0) nnz++;
997
      }
998
    }
999
    return nnz;
1000
  }
1001

    
1002
  public double minColumn(int j) {
1003
    double min = Double.POSITIVE_INFINITY;
1004
    for (int i = 0; i < m; i++) {
1005
      min = Math.min(min, A[i][j]);
1006
    }
1007
    return min;
1008
  }
1009

    
1010
  public double maxColumn(int j) {
1011
    double max = Double.NEGATIVE_INFINITY;
1012
    for (int i = 0; i < m; i++) {
1013
      max = Math.max(max, A[i][j]);
1014
    }
1015
    return max;
1016
  }
1017

    
1018
  public double elementSum() {
1019
    double s = 0;
1020
    for (int i = 0; i < m; i++) {
1021
      for (int j = 0; j < n; j++) {
1022
        s += A[i][j];
1023
      }
1024
    }
1025
    return s;
1026
  }
1027

    
1028
  public Matrix lineSum() {
1029
    Matrix S = new Matrix(m, 1);
1030
    double s[][] = S.getArray();
1031
    for (int i = 0; i < m; i++) {
1032
      for (int j = 0; j < n; j++) {
1033
        s[i][0] += A[i][j];
1034
      }
1035
    }
1036
    return S;
1037
  }
1038

    
1039
  public Matrix lineMean() {
1040
    Matrix S = new Matrix(m, 1);
1041
    double s[][] = S.getArray();
1042
    for (int i = 0; i < m; i++) {
1043
      for (int j = 0; j < n; j++) {
1044
        s[i][0] += A[i][j];
1045
      }
1046
      s[i][0] /= n;
1047
    }
1048
    return S;
1049
  }
1050

    
1051
  public Matrix columnSum() {
1052
    Matrix S = new Matrix(1, n);
1053
    double s[][] = S.getArray();
1054
    for (int j = 0; j < n; j++) {
1055
      for (int i = 0; i < m; i++) {
1056
        s[0][j] += A[i][j];
1057
      }
1058
    }
1059
    return S;
1060
  }
1061

    
1062
  public Matrix columnMean() {
1063
    Matrix S = new Matrix(1, n);
1064
    double s[][] = S.getArray();
1065
    for (int j = 0; j < n; j++) {
1066
      for (int i = 0; i < m; i++) {
1067
        s[0][j] += A[i][j];
1068
      }
1069
      s[0][j] /= m;
1070
    }
1071
    return S;
1072
  }
1073

    
1074
  public Matrix columnCovariance() {
1075
    double mean[] = new double[n];
1076
    for (int j = 0; j < n; j++) {
1077
      for (int i = 0; i < m; i++) {
1078
        mean[j] += A[i][j];
1079
      }
1080
      mean[j] /= m;
1081
    }
1082
    Matrix X = new Matrix(n, n);
1083
    double[][] B = X.getArray();
1084
    double[] Acolj = new double[m];
1085
    int coef = m > 2 ? m-1 : 1;
1086
    for (int j = 0; j < n; j++) {
1087
      for (int k = 0; k < m; k++) {
1088
        Acolj[k] = A[k][j] - mean[j];
1089
      }
1090
      for (int i = 0; i < n; i++) {
1091
        double[] Atrowi = new double[m];
1092
        for (int k = 0; k < m; k++) {
1093
          Atrowi[k] = A[k][i] - mean[i];
1094
        }
1095
        double s = 0;
1096
        for (int k = 0; k < m; k++) {
1097
          s += Atrowi[k] * Acolj[k];
1098
        }
1099
        B[i][j] = s / coef;
1100
      }
1101
    }
1102
    return X;
1103
  }
1104

    
1105
public Matrix firstLineMinus(Matrix B) {
1106
     checkColumnDimension(B);
1107
    Matrix X = new Matrix(m, n);
1108
    double[][] C = X.getArray();
1109
    for (int i = 0; i < m; i++) {
1110
      for (int j = 0; j < n; j++) {
1111
        C[i][j] = A[i][j] - B.A[0][j];
1112
      }
1113
    }
1114
    return X;
1115
 
1116
}
1117
  public Matrix nulColumnSuppression() {
1118
    ArrayList<Integer> cols = new ArrayList<Integer>();
1119
    for (int j = 0; j < n; j++) {
1120
      for (int i = 0; i < m; i++) {
1121
        if (A[i][j] != 0) {
1122
          cols.add(j);
1123
          break;
1124
        }
1125
      }
1126
    }
1127
    int[] c = new int[cols.size()];
1128
    for (int i = 0; i < c.length; i++) {
1129
      c[i] = cols.get(i);
1130
    }
1131
    return getMatrix(0, m - 1, c);
1132
  }
1133

    
1134
  public Matrix arrayInverse() {
1135
    Matrix X = new Matrix(m, n);
1136
    double[][] C = X.getArray();
1137
    for (int i = 0; i < m; i++) {
1138
      for (int j = 0; j < n; j++) {
1139
        C[i][j] = 1 / A[i][j];
1140
      }
1141
    }
1142
    return X;
1143
  }
1144

    
1145
  public Matrix arraySqrt() {
1146
    Matrix X = new Matrix(m, n);
1147
    double[][] C = X.getArray();
1148
    for (int i = 0; i < m; i++) {
1149
      for (int j = 0; j < n; j++) {
1150
        C[i][j] = Math.sqrt(A[i][j]);
1151
      }
1152
    }
1153
    return X;
1154
  }
1155

    
1156
  public Matrix firstColumTimes(Matrix B) {
1157
    checkLineDimension(B);
1158
    Matrix X = new Matrix(m, n);
1159
    double[][] C = X.getArray();
1160
    for (int i = 0; i < m; i++) {
1161
      for (int j = 0; j < n; j++) {
1162

    
1163
        C[i][j] = A[i][j] * B.A[i][0];
1164
      }
1165
    }
1166
    return X;
1167
  }
1168

    
1169
  public Matrix firstColumnTimesEqual(Matrix B) {
1170
    checkLineDimension(B);
1171
    for (int i = 0; i < m; i++) {
1172
       for (int j = 0; j < n; j++) {
1173

    
1174
        A[i][j] *= B.A[i][0];
1175
      }
1176
    }
1177
    return this;
1178
  }
1179

    
1180
  public Matrix firstLineTimesEqual(Matrix B) {
1181
    checkColumnDimension(B);
1182
    for (int i = 0; i < m; i++) {
1183
      for (int j = 0; j < n; j++) {
1184
        A[i][j] *= B.A[0][j];
1185
      }
1186
    }
1187
    return this;
1188
  }
1189

    
1190
  public Matrix firstLineTimes(Matrix B) {
1191
    checkColumnDimension(B);
1192
    Matrix X = new Matrix(m, n);
1193
    double[][] C = X.getArray();
1194
    for (int i = 0; i < m; i++) {
1195
      for (int j = 0; j < n; j++) {
1196
        C[i][j] = A[i][j] * B.A[0][j];
1197
      }
1198
    }
1199
    return X;
1200
  }
1201

    
1202
  public void fixColumnSigns() {
1203
    for (int j = 0; j < n; j++) {
1204
      int i = 0;
1205
      while (i<m && A[i][j] == 0) i++;
1206
      if (i==m || A[i][j] > 0)  continue;
1207
      while (i < m) {
1208
        A[i][j] = -A[i][j];
1209
        i++;
1210
      }
1211
    }
1212
  }
1213

    
1214
  /** Analyse factorielle de correspondances
1215
  @return     Analyse factorielle de correspondances
1216
  @see Analyse factorielle de correspondances
1217
   */
1218
  public AFC afc() {
1219
    return new AFC(this);
1220
  }
1221
}