]> www.ginac.de Git - ginac.git/blobdiff - ginac/indexed.cpp
[nitpick] don't use int instead of std::size_t.
[ginac.git] / ginac / indexed.cpp
index b8b70f7e9d5ae853649c85c709fb895182aaf91d..aa8500399e270facb7fa72a59a6c9277c26214fa 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's indexed expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2006 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
 #include <iostream>
 #include <sstream>
 #include <stdexcept>
+#include <limits>
 
 #include "indexed.h"
 #include "idx.h"
@@ -39,6 +40,7 @@
 #include "utils.h"
 #include "integral.h"
 #include "matrix.h"
+#include "inifcns.h"
 
 namespace GiNaC {
 
@@ -305,7 +307,7 @@ ex indexed::eval(int level) const
                exvector v = seq;
                GINAC_ASSERT(is_exactly_a<symmetry>(symtree));
                int sig = canonicalize(v.begin() + 1, ex_to<symmetry>(symtree));
-               if (sig != INT_MAX) {
+               if (sig != std::numeric_limits<int>::max()) {
                        // Something has changed while sorting indices, more evaluations later
                        if (sig == 0)
                                return _ex0;
@@ -317,6 +319,20 @@ ex indexed::eval(int level) const
        return ex_to<basic>(base).eval_indexed(*this);
 }
 
+ex indexed::real_part() const
+{
+       if(op(0).info(info_flags::real))
+               return *this;
+       return real_part_function(*this).hold();
+}
+
+ex indexed::imag_part() const
+{
+       if(op(0).info(info_flags::real))
+               return 0;
+       return imag_part_function(*this).hold();
+}
+
 ex indexed::thiscontainer(const exvector & v) const
 {
        return indexed(ex_to<symmetry>(symtree), v);
@@ -624,10 +640,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;
 
@@ -635,14 +701,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);
@@ -653,11 +725,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;
                        }
@@ -666,6 +735,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;
 }
 
@@ -1337,7 +1409,7 @@ exvector get_all_dummy_indices_safely(const ex & e)
        else if (is_a<mul>(e) || is_a<ncmul>(e)) {
                exvector dummies;
                exvector free_indices;
-               for (int i=0; i<e.nops(); ++i) {
+               for (std::size_t i = 0; i < e.nops(); ++i) {
                        exvector dummies_of_factor = get_all_dummy_indices_safely(e.op(i));
                        dummies.insert(dummies.end(), dummies_of_factor.begin(),
                                dummies_of_factor.end());
@@ -1353,7 +1425,7 @@ exvector get_all_dummy_indices_safely(const ex & e)
        }
        else if(is_a<add>(e)) {
                exvector result;
-               for(int i=0; i<e.nops(); ++i) {
+               for(std::size_t i = 0; i < e.nops(); ++i) {
                        exvector dummies_of_term = get_all_dummy_indices_safely(e.op(i));
                        sort(dummies_of_term.begin(), dummies_of_term.end());
                        exvector new_vec;
@@ -1486,44 +1558,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;
        }