📄 matrix.java
字号:
/**
* Returns true if the matrix is symmetric.
*
* @return boolean true if matrix is symmetric.
*/
public boolean isSymmetric() {
int nr = m_Elements.length, nc = m_Elements[0].length;
if (nr != nc)
return false;
for(int i = 0; i < nc; i++) {
for(int j = 0; j < i; j++) {
if (m_Elements[i][j] != m_Elements[j][i])
return false;
}
}
return true;
}
/**
* Returns the multiplication of two matrices
*
* @param b the multiplication matrix
* @return the product matrix
*/
public final Matrix multiply(Matrix b) {
int nr = m_Elements.length, nc = m_Elements[0].length;
int bnr = b.m_Elements.length, bnc = b.m_Elements[0].length;
Matrix c = new Matrix(nr, bnc);
for(int i = 0; i < nr; i++) {
for(int j = 0; j< bnc; j++) {
for(int k = 0; k < nc; k++) {
c.m_Elements[i][j] += m_Elements[i][k] * b.m_Elements[k][j];
}
}
}
return c;
}
/**
* Performs a (ridged) linear regression.
*
* @param y the dependent variable vector
* @param ridge the ridge parameter
* @return the coefficients
* @exception IllegalArgumentException if not successful
*/
public final double[] regression(Matrix y, double ridge) {
if (y.numColumns() > 1) {
throw new IllegalArgumentException("Only one dependent variable allowed");
}
int nc = m_Elements[0].length;
double[] b = new double[nc];
Matrix xt = this.transpose();
boolean success = true;
do {
Matrix ss = xt.multiply(this);
// Set ridge regression adjustment
for (int i = 0; i < nc; i++) {
ss.setElement(i, i, ss.getElement(i, i) + ridge);
}
// Carry out the regression
Matrix bb = xt.multiply(y);
for(int i = 0; i < nc; i++) {
b[i] = bb.m_Elements[i][0];
}
try {
ss.solve(b);
success = true;
} catch (Exception ex) {
ridge *= 10;
success = false;
}
} while (!success);
return b;
}
/**
* Performs a weighted (ridged) linear regression.
*
* @param y the dependent variable vector
* @param w the array of data point weights
* @param ridge the ridge parameter
* @return the coefficients
* @exception IllegalArgumentException if the wrong number of weights were
* provided.
*/
public final double[] regression(Matrix y, double [] w, double ridge) {
if (w.length != numRows()) {
throw new IllegalArgumentException("Incorrect number of weights provided");
}
Matrix weightedThis = new Matrix(numRows(), numColumns());
Matrix weightedDep = new Matrix(numRows(), 1);
for (int i = 0; i < w.length; i++) {
double sqrt_weight = Math.sqrt(w[i]);
for (int j = 0; j < numColumns(); j++) {
weightedThis.setElement(i, j, getElement(i, j) * sqrt_weight);
}
weightedDep.setElement(i, 0, y.getElement(i, 0) * sqrt_weight);
}
return weightedThis.regression(weightedDep, ridge);
}
/**
* Returns the L part of the matrix.
* This does only make sense after LU decomposition.
*
* @return matrix with the L part of the matrix;
*/
public Matrix getL() throws Exception {
int nr = m_Elements.length; // num of rows
int nc = m_Elements[0].length; // num of columns
double[][] ld = new double[nr][nc];
for (int i = 0; i < nr; i++) {
for (int j = 0; (j < i) && (j < nc); j++) {
ld[i][j] = m_Elements[i][j];
}
if (i < nc) ld[i][i] = 1;
}
Matrix l = new Matrix(ld);
return l;
}
/**
* Returns the U part of the matrix.
* This does only make sense after LU decomposition.
*
* @return matrix with the U part of a matrix;
*/
public Matrix getU() throws Exception {
int nr = m_Elements.length; // num of rows
int nc = m_Elements[0].length; // num of columns
double[][] ud = new double[nr][nc];
for (int i = 0; i < nr; i++) {
for (int j = i; j < nc ; j++) {
ud[i][j] = m_Elements[i][j];
}
}
Matrix u = new Matrix(ud);
return u;
}
/**
* Performs a LUDecomposition on the matrix.
* It changes the matrix into its LU decomposition using the
* Crout algorithm
*
* @return the indices of the row permutation
* @exception Exception if the matrix is singular
*/
public int [] LUDecomposition() throws Exception {
int nr = m_Elements.length; // num of rows
int nc = m_Elements[0].length; // num of columns
int [] piv = new int[nr];
double [] factor = new double[nr];
double dd;
for (int row = 0; row < nr; row++) {
double max = Math.abs(m_Elements[row][0]);
for (int col = 1; col < nc; col++) {
if ((dd = Math.abs(m_Elements[row][col])) > max)
max = dd;
}
if (max < 0.000000001) {
throw new Exception("Matrix is singular!");
}
factor[row] = 1 / max;
}
for (int i = 1; i < nr; i++) piv[i] = i;
for (int col = 0; col < nc; col++) {
// compute beta i,j
for (int row = 0; (row <= col) && (row < nr); row ++) {
double sum = 0.0;
for (int k = 0; k < row; k++) {
sum += m_Elements[row][k] * m_Elements[k][col];
}
m_Elements[row][col] = m_Elements[row][col] - sum; // beta i,j
;
}
// compute alpha i,j
for (int row = col + 1; row < nr; row ++) {
double sum = 0.0;
for (int k = 0; k < col; k++) {
sum += m_Elements[row][k] * m_Elements[k][col];
}
// alpha i,j before division
m_Elements[row][col] = (m_Elements[row][col] - sum);
}
// find row for division:see if any of the alphas are larger then b j,j
double maxFactor = Math.abs(m_Elements[col][col]) * factor[col];
int newrow = col;
for (int ii = col + 1; ii < nr; ii++) {
if ((Math.abs(m_Elements[ii][col]) * factor[ii]) > maxFactor) {
newrow = ii; // new row
maxFactor = Math.abs(m_Elements[ii][col]) * factor[ii];
}
}
if (newrow != col) {
// swap the rows
for (int kk = 0; kk < nc; kk++) {
double hh = m_Elements[col][kk];
m_Elements[col][kk] = m_Elements[newrow][kk];
m_Elements[newrow][kk] = hh;
}
// remember pivoting
int help = piv[col]; piv[col] = piv[newrow]; piv[newrow] = help;
double hh = factor[col]; factor[col] = factor[newrow]; factor[newrow] = help;
}
if (m_Elements[col][col] == 0.0) {
throw new Exception("Matrix is singular");
}
for (int row = col + 1; row < nr; row ++) {
// divide all
m_Elements[row][col] = m_Elements[row][col] /
m_Elements[col][col];
}
}
return piv;
}
/**
* Solve A*X = B using backward substitution.
* A is current object (this). Note that this matrix will be changed!
* B parameter bb
* X returned in parameter bb
*
* @param bb first vektor B in above equation then X in same equation.
* @exception matrix is singulaer
*/
public void solve(double [] bb) throws Exception {
int nr = m_Elements.length;
int nc = m_Elements[0].length;
double [] b = new double[bb.length];
double [] x = new double[bb.length];
double [] y = new double[bb.length];
int [] piv = this.LUDecomposition();
// change b according to pivot vector
for (int i = 0; i < piv.length; i++) {
b[i] = bb[piv[i]];
}
y[0] = b[0];
for (int row = 1; row < nr; row++) {
double sum = 0.0;
for (int col = 0; col < row; col++) {
sum += m_Elements[row][col] * y[col];
}
y[row] = b[row] - sum;
}
x[nc - 1] = y[nc - 1] / m_Elements[nc - 1][nc - 1];
for (int row = nc - 2; row >= 0; row--) {
double sum = 0.0;
for (int col = row + 1; col < nc; col++) {
sum += m_Elements[row][col] * x[col];
}
x[row] = (y[row] - sum) / m_Elements[row][row];
}
// change x according to pivot vector
for (int i = 0; i < piv.length; i++) {
//bb[piv[i]] = x[i];
bb[i] = x[i];
}
}
/**
* Performs Eigenvalue Decomposition using Householder QR Factorization
*
* This function is adapted from the CERN Jet Java libraries, for it
* the following copyright applies (see also, text on top of file)
* Copyright (C) 1999 CERN - European Organization for Nuclear Research.
*
* Matrix must be symmetrical.
* Eigenvectors are return in parameter V, as columns of the 2D array.
* Eigenvalues are returned in parameter d.
*
*
* @param V double array in which the eigenvectors are returned
* @param d array in which the eigenvalues are returned
* @exception if matrix is not symmetric
*/
public void eigenvalueDecomposition(double [][] V, double [] d) throws Exception {
if (!this.isSymmetric())
throw new Exception("EigenvalueDecomposition: Matrix must be symmetric.");
int n = this.numRows();
double[] e = new double [n]; //todo, don't know what this e is really for!
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
V[i][j] = m_Elements[i][j];
}
}
// Tridiagonalize using householder reduction
tred2(V, d, e, n);
// Diagonalize.
tql2(V, d, e, n);
// Matrix v = new Matrix (V);
// testEigen(v, d);
}
/**
* Symmetric Householder reduction to tridiagonal form.
*
* This function is adapted from the CERN Jet Java libraries, for it
* the following copyright applies (see also, text on top of file)
* Copyright (C) 1999 CERN - European Organization for Nuclear Research.
*
* @param V containing a copy of the values of the matrix
* @param d
* @param e
* @param n size of matrix
* @exception if reduction doesn't work
*/
private void tred2 (double [][] V, double [] d, double [] e, int n) throws Exception {
// This is derived from the Algol procedures tred2 by
// Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
// Fortran subroutine in EISPACK.
for (int j = 0; j < n; j++) {
d[j] = V[n-1][j];
}
// Householder reduction to tridiagonal form.
// Matrix v = new Matrix(V);
// System.out.println("before household - Matrix V \n" + v);
for (int i = n-1; i > 0; i--) {
// Matrix v = new Matrix(V);
// System.out.println("Matrix V \n" + v);
// Scale to avoid under/overflow.
double scale = 0.0;
double h = 0.0;
for (int k = 0; k < i; k++) {
scale = scale + Math.abs(d[k]);
}
if (scale == 0.0) {
e[i] = d[i-1];
for (int j = 0; j < i; j++) {
d[j] = V[i-1][j];
V[i][j] = 0.0;
V[j][i] = 0.0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -