]> www.ginac.de Git - ginac.git/blobdiff - ginac/indexed.cpp
Made unarchiving algorithms order N instead of order N^2.
[ginac.git] / ginac / indexed.cpp
index d39692c4e859d2a8be1f381052caeba203551996..d772b3f4743bd85ff8c127110f888c34801c0c6c 100644 (file)
@@ -3,7 +3,7 @@
  *  Implementation of GiNaC's indexed expressions. */
 
 /*
- *  GiNaC Copyright (C) 1999-2005 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2006 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
@@ -39,6 +39,7 @@
 #include "utils.h"
 #include "integral.h"
 #include "matrix.h"
+#include "inifcns.h"
 
 namespace GiNaC {
 
@@ -53,7 +54,7 @@ GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(indexed, exprseq,
 
 indexed::indexed() : symtree(not_symmetric())
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
 }
 
 //////////
@@ -62,79 +63,79 @@ indexed::indexed() : symtree(not_symmetric())
 
 indexed::indexed(const ex & b) : inherited(b), symtree(not_symmetric())
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const ex & i1) : inherited(b, i1), symtree(not_symmetric())
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const ex & i1, const ex & i2) : inherited(b, i1, i2), symtree(not_symmetric())
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3) : inherited(b, i1, i2, i3), symtree(not_symmetric())
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3, const ex & i4) : inherited(b, i1, i2, i3, i4), symtree(not_symmetric())
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2) : inherited(b, i1, i2), symtree(symm)
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2, const ex & i3) : inherited(b, i1, i2, i3), symtree(symm)
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2, const ex & i3, const ex & i4) : inherited(b, i1, i2, i3, i4), symtree(symm)
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const exvector & v) : inherited(b), symtree(not_symmetric())
 {
        seq.insert(seq.end(), v.begin(), v.end());
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const ex & b, const symmetry & symm, const exvector & v) : inherited(b), symtree(symm)
 {
        seq.insert(seq.end(), v.begin(), v.end());
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
        validate();
 }
 
 indexed::indexed(const symmetry & symm, const exprseq & es) : inherited(es), symtree(symm)
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
 }
 
 indexed::indexed(const symmetry & symm, const exvector & v, bool discardable) : inherited(v, discardable), symtree(symm)
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
 }
 
 indexed::indexed(const symmetry & symm, std::auto_ptr<exvector> vp) : inherited(vp), symtree(symm)
 {
-       tinfo_key = TINFO_indexed;
+       tinfo_key = &indexed::tinfo_static;
 }
 
 //////////
@@ -297,7 +298,7 @@ ex indexed::eval(int level) const
                return f * thiscontainer(v);
        }
 
-       if(this->tinfo()==TINFO_indexed && seq.size()==1)
+       if(this->tinfo()==&indexed::tinfo_static && seq.size()==1)
                return base;
 
        // Canonicalize indices according to the symmetry properties
@@ -317,6 +318,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,6 +639,56 @@ bool reposition_dummy_indices(ex & e, exvector & variant_dummy_indices, exvector
 {
        bool something_changed = false;
 
+       // Canonicalize wrt indices that are dummies within e. I.e., their
+       // symbol occurs twice in an index of e. This is only done if there
+       // is a cyclic symmetry because in that case it may happen that after
+       // raising/lowering an index the indices get reshuffled by ::eval in
+       // such a way that the iterators no longer point to the right objects.
+       if (ex_to<symmetry>(ex_to<indexed>(e).get_symmetry()).has_cyclic()) {
+               // Get dummy pairs of varidxes within the indexed object in e.
+               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;
+                               }
+                       }
+               }
+               // 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 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;
@@ -1486,44 +1551,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;
        }