source: src/main/java/weka/core/Matrix.java @ 22

Last change on this file since 22 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 15.1 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    Matrix.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.core;
24
25import java.io.Reader;
26import java.io.Serializable;
27import java.io.Writer;
28
29/**
30 * Class for performing operations on a matrix of floating-point values.
31 * <p/>
32 * Deprecated: Uses internally the code of the sub-package
33 * <code>weka.core.matrix</code> - only for backwards compatibility.
34 *
35 * @author Gabi Schmidberger (gabi@cs.waikato.ac.nz)
36 * @author Yong Wang (yongwang@cs.waikato.ac.nz)
37 * @author Eibe Frank (eibe@cs.waikato.ac.nz)
38 * @author Len Trigg (eibe@cs.waikato.ac.nz)
39 * @author Fracpete (fracpete at waikato dot ac dot nz)
40 * @version $Revision: 5953 $
41 * @deprecated Use <code>weka.core.matrix.Matrix</code> instead - only for
42 * backwards compatibility.
43 */
44public class Matrix 
45  implements Cloneable, Serializable, RevisionHandler {
46
47  /** for serialization */
48  private static final long serialVersionUID = -3604757095849145838L;
49
50  /**
51   * The actual matrix */
52  protected weka.core.matrix.Matrix m_Matrix = null;
53
54  /**
55   * Constructs a matrix and initializes it with default values.
56   *
57   * @param nr the number of rows
58   * @param nc the number of columns
59   */
60  public Matrix(int nr, int nc) {
61    m_Matrix = new weka.core.matrix.Matrix(nr, nc);
62  }
63
64  /**
65   * Constructs a matrix using a given array.
66   *
67   * @param array the values of the matrix
68   */
69  public Matrix(double[][] array) throws Exception {
70    m_Matrix = new weka.core.matrix.Matrix(array);
71  }
72
73  /**
74   * Reads a matrix from a reader. The first line in the file should
75   * contain the number of rows and columns. Subsequent lines
76   * contain elements of the matrix.
77   *
78   * @param r the reader containing the matrix
79   * @throws Exception if an error occurs
80   */
81  public Matrix(Reader r) throws Exception {
82    m_Matrix = new weka.core.matrix.Matrix(r);
83  }
84
85  /**
86   * Creates and returns a clone of this object.
87   *
88   * @return a clone of this instance.
89   * @throws Exception if an error occurs
90   */
91  public Object clone() {
92    try {
93      return new Matrix(m_Matrix.getArrayCopy());
94    }
95    catch (Exception e) {
96      e.printStackTrace();
97      return null;
98    }
99  }
100
101  /**
102   * Writes out a matrix.
103   *
104   * @param w the output Writer
105   * @throws Exception if an error occurs
106   */
107  public void write(Writer w) throws Exception {
108    m_Matrix.write(w);
109  }
110
111  /**
112   * returns the internal matrix
113   * @see #m_Matrix
114   */
115  protected weka.core.matrix.Matrix getMatrix() {
116    return m_Matrix;
117  }
118
119  /**
120   * Returns the value of a cell in the matrix.
121   *
122   * @param rowIndex the row's index
123   * @param columnIndex the column's index
124   * @return the value of the cell of the matrix
125   */
126  public final double getElement(int rowIndex, int columnIndex) {
127    return m_Matrix.get(rowIndex, columnIndex);
128  }
129
130  /**
131   * Add a value to an element.
132   *
133   * @param rowIndex the row's index.
134   * @param columnIndex the column's index.
135   * @param value the value to add.
136   */
137  public final void addElement(int rowIndex, int columnIndex, double value) {
138    m_Matrix.set(
139        rowIndex, columnIndex, m_Matrix.get(rowIndex, columnIndex) + value);
140  }
141
142  /**
143   * Returns the number of rows in the matrix.
144   *
145   * @return the number of rows
146   */
147  public final int numRows() {
148    return m_Matrix.getRowDimension();
149  }
150
151  /**
152   * Returns the number of columns in the matrix.
153   *
154   * @return the number of columns
155   */
156  public final int numColumns() {
157    return m_Matrix.getColumnDimension();
158  }
159
160  /**
161   * Sets an element of the matrix to the given value.
162   *
163   * @param rowIndex the row's index
164   * @param columnIndex the column's index
165   * @param value the value
166   */
167  public final void setElement(int rowIndex, int columnIndex, double value) {
168    m_Matrix.set(rowIndex, columnIndex, value);
169  }
170
171  /**
172   * Sets a row of the matrix to the given row. Performs a deep copy.
173   *
174   * @param index the row's index
175   * @param newRow an array of doubles
176   */
177  public final void setRow(int index, double[] newRow) {
178    for (int i = 0; i < newRow.length; i++)
179      m_Matrix.set(index, i, newRow[i]);
180  }
181 
182  /**
183   * Gets a row of the matrix and returns it as double array.
184   *
185   * @param index the row's index
186   * @return an array of doubles
187   */
188  public double[] getRow(int index) {
189    double[] newRow = new double[this.numColumns()];
190    for (int i = 0; i < newRow.length; i++)
191      newRow[i] = getElement(index, i);
192
193    return newRow;
194  }
195
196  /**
197   * Gets a column of the matrix and returns it as a double array.
198   *
199   * @param index the column's index
200   * @return an array of doubles
201   */
202  public double[] getColumn(int index) {
203    double[] newColumn = new double[this.numRows()];
204    for (int i = 0; i < newColumn.length; i++)
205      newColumn[i] = getElement(i, index);
206
207    return newColumn;
208  }
209
210  /**
211   * Sets a column of the matrix to the given column. Performs a deep copy.
212   *
213   * @param index the column's index
214   * @param newColumn an array of doubles
215   */
216  public final void setColumn(int index, double[] newColumn) {
217    for (int i = 0; i < numRows(); i++)
218      m_Matrix.set(i, index, newColumn[i]);
219  }
220
221  /**
222   * Converts a matrix to a string
223   *
224   * @return the converted string
225   */
226  public String toString() {
227    return m_Matrix.toString();
228  } 
229   
230  /**
231   * Returns the sum of this matrix with another.
232   *
233   * @return a matrix containing the sum.
234   */
235  public final Matrix add(Matrix other) {
236    try {
237      return new Matrix(m_Matrix.plus(other.getMatrix()).getArrayCopy());
238    }
239    catch (Exception e) {
240      e.printStackTrace();
241      return null;
242    }
243  }
244 
245  /**
246   * Returns the transpose of a matrix.
247   *
248   * @return the transposition of this instance.
249   */
250  public final Matrix transpose() {
251    try {
252      return new Matrix(m_Matrix.transpose().getArrayCopy());
253    }
254    catch (Exception e) {
255      e.printStackTrace();
256      return null;
257    }
258  }
259 
260  /**
261   * Returns true if the matrix is symmetric.
262   *
263   * @return boolean true if matrix is symmetric.
264   */
265  public boolean isSymmetric() {
266    return m_Matrix.isSymmetric();
267  }
268
269  /**
270   * Returns the multiplication of two matrices
271   *
272   * @param b the multiplication matrix
273   * @return the product matrix
274   */
275  public final Matrix multiply(Matrix b) {
276    try {
277      return new Matrix(getMatrix().times(b.getMatrix()).getArrayCopy());
278    }
279    catch (Exception e) {
280      e.printStackTrace();
281      return null;
282    }
283  }
284
285  /**
286   * Performs a (ridged) linear regression.
287   *
288   * @param y the dependent variable vector
289   * @param ridge the ridge parameter
290   * @return the coefficients
291   * @throws IllegalArgumentException if not successful
292   */
293  public final double[] regression(Matrix y, double ridge) {
294    return getMatrix().regression(y.getMatrix(), ridge).getCoefficients();
295  }
296
297  /**
298   * Performs a weighted (ridged) linear regression.
299   *
300   * @param y the dependent variable vector
301   * @param w the array of data point weights
302   * @param ridge the ridge parameter
303   * @return the coefficients
304   * @throws IllegalArgumentException if the wrong number of weights were
305   * provided.
306   */
307  public final double[] regression(Matrix y, double [] w, double ridge) {
308    return getMatrix().regression(y.getMatrix(), w, ridge).getCoefficients();
309  }
310
311  /**
312   * Returns the L part of the matrix.
313   * This does only make sense after LU decomposition.
314   *
315   * @return matrix with the L part of the matrix;
316   * @see #LUDecomposition()
317   */
318  public Matrix getL() throws Exception {
319    int nr = numRows();    // num of rows
320    int nc = numColumns(); // num of columns
321    double[][] ld = new double[nr][nc];
322
323    for (int i = 0; i < nr; i++) {
324      for (int j = 0; (j < i) && (j < nc); j++) {
325        ld[i][j] = getElement(i, j);
326      }
327      if (i < nc) ld[i][i] = 1;
328    }
329    Matrix l = new Matrix(ld);
330    return l;
331  }
332
333  /**
334   * Returns the U part of the matrix.
335   * This does only make sense after LU decomposition.
336   *
337   * @return matrix with the U part of a matrix;
338   * @see #LUDecomposition()
339   */
340  public Matrix getU() throws Exception {
341    int nr = numRows();    // num of rows
342    int nc = numColumns(); // num of columns
343    double[][] ud = new double[nr][nc];
344
345    for (int i = 0; i < nr; i++) {
346      for (int j = i; j < nc ; j++) {
347        ud[i][j] = getElement(i, j);
348      }
349    }
350    Matrix u = new Matrix(ud);
351    return u;
352  }
353 
354  /**
355   * Performs a LUDecomposition on the matrix.
356   * It changes the matrix into its LU decomposition.
357   *
358   * @return the indices of the row permutation
359   */
360  public int[] LUDecomposition() throws Exception {
361    // decompose
362    weka.core.matrix.LUDecomposition lu = m_Matrix.lu();
363
364    // singular? old class throws Exception!
365    if (!lu.isNonsingular())
366        throw new Exception("Matrix is singular");
367
368    weka.core.matrix.Matrix u = lu.getU();
369    weka.core.matrix.Matrix l = lu.getL();
370
371    // modify internal matrix
372    int nr = numRows();
373    int nc = numColumns();
374    for (int i = 0; i < nr; i++) {
375      for (int j = 0; j < nc; j++) {
376        if (j < i)
377          setElement(i, j, l.get(i, j));
378        else
379          setElement(i, j, u.get(i, j));
380      }
381    }
382
383    u = null;
384    l = null;
385   
386    return lu.getPivot();
387  }
388 
389  /**
390   * Solve A*X = B using backward substitution.
391   * A is current object (this). Note that this matrix will be changed!
392   * B parameter bb.
393   * X returned in parameter bb.
394   *
395   * @param bb first vector B in above equation then X in same equation.
396   */
397  public void solve(double[] bb) throws Exception {
398    // solve
399    weka.core.matrix.Matrix x = m_Matrix.solve(
400                                    new weka.core.matrix.Matrix(bb, bb.length));
401   
402    // move X into bb
403    int nr = x.getRowDimension();
404    for (int i = 0; i < nr; i++)
405      bb[i] = x.get(i, 0);
406  }
407
408  /**
409   * Performs Eigenvalue Decomposition using Householder QR Factorization
410   *
411   * Matrix must be symmetrical.
412   * Eigenvectors are return in parameter V, as columns of the 2D array.
413   * (Real parts of) Eigenvalues are returned in parameter d.
414   *
415   * @param V double array in which the eigenvectors are returned
416   * @param d array in which the eigenvalues are returned
417   * @throws Exception if matrix is not symmetric
418   */
419  public void eigenvalueDecomposition(double[][] V, double[] d) 
420    throws Exception {
421
422    // old class only worked with symmetric matrices!
423    if (!this.isSymmetric())
424      throw new Exception("EigenvalueDecomposition: Matrix must be symmetric.");
425   
426    // perform eigenvalue decomposition
427    weka.core.matrix.EigenvalueDecomposition eig = m_Matrix.eig();
428    weka.core.matrix.Matrix v = eig.getV();
429    double[] d2 = eig.getRealEigenvalues();
430   
431    // transfer data
432    int nr = numRows();
433    int nc = numColumns();
434    for (int i = 0; i < nr; i++)
435      for (int j = 0; j < nc; j++)
436        V[i][j] = v.get(i, j);
437
438    for (int i = 0; i < d2.length; i++)
439      d[i] = d2[i];
440  } 
441
442  /**
443   * Returns sqrt(a^2 + b^2) without under/overflow.
444   *   
445   * @param a length of one side of rectangular triangle
446   * @param b length of other side of rectangular triangle
447   * @return lenght of third side
448   */
449  protected static double hypot(double a, double b) {
450    return weka.core.matrix.Maths.hypot(a, b);
451  }
452
453  /**
454   * converts the Matrix into a single line Matlab string: matrix is enclosed
455   * by parentheses, rows are separated by semicolon and single cells by
456   * blanks, e.g., [1 2; 3 4].
457   * @return      the matrix in Matlab single line format
458   */
459  public String toMatlab() {
460    return getMatrix().toMatlab();
461  }
462
463  /**
464   * creates a matrix from the given Matlab string.
465   * @param matlab  the matrix in matlab format
466   * @return        the matrix represented by the given string
467   * @see           #toMatlab()
468   */
469  public static Matrix parseMatlab(String matlab) throws Exception {
470    return new Matrix(weka.core.matrix.Matrix.parseMatlab(matlab).getArray());
471  }
472 
473  /**
474   * Returns the revision string.
475   *
476   * @return            the revision
477   */
478  public String getRevision() {
479    return RevisionUtils.extract("$Revision: 5953 $");
480  }
481 
482  /**
483   * Main method for testing this class.
484   */
485  public static void main(String[] ops) {
486
487    double[] first = {2.3, 1.2, 5};
488    double[] second = {5.2, 1.4, 9};
489    double[] response = {4, 7, 8};
490    double[] weights = {1, 2, 3};
491
492    try {
493      // test eigenvaluedecomposition
494      double[][] m = {{1, 2, 3}, {2, 5, 6},{3, 6, 9}};
495      Matrix M = new Matrix(m);
496      int n = M.numRows();
497      double[][] V = new double[n][n];
498      double[] d = new double[n];
499      double[] e = new double[n];
500      M.eigenvalueDecomposition(V, d);
501      Matrix v = new Matrix(V);
502      // M.testEigen(v, d, );
503      // end of test-eigenvaluedecomposition
504     
505      Matrix a = new Matrix(2, 3);
506      Matrix b = new Matrix(3, 2);
507      System.out.println("Number of columns for a: " + a.numColumns());
508      System.out.println("Number of rows for a: " + a.numRows());
509      a.setRow(0, first);
510      a.setRow(1, second);
511      b.setColumn(0, first);
512      b.setColumn(1, second);
513      System.out.println("a:\n " + a);
514      System.out.println("b:\n " + b);
515      System.out.println("a (0, 0): " + a.getElement(0, 0));
516      System.out.println("a transposed:\n " + a.transpose());
517      System.out.println("a * b:\n " + a.multiply(b));
518      Matrix r = new Matrix(3, 1);
519      r.setColumn(0, response);
520      System.out.println("r:\n " + r);
521      System.out.println("Coefficients of regression of b on r: ");
522      double[] coefficients = b.regression(r, 1.0e-8);
523      for (int i = 0; i < coefficients.length; i++) {
524        System.out.print(coefficients[i] + " ");
525      }
526      System.out.println();
527      System.out.println("Weights: ");
528      for (int i = 0; i < weights.length; i++) {
529        System.out.print(weights[i] + " ");
530      }
531      System.out.println();
532      System.out.println("Coefficients of weighted regression of b on r: ");
533      coefficients = b.regression(r, weights, 1.0e-8);
534      for (int i = 0; i < coefficients.length; i++) {
535        System.out.print(coefficients[i] + " ");
536      }
537      System.out.println();
538      a.setElement(0, 0, 6);
539      System.out.println("a with (0, 0) set to 6:\n " + a);
540      a.write(new java.io.FileWriter("main.matrix"));
541      System.out.println("wrote matrix to \"main.matrix\"\n" + a);
542      a = new Matrix(new java.io.FileReader("main.matrix"));
543      System.out.println("read matrix from \"main.matrix\"\n" + a);
544    } catch (Exception e) {
545      e.printStackTrace();
546    }
547  }
548}
549
Note: See TracBrowser for help on using the repository browser.