-int canonicalize_indices(exvector & iv, bool antisymmetric)
-{
- if (iv.size()<2) {
- // nothing do to for 0 or 1 indices
- return INT_MAX;
- }
-
- bool something_changed=false;
- int sig=1;
- // simple bubble sort algorithm should be sufficient for the small number of indices needed
- exvector::const_iterator last_idx=iv.end();
- exvector::const_iterator next_to_last_idx=iv.end()-1;
- for (exvector::iterator it1=iv.begin(); it1!=next_to_last_idx; ++it1) {
- for (exvector::iterator it2=it1+1; it2!=last_idx; ++it2) {
- int cmpval=(*it1).compare(*it2);
- if (cmpval==1) {
- iter_swap(it1,it2);
- something_changed=true;
- if (antisymmetric) sig=-sig;
- } else if ((cmpval==0) && antisymmetric) {
- something_changed=true;
- sig=0;
- }
- }
- }
- return something_changed ? sig : INT_MAX;
-}
-
-exvector idx_intersect(exvector const & iv1, exvector const & iv2)
-{
- // build a vector of symbolic indices contained in iv1 and iv2 simultaneously
- // assumes (but does not test) that each index occurs at most twice
- exvector iv_intersect;
- for (exvector::const_iterator cit1=iv1.begin(); cit1!=iv1.end(); ++cit1) {
- GINAC_ASSERT(is_ex_of_type(*cit1,idx));
- if (ex_to_idx(*cit1).is_symbolic()) {
- for (exvector::const_iterator cit2=iv2.begin(); cit2!=iv2.end(); ++cit2) {
- GINAC_ASSERT(is_ex_of_type(*cit2,idx));
- if ((*cit1).is_equal(*cit2)) {
- iv_intersect.push_back(*cit1);
- break;
- }
- }
- }
- }
- return iv_intersect;
-}
-
-#define TEST_PERMUTATION(A,B,C,P) \
- if ((iv3[B].is_equal(iv2[0]))&&(iv3[C].is_equal(iv2[1]))) { \
- if (antisymmetric) *sig=P; \
- return iv3[A]; \
- }
-
-ex permute_free_index_to_front(exvector const & iv3, exvector const & iv2,
- bool antisymmetric, int * sig)
-{
- // match (return value,iv2) to iv3 by permuting indices
- // iv3 is always cyclic
-
- GINAC_ASSERT(iv3.size()==3);
- GINAC_ASSERT(iv2.size()==2);
-
- *sig=1;
-
- TEST_PERMUTATION(0,1,2, 1);
- TEST_PERMUTATION(0,2,1, -1);
- TEST_PERMUTATION(1,0,2, -1);
- TEST_PERMUTATION(1,2,0, 1);
- TEST_PERMUTATION(2,0,1, 1);
- TEST_PERMUTATION(2,1,0, -1);
- throw(std::logic_error("permute_free_index_to_front(): no valid permutation found"));
-}
-
-unsigned subs_index_in_exvector(exvector & v, ex const & is, ex const & ir)
-{
- exvector::iterator it;
- unsigned replacements=0;
- unsigned current_replacements;
-
- GINAC_ASSERT(is_ex_of_type(is,idx));
- GINAC_ASSERT(is_ex_of_type(ir,idx));
-
- for (it=v.begin(); it!=v.end(); ++it) {
- current_replacements=count_index(*it,is);
- if (current_replacements>0) {
- (*it)=(*it).subs(is==ir);
- }
- replacements += current_replacements;
- }
- return replacements;
-}
-
-unsigned count_index(ex const & e, ex const & i)
-{
- exvector idxv=e.get_indices();
- unsigned count=0;
- for (exvector::const_iterator cit=idxv.begin(); cit!=idxv.end(); ++cit) {
- if ((*cit).is_equal(i)) count++;
- }
- return count;
-}
-
-ex subs_indices(ex const & e, exvector const & idxv_subs,
- exvector const & idxv_repl)
-{
- GINAC_ASSERT(idxv_subs.size()==idxv_repl.size());
- ex res=e;
- for (unsigned i=0; i<idxv_subs.size(); ++i) {
- res=res.subs(idxv_subs[i]==idxv_repl[i]);
- }
- return res;
-}
-
-#ifndef NO_GINAC_NAMESPACE
+bool is_dummy_pair(const idx & i1, const idx & i2)
+{
+ // The indices must be of exactly the same type
+ if (typeid(i1) != typeid(i2))
+ return false;
+
+ // Same type, let the indices decide whether they are paired
+ return i1.is_dummy_pair_same_type(i2);
+}
+
+bool is_dummy_pair(const ex & e1, const ex & e2)
+{
+ // The expressions must be indices
+ if (!is_a<idx>(e1) || !is_a<idx>(e2))
+ return false;
+
+ return is_dummy_pair(ex_to<idx>(e1), ex_to<idx>(e2));
+}
+
+void find_free_and_dummy(exvector::const_iterator it, exvector::const_iterator itend, exvector & out_free, exvector & out_dummy)
+{
+ out_free.clear();
+ out_dummy.clear();
+
+ // No indices? Then do nothing
+ if (it == itend)
+ return;
+
+ // Only one index? Then it is a free one if it's not numeric
+ if (itend - it == 1) {
+ if (ex_to<idx>(*it).is_symbolic())
+ out_free.push_back(*it);
+ return;
+ }
+
+ // Sort index vector. This will cause dummy indices come to lie next
+ // to each other (because the sort order is defined to guarantee this).
+ exvector v(it, itend);
+ shaker_sort(v.begin(), v.end(), ex_is_less(), ex_swap());
+
+ // Find dummy pairs and free indices
+ it = v.begin(); itend = v.end();
+ exvector::const_iterator last = it++;
+ while (it != itend) {
+ if (is_dummy_pair(*it, *last)) {
+ out_dummy.push_back(*last);
+ it++;
+ if (it == itend)
+ return;
+ } else {
+ if (!it->is_equal(*last) && ex_to<idx>(*last).is_symbolic())
+ out_free.push_back(*last);
+ }
+ last = it++;
+ }
+ if (ex_to<idx>(*last).is_symbolic())
+ out_free.push_back(*last);
+}
+
+ex minimal_dim(const ex & dim1, const ex & dim2)
+{
+ if (dim1.is_equal(dim2) || dim1 < dim2 || (is_exactly_a<numeric>(dim1) && !is_a<numeric>(dim2)))
+ return dim1;
+ else if (dim1 > dim2 || (!is_a<numeric>(dim1) && is_exactly_a<numeric>(dim2)))
+ return dim2;
+ else {
+ std::ostringstream s;
+ s << "minimal_dim(): index dimensions " << dim1 << " and " << dim2 << " cannot be ordered";
+ throw (std::runtime_error(s.str()));
+ }
+}
+