- // 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));
- bool first_index_tried = false;
-
-again:
- if (self_idx->is_symbolic()) {
- for (unsigned 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);
- 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));
- first_index_tried = true;
- goto again;
- }
-
- return false;
+ // Replace the dummy index with this tensor's other index and remove
+ // the tensor (this is valid for contractions with all other tensors)
+ return replace_contr_index(self, other);