]> www.ginac.de Git - ginac.git/blobdiff - ginac/matrix.cpp
- lcm_of_coefficients_denominators(1/2+x^10) returned 1024 instead of 2 and
[ginac.git] / ginac / matrix.cpp
index d6091aa4c1b568c18cdcde9f0944160724e4df1e..1a5d6953c3d994365d9d6b05a60ebf351119e7bd 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of symbolic matrices */
 
 /*
- *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2001 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
 #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"
 
-#ifndef NO_NAMESPACE_GINAC
 namespace GiNaC {
-#endif // ndef NO_NAMESPACE_GINAC
 
 GINAC_IMPLEMENT_REGISTERED_CLASS(matrix, basic)
 
 //////////
-// default constructor, destructor, copy constructor, assignment operator
-// and helpers:
+// default ctor, dtor, copy ctor, assignment operator and helpers:
 //////////
 
 // public
@@ -50,34 +49,13 @@ GINAC_IMPLEMENT_REGISTERED_CLASS(matrix, basic)
 /** Default ctor.  Initializes to 1 x 1-dimensional zero-matrix. */
 matrix::matrix() : inherited(TINFO_matrix), row(1), col(1)
 {
-       debugmsg("matrix default constructor",LOGLEVEL_CONSTRUCT);
+       debugmsg("matrix default ctor",LOGLEVEL_CONSTRUCT);
        m.push_back(_ex0());
 }
 
-matrix::~matrix()
-{
-       debugmsg("matrix destructor",LOGLEVEL_DESTRUCT);
-       destroy(false);
-}
-
-matrix::matrix(const matrix & other)
-{
-       debugmsg("matrix copy constructor",LOGLEVEL_CONSTRUCT);
-       copy(other);
-}
-
-const matrix & matrix::operator=(const matrix & other)
-{
-       debugmsg("matrix operator=",LOGLEVEL_ASSIGNMENT);
-       if (this != &other) {
-               destroy(true);
-               copy(other);
-       }
-       return *this;
-}
-
 // protected
 
+/** For use by copy ctor and assignment operator. */
 void matrix::copy(const matrix & other)
 {
        inherited::copy(other);
@@ -92,7 +70,7 @@ void matrix::destroy(bool call_parent)
 }
 
 //////////
-// other constructors
+// other ctors
 //////////
 
 // public
@@ -104,7 +82,7 @@ void matrix::destroy(bool call_parent)
 matrix::matrix(unsigned r, unsigned c)
   : inherited(TINFO_matrix), row(r), col(c)
 {
-       debugmsg("matrix constructor from unsigned,unsigned",LOGLEVEL_CONSTRUCT);
+       debugmsg("matrix ctor from unsigned,unsigned",LOGLEVEL_CONSTRUCT);
        m.resize(r*c, _ex0());
 }
 
@@ -114,7 +92,7 @@ matrix::matrix(unsigned r, unsigned c)
 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);
+       debugmsg("matrix ctor from unsigned,unsigned,exvector",LOGLEVEL_CONSTRUCT);
 }
 
 //////////
@@ -124,7 +102,7 @@ matrix::matrix(unsigned r, unsigned c, const exvector & m2)
 /** 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);
+       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);
@@ -162,12 +140,6 @@ void matrix::archive(archive_node &n) const
 
 // public
 
-basic * matrix::duplicate() const
-{
-       debugmsg("matrix duplicate",LOGLEVEL_DUPLICATE);
-       return new matrix(*this);
-}
-
 void matrix::print(std::ostream & os, unsigned upper_precedence) const
 {
        debugmsg("matrix print",LOGLEVEL_PRINT);
@@ -187,7 +159,7 @@ void matrix::print(std::ostream & os, unsigned upper_precedence) const
 void matrix::printraw(std::ostream & os) const
 {
        debugmsg("matrix printraw",LOGLEVEL_PRINT);
-       os << "matrix(" << row << "," << col <<",";
+       os << class_name() << "(" << row << "," << col <<",";
        for (unsigned r=0; r<row-1; ++r) {
                os << "(";
                for (unsigned c=0; c<col-1; ++c)
@@ -247,7 +219,7 @@ bool matrix::has(const ex & other) const
        return false;
 }
 
-/** evaluate matrix entry by entry. */
+/** Evaluate matrix entry by entry. */
 ex matrix::eval(int level) const
 {
        debugmsg("matrix eval",LOGLEVEL_MEMBER_FUNCTION);
@@ -271,7 +243,7 @@ ex matrix::eval(int level) const
                                                                                           status_flags::evaluated );
 }
 
-/** evaluate matrix numerically entry by entry. */
+/** Evaluate matrix numerically entry by entry. */
 ex matrix::evalf(int level) const
 {
        debugmsg("matrix evalf",LOGLEVEL_MEMBER_FUNCTION);
@@ -295,6 +267,16 @@ ex matrix::evalf(int level) const
        return matrix(row, col, m2);
 }
 
+ex matrix::subs(const lst & ls, const lst & lr) const
+{
+       exvector m2(row * col);
+       for (unsigned r=0; r<row; ++r)
+               for (unsigned c=0; c<col; ++c)
+                       m2[r*col+c] = m[r*col+c].subs(ls, lr);
+
+       return matrix(row, col, m2);
+}
+
 // protected
 
 int matrix::compare_same_type(const basic & other) const
@@ -322,6 +304,184 @@ int matrix::compare_same_type(const basic & other) const
        return 0;
 }
 
