]> www.ginac.de Git - ginac.git/blobdiff - ginac/indexed.cpp
Backport change in reposition_dummy_indices to 1.3.
[ginac.git] / ginac / indexed.cpp
index 26fb692f019e96713245f70120fde5714827cc89..2de726bfdb2e46bf612c3ce29696493f19209b24 100644 (file)
@@ -297,6 +297,9 @@ ex indexed::eval(int level) const
                return f * thiscontainer(v);
        }
 
+       if(this->tinfo()==TINFO_indexed && seq.size()==1)
+               return base;
+
        // Canonicalize indices according to the symmetry properties
        if (seq.size() > 2) {
                exvector v = seq;
@@ -532,6 +535,15 @@ exvector integral::get_free_indices() const
        return f.get_free_indices();
 }
 
+template<class T> size_t number_of_type(const exvector&v)
+{
+       size_t number = 0;
+       for(exvector::const_iterator i=v.begin(); i!=v.end(); ++i)
+               if(is_exactly_a<T>(*i))
+                       ++number;
+       return number;
+}
+
 /** Rename dummy indices in an expression.
  *
  *  @param e Expression to work on
@@ -540,10 +552,10 @@ exvector integral::get_free_indices() const
  *  @param global_dummy_indices The set of dummy indices that have appeared
  *    before and which we would like to use in "e", too. This gets updated
  *    by the function */
