#include <stdexcept>
#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 {
// 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)
{
m.push_back(_ex0());
}
-// protected
-
-/** For use by copy ctor and assignment operator. */
void matrix::copy(const matrix & other)
{
inherited::copy(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
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<l.nops(); i++) {
+ unsigned x = i % c;
+ unsigned y = i / c;
+ if (y >= 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);
}
}
-/** 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);
}
}
+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; r<row-1; ++r) {
- os << "[[";
- for (unsigned c=0; c<col-1; ++c)
- os << m[r*col+c] << ",";
- os << m[col*(r+1)-1] << "]], ";
- }
- os << "[[";
- for (unsigned c=0; c<col-1; ++c)
- os << m[(row-1)*col+c] << ",";
- os << m[row*col-1] << "]] ]]";
-}
+ debugmsg("matrix print", LOGLEVEL_PRINT);
+
+ if (is_of_type(c, print_tree)) {
+
+ inherited::print(c, level);
+
+ } else {
+
+ c.s << "[[ ";
+ for (unsigned y=0; y<row-1; ++y) {
+ c.s << "[[";
+ for (unsigned x=0; x<col-1; ++x) {
+ m[y*col+x].print(c);
+ c.s << ",";
+ }
+ m[col*(y+1)-1].print(c);
+ c.s << "]], ";
+ }
+ c.s << "[[";
+ for (unsigned x=0; x<col-1; ++x) {
+ m[(row-1)*col+x].print(c);
+ c.s << ",";
+ }
+ m[row*col-1].print(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-1; ++r) {
- os << "(";
- for (unsigned c=0; c<col-1; ++c)
- os << m[r*col+c] << ",";
- os << m[col*(r-1)-1] << "),";
}
- os << "(";
- for (unsigned c=0; c<col-1; ++c)
- os << m[(row-1)*col+c] << ",";
- os << m[row*col-1] << "))";
}
/** nops is defined to be rows x columns. */
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);
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_matrix(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
{
}
+/** Product of matrix and scalar. */
+matrix matrix::mul(const numeric & other) const
+{
+ exvector prod(row * col);
+
+ for (unsigned r=0; r<row; ++r)
+ for (unsigned c=0; c<col; ++c)
+ prod[r*col+c] = m[r*col+c] * other;
+
+ return matrix(row, col, prod);
+}
+
+
/** operator() to access elements.
*
* @param ro row of element
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; i<col; ++i)
- tmp.m[i*col+i] = _ex1();
+ // This routine actually doesn't do anything fancy at all. We compute the
+ // inverse of the matrix A by solving the system A * A^{-1} == Id.
- // create a copy of this matrix
- matrix cpy(*this);
- for (unsigned r1=0; r1<row; ++r1) {
- int indx = cpy.pivot(r1, r1);
- if (indx == -1) {
+ // First populate the identity matrix supposed to become the right hand side.
+ matrix identity(row,col);
+ for (unsigned i=0; i<row; ++i)
+ identity.set(i,i,_ex1());
+
+ // Populate a dummy matrix of variables, just because of compatibility with
+ // matrix::solve() which wants this (for compatibility with under-determined
+ // systems of equations).
+ matrix vars(row,col);
+ for (unsigned r=0; r<row; ++r)
+ for (unsigned c=0; c<col; ++c)
+ vars.set(r,c,symbol());
+
+ matrix sol(row,col);
+ try {
+ sol = this->solve(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; i<col; ++i)
- tmp.m[r1*col+i].swap(tmp.m[indx*col+i]);
- }
- ex a1 = cpy.m[r1*col+r1];
- for (unsigned c=0; c<col; ++c) {
- cpy.m[r1*col+c] /= a1;
- tmp.m[r1*col+c] /= a1;
- }
- for (unsigned r2=0; r2<row; ++r2) {
- if (r2 != r1) {
- if (!cpy.m[r2*col+r1].is_zero()) {
- ex a2 = cpy.m[r2*col+r1];
- // yes, there is something to do in this column
- for (unsigned c=0; c<col; ++c) {
- cpy.m[r2*col+c] -= a2 * cpy.m[r1*col+c];
- if (!cpy.m[r2*col+c].info(info_flags::numeric))
- cpy.m[r2*col+c] = cpy.m[r2*col+c].normal();
- tmp.m[r2*col+c] -= a2 * tmp.m[r1*col+c];
- if (!tmp.m[r2*col+c].info(info_flags::numeric))
- tmp.m[r2*col+c] = tmp.m[r2*col+c].normal();
- }
- }
- }
- }
+ else
+ throw;
}
-
- return tmp;
+ return sol;
}
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();
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<rows; i++)
if (l.op(i).nops() > 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<rows; i++)
for (j=0; j<cols; j++)
if (l.op(i).nops() > j)
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<dim; i++)
+ m.set(i, i, l.op(i));
+
+ return m;
+}
+
} // namespace GiNaC