/* * tmatrix.cpp - simple matrix template class implementation * * Copyright (C) 2004, 2005, 2006, 2008 Stefan Jahn * * This 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 2, or (at your option) * any later version. * * This software 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 package; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, * Boston, MA 02110-1301, USA. * * $Id$ * */ #ifdef HAVE_CONFIG_H #include "config.h" #else // BUG #include "qucs_typedefs.h" #endif #include #include #include #include #include #include "compat.h" #include "logging.h" #include "complex.h" #include "tmatrix.h" namespace qucs { // Constructor creates an unnamed instance of the tmatrix class. template tmatrix::tmatrix () { rows = 0; cols = 0; data = NULL; } /* Constructor creates an unnamed instance of the tmatrix class with a certain number of rows and columns. Creates a square tmatrix. */ template tmatrix::tmatrix (int s) { rows = cols = s; if (s > 0) { data = new nr_type_t[s * s]; memset (data, 0, sizeof (nr_type_t) * s * s); } else data = NULL; } /* Constructor creates an unnamed instance of the tmatrix class with a certain number of rows and columns. */ template tmatrix::tmatrix (int r, int c) { rows = r; cols = c; if (r > 0 && c > 0) { data = new nr_type_t[r * c]; memset (data, 0, sizeof (nr_type_t) * r * c); } else data = NULL; } /* The copy constructor creates a new instance based on the given tmatrix object. */ template tmatrix::tmatrix (const tmatrix & m) { rows = m.rows; cols = m.cols; data = NULL; // copy tmatrix elements if (rows > 0 && cols > 0) { data = new nr_type_t[rows * cols]; memcpy (data, m.data, sizeof (nr_type_t) * rows * cols); } } /* The assignment copy constructor creates a new instance based on the given tmatrix object. */ template const tmatrix& tmatrix::operator=(const tmatrix & m) { if (&m != this) { rows = m.rows; cols = m.cols; delete[] data; if (rows > 0 && cols > 0) { data = new nr_type_t[rows * cols]; memcpy (data, m.data, sizeof (nr_type_t) * rows * cols); } } return *this; } // Destructor deletes a tmatrix object. template tmatrix::~tmatrix () { delete[] data; } // Returns the tmatrix element at the given row and column. template nr_type_t tmatrix::get (int r, int c) { assert (r >= 0 && r < rows && c >= 0 && c < cols); return data[r * cols + c]; } // Sets the tmatrix element at the given row and column. template void tmatrix::set (int r, int c, nr_type_t z) { assert (r >= 0 && r < rows && c >= 0 && c < cols); data[r * cols + c] = z; } // Sets all the tmatrix elements to the given value. template void tmatrix::set (nr_type_t z) { for (int i = 0; i < rows * cols; i++) data[i] = z; } // The function returns the given row in a tvector. template tvector tmatrix::getRow (int r) { assert (r >= 0 && r < rows); tvector res (cols); nr_type_t * dst = res.getData (); nr_type_t * src = &data[r * cols]; memcpy (dst, src, sizeof (nr_type_t) * cols); return res; } // Puts the given tvector into the given row of the tmatrix instance. template void tmatrix::setRow (int r, tvector v) { assert (r >= 0 && r < rows && v.getSize () == cols); nr_type_t * dst = &data[r * cols]; nr_type_t * src = v.getData (); memcpy (dst, src, sizeof (nr_type_t) * cols); } // The function returns the given column in a tvector. template tvector tmatrix::getCol (int c) { assert (c >= 0 && c < cols); tvector res (rows); nr_type_t * dst = res.getData (); nr_type_t * src = &data[c]; for (int r = 0; r < rows; r++, src += cols, dst++) *dst = *src; return res; } // Puts the given tvector into the given column of the tmatrix instance. template void tmatrix::setCol (int c, tvector v) { assert (c >= 0 && c < cols && v.getSize () == rows); nr_type_t * dst = &data[c]; nr_type_t * src = v.getData (); for (int r = 0; r < rows; r++, src++, dst += cols) *dst = *src; } // The function swaps the given rows with each other. template void tmatrix::exchangeRows (int r1, int r2) { assert (r1 >= 0 && r2 >= 0 && r1 < rows && r2 < rows); nr_type_t * s = new nr_type_t[cols]; int len = sizeof (nr_type_t) * cols; memcpy (s, &data[r1 * cols], len); memcpy (&data[r1 * cols], &data[r2 * cols], len); memcpy (&data[r2 * cols], s, len); delete[] s; } // The function swaps the given columns with each other. template void tmatrix::exchangeCols (int c1, int c2) { assert (c1 >= 0 && c2 >= 0 && c1 < cols && c2 < cols); nr_type_t s; for (int r = 0; r < rows * cols; r += cols) { s = data[r + c1]; data[r + c1] = data[r + c2]; data[r + c2] = s; } } // Compute inverse matrix of the given matrix by Gauss-Jordan elimination. template tmatrix inverse (tmatrix a) { nr_double_t MaxPivot; nr_type_t f; tmatrix b; tmatrix e; int i, c, r, pivot, n = a.getCols (); // create temporary matrix and the result matrix b = tmatrix (a); e = teye (n); // create the eye matrix in 'b' and the result in 'e' for (i = 0; i < n; i++) { // find maximum column value for pivoting for (MaxPivot = 0, pivot = r = i; r < n; r++) { if (abs (b.get (r, i)) > MaxPivot) { MaxPivot = abs (b.get (r, i)); pivot = r; } } // exchange rows if necessary assert (MaxPivot != 0); // singular matrix if (i != pivot) { b.exchangeRows (i, pivot); e.exchangeRows (i, pivot); } // compute current row f = b.get (i, i); for (c = 0; c < n; c++) { b.set (i, c, b.get (i, c) / f); e.set (i, c, e.get (i, c) / f); } // compute new rows and columns for (r = 0; r < n; r++) { if (r != i) { f = b.get (r, i); for (c = 0; c < n; c++) { b.set (r, c, b.get (r, c) - f * b.get (i, c)); e.set (r, c, e.get (r, c) - f * e.get (i, c)); } } } } return e; } // Create identity matrix with specified number of rows and columns. template tmatrix teye (int n) { tmatrix res (n); for (int r = 0; r < n; r++) res.set (r, r, 1); return res; } // Intrinsic matrix addition. template tmatrix tmatrix::operator += (tmatrix a) { assert (a.getRows () == rows && a.getCols () == cols); nr_type_t * src = a.getData (); nr_type_t * dst = data; for (int i = 0; i < rows * cols; i++) *dst++ += *src++; return *this; } // Intrinsic matrix substraction. template tmatrix tmatrix::operator -= (tmatrix a) { assert (a.getRows () == rows && a.getCols () == cols); nr_type_t * src = a.getData (); nr_type_t * dst = data; for (int i = 0; i < rows * cols; i++) *dst++ -= *src++; return *this; } // Matrix multiplication. template tmatrix operator * (tmatrix a, tmatrix b) { assert (a.getCols () == b.getRows ()); int r, c, i, n = a.getCols (); nr_type_t z; tmatrix res (a.getRows (), b.getCols ()); for (r = 0; r < a.getRows (); r++) { for (c = 0; c < b.getCols (); c++) { for (i = 0, z = 0; i < n; i++) z += a.get (r, i) * b.get (i, c); res.set (r, c, z); } } return res; } // Multiplication of matrix and vector. template tvector operator * (tmatrix a, tvector b) { assert (a.getCols () == b.size ()); int r, c, n = a.getCols (); nr_type_t z; tvector res (n); for (r = 0; r < n; r++) { for (c = 0, z = 0; c < n; c++) z += a.get (r, c) * b.get (c); res.set (r, z); } return res; } // Multiplication of vector (transposed) and matrix. template tvector operator * (tvector a, tmatrix b) { assert (a.size () == b.getRows ()); int r, c, n = b.getRows (); nr_type_t z; tvector res (n); for (c = 0; c < n; c++) { for (r = 0, z = 0; r < n; r++) z += a.get (r) * b.get (r, c); res.set (c, z); } return res; } // Transpose the matrix in place. template void tmatrix::transpose (void) { nr_type_t v; for (int r = 0; r < getRows (); r++) for (int c = 0; c < r; c++) { v = get (r, c); set (r, c, get (c, r)); set (c, r, v); } } // Checks validity of matrix. template int tmatrix::isFinite (void) { for (int i = 0; i < rows * cols; i++) if (!std::isfinite (real (data[i]))) return 0; return 1; } #ifdef DEBUG // Debug function: Prints the matrix object. template void tmatrix::print (bool realonly) { for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { if (realonly) { fprintf (stderr, "%+.2e%s", (double) real (get (r, c)), c != cols - 1 ? " " : ""); } else { fprintf (stderr, "%+.2e%+.2ei%s", (double) real (get (r, c)), (double) imag (get (r, c)), c != cols - 1 ? " " : ""); } } fprintf (stderr, ";\n"); } } #endif /* DEBUG */ } // namespace qucs