* Implementation of GiNaC's indexed expressions. */
/*
- * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2005 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
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <iostream>
#include "symmetry.h"
#include "operators.h"
#include "lst.h"
-#include "print.h"
#include "archive.h"
+#include "symbol.h"
#include "utils.h"
+#include "integral.h"
+#include "matrix.h"
namespace GiNaC {
-GINAC_IMPLEMENT_REGISTERED_CLASS(indexed, exprseq)
+GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(indexed, exprseq,
+ print_func<print_context>(&indexed::do_print).
+ print_func<print_latex>(&indexed::do_print_latex).
+ print_func<print_tree>(&indexed::do_print_tree))
//////////
// default constructor
//////////
-indexed::indexed() : symtree(sy_none())
+indexed::indexed() : symtree(not_symmetric())
{
tinfo_key = TINFO_indexed;
}
// other constructors
//////////
-indexed::indexed(const ex & b) : inherited(b), symtree(sy_none())
+indexed::indexed(const ex & b) : inherited(b), symtree(not_symmetric())
{
tinfo_key = TINFO_indexed;
validate();
}
-indexed::indexed(const ex & b, const ex & i1) : inherited(b, i1), symtree(sy_none())
+indexed::indexed(const ex & b, const ex & i1) : inherited(b, i1), symtree(not_symmetric())
{
tinfo_key = TINFO_indexed;
validate();
}
-indexed::indexed(const ex & b, const ex & i1, const ex & i2) : inherited(b, i1, i2), symtree(sy_none())
+indexed::indexed(const ex & b, const ex & i1, const ex & i2) : inherited(b, i1, i2), symtree(not_symmetric())
{
tinfo_key = TINFO_indexed;
validate();
}
-indexed::indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3) : inherited(b, i1, i2, i3), symtree(sy_none())
+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;
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(sy_none())
+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;
validate();
validate();
}
-indexed::indexed(const ex & b, const exvector & v) : inherited(b), symtree(sy_none())
+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 = TINFO_indexed;
}
-indexed::indexed(const symmetry & symm, exvector * vp) : inherited(vp), symtree(symm)
+indexed::indexed(const symmetry & symm, std::auto_ptr<exvector> vp) : inherited(vp), symtree(symm)
{
tinfo_key = TINFO_indexed;
}
symtree = sy_anti();
break;
default:
- symtree = sy_none();
+ symtree = not_symmetric();
break;
}
const_cast<symmetry &>(ex_to<symmetry>(symtree)).validate(seq.size() - 1);
// functions overriding virtual functions from base classes
//////////
-void indexed::print(const print_context & c, unsigned level) const
+void indexed::printindices(const print_context & c, unsigned level) const
{
- GINAC_ASSERT(seq.size() > 0);
-
- if (is_a<print_tree>(c)) {
+ if (seq.size() > 1) {
- c.s << std::string(level, ' ') << class_name()
- << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
- << ", " << seq.size()-1 << " indices"
- << ", symmetry=" << symtree << std::endl;
- unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
- seq[0].print(c, level + delta_indent);
- printindices(c, level + delta_indent);
+ exvector::const_iterator it=seq.begin() + 1, itend = seq.end();
- } else {
+ if (is_a<print_latex>(c)) {
- bool is_tex = is_a<print_latex>(c);
- const ex & base = seq[0];
+ // TeX output: group by variance
+ bool first = true;
+ bool covariant = true;
- if (precedence() <= level)
- c.s << (is_tex ? "{(" : "(");
- if (is_tex)
- c.s << "{";
- base.print(c, precedence());
- if (is_tex)
+ while (it != itend) {
+ bool cur_covariant = (is_a<varidx>(*it) ? ex_to<varidx>(*it).is_covariant() : true);
+ if (first || cur_covariant != covariant) { // Variance changed
+ // The empty {} prevents indices from ending up on top of each other
+ if (!first)
+ c.s << "}{}";
+ covariant = cur_covariant;
+ if (covariant)
+ c.s << "_{";
+ else
+ c.s << "^{";
+ }
+ it->print(c, level);
+ c.s << " ";
+ first = false;
+ it++;
+ }
c.s << "}";
- printindices(c, level);
- if (precedence() <= level)
- c.s << (is_tex ? ")}" : ")");
+
+ } else {
+
+ // Ordinary output
+ while (it != itend) {
+ it->print(c, level);
+ it++;
+ }
+ }
}
}
+void indexed::print_indexed(const print_context & c, const char *openbrace, const char *closebrace, unsigned level) const
+{
+ if (precedence() <= level)
+ c.s << openbrace << '(';
+ c.s << openbrace;
+ seq[0].print(c, precedence());
+ c.s << closebrace;
+ printindices(c, level);
+ if (precedence() <= level)
+ c.s << ')' << closebrace;
+}
+
+void indexed::do_print(const print_context & c, unsigned level) const
+{
+ print_indexed(c, "", "", level);
+}
+
+void indexed::do_print_latex(const print_latex & c, unsigned level) const
+{
+ print_indexed(c, "{", "}", level);
+}
+
+void indexed::do_print_tree(const print_tree & c, unsigned level) const
+{
+ c.s << std::string(level, ' ') << class_name() << " @" << this
+ << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
+ << ", " << seq.size()-1 << " indices"
+ << ", symmetry=" << symtree << std::endl;
+ seq[0].print(c, level + c.delta_indent);
+ printindices(c, level + c.delta_indent);
+}
+
bool indexed::info(unsigned inf) const
{
if (inf == info_flags::indexed) return true;
return indexed(ex_to<symmetry>(symtree), v);
}
-ex indexed::thiscontainer(exvector * vp) const
+ex indexed::thiscontainer(std::auto_ptr<exvector> vp) const
{
return indexed(ex_to<symmetry>(symtree), vp);
}
{
GINAC_ASSERT(seq.size() > 0);
- if ((options & expand_options::expand_indexed) && is_exactly_a<add>(seq[0])) {
-
- // expand_indexed expands (a+b).i -> a.i + b.i
- const ex & base = seq[0];
- ex sum = _ex0;
- for (size_t i=0; i<base.nops(); i++) {
+ if (options & expand_options::expand_indexed) {
+ ex newbase = seq[0].expand(options);
+ if (is_exactly_a<add>(newbase)) {
+ ex sum = _ex0;
+ for (size_t i=0; i<newbase.nops(); i++) {
+ exvector s = seq;
+ s[0] = newbase.op(i);
+ sum += thiscontainer(s).expand(options);
+ }
+ return sum;
+ }
+ if (!are_ex_trivially_equal(newbase, seq[0])) {
exvector s = seq;
- s[0] = base.op(i);
- sum += thiscontainer(s).expand();
+ s[0] = newbase;
+ return ex_to<indexed>(thiscontainer(s)).inherited::expand(options);
}
- return sum;
-
- } else
- return inherited::expand(options);
+ }
+ return inherited::expand(options);
}
//////////
// non-virtual functions in this class
//////////
-void indexed::printindices(const print_context & c, unsigned level) const
-{
- if (seq.size() > 1) {
-
- exvector::const_iterator it=seq.begin() + 1, itend = seq.end();
-
- if (is_a<print_latex>(c)) {
-
- // TeX output: group by variance
- bool first = true;
- bool covariant = true;
-
- while (it != itend) {
- bool cur_covariant = (is_a<varidx>(*it) ? ex_to<varidx>(*it).is_covariant() : true);
- if (first || cur_covariant != covariant) { // Variance changed
- // The empty {} prevents indices from ending up on top of each other
- if (!first)
- c.s << "}{}";
- covariant = cur_covariant;
- if (covariant)
- c.s << "_{";
- else
- c.s << "^{";
- }
- it->print(c, level);
- c.s << " ";
- first = false;
- it++;
- }
- c.s << "}";
-
- } else {
-
- // Ordinary output
- while (it != itend) {
- it->print(c, level);
- it++;
- }
- }
- }
-}
-
/** Check whether all indices are of class idx and validate the symmetry
* tree. This function is used internally to make sure that all constructed
* indexed objects really carry indices and not some other classes. */
return free_indices;
}
+struct is_summation_idx : public std::unary_function<ex, bool> {
+ bool operator()(const ex & e)
+ {
+ return is_dummy_pair(e, e);
+ }
+};
+
exvector power::get_free_indices() const
{
- // Return free indices of basis
- return basis.get_free_indices();
+ // Get free indices of basis
+ exvector basis_indices = basis.get_free_indices();
+
+ if (exponent.info(info_flags::even)) {
+ // If the exponent is an even number, then any "free" index that
+ // forms a dummy pair with itself is actually a summation index
+ exvector really_free;
+ std::remove_copy_if(basis_indices.begin(), basis_indices.end(),
+ std::back_inserter(really_free), is_summation_idx());
+ return really_free;
+ } else
+ return basis_indices;
+}
+
+exvector integral::get_free_indices() const
+{
+ if (a.get_free_indices().size() || b.get_free_indices().size())
+ throw (std::runtime_error("integral::get_free_indices: boundary values should not have free indices"));
+ return f.get_free_indices();
}
/** Rename dummy indices in an expression.
else {
while (global_uniq.size() > local_uniq.size())
global_uniq.pop_back();
- return e.subs(lst(local_uniq.begin(), local_uniq.end()), lst(global_uniq.begin(), global_uniq.end()));
+ return e.subs(lst(local_uniq.begin(), local_uniq.end()), lst(global_uniq.begin(), global_uniq.end()), subs_options::no_pattern);
}
}
e = e.subs(lst(
*it2 == ex_to<varidx>(*it2).toggle_variance(),
ex_to<varidx>(*it2).toggle_variance() == *it2
- ));
+ ), subs_options::no_pattern);
something_changed = true;
it2 = ex_to<indexed>(e).seq.begin() + (it2 - it2start);
it2start = ex_to<indexed>(e).seq.begin();
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());
+ e = e.subs(*it2 == ex_to<varidx>(*it2).toggle_variance(), subs_options::no_pattern);
something_changed = true;
it2 = ex_to<indexed>(e).seq.begin() + (it2 - it2start);
it2start = ex_to<indexed>(e).seq.begin();
}
};
-/** 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)
+/* An auxiliary function used by simplify_indexed() and expand_dummy_sum()
+ * It returns an exvector of factors from the supplied product */
+static void product_to_exvector(const ex & e, exvector & v, bool & non_commutative)
{
// Remember whether the product was commutative or noncommutative
// (because we chop it into factors and need to reassemble later)
- bool non_commutative = is_exactly_a<ncmul>(e);
+ non_commutative = is_exactly_a<ncmul>(e);
// Collect factors in an exvector, store squares twice
- exvector v;
v.reserve(e.nops() * 2);
if (is_exactly_a<power>(e)) {
ex f = e.op(i);
if (is_exactly_a<power>(f) && f.op(1).is_equal(_ex2)) {
v.push_back(f.op(0));
- v.push_back(f.op(0));
+ v.push_back(f.op(0));
} else if (is_exactly_a<ncmul>(f)) {
// Noncommutative factor found, split it as well
non_commutative = true; // everything becomes noncommutative, ncmul will sort out the commutative factors later
v.push_back(f);
}
}
+}
+
+/** 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)
+{
+ // Collect factors in an exvector
+ exvector v;
+
+ // Remember whether the product was commutative or noncommutative
+ // (because we chop it into factors and need to reassemble later)
+ bool non_commutative;
+ product_to_exvector(e, v, non_commutative);
// Perform contractions
bool something_changed = false;
* performs contraction of dummy indices where possible and checks whether
* the free indices in sums are consistent.
*
+ * @param options Simplification options (currently unused)
* @return simplified expression */
-ex ex::simplify_indexed() const
+ex ex::simplify_indexed(unsigned options) const
{
exvector free_indices, dummy_indices;
scalar_products sp;
* scalar products by known values if desired.
*
* @param sp Scalar products to be replaced automatically
+ * @param options Simplification options (currently unused)
* @return simplified expression */
-ex ex::simplify_indexed(const scalar_products & sp) const
+ex ex::simplify_indexed(const scalar_products & sp, unsigned options) const
{
exvector free_indices, dummy_indices;
return GiNaC::simplify_indexed(*this, free_indices, dummy_indices, sp);
}
}
+/** Returns all dummy indices from the exvector */
+exvector get_all_dummy_indices(const ex & e)
+{
+ exvector p;
+ bool nc;
+ product_to_exvector(e, p, nc);
+ exvector::const_iterator ip = p.begin(), ipend = p.end();
+ exvector v, v1;
+ while (ip != ipend) {
+ if (is_a<indexed>(*ip)) {
+ v1 = ex_to<indexed>(*ip).get_dummy_indices();
+ v.insert(v.end(), v1.begin(), v1.end());
+ exvector::const_iterator ip1 = ip+1;
+ while (ip1 != ipend) {
+ if (is_a<indexed>(*ip1)) {
+ v1 = ex_to<indexed>(*ip).get_dummy_indices(ex_to<indexed>(*ip1));
+ v.insert(v.end(), v1.begin(), v1.end());
+ }
+ ++ip1;
+ }
+ }
+ ++ip;
+ }
+ return v;
+}
+
+ex rename_dummy_indices_uniquely(const ex & a, const ex & b)
+{
+ exvector va = get_all_dummy_indices(a), vb = get_all_dummy_indices(b), common_indices;
+ set_intersection(va.begin(), va.end(), vb.begin(), vb.end(), std::back_insert_iterator<exvector>(common_indices), ex_is_less());
+ if (common_indices.empty()) {
+ return b;
+ } else {
+ exvector new_indices, old_indices;
+ old_indices.reserve(2*common_indices.size());
+ new_indices.reserve(2*common_indices.size());
+ exvector::const_iterator ip = common_indices.begin(), ipend = common_indices.end();
+ while (ip != ipend) {
+ if (is_a<varidx>(*ip)) {
+ varidx mu((new symbol)->setflag(status_flags::dynallocated), ex_to<varidx>(*ip).get_dim(), ex_to<varidx>(*ip).is_covariant());
+ old_indices.push_back(*ip);
+ new_indices.push_back(mu);
+ old_indices.push_back(ex_to<varidx>(*ip).toggle_variance());
+ new_indices.push_back(mu.toggle_variance());
+ } else {
+ old_indices.push_back(*ip);
+ new_indices.push_back(idx((new symbol)->setflag(status_flags::dynallocated), ex_to<varidx>(*ip).get_dim()));
+ }
+ ++ip;
+ }
+ return b.subs(lst(old_indices.begin(), old_indices.end()), lst(new_indices.begin(), new_indices.end()), subs_options::no_pattern);
+ }
+}
+
+ex expand_dummy_sum(const ex & e, bool subs_idx)
+{
+ ex e_expanded = e.expand();
+ 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()) {
+ 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 {
+ return e;
+ }
+}
+
} // namespace GiNaC