X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?a=blobdiff_plain;f=ginac%2Fmatrix.cpp;h=f76aa9d768f0de53419c0285ebf9fc9485226596;hb=61e847cdfd8455a7ba67a0038add8dd35b4e0bff;hp=a4db03dd9746ee80164769ac970590354e4cb0e2;hpb=26741891dadf23162799009b6fd57b4984bd4ce5;p=ginac.git diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp index a4db03dd..f76aa9d7 100644 --- a/ginac/matrix.cpp +++ b/ginac/matrix.cpp @@ -3,7 +3,7 @@ * Implementation of symbolic matrices */ /* - * GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2000 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 @@ -21,14 +21,24 @@ */ #include +#include #include #include "matrix.h" +#include "archive.h" +#include "numeric.h" +#include "lst.h" +#include "utils.h" #include "debugmsg.h" +#include "power.h" +#include "symbol.h" +#include "normal.h" -#ifndef NO_GINAC_NAMESPACE +#ifndef NO_NAMESPACE_GINAC namespace GiNaC { -#endif // ndef NO_GINAC_NAMESPACE +#endif // ndef NO_NAMESPACE_GINAC + +GINAC_IMPLEMENT_REGISTERED_CLASS(matrix, basic) ////////// // default constructor, destructor, copy constructor, assignment operator @@ -39,10 +49,10 @@ namespace GiNaC { /** Default ctor. Initializes to 1 x 1-dimensional zero-matrix. */ matrix::matrix() - : basic(TINFO_matrix), row(1), col(1) + : inherited(TINFO_matrix), row(1), col(1) { debugmsg("matrix default constructor",LOGLEVEL_CONSTRUCT); - m.push_back(exZERO()); + m.push_back(_ex0()); } matrix::~matrix() @@ -50,13 +60,13 @@ matrix::~matrix() debugmsg("matrix destructor",LOGLEVEL_DESTRUCT); } -matrix::matrix(matrix const & other) +matrix::matrix(const matrix & other) { debugmsg("matrix copy constructor",LOGLEVEL_CONSTRUCT); copy(other); } -matrix const & matrix::operator=(matrix const & other) +const matrix & matrix::operator=(const matrix & other) { debugmsg("matrix operator=",LOGLEVEL_ASSIGNMENT); if (this != &other) { @@ -68,17 +78,17 @@ matrix const & matrix::operator=(matrix const & other) // protected -void matrix::copy(matrix const & other) +void matrix::copy(const matrix & other) { - basic::copy(other); - row=other.row; - col=other.col; - m=other.m; // use STL's vector copying + 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) basic::destroy(call_parent); + if (call_parent) inherited::destroy(call_parent); } ////////// @@ -91,20 +101,59 @@ void matrix::destroy(bool call_parent) * * @param r number of rows * @param c number of cols */ -matrix::matrix(int r, int c) - : basic(TINFO_matrix), row(r), col(c) +matrix::matrix(unsigned r, unsigned c) + : inherited(TINFO_matrix), row(r), col(c) { - debugmsg("matrix constructor from int,int",LOGLEVEL_CONSTRUCT); - m.resize(r*c, exZERO()); + debugmsg("matrix constructor from unsigned,unsigned",LOGLEVEL_CONSTRUCT); + m.resize(r*c, _ex0()); } -// protected + // protected /** Ctor from representation, for internal use only. */ -matrix::matrix(int r, int c, vector const & m2) - : basic(TINFO_matrix), row(r), col(c), m(m2) +matrix::matrix(unsigned r, unsigned c, const exvector & m2) + : inherited(TINFO_matrix), row(r), col(c), m(m2) +{ + debugmsg("matrix constructor from unsigned,unsigned,exvector",LOGLEVEL_CONSTRUCT); +} + +////////// +// archiving +////////// + +/** Construct object from archive_node. */ +matrix::matrix(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst) +{ + debugmsg("matrix constructor 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); + for (unsigned int i=0; true; i++) { + ex e; + if (n.find_ex("m", e, sym_lst, i)) + m.push_back(e); + else + break; + } +} + +/** 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 { - debugmsg("matrix constructor from int,int,vector",LOGLEVEL_CONSTRUCT); + inherited::archive(n); + n.add_unsigned("row", row); + n.add_unsigned("col", col); + exvector::const_iterator i = m.begin(), iend = m.end(); + while (i != iend) { + n.add_ex("m", *i); + i++; + } } ////////// @@ -123,15 +172,15 @@ void matrix::print(ostream & os, unsigned upper_precedence) const { debugmsg("matrix print",LOGLEVEL_PRINT); os << "[[ "; - for (int r=0; r tmp(row*col); - for (int i=0; i::const_iterator r=m.begin(); r!=m.end(); ++r) { + for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) { if ((*r).has(other)) return true; } return false; @@ -199,20 +254,18 @@ ex matrix::eval(int level) const debugmsg("matrix eval",LOGLEVEL_MEMBER_FUNCTION); // check if we have to do anything at all - if ((level==1)&&(flags & status_flags::evaluated)) { + if ((level==1)&&(flags & status_flags::evaluated)) return *this; - } // emergency break - if (level == -max_recursion_level) { + if (level == -max_recursion_level) throw (std::runtime_error("matrix::eval(): recursion limit exceeded")); - } // eval() entry by entry - vector m2(row*col); + exvector m2(row*col); --level; - for (int r=0; r m2(row*col); + exvector m2(row*col); --level; - for (int r=0; r(const_cast(other)); + const matrix & o = static_cast(const_cast(other)); // compare number of rows - if (row != o.rows()) { + if (row != o.rows()) return row < o.rows() ? -1 : 1; - } // compare number of columns - if (col != o.cols()) { + if (col != o.cols()) return col < o.cols() ? -1 : 1; - } // equal number of rows and columns, compare individual elements int cmpval; - for (int r=0; r sum(this->m); - vector::iterator i; - vector::const_iterator ci; + exvector sum(this->m); + exvector::iterator i; + exvector::const_iterator ci; for (i=sum.begin(), ci=other.m.begin(); i!=sum.end(); ++i, ++ci) { @@ -302,18 +351,18 @@ matrix matrix::add(matrix const & other) const return matrix(row,col,sum); } + /** Difference of matrices. * * @exception logic_error (incompatible matrices) */ -matrix matrix::sub(matrix const & other) const +matrix matrix::sub(const matrix & other) const { - if (col != other.col || row != other.row) { + if (col != other.col || row != other.row) throw (std::logic_error("matrix::sub(): incompatible matrices")); - } - vector dif(this->m); - vector::iterator i; - vector::const_iterator ci; + exvector dif(this->m); + exvector::iterator i; + exvector::const_iterator ci; for (i=dif.begin(), ci=other.m.begin(); i!=dif.end(); ++i, ++ci) { @@ -322,279 +371,225 @@ matrix matrix::sub(matrix const & other) const return matrix(row,col,dif); } + /** Product of matrices. * * @exception logic_error (incompatible matrices) */ -matrix matrix::mul(matrix const & other) const +matrix matrix::mul(const matrix & other) const { - if (col != other.row) { + if (col != other.row) throw (std::logic_error("matrix::mul(): incompatible matrices")); - } - vector prod(row*other.col); - for (int i=0; i=row || co<0 || co>=col) { + if (ro<0 || ro>=row || co<0 || co>=col) throw (std::range_error("matrix::operator(): index out of range")); - } return m[ro*col+co]; } + /** Set individual elements manually. * * @exception range_error (index out of range) */ -matrix & matrix::set(int ro, int co, ex value) +matrix & matrix::set(unsigned ro, unsigned co, ex value) { - if (ro<0 || ro>=row || co<0 || co>=col) { + if (ro<0 || ro>=row || co<0 || co>=col) throw (std::range_error("matrix::set(): index out of range")); - } ensure_if_modifiable(); - m[ro*col+co]=value; + m[ro*col+co] = value; return *this; } + /** Transposed of an m x n matrix, producing a new n x m matrix object that * represents the transposed. */ matrix matrix::transpose(void) const { - vector trans(col*row); + exvector trans(col*row); - for (int r=0; rrow==1) // continuation would be pointless + return m[0]; - for (int r1=0; r1 -int permutation_sign(vector s) -{ - if (s.size() < 2) - return 0; - int sigma=1; - for (typename vector::iterator i=s.begin(); i!=s.end()-1; ++i) { - for (typename vector::iterator j=i+1; j!=s.end(); ++j) { - if (*i == *j) - return 0; - if (*i > *j) { - iter_swap(i,j); - sigma = -sigma; - } + if ((*r).info(info_flags::rational_function) && + !(*r).info(info_flags::crational_polynomial)) { + normal_flag = true; } } - return sigma; -} - -/** Determinant built by application of the full permutation group. This - * routine is only called internally by matrix::determinant(). */ -ex determinant_symbolic_perm(const matrix & M) -{ - GINAC_ASSERT(M.rows()==M.cols()); // cannot happen, just in case... - - if (M.rows()==1) { // speed things up - return M(0,0); - } - - ex det; - ex term; - vector sigma(M.cols()); - for (int i=0; i uintpair; // # of zeros, column + vector c_zeros; // number of zeros in column + for (unsigned c=0; c pre_sort; // unfortunately vector can't be used + // for permutation_sign. + for (vector::iterator i=c_zeros.begin(); i!=c_zeros.end(); ++i) + pre_sort.push_back(i->second); + int sign = permutation_sign(pre_sort); + exvector result(row*col); // represents sorted matrix + unsigned c = 0; + for (vector::iterator i=pre_sort.begin(); + i!=pre_sort.end(); + ++i,++c) { + for (unsigned r=0; r::const_iterator r=m.begin(); r!=m.end(); ++r) { - if (!(*r).info(info_flags::numeric)) { - if (normalized) { - return determinant_symbolic_minor(*this).normal(); - } else { - return determinant_symbolic_perm(*this); - } - } - } - // if it turns out that all elements are numeric - return determinant_numeric(*this); -} -/** Trace of a matrix. +/** Trace of a matrix. The result is normalized if it is in some quotient + * field and expanded only otherwise. This implies that the trace of the + * symbolic 2x2 matrix [[a/(a-b),x],[y,b/(b-a)]] is recognized to be unity. * * @return the sum of diagonal elements * @exception logic_error (matrix not square) */ ex matrix::trace(void) const { - if (row != col) { + if (row != col) throw (std::logic_error("matrix::trace(): matrix not square")); - } + GINAC_ASSERT(row*col==m.capacity()); ex tr; - for (int r=0; rmul(B); + c = B.trace()/ex(i+1); + poly -= c*power(lambda,row-i-1); + } + if (row%2) + return -poly; + else + return poly; } matrix M(*this); - for (int r=0; rzero_in_last_row)||(zero_in_this_row=n)); - zero_in_last_row=zero_in_this_row; + zero_in_last_row = zero_in_this_row; } #endif // def DO_GINAC_ASSERT + /* + cout << "after" << endl; + cout << "a=" << a << endl; + cout << "b=" << b << endl; + */ + // assemble solution matrix sol(n,1); - int last_assigned_sol=n+1; - for (int r=m; r>0; --r) { - int first_non_zero=1; - while ((first_non_zero<=n)&&(a.ffe_get(r,first_non_zero).is_zero())) { + unsigned last_assigned_sol = n+1; + for (unsigned r=m; r>0; --r) { + unsigned first_non_zero = 1; + while ((first_non_zero<=n)&&(a.ffe_get(r,first_non_zero).is_zero())) first_non_zero++; - } if (first_non_zero>n) { // row consists only of zeroes, corresponding rhs must be 0 as well if (!b.ffe_get(r,1).is_zero()) { @@ -761,37 +762,29 @@ matrix matrix::fraction_free_elim(matrix const & vars, } else { // assign solutions for vars between first_non_zero+1 and // last_assigned_sol-1: free parameters - for (int c=first_non_zero+1; c<=last_assigned_sol-1; ++c) { + for (unsigned c=first_non_zero+1; c<=last_assigned_sol-1; ++c) { sol.ffe_set(c,1,vars.ffe_get(c,1)); } - ex e=b.ffe_get(r,1); - for (int c=first_non_zero+1; c<=n; ++c) { + ex e = b.ffe_get(r,1); + for (unsigned c=first_non_zero+1; c<=n; ++c) { e=e-a.ffe_get(r,c)*sol.ffe_get(c,1); } sol.ffe_set(first_non_zero,1, (e/a.ffe_get(r,first_non_zero)).normal()); - last_assigned_sol=first_non_zero; + last_assigned_sol = first_non_zero; } } // assign solutions for vars between 1 and // last_assigned_sol-1: free parameters - for (int c=1; c<=last_assigned_sol-1; ++c) { + for (unsigned c=1; c<=last_assigned_sol-1; ++c) sol.ffe_set(c,1,vars.ffe_get(c,1)); - } - - /* - for (int c=1; c<=n; ++c) { - cout << vars.ffe_get(c,1) << "->" << sol.ffe_get(c,1) << endl; - } - */ #ifdef DO_GINAC_ASSERT // test solution with echelon matrix - for (int r=1; r<=m; ++r) { - ex e=0; - for (int c=1; c<=n; ++c) { - e=e+a.ffe_get(r,c)*sol.ffe_get(c,1); - } + for (unsigned r=1; r<=m; ++r) { + ex e = 0; + for (unsigned c=1; c<=n; ++c) + e = e+a.ffe_get(r,c)*sol.ffe_get(c,1); if (!(e-b.ffe_get(r,1)).normal().is_zero()) { cout << "e=" << e; cout << "b.ffe_get(" << r<<",1)=" << b.ffe_get(r,1) << endl; @@ -799,25 +792,24 @@ matrix matrix::fraction_free_elim(matrix const & vars, } GINAC_ASSERT((e-b.ffe_get(r,1)).normal().is_zero()); } - + // test solution with original matrix - for (int r=1; r<=m; ++r) { - ex e=0; - for (int c=1; c<=n; ++c) { - e=e+ffe_get(r,c)*sol.ffe_get(c,1); - } + for (unsigned r=1; r<=m; ++r) { + ex e = 0; + for (unsigned c=1; c<=n; ++c) + e = e+ffe_get(r,c)*sol.ffe_get(c,1); try { - if (!(e-rhs.ffe_get(r,1)).normal().is_zero()) { - cout << "e=" << e << endl; - e.printtree(cout); - ex en=e.normal(); - cout << "e.normal()=" << en << endl; - en.printtree(cout); - cout << "rhs.ffe_get(" << r<<",1)=" << rhs.ffe_get(r,1) << endl; - cout << "diff=" << (e-rhs.ffe_get(r,1)).normal() << endl; - } + if (!(e-rhs.ffe_get(r,1)).normal().is_zero()) { + cout << "e=" << e << endl; + e.printtree(cout); + ex en = e.normal(); + cout << "e.normal()=" << en << endl; + en.printtree(cout); + cout << "rhs.ffe_get(" << r<<",1)=" << rhs.ffe_get(r,1) << endl; + cout << "diff=" << (e-rhs.ffe_get(r,1)).normal() << endl; + } } catch (...) { - ex xxx=e-rhs.ffe_get(r,1); + ex xxx = e - rhs.ffe_get(r,1); cerr << "xxx=" << xxx << endl << endl; } GINAC_ASSERT((e-rhs.ffe_get(r,1)).normal().is_zero()); @@ -825,77 +817,457 @@ matrix matrix::fraction_free_elim(matrix const & vars, #endif // def DO_GINAC_ASSERT return sol; -} +} + +/** Solve a set of equations for an m x n matrix. + * + * @param vars n x p matrix + * @param rhs m x p matrix + * @exception logic_error (incompatible matrices) + * @exception runtime_error (singular matrix) */ +matrix matrix::solve(const matrix & vars, + const matrix & rhs) const +{ + if ((row != rhs.row) || (col != vars.row) || (rhs.col != vars.col)) + throw (std::logic_error("matrix::solve(): incompatible matrices")); -/** Solve simultaneous set of equations. */ -matrix matrix::solve(matrix const & v) const + throw (std::runtime_error("FIXME: need implementation.")); +} + +/** Old and obsolete interface: */ +matrix matrix::old_solve(const matrix & v) const { - if (!(row == col && col == v.row)) { + if ((v.row != col) || (col != v.row)) throw (std::logic_error("matrix::solve(): incompatible matrices")); - } - // build the extended matrix of *this with v attached to the right + // build the augmented matrix of *this with v attached to the right matrix tmp(row,col+v.col); - for (int r=0; rm[r*col+c]; + for (unsigned c=0; c0; --r) { + for (unsigned i=r; irow==1) + return m[0]; + if (this->row==2) + return (m[0]*m[3]-m[2]*m[1]).expand(); + if (this->row==3) + return (m[0]*m[4]*m[8]-m[0]*m[5]*m[7]- + m[1]*m[3]*m[8]+m[2]*m[3]*m[7]+ + m[1]*m[5]*m[6]-m[2]*m[4]*m[6]).expand(); + + // This algorithm can best be understood by looking at a naive + // implementation of Laplace-expansion, like this one: + // ex det; + // matrix minorM(this->row-1,this->col-1); + // for (unsigned r1=0; r1row; ++r1) { + // // shortcut if element(r1,0) vanishes + // if (m[r1*col].is_zero()) + // continue; + // // assemble the minor matrix + // for (unsigned r=0; r Pkey; + Pkey.reserve(this->col); + // key for minor determinant (a subpartition of Pkey) + vector Mkey; + Mkey.reserve(this->col-1); + // we store our subminors in maps, keys being the rows they arise from + typedef map,class ex> Rmap; + typedef map,class ex>::value_type Rmap_value; + Rmap A; + Rmap B; + ex det; + // initialize A with last column: + for (unsigned r=0; rcol; ++r) { + Pkey.erase(Pkey.begin(),Pkey.end()); + Pkey.push_back(r); + A.insert(Rmap_value(Pkey,m[this->col*r+this->col-1])); + } + // proceed from right to left through matrix + for (int c=this->col-2; c>=0; --c) { + Pkey.erase(Pkey.begin(),Pkey.end()); // don't change capacity + Mkey.erase(Mkey.begin(),Mkey.end()); + for (unsigned i=0; icol-c; ++i) + Pkey.push_back(i); + unsigned fc = 0; // controls logic for our strange flipper counter + do { + det = _ex0(); + for (unsigned r=0; rcol-c; ++r) { + // maybe there is nothing to do? + if (m[Pkey[r]*this->col+c].is_zero()) + continue; + // create the sorted key for all possible minors + Mkey.erase(Mkey.begin(),Mkey.end()); + for (unsigned i=0; icol-c; ++i) + if (i!=r) + Mkey.push_back(Pkey[i]); + // Fetch the minors and compute the new determinant + if (r%2) + det -= m[Pkey[r]*this->col+c]*A[Mkey]; + else + det += m[Pkey[r]*this->col+c]*A[Mkey]; + } + // prevent build-up of deep nesting of expressions saves time: + det = det.expand(); + // store the new determinant at its place in B: + if (!det.is_zero()) + B.insert(Rmap_value(Pkey,det)); + // increment our strange flipper counter + for (fc=this->col-c; fc>0; --fc) { + ++Pkey[fc-1]; + if (Pkey[fc-1]col-c) + for (unsigned j=fc; jcol-c; ++j) + Pkey[j] = Pkey[j-1]+1; + } while(fc); + // next column, so change the role of A and B: + A = B; + B.clear(); + } + + return det; +} + +/** Helper function to divide rational functions, as needed in any Bareiss + * elimination scheme over a quotient field. + * + * @see divide() */ +bool rat_divide(const ex & a, const ex & b, ex & q, bool check_args = true) +{ + q = _ex0(); + if (b.is_zero()) + throw(std::overflow_error("rat_divide(): division by zero")); + if (a.is_zero()) + return true; + if (is_ex_exactly_of_type(b, numeric)) { + q = a / b; + return true; + } else if (is_ex_exactly_of_type(a, numeric)) + return false; + ex a_n = a.numer(); + ex a_d = a.denom(); + ex b_n = b.numer(); + ex b_d = b.denom(); + ex n; // new numerator + ex d; // new denominator + bool check = true; + check &= divide(a_n, b_n, n, check_args); + check &= divide(a_d, b_d, d, check_args); + q = n/d; + return check; +} + + +/** Determinant computed by using fraction free elimination. This + * routine is only called internally by matrix::determinant(). + * + * @param normalize may be set to false only in integral domains. */ +ex matrix::determinant_bareiss(bool normalize) const +{ + if (rows()==1) + return m[0]; + + int sign = 1; + ex divisor = 1; + ex dividend; + + // we populate a tmp matrix to subsequently operate on, it should + // be normalized even though this algorithm doesn't need GCDs since + // the elements of *this might be unnormalized, which complicates + // things: + matrix tmp(*this); + exvector::const_iterator i = m.begin(); + exvector::iterator ti = tmp.m.begin(); + for (; i!= m.end(); ++i, ++ti) { + if (normalize) + (*ti) = (*i).normal(); + else + (*ti) = (*i); + } + + for (unsigned r1=0; r10) + sign = -sign; + if (r1>0) { + divisor = tmp.m[(r1-1)*col+(r1-1)].expand(); + // delete the elements we don't need anymore: + for (unsigned c=0; c sol(v.row*v.col); - for (int c=0; c=0; --r) { - sol[r*v.col+c] = tmp[r*tmp.col+c]; - for (int i=r+1; i 0) + sign = -sign; + for (unsigned r2=r1+1; r2m[r2*col+c] -= this->m[r2*col+r1]*this->m[r1*col+c]/this->m[r1*col+r1]; + for (unsigned c=0; c<=r1; ++c) + this->m[r2*col+c] = _ex0(); + } + } + + return sign; +} + + +/** Perform the steps of division free elimination to bring the matrix + * into an upper echelon form. + * + * @return sign is 1 if an even number of rows was swapped, -1 if an odd + * number of rows was swapped and 0 if the matrix is singular. */ +int matrix::division_free_elimination(void) +{ + int sign = 1; + ensure_if_modifiable(); + for (unsigned r1=0; r10) + sign = -sign; + for (unsigned r2=r1+1; r2m[r2*col+c] = this->m[r1*col+r1]*this->m[r2*col+c] - this->m[r2*col+r1]*this->m[r1*col+c]; + for (unsigned c=0; c<=r1; ++c) + this->m[r2*col+c] = _ex0(); + } + } + + return sign; +} + + +/** Perform the steps of Bareiss' one-step fraction free elimination to bring + * the matrix into an upper echelon form. + * + * @return sign is 1 if an even number of rows was swapped, -1 if an odd + * number of rows was swapped and 0 if the matrix is singular. */ +int matrix::fraction_free_elimination(void) +{ + ensure_if_modifiable(); + + // first normal all elements: + for (exvector::iterator i=m.begin(); i!=m.end(); ++i) + (*i) = (*i).normal(); + + // FIXME: this is unfinished, once matrix::determinant_bareiss is + // bulletproof, some code ought to be copy from there to here. + int sign = 1; + ex divisor = 1; + ex dividend; + lst srl; // symbol replacement list for .to_rational() + + for (unsigned r1=0; r10) + sign = -sign; + if (r1>0) + divisor = this->m[(r1-1)*col+(r1-1)].expand(); + for (unsigned r2=r1+1; r2m[r1*col+r1]*this->m[r2*col+c] + -this->m[r2*col+r1]*this->m[r1*col+c]).expand(); +#ifdef DO_GINAC_ASSERT + GINAC_ASSERT(divide(dividend.to_rational(srl), + divisor.to_rational(srl), + this->m[r2*col+c])); +#else + divide(dividend.to_rational(srl), + divisor.to_rational(srl), + this->m[r2*col+c]); +#endif // DO_GINAC_ASSERT + this->m[r2*col+c] = this->m[r2*col+c].subs(srl); } + for (unsigned c=0; c<=r1; ++c) + this->m[r2*col+c] = _ex0(); } } - return matrix(v.row, v.col, sol); + + return sign; } -// protected /** Partial pivoting method. - * Usual pivoting returns the index to the element with the largest absolute - * value and swaps the current row with the one where the element was found. - * Here it does the same with the first non-zero element. (This works fine, - * but may be far from optimal for numerics.) */ -int matrix::pivot(int ro) + * Usual pivoting (symbolic==false) returns the index to the element with the + * largest absolute value in column ro and swaps the current row with the one + * where the element was found. With (symbolic==true) it does the same thing + * with the first non-zero element. + * + * @param ro is the row to be inspected + * @param symbolic signal if we want the first non-zero element to be pivoted + * (true) or the one with the largest absolute value (false). + * @return 0 if no interchange occured, -1 if all are zero (usually signaling + * a degeneracy) and positive integer k means that rows ro and k were swapped. + */ +int matrix::pivot(unsigned ro, bool symbolic) { - int k=ro; + unsigned k = ro; - for (int r=ro; r maxn && + !tmp.is_zero()) { + maxn = tmp; + k = r; + } } } - if (m[k*col+ro].is_zero()) { + if (m[k*col+ro].is_zero()) return -1; - } if (k!=ro) { // swap rows - for (int c=0; c cols) + cols = l.op(i).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; +} + ////////// // global constants ////////// const matrix some_matrix; -type_info const & typeid_matrix=typeid(some_matrix); +const type_info & typeid_matrix=typeid(some_matrix); -#ifndef NO_GINAC_NAMESPACE +#ifndef NO_NAMESPACE_GINAC } // namespace GiNaC -#endif // ndef NO_GINAC_NAMESPACE +#endif // ndef NO_NAMESPACE_GINAC