X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fmatrix.cpp;h=f76aa9d768f0de53419c0285ebf9fc9485226596;hp=37716290f77317e4916b1705073ba3834332b1ce;hb=61e847cdfd8455a7ba67a0038add8dd35b4e0bff;hpb=5b090bb7e4951b48a28c20ba21bf9810c86eb0ca diff --git a/ginac/matrix.cpp b/ginac/matrix.cpp index 37716290..f76aa9d7 100644 --- a/ginac/matrix.cpp +++ b/ginac/matrix.cpp @@ -26,9 +26,13 @@ #include "matrix.h" #include "archive.h" +#include "numeric.h" +#include "lst.h" #include "utils.h" #include "debugmsg.h" -#include "numeric.h" +#include "power.h" +#include "symbol.h" +#include "normal.h" #ifndef NO_NAMESPACE_GINAC namespace GiNaC { @@ -77,9 +81,9 @@ const matrix & matrix::operator=(const matrix & other) void matrix::copy(const matrix & other) { inherited::copy(other); - row=other.row; - col=other.col; - m=other.m; // use STL's vector copying + row = other.row; + col = other.col; + m = other.m; // STL's vector copying invoked here } void matrix::destroy(bool call_parent) @@ -104,7 +108,7 @@ matrix::matrix(unsigned r, unsigned c) m.resize(r*c, _ex0()); } -// protected + // protected /** Ctor from representation, for internal use only. */ matrix::matrix(unsigned r, unsigned c, const exvector & m2) @@ -377,11 +381,13 @@ matrix matrix::mul(const matrix & other) const throw (std::logic_error("matrix::mul(): incompatible matrices")); exvector prod(row*other.col); - for (unsigned i=0; irow*col) { // MAGIC, maybe 10 some day? - if (normal_flag) - return sign*matrix(row,col,result).determinant_minor_sparse().normal(); - return sign*matrix(row,col,result).determinant_minor_sparse(); - } if (normal_flag) - return sign*matrix(row,col,result).determinant_minor_dense().normal(); - return sign*matrix(row,col,result).determinant_minor_dense(); + return sign*matrix(row,col,result).determinant_minor().normal(); + return sign*matrix(row,col,result).determinant_minor(); } @@ -533,24 +539,54 @@ ex matrix::trace(void) const } -/** Characteristic Polynomial. The characteristic polynomial of a matrix M is - * defined as the determiant of (M - lambda * 1) where 1 stands for the unit - * matrix of the same dimension as M. This method returns the characteristic - * polynomial as a new expression. +/** Characteristic Polynomial. Following mathematica notation the + * characteristic polynomial of a matrix M is defined as the determiant of + * (M - lambda * 1) where 1 stands for the unit matrix of the same dimension + * as M. Note that some CASs define it with a sign inside the determinant + * which gives rise to an overall sign if the dimension is odd. This method + * returns the characteristic polynomial collected in powers of lambda as a + * new expression. * * @return characteristic polynomial as new expression * @exception logic_error (matrix not square) * @see matrix::determinant() */ -ex matrix::charpoly(const ex & lambda) const +ex matrix::charpoly(const symbol & lambda) const { if (row != col) throw (std::logic_error("matrix::charpoly(): matrix not square")); + bool numeric_flag = true; + for (exvector::const_iterator r=m.begin(); r!=m.end(); ++r) { + if (!(*r).info(info_flags::numeric)) { + numeric_flag = false; + } + } + + // 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 section is the matrix multiplication. + if (numeric_flag) { + matrix B(*this); + ex c = B.trace(); + 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); + } + if (row%2) + return -poly; + else + return poly; + } + matrix M(*this); for (unsigned r=0; rrow==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(); - - 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; rrow==1) @@ -1039,45 +1015,110 @@ ex matrix::determinant_minor_dense(void) const return det; } - -/* Determinant using a simple Bareiss elimination scheme. Suited for - * sparse matrices. - * - * @return the determinant as a new expression (in expanded form) - * @see matrix::determinant() */ -ex matrix::determinant_bareiss(void) const +/** 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) { - matrix M(*this); - int sign = M.fraction_free_elimination(); - if (sign) - return sign*M(row-1,col-1); - else - return _ex0(); + 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 built by application of the full permutation group. This +/** Determinant computed by using fraction free elimination. This * routine is only called internally by matrix::determinant(). - * NOTE: it is probably inefficient in all cases and may be eliminated. */ -ex matrix::determinant_perm(void) const + * + * @param normalize may be set to false only in integral domains. */ +ex matrix::determinant_bareiss(bool normalize) const { - if (rows()==1) // speed things up + if (rows()==1) return m[0]; - ex det; - ex term; - vector sigma(col); - for (unsigned i=0; i0) + 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; c0) sign = -sign; if (r1>0) - divisor = this->m[(r1-1)*col + (r1-1)]; + divisor = this->m[(r1-1)*col+(r1-1)].expand(); 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])/divisor).normal(); + for (unsigned c=r1+1; cm[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(); } @@ -1213,6 +1275,29 @@ int matrix::pivot(unsigned ro, bool symbolic) return 0; } +/** Convert list of lists to matrix. */ +ex lst_to_matrix(const ex &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); + 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 //////////