X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fmatrix.cpp;h=9f9f67a82c83b62e76431de79ea4bf4054a05047;hp=1a5d6953c3d994365d9d6b05a60ebf351119e7bd;hb=199b64938ab86af572d0816c15d7838730567b2d;hpb=539de73dc25de63f2888f8696d73ac3fc83db45f diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp index 1a5d6953..9f9f67a8 100644 --- a/ginac/matrix.cpp +++ b/ginac/matrix.cpp @@ -25,16 +25,17 @@ #include #include "matrix.h" -#include "archive.h" #include "numeric.h" #include "lst.h" #include "idx.h" #include "indexed.h" -#include "utils.h" -#include "debugmsg.h" #include "power.h" #include "symbol.h" #include "normal.h" +#include "print.h" +#include "archive.h" +#include "utils.h" +#include "debugmsg.h" namespace GiNaC { @@ -44,8 +45,6 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(matrix, basic) // default ctor, dtor, copy ctor, assignment operator and helpers: ////////// -// public - /** Default ctor. Initializes to 1 x 1-dimensional zero-matrix. */ matrix::matrix() : inherited(TINFO_matrix), row(1), col(1) { @@ -53,9 +52,6 @@ matrix::matrix() : inherited(TINFO_matrix), row(1), col(1) m.push_back(_ex0()); } -// protected - -/** For use by copy ctor and assignment operator. */ void matrix::copy(const matrix & other) { inherited::copy(other); @@ -64,10 +60,7 @@ void matrix::copy(const matrix & other) m = other.m; // STL's vector copying invoked here } -void matrix::destroy(bool call_parent) -{ - if (call_parent) inherited::destroy(call_parent); -} +DEFAULT_DESTROY(matrix) ////////// // other ctors @@ -95,11 +88,29 @@ matrix::matrix(unsigned r, unsigned c, const exvector & m2) debugmsg("matrix ctor from unsigned,unsigned,exvector",LOGLEVEL_CONSTRUCT); } +/** Construct matrix from (flat) list of elements. If the list has fewer + * elements than the matrix, the remaining matrix elements are set to zero. + * 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) +{ + debugmsg("matrix ctor from unsigned,unsigned,lst",LOGLEVEL_CONSTRUCT); + m.resize(r*c, _ex0()); + + for (unsigned i=0; i= r) + break; // matrix smaller than list: throw away excessive elements + m[y*c+x] = l.op(i); + } +} + ////////// // archiving ////////// -/** Construct object from archive_node. */ matrix::matrix(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst) { debugmsg("matrix ctor from archive_node", LOGLEVEL_CONSTRUCT); @@ -115,13 +126,6 @@ matrix::matrix(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst } } -/** Unarchive the object. */ -ex matrix::unarchive(const archive_node &n, const lst &sym_lst) -{ - return (new matrix(n, sym_lst))->setflag(status_flags::dynallocated); -} - -/** Archive the object. */ void matrix::archive(archive_node &n) const { inherited::archive(n); @@ -134,42 +138,43 @@ void matrix::archive(archive_node &n) const } } +DEFAULT_UNARCHIVE(matrix) + ////////// // functions overriding virtual functions from bases classes ////////// // public -void matrix::print(std::ostream & os, unsigned upper_precedence) const +void matrix::print(const print_context & c, unsigned level) const { - debugmsg("matrix print",LOGLEVEL_PRINT); - os << "[[ "; - for (unsigned r=0; rbasic::subs(ls, lr, no_pattern); } // protected @@ -319,7 +274,7 @@ ex matrix::eval_indexed(const basic & i) const if (row != 1 && col != 1) throw (std::runtime_error("matrix::eval_indexed(): vector must have exactly 1 index")); - const idx & i1 = ex_to_idx(i.op(1)); + const idx & i1 = ex_to(i.op(1)); if (col == 1) { @@ -329,7 +284,7 @@ ex matrix::eval_indexed(const basic & i) const // Index numeric -> return vector element if (all_indices_unsigned) { - unsigned n1 = ex_to_numeric(i1.get_value()).to_int(); + unsigned n1 = ex_to(i1.get_value()).to_int(); if (n1 >= row) throw (std::runtime_error("matrix::eval_indexed(): value of index exceeds number of vector elements")); return (*this)(n1, 0); @@ -343,7 +298,7 @@ ex matrix::eval_indexed(const basic & i) const // Index numeric -> return vector element if (all_indices_unsigned) { - unsigned n1 = ex_to_numeric(i1.get_value()).to_int(); + unsigned n1 = ex_to(i1.get_value()).to_int(); if (n1 >= col) throw (std::runtime_error("matrix::eval_indexed(): value of index exceeds number of vector elements")); return (*this)(0, n1); @@ -353,8 +308,8 @@ ex matrix::eval_indexed(const basic & i) const } else if (i.nops() == 3) { // Two indices - const idx & i1 = ex_to_idx(i.op(1)); - const idx & i2 = ex_to_idx(i.op(2)); + const idx & i1 = ex_to(i.op(1)); + const idx & i2 = ex_to(i.op(2)); if (!i1.get_dim().is_equal(row)) throw (std::runtime_error("matrix::eval_indexed(): dimension of first index must match number of rows")); @@ -367,7 +322,7 @@ ex matrix::eval_indexed(const basic & i) const // Both indices numeric -> return matrix element if (all_indices_unsigned) { - unsigned n1 = ex_to_numeric(i1.get_value()).to_int(), n2 = ex_to_numeric(i2.get_value()).to_int(); + unsigned n1 = ex_to(i1.get_value()).to_int(), n2 = ex_to(i2.get_value()).to_int(); if (n1 >= row) throw (std::runtime_error("matrix::eval_indexed(): value of first index exceeds number of rows")); if (n2 >= col) @@ -381,6 +336,57 @@ ex matrix::eval_indexed(const basic & i) const return i.hold(); } +/** 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(self.nops() == 2 || self.nops() == 3); + + // Only add two matrices + if (is_ex_of_type(other.op(0), matrix)) { + GINAC_ASSERT(other.nops() == 2 || other.nops() == 3); + + const matrix &self_matrix = ex_to(self.op(0)); + const matrix &other_matrix = ex_to(other.op(0)); + + if (self.nops() == 2 && other.nops() == 2) { // vector + vector + + if (self_matrix.row == other_matrix.row) + return indexed(self_matrix.add(other_matrix), self.op(1)); + else if (self_matrix.row == other_matrix.col) + return indexed(self_matrix.add(other_matrix.transpose()), self.op(1)); + + } else if (self.nops() == 3 && other.nops() == 3) { // matrix + matrix + + if (self.op(1).is_equal(other.op(1)) && self.op(2).is_equal(other.op(2))) + return indexed(self_matrix.add(other_matrix), self.op(1), self.op(2)); + else if (self.op(1).is_equal(other.op(2)) && self.op(2).is_equal(other.op(1))) + return indexed(self_matrix.add(other_matrix.transpose()), self.op(1), self.op(2)); + + } + } + + // Don't know what to do, return unevaluated sum + return self + other; +} + +/** 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(self.nops() == 2 || self.nops() == 3); + + const matrix &self_matrix = ex_to(self.op(0)); + + if (self.nops() == 2) + return indexed(self_matrix.mul(other), self.op(1)); + else // self.nops() == 3 + return indexed(self_matrix.mul(other), self.op(1), self.op(2)); +} + /** Contraction of an indexed matrix with something else. */ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const { @@ -395,8 +401,8 @@ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, ex GINAC_ASSERT(other->nops() == 2 || other->nops() == 3); - const matrix &self_matrix = ex_to_matrix(self->op(0)); - const matrix &other_matrix = ex_to_matrix(other->op(0)); + const matrix &self_matrix = ex_to(self->op(0)); + 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; @@ -494,7 +500,7 @@ bool matrix::contract_with(exvector::iterator self, exvector::iterator other, ex matrix matrix::add(const matrix & other) const { if (col != other.col || row != other.row) - throw (std::logic_error("matrix::add(): incompatible matrices")); + throw std::logic_error("matrix::add(): incompatible matrices"); exvector sum(this->m); exvector::iterator i; @@ -512,7 +518,7 @@ matrix matrix::add(const matrix & other) const matrix matrix::sub(const matrix & other) const { if (col != other.col || row != other.row) - throw (std::logic_error("matrix::sub(): incompatible matrices")); + throw std::logic_error("matrix::sub(): incompatible matrices"); exvector dif(this->m); exvector::iterator i; @@ -530,7 +536,7 @@ matrix matrix::sub(const matrix & other) const matrix matrix::mul(const matrix & other) const { if (this->cols() != other.rows()) - throw (std::logic_error("matrix::mul(): incompatible matrices")); + throw std::logic_error("matrix::mul(): incompatible matrices"); exvector prod(this->rows()*other.cols()); @@ -546,7 +552,78 @@ matrix matrix::mul(const matrix & other) const } -/** operator() to access elements. +/** Product of matrix and scalar. */ +matrix matrix::mul(const numeric & other) const +{ + exvector prod(row * col); + + for (unsigned r=0; r(expn); + prod = this->inverse(); + } else { + k = ex_to(expn); + prod = *this; + } + matrix result(row,col); + for (unsigned r=0; r=row || co>=col) - throw (std::range_error("matrix::set(): index out of range")); - + throw (std::range_error("matrix::operator(): index out of range")); + ensure_if_modifiable(); - m[ro*col+co] = value; - return *this; + return m[ro*col+co]; } @@ -587,7 +665,6 @@ matrix matrix::transpose(void) const return matrix(this->cols(),this->rows(),trans); } - /** Determinant of square matrix. This routine doesn't actually calculate the * determinant, it only implements some heuristics about which algorithm to * run. If all the elements of the matrix are elements of an integral domain @@ -703,7 +780,8 @@ ex matrix::determinant(unsigned algo) const std::vector pre_sort; for (std::vector::iterator i=c_zeros.begin(); i!=c_zeros.end(); ++i) pre_sort.push_back(i->second); - int sign = permutation_sign(pre_sort); + std::vector pre_sort_test(pre_sort); // permutation_sign() modifies the vector so we make a copy here + int sign = permutation_sign(pre_sort_test.begin(), pre_sort_test.end()); exvector result(row*col); // represents sorted matrix unsigned c = 0; for (std::vector::iterator i=pre_sort.begin(); @@ -806,50 +884,32 @@ matrix matrix::inverse(void) const if (row != col) throw (std::logic_error("matrix::inverse(): matrix not square")); - // NOTE: the Gauss-Jordan elimination used here can in principle be - // replaced by two clever calls to gauss_elimination() and some to - // transpose(). Wouldn't be more efficient (maybe less?), just more - // orthogonal. - matrix tmp(row,col); - // set tmp to the unit matrix - for (unsigned i=0; isolve(vars,identity); + } catch (const std::runtime_error & e) { + if (e.what()==std::string("matrix::solve(): inconsistent linear system")) throw (std::runtime_error("matrix::inverse(): singular matrix")); - } - if (indx != 0) { // swap rows r and indx of matrix tmp - for (unsigned i=0; im[k*col+co],numeric)); unsigned kmax = k+1; - numeric mmax = abs(ex_to_numeric(m[kmax*col+co])); + numeric mmax = abs(ex_to(m[kmax*col+co])); while (kmaxm[kmax*col+co],numeric)); - numeric tmp = ex_to_numeric(this->m[kmax*col+co]); + numeric tmp = ex_to(this->m[kmax*col+co]); if (abs(tmp) > mmax) { mmax = tmp; k = kmax; @@ -1357,26 +1418,35 @@ int matrix::pivot(unsigned ro, unsigned co, bool symbolic) return k; } -/** Convert list of lists to matrix. */ -ex lst_to_matrix(const ex &l) +ex lst_to_matrix(const lst & l) { - if (!is_ex_of_type(l, lst)) - throw(std::invalid_argument("argument to lst_to_matrix() must be a lst")); - // Find number of rows and columns unsigned rows = l.nops(), cols = 0, i, j; for (i=0; i cols) cols = l.op(i).nops(); - + // Allocate and fill matrix matrix &m = *new matrix(rows, cols); + m.setflag(status_flags::dynallocated); for (i=0; i j) - m.set(i, j, l.op(i).op(j)); + m(i, j) = l.op(i).op(j); else - m.set(i, j, ex(0)); + m(i, j) = _ex0(); + return m; +} + +ex diag_matrix(const lst & l) +{ + unsigned dim = l.nops(); + + matrix &m = *new matrix(dim, dim); + m.setflag(status_flags::dynallocated); + for (unsigned i=0; i