return i.hold();
}
-/** Try to contract two indexed expressions. If a contraction exists, the
- * function overwrites one or both arguments and returns true. Otherwise it
- * returns false. It is guaranteed that both expressions are of class
- * indexed (or a subclass) and that at least one dummy index has been
- * found.
+/** Try to contract two indexed expressions that appear in the same product.
+ * If a contraction exists, the function overwrites one or both of the
+ * expressions and returns true. Otherwise it returns false. It is
+ * guaranteed that both expressions are of class indexed (or a subclass)
+ * and that at least one dummy index has been found.
*
- * @param self The first indexed expression; it's base object is *this
- * @param other The second indexed expression
+ * @param self Pointer to first indexed expression; it's base object is *this
+ * @param other Pointer to second indexed expression
+ * @param v The complete vector of factors
* @return true if the contraction was successful, false otherwise */
-bool basic::contract_with(ex & self, ex & other) const
+bool basic::contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const
{
// Do nothing
return false;
virtual exvector get_free_indices(void) const;
virtual ex simplify_ncmul(const exvector & v) const;
virtual ex eval_indexed(const basic & i) const;
- virtual bool contract_with(ex & self, ex & other) const;
+ virtual bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const;
protected: // non-const functions should be called from class ex only
virtual ex derivative(const symbol & s) const;
virtual int compare_same_type(const basic & other) const;
}
// Try to contract the first one with the second one
- bool contracted = it1->op(0).bp->contract_with(*it1, *it2);
+ bool contracted = it1->op(0).bp->contract_with(it1, it2, v);
if (!contracted) {
// That didn't work; maybe the second object knows how to
// contract itself with the first one
- contracted = it2->op(0).bp->contract_with(*it2, *it1);
+ contracted = it2->op(0).bp->contract_with(it2, it1, v);
}
if (contracted) {
something_changed = true;
}
/** Contraction of an indexed matrix with something else. */
-bool matrix::contract_with(ex & self, ex & other) const
+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));
+ 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;
}
}
ex evalf(int level=0) const;
ex subs(const lst & ls, const lst & lr) const;
ex eval_indexed(const basic & i) const;
- bool contract_with(ex & self, ex & other) const;
+ bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const;
protected:
unsigned return_type(void) const { return return_types::noncommutative; };
// new virtual functions which can be overridden by derived classes
for (unsigned i=0; i<e.nops(); i++)
c *= lcmcoeff(e.op(i), _num1());
return lcm(c, l);
- } else if (is_ex_exactly_of_type(e, power))
- return pow(lcmcoeff(e.op(0), l), ex_to_numeric(e.op(1)));
+ } else if (is_ex_exactly_of_type(e, power)) {
+ if (is_ex_exactly_of_type(e.op(0), symbol))
+ return l;
+ else
+ return pow(lcmcoeff(e.op(0), l), ex_to_numeric(e.op(1)));
+ }
return l;
}
c += multiply_lcm(e.op(i), lcm);
return c;
} else if (is_ex_exactly_of_type(e, power)) {
- return pow(multiply_lcm(e.op(0), lcm.power(ex_to_numeric(e.op(1)).inverse())), e.op(1));
+ if (is_ex_exactly_of_type(e.op(0), symbol))
+ return e * lcm;
+ else
+ return pow(multiply_lcm(e.op(0), lcm.power(ex_to_numeric(e.op(1)).inverse())), e.op(1));
} else
return e * lcm;
}
}
/** Contraction of an indexed delta tensor with something else. */
-bool tensdelta::contract_with(ex & self, ex & other) const
+bool tensdelta::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() == 3);
- GINAC_ASSERT(is_ex_of_type(self.op(0), tensdelta));
+ GINAC_ASSERT(is_ex_of_type(*self, indexed));
+ GINAC_ASSERT(is_ex_of_type(*other, indexed));
+ GINAC_ASSERT(self->nops() == 3);
+ GINAC_ASSERT(is_ex_of_type(self->op(0), tensdelta));
// Try to contract first index
- const idx *self_idx = &ex_to_idx(self.op(1));
- const idx *free_idx = &ex_to_idx(self.op(2));
+ const idx *self_idx = &ex_to_idx(self->op(1));
+ const idx *free_idx = &ex_to_idx(self->op(2));
bool first_index_tried = false;
again:
if (self_idx->is_symbolic()) {
- for (int i=1; i<other.nops(); i++) {
- const idx &other_idx = ex_to_idx(other.op(i));
+ for (int i=1; i<other->nops(); i++) {
+ const idx &other_idx = ex_to_idx(other->op(i));
if (is_dummy_pair(*self_idx, other_idx)) {
// Contraction found, remove delta tensor and substitute
// index in second object
- self = _ex1();
- other = other.subs(other_idx == *free_idx);
+ *self = _ex1();
+ *other = other->subs(other_idx == *free_idx);
return true;
}
}
if (!first_index_tried) {
// No contraction with first index found, try second index
- self_idx = &ex_to_idx(self.op(2));
- free_idx = &ex_to_idx(self.op(1));
+ self_idx = &ex_to_idx(self->op(2));
+ free_idx = &ex_to_idx(self->op(1));
first_index_tried = true;
goto again;
}
}
/** Contraction of an indexed metric tensor with something else. */
-bool tensmetric::contract_with(ex & self, ex & other) const
+bool tensmetric::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() == 3);
- GINAC_ASSERT(is_ex_of_type(self.op(0), tensmetric));
+ GINAC_ASSERT(is_ex_of_type(*self, indexed));
+ GINAC_ASSERT(is_ex_of_type(*other, indexed));
+ GINAC_ASSERT(self->nops() == 3);
+ GINAC_ASSERT(is_ex_of_type(self->op(0), tensmetric));
// If contracting with the delta tensor, let the delta do it
// (don't raise/lower delta indices)
- if (is_ex_exactly_of_type(other.op(0), tensdelta))
+ if (is_ex_exactly_of_type(other->op(0), tensdelta))
return false;
// Try to contract first index
- const idx *self_idx = &ex_to_idx(self.op(1));
- const idx *free_idx = &ex_to_idx(self.op(2));
+ const idx *self_idx = &ex_to_idx(self->op(1));
+ const idx *free_idx = &ex_to_idx(self->op(2));
bool first_index_tried = false;
again:
if (self_idx->is_symbolic()) {
- for (int i=1; i<other.nops(); i++) {
- const idx &other_idx = ex_to_idx(other.op(i));
+ for (int i=1; i<other->nops(); i++) {
+ const idx &other_idx = ex_to_idx(other->op(i));
if (is_dummy_pair(*self_idx, other_idx)) {
// Contraction found, remove metric tensor and substitute
// index in second object
- self = _ex1();
- other = other.subs(other_idx == *free_idx);
+ *self = _ex1();
+ *other = other->subs(other_idx == *free_idx);
return true;
}
}
if (!first_index_tried) {
// No contraction with first index found, try second index
- self_idx = &ex_to_idx(self.op(2));
- free_idx = &ex_to_idx(self.op(1));
+ self_idx = &ex_to_idx(self->op(2));
+ free_idx = &ex_to_idx(self->op(1));
first_index_tried = true;
goto again;
}
public:
void print(std::ostream & os, unsigned upper_precedence=0) const;
ex eval_indexed(const basic & i) const;
- bool contract_with(ex & self, ex & other) const;
+ bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const;
};
public:
void print(std::ostream & os, unsigned upper_precedence=0) const;
ex eval_indexed(const basic & i) const;
- bool contract_with(ex & self, ex & other) const;
+ bool contract_with(exvector::iterator self, exvector::iterator other, exvector & v) const;
};