*/
#include <stdexcept>
+#include <algorithm>
#include "indexed.h"
#include "idx.h"
#include "ncmul.h"
#include "power.h"
#include "lst.h"
+#include "inifcns.h"
#include "print.h"
#include "archive.h"
#include "utils.h"
return inherited::info(inf);
}
+struct idx_is_not : public binary_function<ex, unsigned, bool> {
+ bool operator() (const ex & e, unsigned inf) const {
+ return !(ex_to_idx(e).get_value().info(inf));
+ }
+};
+
bool indexed::all_index_values_are(unsigned inf) const
{
// No indices? Then no property can be fulfilled
return false;
// Check all indices
- exvector::const_iterator it = seq.begin() + 1, itend = seq.end();
- while (it != itend) {
- GINAC_ASSERT(is_ex_of_type(*it, idx));
- if (!ex_to_idx(*it).get_value().info(inf))
- return false;
- it++;
- }
- return true;
+ return find_if(seq.begin() + 1, seq.end(), bind2nd(idx_is_not(), inf)) == seq.end();
}
int indexed::compare_same_type(const basic & other) const
// reorder index pairs with known symmetry properties, while sort_index_vector()
// always sorts the whole vector.
-/** Bring a vector of indices into a canonic order (don't care about the
- * symmetry of the objects carrying the indices). Dummy indices will lie
- * next to each other after the sorting.
- *
- * @param v Index vector to be sorted */
-static void sort_index_vector(exvector &v)
-{
- // Nothing to sort if less than 2 elements
- if (v.size() < 2)
- return;
-
- // Simple bubble sort algorithm should be sufficient for the small
- // number of indices expected
- exvector::iterator it1 = v.begin(), itend = v.end(), next_to_last_idx = itend - 1;
- while (it1 != next_to_last_idx) {
- exvector::iterator it2 = it1 + 1;
- while (it2 != itend) {
- if (it1->compare(*it2) > 0)
- it1->swap(*it2);
- it2++;
- }
- it1++;
- }
-}
-
/** Bring a vector of indices into a canonic order. This operation only makes
* sense if the object carrying these indices is either symmetric or totally
* antisymmetric with respect to the indices.
if (v1.size() != v2.size())
return false;
- // And also the indices themselves
- exvector::const_iterator ait = v1.begin(), aitend = v1.end(),
- bit = v2.begin(), bitend = v2.end();
- while (ait != aitend) {
- if (!ait->is_equal(*bit))
- return false;
- ait++; bit++;
- }
- return true;
+ return equal(v1.begin(), v1.end(), v2.begin(), ex_is_equal());
}
exvector indexed::get_indices(void) const
return dummy_indices;
}
+bool indexed::has_dummy_index_for(const ex & i) const
+{
+ exvector::const_iterator it = seq.begin() + 1, itend = seq.end();
+ while (it != itend) {
+ if (is_dummy_pair(*it, i))
+ return true;
+ it++;
+ }
+ return false;
+}
+
exvector indexed::get_free_indices(void) const
{
exvector free_indices, dummy_indices;
return basis.get_free_indices();
}
+/** Rename dummy indices in an expression.
+ *
+ * @param e Expression to be worked on
+ * @param local_dummy_indices The set of dummy indices that appear in the
+ * expression "e"
+ * @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)
+{
+ int global_size = global_dummy_indices.size(),
+ local_size = local_dummy_indices.size();
+
+ // Any local dummy indices at all?
+ if (local_size == 0)
+ return e;
+
+ if (global_size < local_size) {
+
+ // More local indices than we encountered before, add the new ones
+ // to the global set
+ 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(ex_is_equal(), *it)) == global_dummy_indices.end()) {
+ global_dummy_indices.push_back(*it);
+ global_size++;
+ remaining--;
+ }
+ it++;
+ }
+ }
+
+ // Replace index symbols in expression
+ GINAC_ASSERT(local_size <= global_size);
+ bool all_equal = true;
+ lst local_syms, global_syms;
+ for (unsigned i=0; i<local_size; i++) {
+ ex loc_sym = local_dummy_indices[i].op(0);
+ ex glob_sym = global_dummy_indices[i].op(0);
+ if (!loc_sym.is_equal(glob_sym)) {
+ all_equal = false;
+ local_syms.append(loc_sym);
+ global_syms.append(glob_sym);
+ }
+ }
+ if (all_equal)
+ return e;
+ else
+ return e.subs(local_syms, global_syms);
+}
+
/** 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, const scalar_products & sp)
+ex simplify_indexed_product(const ex & e, exvector & free_indices, exvector & dummy_indices, const scalar_products & sp)
{
// Remember whether the product was commutative or noncommutative
// (because we chop it into factors and need to reassemble later)
if (!is_ex_of_type(*it1, indexed))
continue;
+ bool first_noncommutative = (it1->return_type() != return_types::commutative);
+
// Indexed factor found, get free indices and look for contraction
// candidates
exvector free1, dummy1;
if (!is_ex_of_type(*it2, indexed))
continue;
+ bool second_noncommutative = (it2->return_type() != return_types::commutative);
+
// Find free indices of second factor and merge them with free
// indices of first factor
exvector un;
}
if (contracted) {
contraction_done:
- if (is_ex_exactly_of_type(*it1, add) || is_ex_exactly_of_type(*it2, add)
+ if (first_noncommutative || second_noncommutative
+ || is_ex_exactly_of_type(*it1, add) || is_ex_exactly_of_type(*it2, add)
|| is_ex_exactly_of_type(*it1, mul) || is_ex_exactly_of_type(*it2, mul)
|| is_ex_exactly_of_type(*it1, ncmul) || is_ex_exactly_of_type(*it2, ncmul)) {
// One of the factors became a sum or product:
// re-expand expression and run again
- ex r = (non_commutative ? ex(ncmul(v)) : ex(mul(v)));
- return simplify_indexed(r, free_indices, sp);
+ // Non-commutative products are always re-expanded to give
+ // simplify_ncmul() the chance to re-order and canonicalize
+ // the product
+ ex r = (non_commutative ? ex(ncmul(v, true)) : ex(mul(v)));
+ return simplify_indexed(r, free_indices, dummy_indices, sp);
}
// Both objects may have new indices now or they might
}
// Find free indices (concatenate them all and call find_free_and_dummy())
- exvector un, dummy_indices;
+ // and all dummy indices that appear
+ exvector un, individual_dummy_indices;
it1 = v.begin(); itend = v.end();
while (it1 != itend) {
- exvector free_indices_of_factor = it1->get_free_indices();
+ exvector free_indices_of_factor;
+ if (is_ex_of_type(*it1, indexed)) {
+ exvector dummy_indices_of_factor;
+ find_free_and_dummy(ex_to_indexed(*it1).seq.begin() + 1, ex_to_indexed(*it1).seq.end(), free_indices_of_factor, dummy_indices_of_factor);
+ individual_dummy_indices.insert(individual_dummy_indices.end(), dummy_indices_of_factor.begin(), dummy_indices_of_factor.end());
+ } else
+ free_indices_of_factor = it1->get_free_indices();
un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
it1++;
}
- find_free_and_dummy(un, free_indices, dummy_indices);
+ exvector local_dummy_indices;
+ find_free_and_dummy(un, free_indices, local_dummy_indices);
+ local_dummy_indices.insert(local_dummy_indices.end(), individual_dummy_indices.begin(), individual_dummy_indices.end());
ex r;
if (something_changed)
- r = non_commutative ? ex(ncmul(v)) : ex(mul(v));
+ r = non_commutative ? ex(ncmul(v, true)) : ex(mul(v));
else
r = e;
+ // Dummy index renaming
+ r = rename_dummy_indices(r, dummy_indices, local_dummy_indices);
+
// Product of indexed object with a scalar?
if (is_ex_exactly_of_type(r, mul) && r.nops() == 2
&& is_ex_exactly_of_type(r.op(1), numeric) && is_ex_of_type(r.op(0), indexed))
}
/** Simplify indexed expression, return list of free indices. */
-ex simplify_indexed(const ex & e, exvector & free_indices, const scalar_products & sp)
+ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indices, const scalar_products & sp)
{
// Expand the expression
ex e_expanded = e.expand();
// Simplification of single indexed object: just find the free indices
+ // and perform dummy index renaming
if (is_ex_of_type(e_expanded, indexed)) {
const indexed &i = ex_to_indexed(e_expanded);
- exvector dummy_indices;
- find_free_and_dummy(i.seq.begin() + 1, i.seq.end(), free_indices, dummy_indices);
- return e_expanded;
+ exvector local_dummy_indices;
+ find_free_and_dummy(i.seq.begin() + 1, i.seq.end(), free_indices, local_dummy_indices);
+ return rename_dummy_indices(e_expanded, dummy_indices, local_dummy_indices);
}
// Simplification of sum = sum of simplifications, check consistency of
for (unsigned i=0; i<e_expanded.nops(); i++) {
exvector free_indices_of_term;
- ex term = simplify_indexed(e_expanded.op(i), free_indices_of_term, sp);
+ ex term = simplify_indexed(e_expanded.op(i), free_indices_of_term, dummy_indices, sp);
if (!term.is_zero()) {
if (first) {
free_indices = free_indices_of_term;
if (is_ex_exactly_of_type(e_expanded, mul)
|| is_ex_exactly_of_type(e_expanded, ncmul)
|| (is_ex_exactly_of_type(e_expanded, power) && is_ex_of_type(e_expanded.op(0), indexed) && e_expanded.op(1).is_equal(_ex2())))
- return simplify_indexed_product(e_expanded, free_indices, sp);
+ return simplify_indexed_product(e_expanded, free_indices, dummy_indices, sp);
// Cannot do anything
free_indices.clear();
ex simplify_indexed(const ex & e)
{
- exvector free_indices;
+ exvector free_indices, dummy_indices;
scalar_products sp;
- return simplify_indexed(e, free_indices, sp);
+ return simplify_indexed(e, free_indices, dummy_indices, sp);
}
ex simplify_indexed(const ex & e, const scalar_products & sp)
{
- exvector free_indices;
- return simplify_indexed(e, free_indices, sp);
+ exvector free_indices, dummy_indices;
+ return simplify_indexed(e, free_indices, dummy_indices, sp);
+}
+
+ex symmetrize(const ex & e)
+{
+ return symmetrize(e, e.get_free_indices());
+}
+
+ex antisymmetrize(const ex & e)
+{
+ return antisymmetrize(e, e.get_free_indices());
}
//////////
spm[make_key(v1, v2)] = sp;
}
+void scalar_products::add_vectors(const lst & l)
+{
+ // Add all possible pairs of products
+ unsigned num = l.nops();
+ for (unsigned i=0; i<num; i++) {
+ ex a = l.op(i);
+ for (unsigned j=0; j<num; j++) {
+ ex b = l.op(j);
+ add(a, b, a*b);
+ }
+ }
+}
+
void scalar_products::clear(void)
{
spm.clear();