+ const spinidx & i1 = ex_to<spinidx>(i.op(1));
+ const spinidx & i2 = ex_to<spinidx>(i.op(2));
+
+ // Convolutions are zero
+ if (!(static_cast<const indexed &>(i).get_dummy_indices().empty()))
+ return _ex0;
+
+ // Numeric evaluation
+ if (static_cast<const indexed &>(i).all_index_values_are(info_flags::nonnegint)) {
+ int n1 = ex_to<numeric>(i1.get_value()).to_int(), n2 = ex_to<numeric>(i2.get_value()).to_int();
+ if (n1 == n2)
+ return _ex0;
+ else if (n1 < n2)
+ return _ex1;
+ else
+ return _ex_1;
+ }
+
+ // No further simplifications
+ return i.hold();
+}
+
+/** Automatic symbolic evaluation of an indexed epsilon tensor. */
+ex tensepsilon::eval_indexed(const basic & i) const
+{
+ GINAC_ASSERT(is_a<indexed>(i));
+ GINAC_ASSERT(i.nops() > 1);
+ GINAC_ASSERT(is_a<tensepsilon>(i.op(0)));
+
+ // Convolutions are zero
+ if (!(static_cast<const indexed &>(i).get_dummy_indices().empty()))
+ return _ex0;
+
+ // Numeric evaluation
+ if (static_cast<const indexed &>(i).all_index_values_are(info_flags::nonnegint)) {
+
+ // Get sign of index permutation (the indices should already be in
+ // a canonic order but we can't assume what exactly that order is)
+ std::vector<int> v;
+ v.reserve(i.nops() - 1);
+ for (unsigned j=1; j<i.nops(); j++)
+ v.push_back(ex_to<numeric>(ex_to<idx>(i.op(j)).get_value()).to_int());
+ int sign = permutation_sign(v.begin(), v.end());
+
+ // In a Minkowski space, check for covariant indices
+ if (minkowski) {
+ for (unsigned j=1; j<i.nops(); j++) {
+ const ex & x = i.op(j);
+ if (!is_ex_of_type(x, varidx))
+ throw(std::runtime_error("indices of epsilon tensor in Minkowski space must be of type varidx"));
+ if (ex_to<varidx>(x).is_covariant())
+ if (ex_to<idx>(x).get_value().is_zero())
+ sign = (pos_sig ? -sign : sign);
+ else
+ sign = (pos_sig ? sign : -sign);
+ }
+ }
+
+ return sign;
+ }
+
+ // No further simplifications
+ return i.hold();
+}
+
+bool tensor::replace_contr_index(exvector::iterator self, exvector::iterator other) const
+{
+ // Try to contract the first index
+ const idx *self_idx = &ex_to<idx>(self->op(1));
+ const idx *free_idx = &ex_to<idx>(self->op(2));