]> www.ginac.de Git - ginac.git/blobdiff - ginac/matrix.cpp
- simplify_indexed() simplifies c*(M).i.j -> (M').i.j (c: numeric, M: matrix)
[ginac.git] / ginac / matrix.cpp
index a63275f54338e7688065a79176091e36902503a1..650799e55f6353db6807e1d42a8d7904cc55291b 100644 (file)
@@ -95,6 +95,25 @@ matrix::matrix(unsigned r, unsigned c, const exvector & m2)
        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
 //////////
@@ -381,104 +400,150 @@ ex matrix::eval_indexed(const basic & i) const
        return i.hold();
 }
 
-/** Contraction of an indexed matrix with something else. */
-bool matrix::contract_with(ex & self, ex & other) const
+/** Sum of two indexed matrices. */
+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);
+
+       // Only add two matrices
+       if (is_ex_of_type(other.op(0), matrix)) {
+               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 && other.nops() == 2) { // vector + vector
+
+                       if (self_matrix.row == other_matrix.row)
+                               return indexed(self_matrix.add(other_matrix), self.op(1));
+                       else if (self_matrix.row == other_matrix.col)
+                               return indexed(self_matrix.add(other_matrix.transpose()), self.op(1));
+
+               } else if (self.nops() == 3 && other.nops() == 3) { // matrix + matrix
+
+                       if (self.op(1).is_equal(other.op(1)) && self.op(2).is_equal(other.op(2)))
+                               return indexed(self_matrix.add(other_matrix), self.op(1), self.op(2));
+                       else if (self.op(1).is_equal(other.op(2)) && self.op(2).is_equal(other.op(1)))
+                               return indexed(self_matrix.add(other_matrix.transpose()), self.op(1), self.op(2));
+
+               }
+       }
+
+       // Don't know what to do, return unevaluated sum
+       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
+{
+       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))
+       if (!is_ex_of_type(other->op(0), matrix))
                return false;
 
-       GINAC_ASSERT(other.nops() == 2 || other.nops() == 3);
+       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));
+       const matrix &self_matrix = ex_to_matrix(self->op(0));
+       const matrix &other_matrix = ex_to_matrix(other->op(0));
 
-       if (self.nops() == 2) {
+       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)
+               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);
+                                       *self = self_matrix.transpose().mul(other_matrix)(0, 0);
                                } else {
                                        // Column vector * row vector, swap factors
-                                       self = other_matrix.mul(self_matrix)(0, 0);
+                                       *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);
+                                       *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);
+                                       *self = self_matrix.mul(other_matrix.transpose())(0, 0);
                                }
                        }
-                       other = _ex1();
+                       *other = _ex1();
                        return true;
 
                } else { // vector * matrix
 
-                       GINAC_ASSERT(other.nops() == 3);
-
                        // B_i * A_ij = (B*A)_j (B is row vector)
-                       if (is_dummy_pair(self.op(1), other.op(1))) {
+                       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));
+                                       *self = indexed(self_matrix.mul(other_matrix), other->op(2));
                                else
-                                       self = indexed(self_matrix.transpose().mul(other_matrix), other.op(2));
-                               other = _ex1();
+                                       *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 (is_dummy_pair(self->op(1), other->op(2))) {
                                if (self_matrix.col == 1)
-                                       self = indexed(other_matrix.mul(self_matrix), other.op(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();
+                                       *self = indexed(other_matrix.mul(self_matrix.transpose()), other->op(1));
+                               *other = _ex1();
                                return true;
                        }
                }
 
-       } else if (other.nops() == 3) { // matrix * matrix
-
-               GINAC_ASSERT(self.nops() == 3);
-               GINAC_ASSERT(other.nops() == 3);
+       } 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();
+               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();
+               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();
+               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();
+               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;
                }
        }
@@ -551,6 +616,19 @@ matrix matrix::mul(const matrix & other) 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
@@ -1362,12 +1440,8 @@ int matrix::pivot(unsigned ro, unsigned co, bool symbolic)
        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++)
@@ -1385,4 +1459,15 @@ ex lst_to_matrix(const ex &l)
        return m;
 }
 
+ex diag_matrix(const lst & l)
+{
+       unsigned dim = l.nops();
+
+       matrix &m = *new matrix(dim, dim);
+       for (unsigned i=0; i<dim; i++)
+               m.set(i, i, l.op(i));
+
+       return m;
+}
+
 } // namespace GiNaC