+/** 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));
+
+       bool all_indices_unsigned = static_cast<const indexed &>(i).all_index_values_are(info_flags::nonnegint);
+
+       // Check indices
+       if (i.nops() == 2) {
+
+               // One index, must be one-dimensional vector
+               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));
+
+               if (col == 1) {
+
+                       // Column vector
+                       if (!i1.get_dim().is_equal(row))
+                               throw (std::runtime_error("matrix::eval_indexed(): dimension of index must match number of vector elements"));
+
+                       // Index numeric -> return vector element
+                       if (all_indices_unsigned) {
+                               unsigned n1 = ex_to_numeric(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);
+                       }
+
+               } else {
+
+                       // Row vector
+                       if (!i1.get_dim().is_equal(col))
+                               throw (std::runtime_error("matrix::eval_indexed(): dimension of index must match number of vector elements"));
+
+                       // Index numeric -> return vector element
+                       if (all_indices_unsigned) {
+                               unsigned n1 = ex_to_numeric(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);
+                       }
+               }
+
+       } 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));
+
+               if (!i1.get_dim().is_equal(row))
+                       throw (std::runtime_error("matrix::eval_indexed(): dimension of first index must match number of rows"));
+               if (!i2.get_dim().is_equal(col))
+                       throw (std::runtime_error("matrix::eval_indexed(): dimension of second index must match number of columns"));
+
+               // Pair of dummy indices -> compute trace
+               if (is_dummy_pair(i1, i2))
+                       return trace();
+
+               // 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();
+                       if (n1 >= row)
+                               throw (std::runtime_error("matrix::eval_indexed(): value of first index exceeds number of rows"));
+                       if (n2 >= col)
+                               throw (std::runtime_error("matrix::eval_indexed(): value of second index exceeds number of columns"));
+                       return (*this)(n1, n2);
+               }
+
+       } else
+               throw (std::runtime_error("matrix::eval_indexed(): matrix must have exactly 2 indices"));
+
+       return i.hold();
+}
+
+/** 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(self->nops() == 2 || self->nops() == 3);
+       GINAC_ASSERT(is_ex_of_type(self->op(0), matrix));
+
+       // Only contract with other matrices
+       if (!is_ex_of_type(other->op(0), matrix))
+               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));
+
+       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) {
+                                       // Column vector * column vector, transpose first vector
+                                       *self = self_matrix.transpose().mul(other_matrix)(0, 0);
+                               } else {
+                                       // Column vector * row vector, swap factors
+                                       *self = other_matrix.mul(self_matrix)(0, 0);
+                               }
+                       } else {
+                               if (other_matrix.col == 1) {
+                                       // Row vector * column vector, perfect
+                                       *self = self_matrix.mul(other_matrix)(0, 0);
+                               } else {
+                                       // Row vector * row vector, transpose second vector
+                                       *self = self_matrix.mul(other_matrix.transpose())(0, 0);
+                               }
+                       }
+                       *other = _ex1();
+                       return true;
+
+               } else { // vector * matrix
+
+                       // B_i * A_ij = (B*A)_j (B is row vector)
+                       if (is_dummy_pair(self->op(1), other->op(1))) {
+                               if (self_matrix.row == 1)
+                                       *self = indexed(self_matrix.mul(other_matrix), other->op(2));
+                               else
+                                       *self = indexed(self_matrix.transpose().mul(other_matrix), other->op(2));
+                               *other = _ex1();
+                               return true;
+                       }
+
+                       // B_j * A_ij = (A*B)_i (B is column vector)
+                       if (is_dummy_pair(self->op(1), other->op(2))) {
+                               if (self_matrix.col == 1)
+                                       *self = indexed(other_matrix.mul(self_matrix), other->op(1));
+                               else
+                                       *self = indexed(other_matrix.mul(self_matrix.transpose()), other->op(1));
+                               *other = _ex1();
+                               return true;
+                       }
+               }
+
+       } else if (other->nops() == 3) { // matrix * matrix
+
+               // 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();
+                       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();
+                       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();
+                       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();
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+
 //////////
 // non-virtual functions in this class
 //////////
@@ -647,7 +807,7 @@ matrix matrix::inverse(void) const
                throw (std::logic_error("matrix::inverse(): matrix not square"));
        
        // NOTE: the Gauss-Jordan elimination used here can in principle be
-       // replaced this by two clever calls to gauss_elimination() and some to
+       // 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);
@@ -673,14 +833,17 @@ matrix matrix::inverse(void) const
                }
                for (unsigned r2=0; r2<row; ++r2) {
                        if (r2 != r1) {
-                               ex a2 = cpy.m[r2*col+r1];
-                               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();
+                               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();
+                                       }
                                }
                        }
                }
@@ -944,11 +1107,14 @@ int matrix::gauss_elimination(const bool det)
                        if (indx > 0)
                                sign = -sign;
                        for (unsigned r2=r0+1; r2<m; ++r2) {
-                               ex piv = this->m[r2*n+r1] / this->m[r0*n+r1];
-                               for (unsigned c=r1+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();
+                               if (!this->m[r2*n+r1].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) {
+                                               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)
@@ -1186,7 +1352,7 @@ int matrix::pivot(unsigned ro, unsigned co, bool symbolic)
        // matrix needs pivoting, so swap rows k and ro
        ensure_if_modifiable();
        for (unsigned c=0; c<col; ++c)
-               m[k*col+c].swap(m[ro*col+c]);
+               this->m[k*col+c].swap(this->m[ro*col+c]);
        
        return k;
 }
@@ -1214,13 +1380,4 @@ ex lst_to_matrix(const ex &l)
        return m;
 }
 
-//////////
-// global constants
-//////////
-
-const matrix some_matrix;
-const std::type_info & typeid_matrix = typeid(some_matrix);
-
-#ifndef NO_NAMESPACE_GINAC
 } // namespace GiNaC
-#endif // ndef NO_NAMESPACE_GINAC