-static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, exvector & local_dummy_indices)
+template<class T> static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, exvector & local_dummy_indices)
 {
-       size_t global_size = global_dummy_indices.size(),
-              local_size = local_dummy_indices.size();
+       size_t global_size = number_of_type<T>(global_dummy_indices),
+              local_size = number_of_type<T>(local_dummy_indices);
 
        // Any local dummy indices at all?
        if (local_size == 0)
@@ -557,7 +569,7 @@ static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, ex
                int remaining = local_size - global_size;
                exvector::const_iterator it = local_dummy_indices.begin(), itend = local_dummy_indices.end();
                while (it != itend && remaining > 0) {
-                       if (find_if(global_dummy_indices.begin(), global_dummy_indices.end(), bind2nd(op0_is_equal(), *it)) == global_dummy_indices.end()) {
+                       if (is_exactly_a<T>(*it) && find_if(global_dummy_indices.begin(), global_dummy_indices.end(), bind2nd(idx_is_equal_ignore_dim(), *it)) == global_dummy_indices.end()) {
                                global_dummy_indices.push_back(*it);
                                global_size++;
                                remaining--;
@@ -575,11 +587,13 @@ static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, ex
        exvector local_syms, global_syms;
        local_syms.reserve(local_size);
        global_syms.reserve(local_size);
-       for (size_t i=0; i<local_size; i++)
-               local_syms.push_back(local_dummy_indices[i].op(0));
+       for (size_t i=0; local_syms.size()!=local_size; i++)
+               if(is_exactly_a<T>(local_dummy_indices[i]))
+                       local_syms.push_back(local_dummy_indices[i].op(0));
        shaker_sort(local_syms.begin(), local_syms.end(), ex_is_less(), ex_swap());
-       for (size_t i=0; i<local_size; i++) // don't use more global symbols than necessary
-               global_syms.push_back(global_dummy_indices[i].op(0));
+       for (size_t i=0; global_syms.size()!=local_size; i++) // don't use more global symbols than necessary
+               if(is_exactly_a<T>(global_dummy_indices[i]))
+                       global_syms.push_back(global_dummy_indices[i].op(0));
        shaker_sort(global_syms.begin(), global_syms.end(), ex_is_less(), ex_swap());
 
        // Remove common indices
@@ -618,10 +632,60 @@ bool reposition_dummy_indices(ex & e, exvector & variant_dummy_indices, exvector
 {
        bool something_changed = false;
 
+       // Find dummy symbols that occur twice in the same indexed object.
+       exvector local_var_dummies;
+       local_var_dummies.reserve(e.nops()/2);
+       for (size_t i=1; i<e.nops(); ++i) {
+               if (!is_a<varidx>(e.op(i)))
+                       continue;
+               for (size_t j=i+1; j<e.nops(); ++j) {
+                       if (is_dummy_pair(e.op(i), e.op(j))) {
+                               local_var_dummies.push_back(e.op(i));
+                               for (exvector::iterator k = variant_dummy_indices.begin();
+                                               k!=variant_dummy_indices.end(); ++k) {
+                                       if (e.op(i).op(0) == k->op(0)) {
+                                               variant_dummy_indices.erase(k);
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+               }
+       }
+
+       // In the case where a dummy symbol occurs twice in the same indexed object
+       // we try all posibilities of raising/lowering and keep the least one in
+       // the sense of ex_is_less.
+       ex optimal_e = e;
+       size_t numpossibs = 1 << local_var_dummies.size();
+       for (size_t i=0; i<numpossibs; ++i) {
+               ex try_e = e;
+               for (size_t j=0; j<local_var_dummies.size(); ++j) {
+                       exmap m;
+                       if (1<<j & i) {
+                               ex curr_idx = local_var_dummies[j];
+                               ex curr_toggle = ex_to<varidx>(curr_idx).toggle_variance();
+                               m[curr_idx] = curr_toggle;
+                               m[curr_toggle] = curr_idx;
+                       }
+                       try_e = e.subs(m, subs_options::no_pattern);
+               }
+               if(ex_is_less()(try_e, optimal_e))
+               {       optimal_e = try_e;
+                       something_changed = true;
+               }
+       }
+       e = optimal_e;
+
+       if (!is_a<indexed>(e))
+               return true;
+
+       exvector seq = ex_to<indexed>(e).seq;
+
        // If a dummy index is encountered for the first time in the
        // product, pull it up, otherwise, pull it down
-       exvector::const_iterator it2, it2start, it2end;
-       for (it2start = ex_to<indexed>(e).seq.begin(), it2end = ex_to<indexed>(e).seq.end(), it2 = it2start + 1; it2 != it2end; ++it2) {
+       for (exvector::iterator it2 = seq.begin()+1, it2end = seq.end();
+                       it2 != it2end; ++it2) {
                if (!is_exactly_a<varidx>(*it2))
                        continue;
 
@@ -629,14 +693,20 @@ bool reposition_dummy_indices(ex & e, exvector & variant_dummy_indices, exvector
                for (vit = variant_dummy_indices.begin(), vitend = variant_dummy_indices.end(); vit != vitend; ++vit) {
                        if (it2->op(0).is_equal(vit->op(0))) {
                                if (ex_to<varidx>(*it2).is_covariant()) {
-                                       e = e.subs(lst(
-                                               *it2 == ex_to<varidx>(*it2).toggle_variance(),
-                                               ex_to<varidx>(*it2).toggle_variance() == *it2
-                                       ), subs_options::no_pattern);
+                                       /*
+                                        * N.B. we don't want to use
+                                        *
+                                        *  e = e.subs(lst(
+                                        *  *it2 == ex_to<varidx>(*it2).toggle_variance(),
+                                        *  ex_to<varidx>(*it2).toggle_variance() == *it2
+                                        *  ), subs_options::no_pattern);
+                                        *
+                                        * since this can trigger non-trivial repositioning of indices,
+                                        * e.g. due to non-trivial symmetry properties of e, thus
+                                        * invalidating iterators
+                                        */
+                                       *it2 = ex_to<varidx>(*it2).toggle_variance();
                                        something_changed = true;
-                                       it2 = ex_to<indexed>(e).seq.begin() + (it2 - it2start);
-                                       it2start = ex_to<indexed>(e).seq.begin();
-                                       it2end = ex_to<indexed>(e).seq.end();
                                }
                                moved_indices.push_back(*vit);
                                variant_dummy_indices.erase(vit);
@@ -647,11 +717,8 @@ bool reposition_dummy_indices(ex & e, exvector & variant_dummy_indices, exvector
                for (vit = moved_indices.begin(), vitend = moved_indices.end(); vit != vitend; ++vit) {
                        if (it2->op(0).is_equal(vit->op(0))) {
                                if (ex_to<varidx>(*it2).is_contravariant()) {
-                                       e = e.subs(*it2 == ex_to<varidx>(*it2).toggle_variance(), subs_options::no_pattern);
+                                       *it2 = ex_to<varidx>(*it2).toggle_variance();
                                        something_changed = true;
-                                       it2 = ex_to<indexed>(e).seq.begin() + (it2 - it2start);
-                                       it2start = ex_to<indexed>(e).seq.begin();
-                                       it2end = ex_to<indexed>(e).seq.end();
                                }
                                goto next_index;
                        }
@@ -660,6 +727,9 @@ bool reposition_dummy_indices(ex & e, exvector & variant_dummy_indices, exvector
 next_index: ;
        }
 
+       if (something_changed)
+               e = ex_to<indexed>(e).thiscontainer(seq);
+
        return something_changed;
 }
 
@@ -707,6 +777,18 @@ static void product_to_exvector(const ex & e, exvector & v, bool & non_commutati
 // Forward declaration needed in absence of friend injection, C.f. [namespace.memdef]:
 ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indices, const scalar_products & sp);
 
+template<class T> ex idx_symmetrization(const ex& r,const exvector& local_dummy_indices)
+{      exvector dummy_syms;
+       dummy_syms.reserve(r.nops());
+       for (exvector::const_iterator it = local_dummy_indices.begin(); it != local_dummy_indices.end(); ++it)
+                       if(is_exactly_a<T>(*it))
+                               dummy_syms.push_back(it->op(0));
+       if(dummy_syms.size() < 2)
+               return r;
+       ex q=symmetrize(r, dummy_syms);
+       return q;
+}
+
 /** Simplify product of indexed expressions (commutative, noncommutative and
  *  simple squares), return list of free indices. */
 ex simplify_indexed_product(const ex & e, exvector & free_indices, exvector & dummy_indices, const scalar_products & sp)
@@ -759,20 +841,12 @@ try_again:
 
                        // At least one dummy index, is it a defined scalar product?
                        bool contracted = false;
-                       if (free.empty()) {
-
-                               // Find minimal dimension of all indices of both factors
-                               exvector::const_iterator dit = ex_to<indexed>(*it1).seq.begin() + 1, ditend = ex_to<indexed>(*it1).seq.end();
-                               ex dim = ex_to<idx>(*dit).get_dim();
-                               ++dit;
-                               for (; dit != ditend; ++dit) {
-                                       dim = minimal_dim(dim, ex_to<idx>(*dit).get_dim());
-                               }
-                               dit = ex_to<indexed>(*it2).seq.begin() + 1;
-                               ditend = ex_to<indexed>(*it2).seq.end();
-                               for (; dit != ditend; ++dit) {
-                                       dim = minimal_dim(dim, ex_to<idx>(*dit).get_dim());
-                               }
+                       if (free.empty() && it1->nops()==2 && it2->nops()==2) {
+
+                               ex dim = minimal_dim(
+                                       ex_to<idx>(it1->op(1)).get_dim(),
+                                       ex_to<idx>(it2->op(1)).get_dim()
+                               );
 
                                // User-defined scalar product?
                                if (sp.is_defined(*it1, *it2, dim)) {
@@ -867,19 +941,26 @@ contraction_done:
        // The result should be symmetric with respect to exchange of dummy
        // indices, so if the symmetrization vanishes, the whole expression is
        // zero. This detects things like eps.i.j.k * p.j * p.k = 0.
-       if (local_dummy_indices.size() >= 2) {
-               exvector dummy_syms;
-               dummy_syms.reserve(local_dummy_indices.size());
-               for (exvector::const_iterator it = local_dummy_indices.begin(); it != local_dummy_indices.end(); ++it)
-                       dummy_syms.push_back(it->op(0));
-               if (symmetrize(r, dummy_syms).is_zero()) {
-                       free_indices.clear();
-                       return _ex0;
-               }
+       ex q = idx_symmetrization<idx>(r, local_dummy_indices);
+       if (q.is_zero()) {
+               free_indices.clear();
+               return _ex0;
+       }
+       q = idx_symmetrization<varidx>(q, local_dummy_indices);
+       if (q.is_zero()) {
+               free_indices.clear();
+               return _ex0;
+       }
+       q = idx_symmetrization<spinidx>(q, local_dummy_indices);
+       if (q.is_zero()) {
+               free_indices.clear();
+               return _ex0;
        }
 
        // Dummy index renaming
-       r = rename_dummy_indices(r, dummy_indices, local_dummy_indices);
+       r = rename_dummy_indices<idx>(r, dummy_indices, local_dummy_indices);
+       r = rename_dummy_indices<varidx>(r, dummy_indices, local_dummy_indices);
+       r = rename_dummy_indices<spinidx>(r, dummy_indices, local_dummy_indices);
 
        // Product of indexed object with a scalar?
        if (is_exactly_a<mul>(r) && r.nops() == 2
@@ -946,6 +1027,17 @@ public:
        }
 };
 
+bool hasindex(const ex &x, const ex &sym)
+{      
+       if(is_a<idx>(x) && x.op(0)==sym)
+               return true;
+       else
+               for(size_t i=0; i<x.nops(); ++i)
+                       if(hasindex(x.op(i), sym))
+                               return true;
+       return false;
+}
+
 /** Simplify indexed expression, return list of free indices. */
 ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indices, const scalar_products & sp)
 {
@@ -974,7 +1066,10 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
                }
 
                // Rename the dummy indices
-               return rename_dummy_indices(e_expanded, dummy_indices, local_dummy_indices);
+               e_expanded = rename_dummy_indices<idx>(e_expanded, dummy_indices, local_dummy_indices);
+               e_expanded = rename_dummy_indices<varidx>(e_expanded, dummy_indices, local_dummy_indices);
+               e_expanded = rename_dummy_indices<spinidx>(e_expanded, dummy_indices, local_dummy_indices);
+               return e_expanded;
        }
 
        // Simplification of sum = sum of simplifications, check consistency of
@@ -1018,18 +1113,19 @@ ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indi
                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);
+                       exvector dummy_indices_of_term;
+                       dummy_indices_of_term.reserve(dummy_indices.size());
+                       for(exvector::iterator i=dummy_indices.begin(); i!=dummy_indices.end(); ++i)
+                               if(hasindex(term,i->op(0)))
+                                       dummy_indices_of_term.push_back(*i);
+                       ex term_symm = idx_symmetrization<idx>(term, dummy_indices_of_term);
+                       term_symm = idx_symmetrization<varidx>(term_symm, dummy_indices_of_term);
+                       term_symm = idx_symmetrization<spinidx>(term_symm, dummy_indices_of_term);
                        if (term_symm.is_zero())
                                continue;
                        terms.push_back(terminfo(term, term_symm));
@@ -1355,44 +1451,33 @@ ex expand_dummy_sum(const ex & e, bool subs_idx)
        pointer_to_map_function_1arg<bool> fcn(expand_dummy_sum, subs_idx);
        if (is_a<add>(e_expanded) || is_a<lst>(e_expanded) || is_a<matrix>(e_expanded)) {
                return e_expanded.map(fcn);
-       } else if (is_a<ncmul>(e_expanded) || is_a<mul>(e_expanded) || is_a<power>(e_expanded)) {
-               exvector v = get_all_dummy_indices(e_expanded);
-               exvector::const_iterator it = v.begin(), itend = v.end();
-               while (it != itend) {
-                       varidx nu = ex_to<varidx>(*it);
-                       if (nu.is_dim_numeric()) {
-                               ex en = 0;
-                               for (int i=0; i < ex_to<numeric>(nu.get_dim()).to_int(); i++) {
-                                       if (is_a<varidx>(nu) && !subs_idx) {
-                                               en += e_expanded.subs(lst(nu == varidx(i, nu.get_dim(), true), nu.toggle_variance() == varidx(i, nu.get_dim())));
-                                       } else {
-                                               en += e_expanded.subs(lst(nu == idx(i, nu.get_dim()), nu.toggle_variance() == idx(i, nu.get_dim())));
-                                       }
-                               }
-                               return expand_dummy_sum(en, subs_idx);
-                       } 
-                       ++it;
-               }
-               return e;
-       } else if (is_a<indexed>(e_expanded)) {
-               exvector v = ex_to<indexed>(e_expanded).get_dummy_indices();
-               exvector::const_iterator it = v.begin(), itend = v.end();
-               while (it != itend) {
-                       varidx nu = ex_to<varidx>(*it);
-                       if (nu.is_dim_numeric()) {
+       } else if (is_a<ncmul>(e_expanded) || is_a<mul>(e_expanded) || is_a<power>(e_expanded) || is_a<indexed>(e_expanded)) {
+               exvector v;
+               if (is_a<indexed>(e_expanded))
+                       v = ex_to<indexed>(e_expanded).get_dummy_indices();
+               else
+                       v = get_all_dummy_indices(e_expanded);
+               ex result = e_expanded;
+               for(exvector::const_iterator it=v.begin(); it!=v.end(); ++it) {
+                       ex nu = *it;
+                       if (ex_to<idx>(nu).get_dim().info(info_flags::nonnegint)) {
+                               int idim = ex_to<numeric>(ex_to<idx>(nu).get_dim()).to_int();
                                ex en = 0;
-                               for (int i=0; i < ex_to<numeric>(nu.get_dim()).to_int(); i++) {
-                                       if (is_a<varidx>(nu) && !subs_idx) {
-                                               en += e_expanded.subs(lst(nu == varidx(i, nu.get_dim(), true), nu.toggle_variance() == varidx(i, nu.get_dim())));
+                               for (int i=0; i < idim; i++) {
+                                       if (subs_idx && is_a<varidx>(nu)) {
+                                               ex other = ex_to<varidx>(nu).toggle_variance();
+                                               en += result.subs(lst(
+                                                       nu == idx(i, idim),
+                                                       other == idx(i, idim)
+                                               ));
                                        } else {
-                                               en += e_expanded.subs(lst(nu == idx(i, nu.get_dim()), nu.toggle_variance() == idx(i, nu.get_dim())));
+                                               en += result.subs( nu.op(0) == i );
                                        }
                                }
-                               return expand_dummy_sum(en, subs_idx);
-                       } 
-                       ++it;
+                               result = en;
+                       }
                }
-               return e;
+               return result;
        } else {
                return e;
        }