* Implementation of symbolic matrices */
/*
- * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2004 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
GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(matrix, basic,
print_func<print_context>(&matrix::do_print).
print_func<print_latex>(&matrix::do_print_latex).
- print_func<print_tree>(&basic::do_print_tree).
+ print_func<print_tree>(&matrix::do_print_tree).
print_func<print_python_repr>(&matrix::do_print_python_repr))
//////////
//////////
/** 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)
{
- m.push_back(_ex0);
+ setflag(status_flags::not_shareable);
}
//////////
* @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)
{
- m.resize(r*c, _ex0);
+ setflag(status_flags::not_shareable);
}
// 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)
+{
+ setflag(status_flags::not_shareable);
+}
/** 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)
+ : inherited(TINFO_matrix), row(r), col(c), m(r*c, _ex0)
{
- m.resize(r*c, _ex0);
+ setflag(status_flags::not_shareable);
size_t i = 0;
for (lst::const_iterator it = l.begin(); it != l.end(); ++it, ++i) {
matrix::matrix(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
{
+ 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);
// public
-void matrix::print_elements(const print_context & c, const std::string & row_start, const std::string & row_end, const std::string & row_sep, const std::string & col_sep) 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
{
for (unsigned ro=0; ro<row; ++ro) {
c.s << row_start;
return matrix(row, col, m2).subs_one_level(mp, options);
}
+/** Complex conjugate every matrix entry. */
+ex matrix::conjugate() const
+{
+ exvector * ev = 0;
+ for (exvector::const_iterator i=m.begin(); i!=m.end(); ++i) {
+ ex x = i->conjugate();
+ if (ev) {
+ ev->push_back(x);
+ continue;
+ }
+ if (are_ex_trivially_equal(x, *i)) {
+ continue;
+ }
+ ev = new exvector;
+ ev->reserve(m.size());
+ for (exvector::const_iterator j=m.begin(); j!=i; ++j) {
+ ev->push_back(*j);
+ }
+ ev->push_back(x);
+ }
+ if (ev) {
+ ex result = matrix(row, col, *ev);
+ delete ev;
+ return result;
+ }
+ return *this;
+}
+
// protected
int matrix::compare_same_type(const basic & other) 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;
else
return m[0].expand();
}
-
+
// Compute the determinant
switch(algo) {
case determinant_algo::gauss: {
tr += m[r*col+r];
if (tr.info(info_flags::rational_function) &&
- !tr.info(info_flags::crational_polynomial))
+ !tr.info(info_flags::crational_polynomial))
return tr.normal();
else
return tr.expand();
* @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"));
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; i<row; ++i) {
for (unsigned j=0; j<row; ++j)
B.m[j*col+j] -= c;
B = this->mul(B);
c = B.trace() / ex(i+1);
- poly -= c*power(lambda,row-i-1);
+ poly -= c*power(lambda, row-i-1);
}
if (row%2)
return -poly;
*
* @param vars n x p matrix, all elements must be symbols
* @param rhs m x p matrix
+ * @param algo selects the solving algorithm
* @return n x p solution matrix
* @exception logic_error (incompatible matrices)
* @exception invalid_argument (1st argument must be matrix of symbols)
* @exception runtime_error (inconsistent linear system)
* @see solve_algo */
matrix matrix::solve(const matrix & vars,
- const matrix & rhs,
- unsigned algo) const
+ const matrix & rhs,
+ unsigned algo) const
{
const unsigned m = this->rows();
const unsigned n = this->cols();
}
+/** Compute the rank of this matrix. */
+unsigned matrix::rank() const
+{
+ // Method:
+ // Transform this matrix into upper echelon form and then count the
+ // number of non-zero rows.
+
+ GINAC_ASSERT(row*col==m.capacity());
+
+ // Actually, any elimination scheme will do since we are only
+ // interested in the echelon matrix' zeros.
+ matrix to_eliminate = *this;
+ to_eliminate.fraction_free_elimination();
+
+ unsigned r = row*col; // index of last non-zero element
+ while (r--) {
+ if (!to_eliminate.m[r].is_zero())
+ return 1+r/col;
+ }
+ return 0;
+}
+
+
// protected
/** Recursive determinant for small matrices having at least one symbolic
int sign = 1;
unsigned r0 = 0;
- for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
- int indx = pivot(r0, r1, true);
+ for (unsigned c0=0; c0<n && r0<m-1; ++c0) {
+ int indx = pivot(r0, c0, true);
if (indx == -1) {
sign = 0;
if (det)
if (indx > 0)
sign = -sign;
for (unsigned r2=r0+1; r2<m; ++r2) {
- if (!this->m[r2*n+r1].is_zero()) {
+ if (!this->m[r2*n+c0].is_zero()) {
// yes, there is something to do in this row
- ex piv = this->m[r2*n+r1] / this->m[r0*n+r1];
- for (unsigned c=r1+1; c<n; ++c) {
+ ex piv = this->m[r2*n+c0] / this->m[r0*n+c0];
+ for (unsigned c=c0+1; c<n; ++c) {
this->m[r2*n+c] -= piv * this->m[r0*n+c];
if (!this->m[r2*n+c].info(info_flags::numeric))
this->m[r2*n+c] = this->m[r2*n+c].normal();
}
}
// fill up left hand side with zeros
- for (unsigned c=0; c<=r1; ++c)
+ for (unsigned c=r0; c<=c0; ++c)
this->m[r2*n+c] = _ex0;
}
if (det) {
++r0;
}
}
-
+ // clear remaining rows
+ for (unsigned r=r0+1; r<m; ++r) {
+ for (unsigned c=0; c<n; ++c)
+ this->m[r*n+c] = _ex0;
+ }
+
return sign;
}
int sign = 1;
unsigned r0 = 0;
- for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
- int indx = pivot(r0, r1, true);
+ for (unsigned c0=0; c0<n && r0<m-1; ++c0) {
+ int indx = pivot(r0, c0, true);
if (indx==-1) {
sign = 0;
if (det)
if (indx>0)
sign = -sign;
for (unsigned r2=r0+1; r2<m; ++r2) {
- for (unsigned c=r1+1; c<n; ++c)
- 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();
+ for (unsigned c=c0+1; c<n; ++c)
+ this->m[r2*n+c] = (this->m[r0*n+c0]*this->m[r2*n+c] - this->m[r2*n+c0]*this->m[r0*n+c]).expand();
// fill up left hand side with zeros
- for (unsigned c=0; c<=r1; ++c)
+ for (unsigned c=r0; c<=c0; ++c)
this->m[r2*n+c] = _ex0;
}
if (det) {
++r0;
}
}
-
+ // clear remaining rows
+ for (unsigned r=r0+1; r<m; ++r) {
+ for (unsigned c=0; c<n; ++c)
+ this->m[r*n+c] = _ex0;
+ }
+
return sign;
}
// 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) {
}
unsigned r0 = 0;
- for (unsigned r1=0; (r1<n-1)&&(r0<m-1); ++r1) {
- int indx = tmp_n.pivot(r0, r1, true);
+ for (unsigned c0=0; c0<n && r0<m-1; ++c0) {
+ int indx = tmp_n.pivot(r0, c0, true);
if (indx==-1) {
sign = 0;
if (det)
if (indx>0) {
sign = -sign;
// tmp_n's rows r0 and indx were swapped, do the same in tmp_d:
- for (unsigned c=r1; c<n; ++c)
+ for (unsigned c=c0; c<n; ++c)
tmp_d.m[n*indx+c].swap(tmp_d.m[n*r0+c]);
}
for (unsigned r2=r0+1; r2<m; ++r2) {
- for (unsigned c=r1+1; c<n; ++c) {
- dividend_n = (tmp_n.m[r0*n+r1]*tmp_n.m[r2*n+c]*
- tmp_d.m[r2*n+r1]*tmp_d.m[r0*n+c]
- -tmp_n.m[r2*n+r1]*tmp_n.m[r0*n+c]*
- tmp_d.m[r0*n+r1]*tmp_d.m[r2*n+c]).expand();
- dividend_d = (tmp_d.m[r2*n+r1]*tmp_d.m[r0*n+c]*
- tmp_d.m[r0*n+r1]*tmp_d.m[r2*n+c]).expand();
+ for (unsigned c=c0+1; c<n; ++c) {
+ dividend_n = (tmp_n.m[r0*n+c0]*tmp_n.m[r2*n+c]*
+ tmp_d.m[r2*n+c0]*tmp_d.m[r0*n+c]
+ -tmp_n.m[r2*n+c0]*tmp_n.m[r0*n+c]*
+ tmp_d.m[r0*n+c0]*tmp_d.m[r2*n+c]).expand();
+ dividend_d = (tmp_d.m[r2*n+c0]*tmp_d.m[r0*n+c]*
+ tmp_d.m[r0*n+c0]*tmp_d.m[r2*n+c]).expand();
bool check = divide(dividend_n, divisor_n,
tmp_n.m[r2*n+c], true);
check &= divide(dividend_d, divisor_d,
GINAC_ASSERT(check);
}
// fill up left hand side with zeros
- for (unsigned c=0; c<=r1; ++c)
+ for (unsigned c=r0; c<=c0; ++c)
tmp_n.m[r2*n+c] = _ex0;
}
- if ((r1<n-1)&&(r0<m-1)) {
+ if (c0<n && r0<m-1) {
// compute next iteration's divisor
- divisor_n = tmp_n.m[r0*n+r1].expand();
- divisor_d = tmp_d.m[r0*n+r1].expand();
+ divisor_n = tmp_n.m[r0*n+c0].expand();
+ divisor_d = tmp_d.m[r0*n+c0].expand();
if (det) {
// save space by deleting no longer needed elements
for (unsigned c=0; c<n; ++c) {
++r0;
}
}
+ // clear remaining rows
+ for (unsigned r=r0+1; r<m; ++r) {
+ for (unsigned c=0; c<n; ++c)
+ tmp_n.m[r*n+c] = _ex0;
+ }
+
// repopulate *this matrix:
exvector::iterator it = this->m.begin(), itend = this->m.end();
tmp_n_it = tmp_n.m.begin();