X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fmatrix.cpp;h=4828bb9392db1e87666e382a77e5c4a5368f0cfb;hp=1a5d6953c3d994365d9d6b05a60ebf351119e7bd;hb=1b48bfdf43c8d104cb8b06147f27cb9efe42cb16;hpb=539de73dc25de63f2888f8696d73ac3fc83db45f diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp index 1a5d6953..4828bb93 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,57 +20,43 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include +#include #include #include #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 "add.h" #include "power.h" #include "symbol.h" +#include "operators.h" #include "normal.h" +#include "print.h" +#include "archive.h" +#include "utils.h" namespace GiNaC { GINAC_IMPLEMENT_REGISTERED_CLASS(matrix, basic) ////////// -// default ctor, dtor, copy ctor, assignment operator and helpers: +// default constructor ////////// -// public - /** Default ctor. Initializes to 1 x 1-dimensional zero-matrix. */ matrix::matrix() : inherited(TINFO_matrix), row(1), col(1) { - debugmsg("matrix default ctor",LOGLEVEL_CONSTRUCT); - m.push_back(_ex0()); -} - -// protected - -/** For use by copy ctor and assignment operator. */ -void matrix::copy(const matrix & other) -{ - inherited::copy(other); - row = other.row; - col = other.col; - m = other.m; // STL's vector copying invoked here -} - -void matrix::destroy(bool call_parent) -{ - if (call_parent) inherited::destroy(call_parent); + m.push_back(_ex0); } ////////// -// other ctors +// other constructors ////////// // public @@ -82,27 +68,40 @@ void matrix::destroy(bool call_parent) matrix::matrix(unsigned r, unsigned c) : inherited(TINFO_matrix), row(r), col(c) { - debugmsg("matrix ctor from unsigned,unsigned",LOGLEVEL_CONSTRUCT); - m.resize(r*c, _ex0()); + m.resize(r*c, _ex0); } // protected /** Ctor from representation, for internal use only. */ matrix::matrix(unsigned r, unsigned c, const exvector & m2) - : inherited(TINFO_matrix), row(r), col(c), m(m2) + : inherited(TINFO_matrix), row(r), col(c), m(m2) {} + +/** 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,exvector",LOGLEVEL_CONSTRUCT); + m.resize(r*c, _ex0); + + size_t i = 0; + for (lst::const_iterator it = l.begin(); it != l.end(); ++it, ++i) { + size_t x = i % c; + size_t y = i / c; + if (y >= r) + break; // matrix smaller than list: throw away excessive elements + m[y*c+x] = *it; + } } ////////// // archiving ////////// -/** Construct object from archive_node. */ -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); if (!(n.find_unsigned("row", row)) || !(n.find_unsigned("col", col))) throw (std::runtime_error("unknown matrix dimensions in archive")); m.reserve(row * col); @@ -115,13 +114,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,96 +126,90 @@ 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(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; r(c)) { + + inherited::print(c, level); + + } else { + + if (is_a(c)) + c.s << class_name() << '('; + + if (is_a(c)) + c.s << "\\left(\\begin{array}{" << std::string(col,'c') << "}"; + else + c.s << "["; + + for (unsigned ro=0; ro(c)) + c.s << "["; + for (unsigned co=0; co(c)) + c.s << "&"; + else + c.s << ","; + } else { + if (!is_a(c)) + c.s << "]"; + } + } + if (ro(c)) + c.s << "\\\\"; + else + c.s << ","; + } + } + + if (is_a(c)) + c.s << "\\end{array}\\right)"; + else + c.s << "]"; + + if (is_a(c)) + c.s << ')'; -void matrix::printraw(std::ostream & os) const -{ - debugmsg("matrix printraw",LOGLEVEL_PRINT); - os << class_name() << "(" << row << "," << col <<","; - for (unsigned r=0; r(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 { - return m[i]; -} - -/** returns matrix entry at position (i/col, i%col). */ -ex & matrix::let_op(int i) -{ - GINAC_ASSERT(i>=0); GINAC_ASSERT(isetflag(status_flags::dynallocated | - status_flags::evaluated ); -} - -/** Evaluate matrix numerically entry by entry. */ -ex matrix::evalf(int level) const -{ - debugmsg("matrix evalf",LOGLEVEL_MEMBER_FUNCTION); - - // check if we have to do anything at all - if (level==1) - return *this; - - // emergency break - if (level == -max_recursion_level) { - throw (std::runtime_error("matrix::evalf(): recursion limit exceeded")); - } - - // evalf() entry by entry - exvector m2(row*col); - --level; - for (unsigned r=0; r(const_cast(other)); + GINAC_ASSERT(is_exactly_a(other)); + const matrix &o = static_cast(other); // compare number of rows if (row != o.rows()) @@ -304,11 +266,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); @@ -319,7 +291,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 +301,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 +315,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 +325,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 +339,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,28 +353,77 @@ 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_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_a(other.op(0))) { + 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_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)); + + 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 { - 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); - 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; 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) { @@ -421,7 +442,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 @@ -432,7 +453,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; } @@ -442,7 +463,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; } } @@ -452,28 +473,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; } } @@ -494,13 +515,13 @@ 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; - exvector::const_iterator ci; - for (i=sum.begin(), ci=other.m.begin(); i!=sum.end(); ++i, ++ci) - (*i) += (*ci); + exvector::iterator i = sum.begin(), end = sum.end(); + exvector::const_iterator ci = other.m.begin(); + while (i != end) + *i++ += *ci++; return matrix(row,col,sum); } @@ -512,13 +533,13 @@ 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; - exvector::const_iterator ci; - for (i=dif.begin(), ci=other.m.begin(); i!=dif.end(); ++i, ++ci) - (*i) -= (*ci); + exvector::iterator i = dif.begin(), end = dif.end(); + exvector::const_iterator ci = other.m.begin(); + while (i != end) + *i++ -= *ci++; return matrix(row,col,dif); } @@ -530,7 +551,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 +567,79 @@ 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)) { + // 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 b = ex_to(expn); + matrix A(row,col); + if (expn.info(info_flags::negative)) { + b *= -1; + A = this->inverse(); + } else { + A = *this; + } + matrix C(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]; } /** Transposed of an m x n matrix, producing a new n x m matrix object that * represents the transposed. */ -matrix matrix::transpose(void) const +matrix matrix::transpose() const { exvector trans(this->cols()*this->rows()); @@ -587,7 +681,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 @@ -612,9 +705,10 @@ ex matrix::determinant(unsigned algo) const bool numeric_flag = true; bool normal_flag = false; unsigned sparse_count = 0; // counts non-zero elements - for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) { + exvector::const_iterator r = m.begin(), rend = m.end(); + while (r != rend) { lst srl; // symbol replacement list - ex rtest = (*r).to_rational(srl); + ex rtest = r->to_rational(srl); if (!rtest.is_zero()) ++sparse_count; if (!rtest.info(info_flags::numeric)) @@ -622,6 +716,7 @@ ex matrix::determinant(unsigned algo) const if (!rtest.info(info_flags::crational_polynomial) && rtest.info(info_flags::rational_function)) normal_flag = true; + ++r; } // Here is the heuristics in case this routine has to decide: @@ -674,7 +769,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::iterator i=c_zeros.begin(); i!=c_zeros.end(); ++i) + for (std::vector::const_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(); + for (std::vector::const_iterator i=pre_sort.begin(); i!=pre_sort.end(); ++i,++c) { for (unsigned r=0; rinfo(info_flags::numeric)) numeric_flag = false; - } + ++r; } // The pure numeric case is traditionally rather common. Hence, it is // 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); @@ -779,20 +880,22 @@ ex matrix::charpoly(const symbol & lambda) const for (unsigned j=0; jmul(B); - c = B.trace()/ex(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; rsolve(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; iinfo(info_flags::numeric)) numeric_flag = false; + ++r; } // Here is the heuristics in case this routine has to decide: @@ -912,8 +999,10 @@ matrix matrix::solve(const matrix & vars, switch(algo) { case solve_algo::gauss: aug.gauss_elimination(); + break; case solve_algo::divfree: aug.division_free_elimination(); + break; case solve_algo::bareiss: default: aug.fraction_free_elimination(); @@ -936,19 +1025,18 @@ matrix matrix::solve(const matrix & vars, // assign solutions for vars between fnz+1 and // last_assigned_sol-1: free parameters for (unsigned c=fnz; ccols(); @@ -992,9 +1080,9 @@ ex matrix::determinant_minor(void) const // 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; } @@ -1165,12 +1253,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; } @@ -1200,7 +1288,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 @@ -1238,13 +1326,13 @@ int matrix::fraction_free_elimination(const bool det) matrix tmp_n(*this); matrix tmp_d(m,n); // for denominators, if needed lst srl; // symbol replacement list - exvector::iterator it = this->m.begin(); - exvector::iterator tmp_n_it = tmp_n.m.begin(); - exvector::iterator tmp_d_it = tmp_d.m.begin(); - for (; it!= this->m.end(); ++it, ++tmp_n_it, ++tmp_d_it) { - (*tmp_n_it) = (*it).normal().to_rational(srl); - (*tmp_d_it) = (*tmp_n_it).denom(); - (*tmp_n_it) = (*tmp_n_it).numer(); + 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) { + ex nd = cit->normal().to_rational(srl).numer_denom(); + ++cit; + *tmp_n_it++ = nd.op(0); + *tmp_d_it++ = nd.op(1); } unsigned r0 = 0; @@ -1278,7 +1366,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.begin(); + exvector::iterator it = this->m.begin(), itend = this->m.end(); tmp_n_it = tmp_n.m.begin(); tmp_d_it = tmp_d.m.begin(); - for (; it!= this->m.end(); ++it, ++tmp_n_it, ++tmp_d_it) - (*it) = ((*tmp_n_it)/(*tmp_d_it)).subs(srl); + while (it != itend) + *it++ = ((*tmp_n_it++)/(*tmp_d_it++)).subs(srl, subs_options::no_pattern); return sign; } @@ -1328,12 +1416,12 @@ int matrix::pivot(unsigned ro, unsigned co, bool symbolic) ++k; } else { // search largest element in column co beginning at row ro - GINAC_ASSERT(is_ex_of_type(this->m[k*col+co],numeric)); + GINAC_ASSERT(is_exactly_a(this->m[k*col+co])); 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]); + 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; k = kmax; @@ -1357,27 +1445,94 @@ 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")); - + 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); - for (i=0; i j) - m.set(i, j, l.op(i).op(j)); - else - m.set(i, j, ex(0)); - 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) +{ + 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; + + return M; +} + +ex unit_matrix(unsigned r, unsigned c) +{ + matrix &Id = *new matrix(r, c); + Id.setflag(status_flags::dynallocated); + for (unsigned i=0; i 10 || c > 10); + bool single_row = (r == 1 || c == 1); + + for (unsigned i=0; i