/** @(#) matrixdouble/squaredmatrix.cpp */ /** * Define las funciones del encabezado. * @author Daniel Alba Cuellar, Omar Posada Villarreal * @version 1.0, 01/03/2002 */ #include "squaredmatrix.h" // constructor, ~, friend----------------------------------------------------- /** No se limpia porque se copiaran los datos. */ SquaredMatrix :: SquaredMatrix(RectangularMatrix &matrix) : RectangularMatrix(matrix.getRows(), matrix.getRows(), matrix.getLogic(), false) { copyFrom(matrix); } /* Destructor predeterminado. */ /** Libera recursos. */ // operator------------------------------------------------------------------- // public--------------------------------------------------------------------- /** Copia el triangulo superior actual al triangulo inferior para obtener una * matriz simetrica rellena. No toca la diagonal. * Logica cero (row), var(col). */ void SquaredMatrix :: upperTriangularToSymmetric() { int i, j; int nc = columns + logic; for (i = 0; i < (rows - 1); ++i) { for (j = (i + 1 + logic); j < nc; ++j) { m[j - logic][i + logic] = m[i][j]; } } } /** Forma la matriz R en la actual de la factorizacion QR, * en base a la original A y la diagonal. * R deberia ser Triangular superior. * No checa dimensiones. * Uso: * R.createRMatrix(A, d); * Logica uno. * @param A Original obtenida de qrdcmp(). * @param d Diagonal */ void SquaredMatrix :: createRMatrix(SquaredMatrix &A, VectorDouble &d) { setLogic(1); A.setLogic(1); d.setLogic(1); int i, j; clean(); // Copiar la triangular superior for (i = 1; i <= (rows - 1) ; ++i) { for (j = (i + 1); j <= columns; ++j) { m[i - 1][j] = A[i][j]; //m[][] equiv R[][] } } /* for (i = 1; i <= (n - 1) ; ++i) { for (j = (i + 1); j <= n ; ++j) { R(i, j) = A[i][j]; } } */ // Copia la diagonal for (i = 1; i <= rows; ++i) { m[i - 1][i] = d[i]; } } /** Calcula la norma max para la matriz actual. * Logica uno. */ double SquaredMatrix :: norm1() { //* Compute norm1 for M[m,n] (matrix) setLogic(1); double max = 0.0; double sum = 0.0; int i, j; for (i = 1; i <= rows; ++i) { sum += fabs(m[i-1][1]); } max = sum; for (j = 2; j <= columns; ++j) { sum = 0.0; for (i = 1; i <= rows; ++i) { sum += fabs(m[i -1][j]); } if (sum > max) { max = sum; } } return max; } /** Estima el numero de condicion "l1" de una matriz triangular superior "R", * usando el algoritmo contenido en Cline, Moler, Sterwart, Wilkinson [1979]. */ double SquaredMatrix :: condition() { setLogic(1); int n = rows; VectorDouble x(n, 1); VectorDouble diag(n, 1); // antes M2 Diagonal de la matriz VectorDouble p(n, 1); VectorDouble pm(n, 1); double xp; double xm; double temp; double tempm; double xnorm; int i, j; // 1, 2. double est; est = norm1(); // Estimador del numero de condicion // 3. diag = takeDiagonal(); x[1] = 1.0 / diag[1]; // 4. for (i = 2; i <= n; ++i) { p[i] = m[0][i] * x[1]; } //5. for (j = 2; j <= n ; ++j) { xp = (1.0 - p[j]) / diag[j]; xm = ( -1.0 - p[j]) / diag[j]; temp = fabs(xp); tempm = fabs(xm); // 5.5 for (i = (j + 1); i <= n; ++i) { pm[i] += (m[j - 1][i] * xm); tempm += fabs(pm[i]) / fabs(diag[i]); p[i] += m[j - 1][i] * xp; temp += fabs(p[i]) / fabs(diag[i]); } if (temp >= tempm) { x[j] = xp; // ej = 1 } else { x[j] = xm; for (i = (j + 1); i <= n; ++i) { p[i] = pm[i]; } } // if } // for xnorm = x.norm1(); est = est / xnorm; return est; } /** Calcula la cota inferior de los eigen valores de una matriz simetrica. * <pre> * minEigVal = min{1 <= i <= n} (aii - sum{j=1, j!=i}(|aij|) ) * </pre> * @see Dennis. pag 60. Teorema de Gershgorin. */ double SquaredMatrix :: findMinLimitEigenValue() { double minEig = numeric_limits<double>::max(); double sum; // == aux int i, j; for (i = 0; i < rows; ++i) { sum = 0.0; for (j = 0; j < columns; ++j) { sum += fabs(m[i].v[j]); } sum = m[i].v[i] - sum - fabs(m[i].v[i]); // quitar i!=j if (sum < minEig) { minEig = sum; } } return minEig; } /** Calcula la cota superior de los eigen valores de una matriz simetrica. * <pre> * maxEigVal = max{1 <= i <= n} (aii + sum{j=1, j!=i}(|aij|) ) * </pre> * @see Dennis. pag 60. Teorema de Gershgorin. */ double SquaredMatrix :: findMaxLimitEigenValue() { double maxEig = numeric_limits<double>::min(); double sum; // == aux int i, j; for (i = 0; i < rows; ++i) { sum = 0.0; for (j = 0; j < columns; ++j) { sum += fabs(m[i].v[j]); } sum = m[i].v[i] + sum - fabs(m[i].v[i]); // quitar i!=j if (sum > maxEig) { maxEig = sum; } } return maxEig; } /** Convierte a la matriz actual en identidad. * Ceros excepto en la diagonal con unos. */ void SquaredMatrix :: toIdentity() { clean(); int i; for (i = 0; i < rows; ++i) { m[i].v[i] = 1.0; } } /** Realiza M pasos iterativos del metodo de la potencia * para obtener el eigenvalor dominante de la matriz actual. * Tambien incorpora un proceso de ortogonalizacion * para encontrar los sucesivos eigenvalores. * @author Daniel Alba Cuellar, Omar Posada Villarreal (generalizar) * @param x Vector inicial proporcionado por el usuario. * @param M numero de iteraciones. * @param seq se intenta encontrar el eigenvalor numero seq. [1, n]. * @param return V Almacena en la matriz V el eigenvector generado. * Para encontrar el de mayor valor absoluto, seq = 1. * @param return w Eigen vector generado. * @return Maximo eigen valor. */ /* main A = this, n = rows // realiza el proceso iterativo para encontrar los n eigenvalores de A for (i=1; i <= n; i++) { printf("eigenvector %d:\n", i); power_d( iter, i ); // almacena en la matriz V el eigenvector generado for (j=1; j <= n; j++) V[j][i] = w[j]; } */ // Falta probarlo double SquaredMatrix :: dominantEigenValue(VectorDouble &x, int M, int seq, SquaredMatrix &V, VectorDouble &w) { int k, i, j, l; double r; // cociente Raleigh, eigen valor, lambda double max_y; VectorDouble y(rows, 1); VectorDouble v_temp(rows, 1); /* vector temporal */ double e_temp; /* escalar temporal */ //n == rows w = x; /* Proceso de ortogonalizacion: construye un vector inicial w a ser usado por el metodo de la potencia */ /* w = x - suma((V(.,j)*x/V(.,j)*V(.,j))V(.,j)). V(.,i) es el j-ésimo eigenvector de A. */ for (j=1; j < seq; j++) { /* extrae el j-ésimo eigenvector de la matriz V */ for (l=1; l <= rows; l++) v_temp[l] = V[l][j]; // innerProduct <v_temp, x> / <v_temp,v_temp> e_temp = (v_temp * x) / (v_temp * v_temp); for (l=1; l <= rows; l++) w[l] = w[l] - e_temp * v_temp[l]; } /* aqui comienza el metodo de la potencia */ for (k = 1; k <= M; k++) { /* y = Aw */ y = (*this) * w; /* r = w*y/w*w. esta es la aproximacion del eigenvalor por medio del cociente de Rayleigh */ r = (w * y) / (w * w); /* calcula la norma infinito de y */ max_y = fabs(y[1]); for (i = 2; i <= rows; i++) { if (fabs(y[i]) > max_y) { max_y = fabs(y[i]); } } /* w = y/norma(y). norma(y) es la norma infinito de y */ for (i = 1; i <= rows; i++) { y[i] = y[i]/max_y; w[i] = y[i]; } /* Proceso de ortogonalizacion: elimina de w los errores de redondeo */ /* w = x - suma((V(.,j)*x/V(.,j)*V(.,j))V(.,j)). V(.,i) es el j-ésimo eigenvector de A. */ for (j=1; j < seq; j++) { /* extrae el j-ésimo eigenvector de la matriz V */ for (l=1; l <= rows; l++) v_temp[l] = V[l][j]; e_temp = (v_temp * y)/(v_temp * v_temp); for (l=1; l <= rows; l++) w[l] = w[l] - e_temp * v_temp[l]; } } return r; } // private-------------------------------------------------------------------- // Fin------------------------------------------------------------------------