/** @(#) matrixdouble/rectangularmatrix.cpp */ /** * Define las funciones del encabezado. * @author Daniel Alba Cuellar, Omar Posada Villarreal * @version 1.0, 27/02/2002 */ #include "rectangularmatrix.h" // constructor, ~, friend----------------------------------------------------- /** * Construye una matrix rectangular de nr x nc. * Reserva memoria. * @param cleanMe true: Limpia la matriz con 0.0. false: no inicializa. */ RectangularMatrix :: RectangularMatrix( int theRows, int theColumns, int theLogic, bool cleanMe) : MatrixDouble(theRows, theColumns, theLogic) { m = NULL; resize(theRows, theColumns, theLogic, cleanMe); } /** Libera recursos. */ RectangularMatrix :: ~RectangularMatrix() { deleteRectangular(); //No usar delete[] m; } /** Usado por destructor y resize. */ void RectangularMatrix :: deleteRectangular() { int i; // No llamar al destructor, error por acceder a m[i] // DestructorVectorDouble *pRow; pRow = &(m[i]); delete pRow; for (i = 0; i < rows; ++i) { m[i].deleteArray(); //solo libera memo del arreglo } if (m != NULL) { delete[] m; // No usar m = NULL; } } /* template<class T> void Matriz<T>::liberaMemoria() { for(int i=0; i<m_renglones; i++){ delete[] m_matriz[i].m_vector; m_matriz[i].m_vector=NULL; } if(m_matriz!=NULL) delete [] m_matriz; m_matriz=NULL; }*/ /** Reconstruye todos los parametros de la matriz. * Libera y asigna memoria. Se pierden los datos. * Si es de misma logica, no cambia. * Si es del mismo taman~o, no cambia. * Logica cero. */ void RectangularMatrix :: resize( int theRows, int theColumns, int theLogic, bool cleanMe) { /* algort resize(theRows, theColumns); // 1. Mantener orden setLogic(theLogic); // 2. Necesita memoria if (cleanMe) { // 3. Necesita logica clean(); } */ int validRows = ((theRows < 1) ? 1 : theRows); int validColumns = ((theColumns < 1) ? 1 : theColumns); logic = (theLogic ? 1 : 0); // Si es 1a creacion //ERROR EN LA 2A CORRIDA if (m == NULL) { // 1o. m = new VectorDouble[validRows]; // Si es de nueva creacion, se debe salir. Se debe duplicar codigo } else if (rows != validRows) { deleteRectangular(); // Error si se trata de llamar al constructor m = new VectorDouble[validRows]; } // Si el numero de columna no varia, lo checa VectorDouble int i; for (i = 0; i < validRows; ++i) { m[i].resize(validColumns, logic, cleanMe); // no usar new VectorDouble(columns, logic, cleanMe); } rows = validRows; columns = validColumns; } // operator------------------------------------------------------------------- /** * Muestra la matriz en la consola. No muestra las dimensiones. * Logica variable. * @param outStr Destino del flujo. * @param matrix Matriz a mostrar. * @return Matriz * @version usa << de vector */ ostream & operator<<(ostream &outStr, const RectangularMatrix &matrix) { //matrix.print(); // sig vers outStr << int i; // Ajuste a la logica int first = matrix.getLogic(); int nr = matrix.getRows() + first; //* @version usa << de vector for (i = first; i < nr; ++i) { outStr << matrix[i] << endl; } return outStr; } /** * Entrada de la matriz en la consola. * Permite lectura de archivo de las dimensiones y los datos. * No se lee la logica de la matriz. * Logica variable. * Uso: * 2 3 * 1 2 3 * 4 5 6 * @param outStr Destino del flujo. * @param matrix Matriz a mostrar. * @return Matriz */ istream & operator>>(istream &inpStr, RectangularMatrix &matrix) { //matrix.read(); // sig inpStr >> int i, j; int nr, nc; double value; inpStr >> nr; inpStr >> nc; int first = matrix.getLogic(); matrix.resize(nr, nc, first, true); // first == logic // Ajuste a la logica nr += first; nc += first; for (i = first; i < nr; ++i) { for (j = first; j < nc; ++j) { inpStr >> value; matrix[i][j] = value; // error si inpStr >> matrix(i, j) } } return inpStr; } /** * Permite asignacion (operator=). * Logica 0, (0, 0) apunta al matematico A 1,1 esq sup izq * @param row Logica cero: [0, row -1]. Logica uno: [1, row] * @param column Logica cero: [0, col -1]. Logica uno: [1, col] */ double & RectangularMatrix :: operator()(int row, int column) throw (invalid_argument) { if ( (row < logic) || (row >= (rows + logic)) || (column < logic) || (column >= (columns + logic)) ) { throw invalid_argument("operator(): indices fuera de rango."); } return m[row - logic][column]; } /** @version const Sino error por rvalue. */ const double & RectangularMatrix :: operator()(int row, int column) const throw (invalid_argument) { if ( (row < logic) || (row >= (rows + logic)) || (column < logic) || (column >= (columns + logic)) ) { throw invalid_argument("operator(): indices fuera de rango."); } return m[row - logic][column]; } /** * Multiplica la matriz actual por un vector columna * (arreglo unidimensional de "double") * y crea un vector columna "b" de taman~o m para * almacenar el resultado a partir de la dimension de A. * Por default se refiere a postmultiplicacion. * Es decir, se multiplica la matriz por un vector columna. * Este metodo puede ser sobreescrito ("override") para eficientarlo * ya que recorre todos los elementos (existan o no) de la matriz. * Las dimensiones de las matrices deben ser * A(n x m) b(m x 1) = c(m x 1). * Ejemplo: <p><code> * arrDoubC = mdA.multiplyBy(arrDoubB) * </code></p> * No checa dimensiones, ni logica * Logica cero. * @return Vector columna (double[]) producto entre * "MatrixDouble" y el vector columna "b". * "null" si las dimensiones no coinciden. * @see #premultiply */ //Nota: Debe ser sobreescrita para eficientar VectorDouble RectangularMatrix :: operator*(VectorDouble &left) { /* Serge Lang. * A n*m b m*1 = C n*1 * c [i] = Sum(j = 1, m , aij bj) */ left.setLogic(logic); VectorDouble res(rows, logic); int i, j; //contadores double sum; //double mi, lj; /*Barre matriz de izq a der, arriba a abajo*/ for (i = 0; i < rows; i++) { sum = 0.0; for (j = 0; j < columns; j++) { //mi = m[i][j + logic]; //lj =left[j + logic]; sum += m[i][j + logic] * left[j + logic]; } res[i + logic] = sum; } // for i return res; // Resultado } /** * Multiplica la matriz actual por un escalar * y crea una matriz cuadrada del mismo taman~o * Ejemplo: * No checa dimensiones, ni logica * Logica cero. * @return RectangularMatrix */ //Nota: Debe ser sobreescrita para eficientar // No se puede regresar RectangularMatrix error del destructor //RectangularMatrix RectangularMatrix :: operator*(double left) { // static void RectangularMatrix :: multiply( RectangularMatrix &right, double left, RectangularMatrix &res) throw (runtime_error) { // *RectangularMatrix res(rows, columns, logic); bool logic = right.getLogic(); int rightRow = right.getRows(); int rightCol = right.getColumns(); // == left.Row int i, j; //contadores /*Barre matriz de izq a der, arriba a abajo*/ try { for (i = 0; i < rightRow; i++) { for (j = 0; j < rightCol; j++) { res.m[i][j + logic] = right.m[i][j + logic] * left; } } // for i } catch(...) { throw runtime_error("multiply: Desbordamiento float"); } //return res; } /** Multiplica la matriz actual por la del argumento. * Las dimensiones de las matrices deben ser * A(n x m) B(m x p) = c(n x p). * Se deja la logica igual para todos. * No checa dimension m. * Logica cero. * @return Matriz de dimensiones rows x left.columns */ // No se puede regresar RectangularMatrix error del destructor //RectangularMatrix RectangularMatrix :: operator*(RectangularMatrix &left) { // static void RectangularMatrix :: multiply( RectangularMatrix &right, RectangularMatrix &left, RectangularMatrix &res) { /* Serge Lang. * A n*m b m*p = C n*p * c [i] = Sum(j = 1, m , aij bj) */ bool logic = right.getLogic(); int rightRow = right.getRows(); int rightCol = right.getColumns(); // == left.Row int leftCol = left.getColumns(); right.setLogic(logic); left.setLogic(logic); res.resize(rightRow, leftCol, logic, false); int i, j, k; double sum; /*Barre matriz de izq a der, arriba a abajo*/ for (i = 0; i < rightRow; i++) { for (k = 0; k < leftCol; k++) { /*Para cada elemento aij*/ sum = 0.0; for (j = 0; j < rightCol; j++) { // suma += aij * bjk sum += right.m[i][j + logic] * left.m[j][k + logic]; } // cik = suma; // debug res.m[i][k + logic] = sum; } //for k } // for i //return res; // Resultado } /** Suma las matrices, regresa una nueva matriz con el resultado. * No checa dimensiones, ni logica * Logica cero. * @return Matriz con las mismas caracteristicas que la matriz actual. */ // No se puede regresar RectangularMatrix error del destructor //RectangularMatrix RectangularMatrix :: operator+(RectangularMatrix &left) { // static void RectangularMatrix :: add( RectangularMatrix &right, RectangularMatrix &left, RectangularMatrix &res) { bool logic = right.getLogic(); int rightRow = right.getRows(); int rightCol = right.getColumns(); right.setLogic(logic); left.setLogic(logic); res.resize(rightRow, rightCol, logic, false); int i, j; //contadores for (i = 0; i < rightRow; i++) { for (j = 0; j < rightCol; j++) { res.m[i][j+logic] = right.m[i][j+logic] + left.m[i][j+logic]; } } // for i //return res; // Resultado } /** Resta las matrices, regresa una nueva matriz con el resultado. * Actual = right (operador) left. * No checa dimensiones, ni logica * Logica cero. * @return Matriz con las mismas caracteristicas que la matriz actual. */ // No se puede regresar RectangularMatrix error del destructor //RectangularMatrix RectangularMatrix :: operator-(RectangularMatrix &left) { // static void RectangularMatrix :: substract( RectangularMatrix &right, RectangularMatrix &left, RectangularMatrix &res) { bool logic = right.getLogic(); int rightRow = right.getRows(); int rightCol = right.getColumns(); left.setLogic(logic); res.resize(rightRow, rightCol, logic, false); //RectangularMatrix res(rows, columns, logic, false); int i, j; //contadores for (i = 0; i < rightRow; i++) { for (j = 0; j < rightCol; j++) { res.m[i][j+logic] = right.m[i][j+logic] - left.m[i][j+logic]; } } // for i //return res; // Resultado } // public--------------------------------------------------------------------- /** * Llena la matriz con el valor indicado. * Logica cero. * @author Omar Posada Villarreal * @param value Cada elemento valdra este numero. */ void RectangularMatrix :: fill(double value) { int i; for (i = 0; i < rows; ++i) { m[i].fill(value); } } /** Muestra la matriz en la consola. * Logica variable. * @version usa << de vector. */ void RectangularMatrix :: print() const { int i; //cout << "Matriz (" << rows << " x " << columns << ")\n"; for (i = 0; i < rows; ++i) { //* @version usa << de vector cout << m[i] << endl; } } /** * Muestra la matriz en la consola con un cierto numero de digitos. * @param digits Numero de digitos a mostra (fixed). */ void RectangularMatrix :: print(int digits) const { cout << setiosflags(ios::fixed) << setprecision(digits); print(); } /** * Entrada de la matriz sin las dimensiones en la consola. * Logica uno (row), variable(col).*/ void RectangularMatrix :: readElements() { int i, j; int nc = columns + logic ; cout << "\nTeclee elementos de la matriz (" << rows << " x " << columns << ")\n"; for (i = 0; i < rows; ++i) { for (j = logic; j < nc; ++j) { cout << "[" << (i+logic) << "][" << j << "]: "; cin >> m[i][j]; } } } /** * Cambia la logica de la matriz. * Logica cero. * @param theLogica 0: Logica cero. !=0: Logica 1. */ void RectangularMatrix :: setLogic(int theLogic) { int validLogic = (theLogic ? 1 : 0); // Si cambia la logica, cambia la de los renglones if (logic != validLogic) { logic = validLogic; int i; for (i = 0; i < rows; ++i) { m[i].setLogic(logic); } } } /** Transpone una matriz. Se ajustan dimensiones de la actual */ void RectangularMatrix :: transpose(RectangularMatrix &matrix) { int mRow = matrix.getRows(); int mCol = matrix.getColumns(); int mLogic = matrix.getLogic(); if ((rows != mCol) || (columns !=mRow)) { resize(mCol, mRow, mLogic, false); } int i, j; for (i = 0; i < mRow; ++i) { for (j = 0; j < mCol; ++j) { m[j].v[i] = matrix.m[i].v[j]; } } } /** @return Vector con la diagonal con la misma logica y la dimension menor. */ VectorDouble RectangularMatrix :: takeDiagonal() { int n = min(rows, columns); VectorDouble diag(n, logic); int i; for (i = 0; i < n; i++) { diag[i + logic] = m[i][i + logic]; } return diag; } /** Copia los datos a la matriz actual. * No checa dimensiones. */ void RectangularMatrix :: copyFrom(RectangularMatrix &matrix) { int i, j; for (i = 0; i < rows; ++i) { for (j = 0; j < columns; ++j) { m[i][j + logic] = matrix.m[i][j + logic]; } } } /** * Resta dos matrices (A y B) y crea una de resultado. * <p>C = A - B</p> * No olvidar hacer un casting al resultado. Ejemplo de uso: * <p><code> * rmRes = (RectangularMatrix)MatrixDouble.substract(rmA, rmB); * </code></p> * Se recomienda que las tres matrices sean del mismo tipo * para que no se pierdan elementos. * La matriz C debe ser del mismo tipo que A. * La matriz C se crea con las dimensiones y el tipo de * de la matriz A. * @throws IllegalArgumentException Matrices con dimensiones distintas. * @return Matriz con el resultado. */ /*public static MatrixDouble substract(MatrixDouble mdA, MatrixDouble mdB) { int rowsA = mdA.getRows(); int columnsA = mdA.getColumns(); int rowsB = mdB.getRows(); int columnsB = mdB.getColumns(); MatrixDouble mdC = null; // Resultado int i; int j; if ( (rowsA != rowsB) || (columnsA != columnsB) ) { System.err.println("substract: " + "Matrices con dimensiones distintas."); throw new IllegalArgumentException( "substract: " + "Matrices con dimensiones distintas."); } // Crea una matriz de resultados fija. mdC = mdA.newMatrix(rowsA, columnsA, mdA.memoryRows, mdA.memoryColumns); for (i = 0; i < rowsA; i++) { for (j = 0; j < columnsA; j++) { mdC.setE(i, j, mdA.getE(i, j) - mdB.getE(i, j) ); } } return (MatrixDouble)mdC; //exito } //------------------------------------------------------------------- */ // private-------------------------------------------------------------------- // Fin------------------------------------------------------------------------