/***********************************************************************
This file is part of KEEL-software, the Data Mining tool for regression,
classification, clustering, pattern mining and so on.
Copyright (C) 2004-2010
F. Herrera (herrera@decsai.ugr.es)
L. S�nchez (luciano@uniovi.es)
J. Alcal�-Fdez (jalcala@decsai.ugr.es)
S. Garc�a (sglopez@ujaen.es)
A. Fern�ndez (alberto.fernandez@ujaen.es)
J. Luengo (julianlm@decsai.ugr.es)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/
**********************************************************************/
package keel.Algorithms.Genetic_Rule_Learning.M5Rules;
/**
* Class for handling a matrix
*/
public final class M5Matrix {
double[][] elements;
/**
* Constructs a matrix
* @param nr the number of the rows
* @param nc the number of the columns
*/
public M5Matrix(int nr, int nc) {
elements = new double[nr][nc];
}
/**
* Converts a matrix to a string
* @param nrl the smallest index of the rows
* @param nrh the largest index of the rows
* @param ncl the smallest index of the column
* @param nch the largest index of the column
* @return the converted string
*/
public final String toString(int nrl, int nrh, int ncl, int nch) {
int i, j;
StringBuffer text = new StringBuffer();
text.append("Printing matrix[" + nrl + ":" + nrh + "][" + ncl + ":" +
nch + "]:\n");
for (i = nrl; i <= nrh; i++) {
for (j = ncl; j <= nch; j++) {
text.append("\t" + M5.doubleToStringG(elements[i][j], 5, 3));
}
text.append("\n");
}
return text.toString();
}
/**
* Returns the transpose of a matrix [0:n-1][0:m-1]
* @param n the number of rows
* @param m the number of columns
* @return the transposed matrix
*/
public final M5Matrix transpose(int n, int m) {
int i, j;
M5Matrix b;
b = new M5Matrix(m, n);
for (i = 0; i <= m - 1; i++) {
for (j = 0; j <= n - 1; j++) {
b.elements[i][j] = elements[j][i];
}
}
return b;
}
/**
* Reurns the multiplication of two matrices
* @param b the multiplication matrix
* @param l the number of the rows of the instance matrix
* @param m the number of the columns of the instance matrix, and the number of the rows of matrix b
* @param n the number of the columns of matrix b
* @return the product matrix
*/
public final M5Matrix multiply(M5Matrix b, int l, int m, int n) {
int i, j, k;
M5Matrix c;
c = new M5Matrix(l, n);
for (i = 0; i <= l - 1; i++) {
for (j = 0; j <= n - 1; j++) {
for (k = 0; k <= m - 1; k++) {
c.elements[i][j] += elements[i][k] * b.elements[k][j];
}
}
}
return c;
}
/**
* Linear regression
* @param y the dependent variable vector
* @param n the number of the observations
* @param m the number of the coefficients
* @return the coefficients
*/
public final double[] regression(M5Matrix y, int n, int m) { // x[0:n-1][0:m-1], y[0:n-1][0:0] b[0:m-1]
int i, indx[];
double b[];
M5Matrix ss, xt, d, bb;
xt = this.transpose(n, m);
ss = xt.multiply(this, m, n, m);
bb = xt.multiply(y, m, n, 1);
b = new double[m];
for (i = 0; i <= m - 1; i++) {
b[i] = bb.elements[i][0];
}
indx = new int[m];
ss.ludcmp(m, indx);
ss.lubksb(m, indx, b);
return b;
}
/**
* LU backward substitution
* @param n the number of the coefficients
* @param indx the index
* @param b the double vector, storing constant terms in the equation sets; it later stores the computed coefficients' values
*/
public final void lubksb(int n, int[] indx, double b[]) {
int i, ii = -1, ip, j;
double sum;
for (i = 0; i <= n - 1; i++) {
ip = indx[i];
sum = b[ip];
b[ip] = b[i];
if (ii != -1) {
for (j = ii; j <= i - 1; j++) {
sum -= elements[i][j] * b[j];
}
} else if (sum != 0.0) {
ii = i;
}
b[i] = sum;
}
for (i = n - 1; i >= 0; i--) {
sum = b[i];
for (j = i + 1; j <= n - 1; j++) {
sum -= elements[i][j] * b[j];
}
b[i] = sum / elements[i][i];
}
}
/**
* LU decomposition
* @param n the number of coefficients
* @param indx the index
* @return the integer vector of the attributes's singularities
*/
public final int[] ludcmp(int n, int[] indx) {
int i, imax = -1, j, k, singulars[];
double big, dum, sum, temp;
double vv[];
double TINY = 1.e-20;
singulars = new int[n];
for (i = 0; i <= n - 1; i++) {
singulars[i] = 0;
}
vv = new double[n];
for (i = 0; i <= n - 1; i++) {
big = 0.0;
for (j = 0; j <= n - 1; j++) {
if ((temp = Math.abs(elements[i][j])) > big) {
big = temp;
}
}
if (big < 0.000000001) {
elements[i][i] = 1.0;
big = 1.0;
singulars[i] = 1;
}
/* m5error("Singular matrix in routine ludcmp");*/
vv[i] = 1.0 / big;
}
for (j = 0; j <= n - 1; j++) {
for (i = 0; i < j; i++) {
sum = elements[i][j];
for (k = 0; k < i; k++) {
sum -= elements[i][k] * elements[k][j];
}
elements[i][j] = sum;
}
big = 0.0;
for (i = j; i <= n - 1; i++) {
sum = elements[i][j];
for (k = 0; k < j; k++) {
sum -= elements[i][k] * elements[k][j];
}
elements[i][j] = sum;
if ((dum = vv[i] * Math.abs(sum)) >= big) {
big = dum;
imax = i;
}
}
if (j != imax) {
for (k = 0; k <= n - 1; k++) {
dum = elements[imax][k];
elements[imax][k] = elements[j][k];
elements[j][k] = dum;
}
vv[imax] = vv[j];
}
indx[j] = imax;
if (elements[j][j] == 0.0) {
elements[j][j] = TINY;
}
if (j != n - 1) {
dum = 1.0 / (elements[j][j]);
for (i = j + 1; i <= n - 1; i++) {
elements[i][j] *= dum;
}
}
}
return singulars;
}
}