+ // If the sum turns out to be zero, we are finished
+ if (sum.is_zero()) {
+ free_indices.clear();
+ return sum;
+ }
+
+ // More than one term and more than one dummy index?
+ size_t num_terms_orig = (is_exactly_a<add>(sum) ? sum.nops() : 1);
+ if (num_terms_orig < 2 || dummy_indices.size() < 2)
+ return sum;
+
+ // Yes, construct vector of all dummy index symbols
+ exvector dummy_syms;
+ dummy_syms.reserve(dummy_indices.size());
+ for (exvector::const_iterator it = dummy_indices.begin(); it != dummy_indices.end(); ++it)
+ dummy_syms.push_back(it->op(0));
+
+ // Chop the sum into terms and symmetrize each one over the dummy
+ // indices
+ std::vector<terminfo> terms;
+ for (size_t i=0; i<sum.nops(); i++) {
+ const ex & term = sum.op(i);
+ ex term_symm = symmetrize(term, dummy_syms);
+ if (term_symm.is_zero())
+ continue;
+ terms.push_back(terminfo(term, term_symm));
+ }
+
+ // Sort by symmetrized terms
+ std::sort(terms.begin(), terms.end(), terminfo_is_less());
+
+ // Combine equal symmetrized terms
+ std::vector<terminfo> terms_pass2;
+ for (std::vector<terminfo>::const_iterator i=terms.begin(); i!=terms.end(); ) {
+ size_t num = 1;
+ std::vector<terminfo>::const_iterator j = i + 1;
+ while (j != terms.end() && j->symm == i->symm) {
+ num++;
+ j++;
+ }
+ terms_pass2.push_back(terminfo(i->orig * num, i->symm * num));
+ i = j;
+ }
+
+ // If there is only one term left, we are finished
+ if (terms_pass2.size() == 1)
+ return terms_pass2[0].orig;
+
+ // Chop the symmetrized terms into subterms
+ std::vector<symminfo> sy;
+ for (std::vector<terminfo>::const_iterator i=terms_pass2.begin(); i!=terms_pass2.end(); ++i) {
+ if (is_exactly_a<add>(i->symm)) {
+ size_t num = i->symm.nops();
+ for (size_t j=0; j<num; j++)
+ sy.push_back(symminfo(i->symm.op(j), i->orig, num));
+ } else
+ sy.push_back(symminfo(i->symm, i->orig, 1));
+ }
+
+ // Sort by symmetrized subterms
+ std::sort(sy.begin(), sy.end(), symminfo_is_less_by_symmterm());
+
+ // Combine equal symmetrized subterms
+ std::vector<symminfo> sy_pass2;
+ exvector result;
+ for (std::vector<symminfo>::const_iterator i=sy.begin(); i!=sy.end(); ) {
+
+ // Combine equal terms
+ std::vector<symminfo>::const_iterator j = i + 1;
+ if (j != sy.end() && j->symmterm == i->symmterm) {
+
+ // More than one term, collect the coefficients
+ ex coeff = i->coeff;
+ while (j != sy.end() && j->symmterm == i->symmterm) {
+ coeff += j->coeff;
+ j++;
+ }
+
+ // Add combined term to result
+ if (!coeff.is_zero())
+ result.push_back(coeff * i->symmterm);
+
+ } else {
+
+ // Single term, store for second pass
+ sy_pass2.push_back(*i);
+ }
+
+ i = j;
+ }
+
+ // Were there any remaining terms that didn't get combined?
+ if (sy_pass2.size() > 0) {
+
+ // Yes, sort by their original terms
+ std::sort(sy_pass2.begin(), sy_pass2.end(), symminfo_is_less_by_orig());
+
+ for (std::vector<symminfo>::const_iterator i=sy_pass2.begin(); i!=sy_pass2.end(); ) {
+
+ // How many symmetrized terms of this original term are left?
+ size_t num = 1;
+ std::vector<symminfo>::const_iterator j = i + 1;
+ while (j != sy_pass2.end() && j->orig == i->orig) {
+ num++;
+ j++;
+ }
+
+ if (num == i->num) {
+
+ // All terms left, then add the original term to the result
+ result.push_back(i->orig);
+
+ } else {
+
+ // Some terms were combined with others, add up the remaining symmetrized terms
+ std::vector<symminfo>::const_iterator k;
+ for (k=i; k!=j; k++)
+ result.push_back(k->coeff * k->symmterm);
+ }
+
+ i = j;
+ }
+ }
+
+ // Add all resulting terms
+ ex sum_symm = (new add(result))->setflag(status_flags::dynallocated);
+ if (sum_symm.is_zero())
+ free_indices.clear();
+ return sum_symm;