X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fmatrix.cpp;h=2c191ff4f69c04d993b2724b16f13e13d445156e;hp=8d2e0b88b99e9fb7f8e5fb5e374b7c2dfcfd03e8;hb=ffad02322624ab79fdad1a23a3aa83cd67376151;hpb=ed21ddd5e2bc0af018c10934342f526d0ae4b7a7 diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp index 8d2e0b88..2c191ff4 100644 --- a/ginac/matrix.cpp +++ b/ginac/matrix.cpp @@ -3,7 +3,7 @@ * Implementation of symbolic matrices */ /* - * GiNaC Copyright (C) 1999-2001 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany * * 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 @@ -20,6 +20,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include +#include #include #include #include @@ -29,41 +32,34 @@ #include "lst.h" #include "idx.h" #include "indexed.h" +#include "add.h" #include "power.h" #include "symbol.h" +#include "operators.h" #include "normal.h" -#include "print.h" #include "archive.h" #include "utils.h" -#include "debugmsg.h" namespace GiNaC { -GINAC_IMPLEMENT_REGISTERED_CLASS(matrix, basic) +GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(matrix, basic, + print_func(&matrix::do_print). + print_func(&matrix::do_print_latex). + print_func(&basic::do_print_tree). + print_func(&matrix::do_print_python_repr)) ////////// -// default ctor, dtor, copy ctor, assignment operator and helpers: +// default constructor ////////// /** Default ctor. Initializes to 1 x 1-dimensional zero-matrix. */ -matrix::matrix() : inherited(TINFO_matrix), row(1), col(1) +matrix::matrix() : inherited(TINFO_matrix), row(1), col(1), m(1, _ex0) { - debugmsg("matrix default ctor",LOGLEVEL_CONSTRUCT); - m.push_back(_ex0()); + setflag(status_flags::not_shareable); } -void matrix::copy(const matrix & other) -{ - inherited::copy(other); - row = other.row; - col = other.col; - m = other.m; // STL's vector copying invoked here -} - -DEFAULT_DESTROY(matrix) - ////////// -// other ctors +// other constructors ////////// // public @@ -73,10 +69,9 @@ DEFAULT_DESTROY(matrix) * @param r number of rows * @param c number of cols */ matrix::matrix(unsigned r, unsigned c) - : inherited(TINFO_matrix), row(r), col(c) + : inherited(TINFO_matrix), row(r), col(c), m(r*c, _ex0) { - debugmsg("matrix ctor from unsigned,unsigned",LOGLEVEL_CONSTRUCT); - m.resize(r*c, _ex0()); + setflag(status_flags::not_shareable); } // protected @@ -85,7 +80,7 @@ matrix::matrix(unsigned r, unsigned c) matrix::matrix(unsigned r, unsigned c, const exvector & m2) : inherited(TINFO_matrix), row(r), col(c), m(m2) { - debugmsg("matrix ctor from unsigned,unsigned,exvector",LOGLEVEL_CONSTRUCT); + setflag(status_flags::not_shareable); } /** Construct matrix from (flat) list of elements. If the list has fewer @@ -93,17 +88,17 @@ matrix::matrix(unsigned r, unsigned c, const exvector & m2) * If the list has more elements than the matrix, the excessive elements are * thrown away. */ matrix::matrix(unsigned r, unsigned c, const lst & l) - : inherited(TINFO_matrix), row(r), col(c) + : inherited(TINFO_matrix), row(r), col(c), m(r*c, _ex0) { - debugmsg("matrix ctor from unsigned,unsigned,lst",LOGLEVEL_CONSTRUCT); - m.resize(r*c, _ex0()); + setflag(status_flags::not_shareable); - for (unsigned i=0; i= r) break; // matrix smaller than list: throw away excessive elements - m[y*c+x] = l.op(i); + m[y*c+x] = *it; } } @@ -111,9 +106,10 @@ matrix::matrix(unsigned r, unsigned c, const lst & l) // archiving ////////// -matrix::matrix(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst) +matrix::matrix(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst) { - debugmsg("matrix ctor from archive_node", LOGLEVEL_CONSTRUCT); + setflag(status_flags::not_shareable); + if (!(n.find_unsigned("row", row)) || !(n.find_unsigned("col", col))) throw (std::runtime_error("unknown matrix dimensions in archive")); m.reserve(row * col); @@ -141,68 +137,74 @@ void matrix::archive(archive_node &n) const DEFAULT_UNARCHIVE(matrix) ////////// -// functions overriding virtual functions from bases classes +// functions overriding virtual functions from base classes ////////// // public -void matrix::print(const print_context & c, unsigned level) const +void matrix::print_elements(const print_context & c, const char *row_start, const char *row_end, const char *row_sep, const char *col_sep) const { - debugmsg("matrix print", LOGLEVEL_PRINT); - - if (is_of_type(c, print_tree)) { - - inherited::print(c, level); + for (unsigned ro=0; ro(row) * static_cast(col); } /** returns matrix entry at position (i/col, i%col). */ -ex matrix::op(int i) const +ex matrix::op(size_t i) const { + GINAC_ASSERT(i=0); GINAC_ASSERT(isetflag(status_flags::dynallocated | - status_flags::evaluated ); + status_flags::evaluated); } -ex matrix::subs(const lst & ls, const lst & lr, bool no_pattern) const +ex matrix::subs(const exmap & mp, unsigned options) const { exvector m2(row * col); for (unsigned r=0; rbasic::subs(ls, lr, no_pattern); + return matrix(row, col, m2).subs_one_level(mp, options); } // protected int matrix::compare_same_type(const basic & other) const { - GINAC_ASSERT(is_exactly_of_type(other, matrix)); - const matrix & o = static_cast(other); + GINAC_ASSERT(is_exactly_a(other)); + const matrix &o = static_cast(other); // compare number of rows if (row != o.rows()) @@ -259,11 +261,21 @@ int matrix::compare_same_type(const basic & other) const return 0; } +bool matrix::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_exactly_a(other)); + const matrix & o = static_cast(other); + + // The number of rows and columns must be the same. This is necessary to + // prevent a 2x3 matrix from matching a 3x2 one. + return row == o.rows() && col == o.cols(); +} + /** Automatic symbolic evaluation of an indexed matrix. */ ex matrix::eval_indexed(const basic & i) const { - GINAC_ASSERT(is_of_type(i, indexed)); - GINAC_ASSERT(is_ex_of_type(i.op(0), matrix)); + GINAC_ASSERT(is_a(i)); + GINAC_ASSERT(is_a(i.op(0))); bool all_indices_unsigned = static_cast(i).all_index_values_are(info_flags::nonnegint); @@ -339,13 +351,13 @@ ex matrix::eval_indexed(const basic & i) const /** Sum of two indexed matrices. */ ex matrix::add_indexed(const ex & self, const ex & other) const { - GINAC_ASSERT(is_ex_of_type(self, indexed)); - GINAC_ASSERT(is_ex_of_type(self.op(0), matrix)); - GINAC_ASSERT(is_ex_of_type(other, indexed)); + GINAC_ASSERT(is_a(self)); + GINAC_ASSERT(is_a(self.op(0))); + GINAC_ASSERT(is_a(other)); GINAC_ASSERT(self.nops() == 2 || self.nops() == 3); // Only add two matrices - if (is_ex_of_type(other.op(0), matrix)) { + if (is_a(other.op(0))) { GINAC_ASSERT(other.nops() == 2 || other.nops() == 3); const matrix &self_matrix = ex_to(self.op(0)); @@ -375,8 +387,8 @@ ex matrix::add_indexed(const ex & self, const ex & other) const /** Product of an indexed matrix with a number. */ ex matrix::scalar_mul_indexed(const ex & self, const numeric & other) const { - GINAC_ASSERT(is_ex_of_type(self, indexed)); - GINAC_ASSERT(is_ex_of_type(self.op(0), matrix)); + GINAC_ASSERT(is_a(self)); + GINAC_ASSERT(is_a(self.op(0))); GINAC_ASSERT(self.nops() == 2 || self.nops() == 3); const matrix &self_matrix = ex_to(self.op(0)); @@ -390,13 +402,13 @@ ex matrix::scalar_mul_indexed(const ex & self, const numeric & other) const /** Contraction of an indexed matrix with something else. */ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const { - GINAC_ASSERT(is_ex_of_type(*self, indexed)); - GINAC_ASSERT(is_ex_of_type(*other, indexed)); + GINAC_ASSERT(is_a(*self)); + GINAC_ASSERT(is_a(*other)); GINAC_ASSERT(self->nops() == 2 || self->nops() == 3); - GINAC_ASSERT(is_ex_of_type(self->op(0), matrix)); + GINAC_ASSERT(is_a(self->op(0))); // Only contract with other matrices - if (!is_ex_of_type(other->op(0), matrix)) + if (!is_a(other->op(0))) return false; GINAC_ASSERT(other->nops() == 2 || other->nops() == 3); @@ -405,10 +417,8 @@ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, ex const matrix &other_matrix = ex_to(other->op(0)); if (self->nops() == 2) { - unsigned self_dim = (self_matrix.col == 1) ? self_matrix.row : self_matrix.col; if (other->nops() == 2) { // vector * vector (scalar product) - unsigned other_dim = (other_matrix.col == 1) ? other_matrix.row : other_matrix.col; if (self_matrix.col == 1) { if (other_matrix.col == 1) { @@ -427,7 +437,7 @@ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, ex *self = self_matrix.mul(other_matrix.transpose())(0, 0); } } - *other = _ex1(); + *other = _ex1; return true; } else { // vector * matrix @@ -438,7 +448,7 @@ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, ex *self = indexed(self_matrix.mul(other_matrix), other->op(2)); else *self = indexed(self_matrix.transpose().mul(other_matrix), other->op(2)); - *other = _ex1(); + *other = _ex1; return true; } @@ -448,7 +458,7 @@ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, ex *self = indexed(other_matrix.mul(self_matrix), other->op(1)); else *self = indexed(other_matrix.mul(self_matrix.transpose()), other->op(1)); - *other = _ex1(); + *other = _ex1; return true; } } @@ -458,28 +468,28 @@ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, ex // A_ij * B_jk = (A*B)_ik if (is_dummy_pair(self->op(2), other->op(1))) { *self = indexed(self_matrix.mul(other_matrix), self->op(1), other->op(2)); - *other = _ex1(); + *other = _ex1; return true; } // A_ij * B_kj = (A*Btrans)_ik if (is_dummy_pair(self->op(2), other->op(2))) { *self = indexed(self_matrix.mul(other_matrix.transpose()), self->op(1), other->op(1)); - *other = _ex1(); + *other = _ex1; return true; } // A_ji * B_jk = (Atrans*B)_ik if (is_dummy_pair(self->op(1), other->op(1))) { *self = indexed(self_matrix.transpose().mul(other_matrix), self->op(2), other->op(2)); - *other = _ex1(); + *other = _ex1; return true; } // A_ji * B_kj = (B*A)_ki if (is_dummy_pair(self->op(1), other->op(2))) { *self = indexed(other_matrix.mul(self_matrix), other->op(1), self->op(2)); - *other = _ex1(); + *other = _ex1; return true; } } @@ -587,36 +597,37 @@ matrix matrix::pow(const ex & expn) const if (col!=row) throw (std::logic_error("matrix::pow(): matrix not square")); - if (is_ex_exactly_of_type(expn, numeric)) { + if (is_exactly_a(expn)) { // Integer cases are computed by successive multiplication, using the // obvious shortcut of storing temporaries, like A^4 == (A*A)*(A*A). if (expn.info(info_flags::integer)) { - numeric k; - matrix prod(row,col); + numeric b = ex_to(expn); + matrix A(row,col); if (expn.info(info_flags::negative)) { - k = -ex_to(expn); - prod = this->inverse(); + b *= -1; + A = this->inverse(); } else { - k = ex_to(expn); - prod = *this; + A = *this; } - matrix result(row,col); + matrix C(row,col); for (unsigned r=0; rcols()*this->rows()); @@ -691,7 +702,7 @@ ex matrix::determinant(unsigned algo) const unsigned sparse_count = 0; // counts non-zero elements exvector::const_iterator r = m.begin(), rend = m.end(); while (r != rend) { - lst srl; // symbol replacement list + exmap srl; // symbol replacement list ex rtest = r->to_rational(srl); if (!rtest.is_zero()) ++sparse_count; @@ -753,7 +764,7 @@ ex matrix::determinant(unsigned algo) const int sign; sign = tmp.division_free_elimination(true); if (sign==0) - return _ex0(); + return _ex0; ex det = tmp.m[row*col-1]; // factor out accumulated bogus slag for (unsigned d=0; d uintpair; std::vector c_zeros; // number of zeros in column for (unsigned c=0; c pre_sort; for (std::vector::const_iterator i=c_zeros.begin(); i!=c_zeros.end(); ++i) pre_sort.push_back(i->second); @@ -808,7 +822,7 @@ ex matrix::determinant(unsigned algo) const * * @return the sum of diagonal elements * @exception logic_error (matrix not square) */ -ex matrix::trace(void) const +ex matrix::trace() const { if (row != col) throw (std::logic_error("matrix::trace(): matrix not square")); @@ -836,14 +850,14 @@ ex matrix::trace(void) const * @return characteristic polynomial as new expression * @exception logic_error (matrix not square) * @see matrix::determinant() */ -ex matrix::charpoly(const symbol & lambda) const +ex matrix::charpoly(const ex & lambda) const { if (row != col) throw (std::logic_error("matrix::charpoly(): matrix not square")); bool numeric_flag = true; exvector::const_iterator r = m.begin(), rend = m.end(); - while (r != rend) { + while (r!=rend && numeric_flag==true) { if (!r->info(info_flags::numeric)) numeric_flag = false; ++r; @@ -853,27 +867,30 @@ ex matrix::charpoly(const symbol & lambda) const // trapped and we use Leverrier's algorithm which goes as row^3 for // every coefficient. The expensive part is the matrix multiplication. if (numeric_flag) { + matrix B(*this); ex c = B.trace(); - ex poly = power(lambda,row)-c*power(lambda,row-1); + ex poly = power(lambda, row) - c*power(lambda, row-1); for (unsigned i=1; imul(B); - c = B.trace()/ex(i+1); - poly -= c*power(lambda,row-i-1); + c = B.trace() / ex(i+1); + poly -= c*power(lambda, row-i-1); } if (row%2) return -poly; else return poly; - } + + } else { - matrix M(*this); - for (unsigned r=0; rinfo(info_flags::numeric)) numeric_flag = false; ++r; @@ -1033,7 +1051,7 @@ matrix matrix::solve(const matrix & vars, * * @return the determinant as a new expression (in expanded form) * @see matrix::determinant() */ -ex matrix::determinant_minor(void) const +ex matrix::determinant_minor() const { // for small matrices the algorithm does not make any sense: const unsigned n = this->cols(); @@ -1104,7 +1122,7 @@ ex matrix::determinant_minor(void) const Pkey.push_back(i); unsigned fc = 0; // controls logic for our strange flipper counter do { - det = _ex0(); + det = _ex0; for (unsigned r=0; rm[r2*n+c] = _ex0(); + this->m[r2*n+c] = _ex0; } if (det) { // save space by deleting no longer needed elements for (unsigned c=r0+1; cm[r0*n+c] = _ex0(); + this->m[r0*n+c] = _ex0; } ++r0; } @@ -1231,12 +1249,12 @@ int matrix::division_free_elimination(const bool det) this->m[r2*n+c] = (this->m[r0*n+r1]*this->m[r2*n+c] - this->m[r2*n+r1]*this->m[r0*n+c]).expand(); // fill up left hand side with zeros for (unsigned c=0; c<=r1; ++c) - this->m[r2*n+c] = _ex0(); + this->m[r2*n+c] = _ex0; } if (det) { // save space by deleting no longer needed elements for (unsigned c=r0+1; cm[r0*n+c] = _ex0(); + this->m[r0*n+c] = _ex0; } ++r0; } @@ -1266,7 +1284,7 @@ int matrix::fraction_free_elimination(const bool det) // // Bareiss (fraction-free) elimination in addition divides that element // by m[k-1](k-1,k-1) for k>1, where it can be shown by means of the - // Sylvester determinant that this really divides m[k+1](r,c). + // Sylvester identity that this really divides m[k+1](r,c). // // We also allow rational functions where the original prove still holds. // However, we must care for numerator and denominator separately and @@ -1303,7 +1321,7 @@ int matrix::fraction_free_elimination(const bool det) // makes things more complicated than they need to be. matrix tmp_n(*this); matrix tmp_d(m,n); // for denominators, if needed - lst srl; // symbol replacement list + exmap srl; // symbol replacement list exvector::const_iterator cit = this->m.begin(), citend = this->m.end(); exvector::iterator tmp_n_it = tmp_n.m.begin(), tmp_d_it = tmp_d.m.begin(); while (cit != citend) { @@ -1344,7 +1362,7 @@ int matrix::fraction_free_elimination(const bool det) } // fill up left hand side with zeros for (unsigned c=0; c<=r1; ++c) - tmp_n.m[r2*n+c] = _ex0(); + tmp_n.m[r2*n+c] = _ex0; } if ((r1m[k*col+co],numeric)); + GINAC_ASSERT(is_exactly_a(this->m[k*col+co])); unsigned kmax = k+1; numeric mmax = abs(ex_to(m[kmax*col+co])); while (kmaxm[kmax*col+co],numeric)); + GINAC_ASSERT(is_exactly_a(this->m[kmax*col+co])); numeric tmp = ex_to(this->m[kmax*col+co]); if (abs(tmp) > mmax) { mmax = tmp; @@ -1425,34 +1443,92 @@ int matrix::pivot(unsigned ro, unsigned co, bool symbolic) ex lst_to_matrix(const lst & l) { + lst::const_iterator itr, itc; + // Find number of rows and columns - unsigned rows = l.nops(), cols = 0, i, j; - for (i=0; i cols) - cols = l.op(i).nops(); + size_t rows = l.nops(), cols = 0; + for (itr = l.begin(); itr != l.end(); ++itr) { + if (!is_a(*itr)) + throw (std::invalid_argument("lst_to_matrix: argument must be a list of lists")); + if (itr->nops() > cols) + cols = itr->nops(); + } // Allocate and fill matrix - matrix &m = *new matrix(rows, cols); - m.setflag(status_flags::dynallocated); - for (i=0; i j) - m(i, j) = l.op(i).op(j); - else - m(i, j) = _ex0(); - return m; + matrix &M = *new matrix(rows, cols); + M.setflag(status_flags::dynallocated); + + unsigned i; + for (itr = l.begin(), i = 0; itr != l.end(); ++itr, ++i) { + unsigned j; + for (itc = ex_to(*itr).begin(), j = 0; itc != ex_to(*itr).end(); ++itc, ++j) + M(i, j) = *itc; + } + + return M; } ex diag_matrix(const lst & l) { - unsigned dim = l.nops(); + lst::const_iterator it; + size_t dim = l.nops(); + + // Allocate and fill matrix + matrix &M = *new matrix(dim, dim); + M.setflag(status_flags::dynallocated); + + unsigned i; + for (it = l.begin(), i = 0; it != l.end(); ++it, ++i) + M(i, i) = *it; - matrix &m = *new matrix(dim, dim); - m.setflag(status_flags::dynallocated); - for (unsigned i=0; i 10 || c > 10); + bool single_row = (r == 1 || c == 1); + + for (unsigned i=0; i