]> www.ginac.de Git - ginac.git/blob - ginac/indexed.cpp
* Now two different simplification paths in clifford::contract_with().
[ginac.git] / ginac / indexed.cpp
1 /** @file indexed.cpp
2  *
3  *  Implementation of GiNaC's indexed expressions. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2005 Johannes Gutenberg University Mainz, Germany
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #include <iostream>
24 #include <sstream>
25 #include <stdexcept>
26
27 #include "indexed.h"
28 #include "idx.h"
29 #include "add.h"
30 #include "mul.h"
31 #include "ncmul.h"
32 #include "power.h"
33 #include "relational.h"
34 #include "symmetry.h"
35 #include "operators.h"
36 #include "lst.h"
37 #include "archive.h"
38 #include "symbol.h"
39 #include "utils.h"
40 #include "integral.h"
41 #include "matrix.h"
42
43 namespace GiNaC {
44
45 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(indexed, exprseq,
46   print_func<print_context>(&indexed::do_print).
47   print_func<print_latex>(&indexed::do_print_latex).
48   print_func<print_tree>(&indexed::do_print_tree))
49
50 //////////
51 // default constructor
52 //////////
53
54 indexed::indexed() : symtree(not_symmetric())
55 {
56         tinfo_key = TINFO_indexed;
57 }
58
59 //////////
60 // other constructors
61 //////////
62
63 indexed::indexed(const ex & b) : inherited(b), symtree(not_symmetric())
64 {
65         tinfo_key = TINFO_indexed;
66         validate();
67 }
68
69 indexed::indexed(const ex & b, const ex & i1) : inherited(b, i1), symtree(not_symmetric())
70 {
71         tinfo_key = TINFO_indexed;
72         validate();
73 }
74
75 indexed::indexed(const ex & b, const ex & i1, const ex & i2) : inherited(b, i1, i2), symtree(not_symmetric())
76 {
77         tinfo_key = TINFO_indexed;
78         validate();
79 }
80
81 indexed::indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3) : inherited(b, i1, i2, i3), symtree(not_symmetric())
82 {
83         tinfo_key = TINFO_indexed;
84         validate();
85 }
86
87 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())
88 {
89         tinfo_key = TINFO_indexed;
90         validate();
91 }
92
93 indexed::indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2) : inherited(b, i1, i2), symtree(symm)
94 {
95         tinfo_key = TINFO_indexed;
96         validate();
97 }
98
99 indexed::indexed(const ex & b, const symmetry & symm, const ex & i1, const ex & i2, const ex & i3) : inherited(b, i1, i2, i3), symtree(symm)
100 {
101         tinfo_key = TINFO_indexed;
102         validate();
103 }
104
105 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)
106 {
107         tinfo_key = TINFO_indexed;
108         validate();
109 }
110
111 indexed::indexed(const ex & b, const exvector & v) : inherited(b), symtree(not_symmetric())
112 {
113         seq.insert(seq.end(), v.begin(), v.end());
114         tinfo_key = TINFO_indexed;
115         validate();
116 }
117
118 indexed::indexed(const ex & b, const symmetry & symm, const exvector & v) : inherited(b), symtree(symm)
119 {
120         seq.insert(seq.end(), v.begin(), v.end());
121         tinfo_key = TINFO_indexed;
122         validate();
123 }
124
125 indexed::indexed(const symmetry & symm, const exprseq & es) : inherited(es), symtree(symm)
126 {
127         tinfo_key = TINFO_indexed;
128 }
129
130 indexed::indexed(const symmetry & symm, const exvector & v, bool discardable) : inherited(v, discardable), symtree(symm)
131 {
132         tinfo_key = TINFO_indexed;
133 }
134
135 indexed::indexed(const symmetry & symm, std::auto_ptr<exvector> vp) : inherited(vp), symtree(symm)
136 {
137         tinfo_key = TINFO_indexed;
138 }
139
140 //////////
141 // archiving
142 //////////
143
144 indexed::indexed(const archive_node &n, lst &sym_lst) : inherited(n, sym_lst)
145 {
146         if (!n.find_ex("symmetry", symtree, sym_lst)) {
147                 // GiNaC versions <= 0.9.0 had an unsigned "symmetry" property
148                 unsigned symm = 0;
149                 n.find_unsigned("symmetry", symm);
150                 switch (symm) {
151                         case 1:
152                                 symtree = sy_symm();
153                                 break;
154                         case 2:
155                                 symtree = sy_anti();
156                                 break;
157                         default:
158                                 symtree = not_symmetric();
159                                 break;
160                 }
161                 const_cast<symmetry &>(ex_to<symmetry>(symtree)).validate(seq.size() - 1);
162         }
163 }
164
165 void indexed::archive(archive_node &n) const
166 {
167         inherited::archive(n);
168         n.add_ex("symmetry", symtree);
169 }
170
171 DEFAULT_UNARCHIVE(indexed)
172
173 //////////
174 // functions overriding virtual functions from base classes
175 //////////
176
177 void indexed::printindices(const print_context & c, unsigned level) const
178 {
179         if (seq.size() > 1) {
180
181                 exvector::const_iterator it=seq.begin() + 1, itend = seq.end();
182
183                 if (is_a<print_latex>(c)) {
184
185                         // TeX output: group by variance
186                         bool first = true;
187                         bool covariant = true;
188
189                         while (it != itend) {
190                                 bool cur_covariant = (is_a<varidx>(*it) ? ex_to<varidx>(*it).is_covariant() : true);
191                                 if (first || cur_covariant != covariant) { // Variance changed
192                                         // The empty {} prevents indices from ending up on top of each other
193                                         if (!first)
194                                                 c.s << "}{}";
195                                         covariant = cur_covariant;
196                                         if (covariant)
197                                                 c.s << "_{";
198                                         else
199                                                 c.s << "^{";
200                                 }
201                                 it->print(c, level);
202                                 c.s << " ";
203                                 first = false;
204                                 it++;
205                         }
206                         c.s << "}";
207
208                 } else {
209
210                         // Ordinary output
211                         while (it != itend) {
212                                 it->print(c, level);
213                                 it++;
214                         }
215                 }
216         }
217 }
218
219 void indexed::print_indexed(const print_context & c, const char *openbrace, const char *closebrace, unsigned level) const
220 {
221         if (precedence() <= level)
222                 c.s << openbrace << '(';
223         c.s << openbrace;
224         seq[0].print(c, precedence());
225         c.s << closebrace;
226         printindices(c, level);
227         if (precedence() <= level)
228                 c.s << ')' << closebrace;
229 }
230
231 void indexed::do_print(const print_context & c, unsigned level) const
232 {
233         print_indexed(c, "", "", level);
234 }
235
236 void indexed::do_print_latex(const print_latex & c, unsigned level) const
237 {
238         print_indexed(c, "{", "}", level);
239 }
240
241 void indexed::do_print_tree(const print_tree & c, unsigned level) const
242 {
243         c.s << std::string(level, ' ') << class_name() << " @" << this
244             << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
245             << ", " << seq.size()-1 << " indices"
246             << ", symmetry=" << symtree << std::endl;
247         seq[0].print(c, level + c.delta_indent);
248         printindices(c, level + c.delta_indent);
249 }
250
251 bool indexed::info(unsigned inf) const
252 {
253         if (inf == info_flags::indexed) return true;
254         if (inf == info_flags::has_indices) return seq.size() > 1;
255         return inherited::info(inf);
256 }
257
258 struct idx_is_not : public std::binary_function<ex, unsigned, bool> {
259         bool operator() (const ex & e, unsigned inf) const {
260                 return !(ex_to<idx>(e).get_value().info(inf));
261         }
262 };
263
264 bool indexed::all_index_values_are(unsigned inf) const
265 {
266         // No indices? Then no property can be fulfilled
267         if (seq.size() < 2)
268                 return false;
269
270         // Check all indices
271         return find_if(seq.begin() + 1, seq.end(), bind2nd(idx_is_not(), inf)) == seq.end();
272 }
273
274 int indexed::compare_same_type(const basic & other) const
275 {
276         GINAC_ASSERT(is_a<indexed>(other));
277         return inherited::compare_same_type(other);
278 }
279
280 ex indexed::eval(int level) const
281 {
282         // First evaluate children, then we will end up here again
283         if (level > 1)
284                 return indexed(ex_to<symmetry>(symtree), evalchildren(level));
285
286         const ex &base = seq[0];
287
288         // If the base object is 0, the whole object is 0
289         if (base.is_zero())
290                 return _ex0;
291
292         // If the base object is a product, pull out the numeric factor
293         if (is_exactly_a<mul>(base) && is_exactly_a<numeric>(base.op(base.nops() - 1))) {
294                 exvector v(seq);
295                 ex f = ex_to<numeric>(base.op(base.nops() - 1));
296                 v[0] = seq[0] / f;
297                 return f * thiscontainer(v);
298         }
299
300         // Canonicalize indices according to the symmetry properties
301         if (seq.size() > 2) {
302                 exvector v = seq;
303                 GINAC_ASSERT(is_exactly_a<symmetry>(symtree));
304                 int sig = canonicalize(v.begin() + 1, ex_to<symmetry>(symtree));
305                 if (sig != INT_MAX) {
306                         // Something has changed while sorting indices, more evaluations later
307                         if (sig == 0)
308                                 return _ex0;
309                         return ex(sig) * thiscontainer(v);
310                 }
311         }
312
313         // Let the class of the base object perform additional evaluations
314         return ex_to<basic>(base).eval_indexed(*this);
315 }
316
317 ex indexed::thiscontainer(const exvector & v) const
318 {
319         return indexed(ex_to<symmetry>(symtree), v);
320 }
321
322 ex indexed::thiscontainer(std::auto_ptr<exvector> vp) const
323 {
324         return indexed(ex_to<symmetry>(symtree), vp);
325 }
326
327 ex indexed::expand(unsigned options) const
328 {
329         GINAC_ASSERT(seq.size() > 0);
330
331         if (options & expand_options::expand_indexed) {
332                 ex newbase = seq[0].expand(options);
333                 if (is_exactly_a<add>(newbase)) {
334                         ex sum = _ex0;
335                         for (size_t i=0; i<newbase.nops(); i++) {
336                                 exvector s = seq;
337                                 s[0] = newbase.op(i);
338                                 sum += thiscontainer(s).expand(options);
339                         }
340                         return sum;
341                 }
342                 if (!are_ex_trivially_equal(newbase, seq[0])) {
343                         exvector s = seq;
344                         s[0] = newbase;
345                         return ex_to<indexed>(thiscontainer(s)).inherited::expand(options);
346                 }
347         }
348         return inherited::expand(options);
349 }
350
351 //////////
352 // virtual functions which can be overridden by derived classes
353 //////////
354
355 // none
356
357 //////////
358 // non-virtual functions in this class
359 //////////
360
361 /** Check whether all indices are of class idx and validate the symmetry
362  *  tree. This function is used internally to make sure that all constructed
363  *  indexed objects really carry indices and not some other classes. */
364 void indexed::validate() const
365 {
366         GINAC_ASSERT(seq.size() > 0);
367         exvector::const_iterator it = seq.begin() + 1, itend = seq.end();
368         while (it != itend) {
369                 if (!is_a<idx>(*it))
370                         throw(std::invalid_argument("indices of indexed object must be of type idx"));
371                 it++;
372         }
373
374         if (!symtree.is_zero()) {
375                 if (!is_exactly_a<symmetry>(symtree))
376                         throw(std::invalid_argument("symmetry of indexed object must be of type symmetry"));
377                 const_cast<symmetry &>(ex_to<symmetry>(symtree)).validate(seq.size() - 1);
378         }
379 }
380
381 /** Implementation of ex::diff() for an indexed object always returns 0.
382  *
383  *  @see ex::diff */
384 ex indexed::derivative(const symbol & s) const
385 {
386         return _ex0;
387 }
388
389 //////////
390 // global functions
391 //////////
392
393 struct idx_is_equal_ignore_dim : public std::binary_function<ex, ex, bool> {
394         bool operator() (const ex &lh, const ex &rh) const
395         {
396                 if (lh.is_equal(rh))
397                         return true;
398                 else
399                         try {
400                                 // Replacing the dimension might cause an error (e.g. with
401                                 // index classes that only work in a fixed number of dimensions)
402                                 return lh.is_equal(ex_to<idx>(rh).replace_dim(ex_to<idx>(lh).get_dim()));
403                         } catch (...) {
404                                 return false;
405                         }
406         }
407 };
408
409 /** Check whether two sorted index vectors are consistent (i.e. equal). */
410 static bool indices_consistent(const exvector & v1, const exvector & v2)
411 {
412         // Number of indices must be the same
413         if (v1.size() != v2.size())
414                 return false;
415
416         return equal(v1.begin(), v1.end(), v2.begin(), idx_is_equal_ignore_dim());
417 }
418
419 exvector indexed::get_indices() const
420 {
421         GINAC_ASSERT(seq.size() >= 1);
422         return exvector(seq.begin() + 1, seq.end());
423 }
424
425 exvector indexed::get_dummy_indices() const
426 {
427         exvector free_indices, dummy_indices;
428         find_free_and_dummy(seq.begin() + 1, seq.end(), free_indices, dummy_indices);
429         return dummy_indices;
430 }
431
432 exvector indexed::get_dummy_indices(const indexed & other) const
433 {
434         exvector indices = get_free_indices();
435         exvector other_indices = other.get_free_indices();
436         indices.insert(indices.end(), other_indices.begin(), other_indices.end());
437         exvector dummy_indices;
438         find_dummy_indices(indices, dummy_indices);
439         return dummy_indices;
440 }
441
442 bool indexed::has_dummy_index_for(const ex & i) const
443 {
444         exvector::const_iterator it = seq.begin() + 1, itend = seq.end();
445         while (it != itend) {
446                 if (is_dummy_pair(*it, i))
447                         return true;
448                 it++;
449         }
450         return false;
451 }
452
453 exvector indexed::get_free_indices() const
454 {
455         exvector free_indices, dummy_indices;
456         find_free_and_dummy(seq.begin() + 1, seq.end(), free_indices, dummy_indices);
457         return free_indices;
458 }
459
460 exvector add::get_free_indices() const
461 {
462         exvector free_indices;
463         for (size_t i=0; i<nops(); i++) {
464                 if (i == 0)
465                         free_indices = op(i).get_free_indices();
466                 else {
467                         exvector free_indices_of_term = op(i).get_free_indices();
468                         if (!indices_consistent(free_indices, free_indices_of_term))
469                                 throw (std::runtime_error("add::get_free_indices: inconsistent indices in sum"));
470                 }
471         }
472         return free_indices;
473 }
474
475 exvector mul::get_free_indices() const
476 {
477         // Concatenate free indices of all factors
478         exvector un;
479         for (size_t i=0; i<nops(); i++) {
480                 exvector free_indices_of_factor = op(i).get_free_indices();
481                 un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
482         }
483
484         // And remove the dummy indices
485         exvector free_indices, dummy_indices;
486         find_free_and_dummy(un, free_indices, dummy_indices);
487         return free_indices;
488 }
489
490 exvector ncmul::get_free_indices() const
491 {
492         // Concatenate free indices of all factors
493         exvector un;
494         for (size_t i=0; i<nops(); i++) {
495                 exvector free_indices_of_factor = op(i).get_free_indices();
496                 un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
497         }
498
499         // And remove the dummy indices
500         exvector free_indices, dummy_indices;
501         find_free_and_dummy(un, free_indices, dummy_indices);
502         return free_indices;
503 }
504
505 struct is_summation_idx : public std::unary_function<ex, bool> {
506         bool operator()(const ex & e)
507         {
508                 return is_dummy_pair(e, e);
509         }
510 };
511
512 exvector power::get_free_indices() const
513 {
514         // Get free indices of basis
515         exvector basis_indices = basis.get_free_indices();
516
517         if (exponent.info(info_flags::even)) {
518                 // If the exponent is an even number, then any "free" index that
519                 // forms a dummy pair with itself is actually a summation index
520                 exvector really_free;
521                 std::remove_copy_if(basis_indices.begin(), basis_indices.end(),
522                                     std::back_inserter(really_free), is_summation_idx());
523                 return really_free;
524         } else
525                 return basis_indices;
526 }
527
528 exvector integral::get_free_indices() const
529 {
530         if (a.get_free_indices().size() || b.get_free_indices().size())
531                 throw (std::runtime_error("integral::get_free_indices: boundary values should not have free indices"));
532         return f.get_free_indices();
533 }
534
535 /** Rename dummy indices in an expression.
536  *
537  *  @param e Expression to work on
538  *  @param local_dummy_indices The set of dummy indices that appear in the
539  *    expression "e"
540  *  @param global_dummy_indices The set of dummy indices that have appeared
541  *    before and which we would like to use in "e", too. This gets updated
542  *    by the function */
543 static ex rename_dummy_indices(const ex & e, exvector & global_dummy_indices, exvector & local_dummy_indices)
544 {
545         size_t global_size = global_dummy_indices.size(),
546                local_size = local_dummy_indices.size();
547
548         // Any local dummy indices at all?
549         if (local_size == 0)
550                 return e;
551
552         if (global_size < local_size) {
553
554                 // More local indices than we encountered before, add the new ones
555                 // to the global set
556                 size_t old_global_size = global_size;
557                 int remaining = local_size - global_size;
558                 exvector::const_iterator it = local_dummy_indices.begin(), itend = local_dummy_indices.end();
559                 while (it != itend && remaining > 0) {
560                         if (find_if(global_dummy_indices.begin(), global_dummy_indices.end(), bind2nd(op0_is_equal(), *it)) == global_dummy_indices.end()) {
561                                 global_dummy_indices.push_back(*it);
562                                 global_size++;
563                                 remaining--;
564                         }
565                         it++;
566                 }
567
568                 // If this is the first set of local indices, do nothing
569                 if (old_global_size == 0)
570                         return e;
571         }
572         GINAC_ASSERT(local_size <= global_size);
573
574         // Construct vectors of index symbols
575         exvector local_syms, global_syms;
576         local_syms.reserve(local_size);
577         global_syms.reserve(local_size);
578         for (size_t i=0; i<local_size; i++)
579                 local_syms.push_back(local_dummy_indices[i].op(0));
580         shaker_sort(local_syms.begin(), local_syms.end(), ex_is_less(), ex_swap());
581         for (size_t i=0; i<local_size; i++) // don't use more global symbols than necessary
582                 global_syms.push_back(global_dummy_indices[i].op(0));
583         shaker_sort(global_syms.begin(), global_syms.end(), ex_is_less(), ex_swap());
584
585         // Remove common indices
586         exvector local_uniq, global_uniq;
587         set_difference(local_syms.begin(), local_syms.end(), global_syms.begin(), global_syms.end(), std::back_insert_iterator<exvector>(local_uniq), ex_is_less());
588         set_difference(global_syms.begin(), global_syms.end(), local_syms.begin(), local_syms.end(), std::back_insert_iterator<exvector>(global_uniq), ex_is_less());
589
590         // Replace remaining non-common local index symbols by global ones
591         if (local_uniq.empty())
592                 return e;
593         else {
594                 while (global_uniq.size() > local_uniq.size())
595                         global_uniq.pop_back();
596                 return e.subs(lst(local_uniq.begin(), local_uniq.end()), lst(global_uniq.begin(), global_uniq.end()), subs_options::no_pattern);
597         }
598 }
599
600 /** Given a set of indices, extract those of class varidx. */
601 static void find_variant_indices(const exvector & v, exvector & variant_indices)
602 {
603         exvector::const_iterator it1, itend;
604         for (it1 = v.begin(), itend = v.end(); it1 != itend; ++it1) {
605                 if (is_exactly_a<varidx>(*it1))
606                         variant_indices.push_back(*it1);
607         }
608 }
609
610 /** Raise/lower dummy indices in a single indexed objects to canonicalize their
611  *  variance.
612  *
613  *  @param e Object to work on
614  *  @param variant_dummy_indices The set of indices that might need repositioning (will be changed by this function)
615  *  @param moved_indices The set of indices that have been repositioned (will be changed by this function)
616  *  @return true if 'e' was changed */
617 bool reposition_dummy_indices(ex & e, exvector & variant_dummy_indices, exvector & moved_indices)
618 {
619         bool something_changed = false;
620
621         // If a dummy index is encountered for the first time in the
622         // product, pull it up, otherwise, pull it down
623         exvector::const_iterator it2, it2start, it2end;
624         for (it2start = ex_to<indexed>(e).seq.begin(), it2end = ex_to<indexed>(e).seq.end(), it2 = it2start + 1; it2 != it2end; ++it2) {
625                 if (!is_exactly_a<varidx>(*it2))
626                         continue;
627
628                 exvector::iterator vit, vitend;
629                 for (vit = variant_dummy_indices.begin(), vitend = variant_dummy_indices.end(); vit != vitend; ++vit) {
630                         if (it2->op(0).is_equal(vit->op(0))) {
631                                 if (ex_to<varidx>(*it2).is_covariant()) {
632                                         e = e.subs(lst(
633                                                 *it2 == ex_to<varidx>(*it2).toggle_variance(),
634                                                 ex_to<varidx>(*it2).toggle_variance() == *it2
635                                         ), subs_options::no_pattern);
636                                         something_changed = true;
637                                         it2 = ex_to<indexed>(e).seq.begin() + (it2 - it2start);
638                                         it2start = ex_to<indexed>(e).seq.begin();
639                                         it2end = ex_to<indexed>(e).seq.end();
640                                 }
641                                 moved_indices.push_back(*vit);
642                                 variant_dummy_indices.erase(vit);
643                                 goto next_index;
644                         }
645                 }
646
647                 for (vit = moved_indices.begin(), vitend = moved_indices.end(); vit != vitend; ++vit) {
648                         if (it2->op(0).is_equal(vit->op(0))) {
649                                 if (ex_to<varidx>(*it2).is_contravariant()) {
650                                         e = e.subs(*it2 == ex_to<varidx>(*it2).toggle_variance(), subs_options::no_pattern);
651                                         something_changed = true;
652                                         it2 = ex_to<indexed>(e).seq.begin() + (it2 - it2start);
653                                         it2start = ex_to<indexed>(e).seq.begin();
654                                         it2end = ex_to<indexed>(e).seq.end();
655                                 }
656                                 goto next_index;
657                         }
658                 }
659
660 next_index: ;
661         }
662
663         return something_changed;
664 }
665
666 /* Ordering that only compares the base expressions of indexed objects. */
667 struct ex_base_is_less : public std::binary_function<ex, ex, bool> {
668         bool operator() (const ex &lh, const ex &rh) const
669         {
670                 return (is_a<indexed>(lh) ? lh.op(0) : lh).compare(is_a<indexed>(rh) ? rh.op(0) : rh) < 0;
671         }
672 };
673
674 /* An auxiliary function used by simplify_indexed() and expand_dummy_sum() 
675  * It returns an exvector of factors from the supplied product */
676 static void product_to_exvector(const ex & e, exvector & v, bool & non_commutative)
677 {
678         // Remember whether the product was commutative or noncommutative
679         // (because we chop it into factors and need to reassemble later)
680         non_commutative = is_exactly_a<ncmul>(e);
681
682         // Collect factors in an exvector, store squares twice
683         v.reserve(e.nops() * 2);
684
685         if (is_exactly_a<power>(e)) {
686                 // We only get called for simple squares, split a^2 -> a*a
687                 GINAC_ASSERT(e.op(1).is_equal(_ex2));
688                 v.push_back(e.op(0));
689                 v.push_back(e.op(0));
690         } else {
691                 for (size_t i=0; i<e.nops(); i++) {
692                         ex f = e.op(i);
693                         if (is_exactly_a<power>(f) && f.op(1).is_equal(_ex2)) {
694                                 v.push_back(f.op(0));
695                                 v.push_back(f.op(0));
696                         } else if (is_exactly_a<ncmul>(f)) {
697                                 // Noncommutative factor found, split it as well
698                                 non_commutative = true; // everything becomes noncommutative, ncmul will sort out the commutative factors later
699                                 for (size_t j=0; j<f.nops(); j++)
700                                         v.push_back(f.op(j));
701                         } else
702                                 v.push_back(f);
703                 }
704         }
705 }
706
707 /** Simplify product of indexed expressions (commutative, noncommutative and
708  *  simple squares), return list of free indices. */
709 ex simplify_indexed_product(const ex & e, exvector & free_indices, exvector & dummy_indices, const scalar_products & sp)
710 {
711         // Collect factors in an exvector
712         exvector v;
713
714         // Remember whether the product was commutative or noncommutative
715         // (because we chop it into factors and need to reassemble later)
716         bool non_commutative;
717         product_to_exvector(e, v, non_commutative);
718
719         // Perform contractions
720         bool something_changed = false;
721         GINAC_ASSERT(v.size() > 1);
722         exvector::iterator it1, itend = v.end(), next_to_last = itend - 1;
723         for (it1 = v.begin(); it1 != next_to_last; it1++) {
724
725 try_again:
726                 if (!is_a<indexed>(*it1))
727                         continue;
728
729                 bool first_noncommutative = (it1->return_type() != return_types::commutative);
730
731                 // Indexed factor found, get free indices and look for contraction
732                 // candidates
733                 exvector free1, dummy1;
734                 find_free_and_dummy(ex_to<indexed>(*it1).seq.begin() + 1, ex_to<indexed>(*it1).seq.end(), free1, dummy1);
735
736                 exvector::iterator it2;
737                 for (it2 = it1 + 1; it2 != itend; it2++) {
738
739                         if (!is_a<indexed>(*it2))
740                                 continue;
741
742                         bool second_noncommutative = (it2->return_type() != return_types::commutative);
743
744                         // Find free indices of second factor and merge them with free
745                         // indices of first factor
746                         exvector un;
747                         find_free_and_dummy(ex_to<indexed>(*it2).seq.begin() + 1, ex_to<indexed>(*it2).seq.end(), un, dummy1);
748                         un.insert(un.end(), free1.begin(), free1.end());
749
750                         // Check whether the two factors share dummy indices
751                         exvector free, dummy;
752                         find_free_and_dummy(un, free, dummy);
753                         size_t num_dummies = dummy.size();
754                         if (num_dummies == 0)
755                                 continue;
756
757                         // At least one dummy index, is it a defined scalar product?
758                         bool contracted = false;
759                         if (free.empty()) {
760
761                                 // Find minimal dimension of all indices of both factors
762                                 exvector::const_iterator dit = ex_to<indexed>(*it1).seq.begin() + 1, ditend = ex_to<indexed>(*it1).seq.end();
763                                 ex dim = ex_to<idx>(*dit).get_dim();
764                                 ++dit;
765                                 for (; dit != ditend; ++dit) {
766                                         dim = minimal_dim(dim, ex_to<idx>(*dit).get_dim());
767                                 }
768                                 dit = ex_to<indexed>(*it2).seq.begin() + 1;
769                                 ditend = ex_to<indexed>(*it2).seq.end();
770                                 for (; dit != ditend; ++dit) {
771                                         dim = minimal_dim(dim, ex_to<idx>(*dit).get_dim());
772                                 }
773
774                                 // User-defined scalar product?
775                                 if (sp.is_defined(*it1, *it2, dim)) {
776
777                                         // Yes, substitute it
778                                         *it1 = sp.evaluate(*it1, *it2, dim);
779                                         *it2 = _ex1;
780                                         goto contraction_done;
781                                 }
782                         }
783
784                         // Try to contract the first one with the second one
785                         contracted = ex_to<basic>(it1->op(0)).contract_with(it1, it2, v);
786                         if (!contracted) {
787
788                                 // That didn't work; maybe the second object knows how to
789                                 // contract itself with the first one
790                                 contracted = ex_to<basic>(it2->op(0)).contract_with(it2, it1, v);
791                         }
792                         if (contracted) {
793 contraction_done:
794                                 if (first_noncommutative || second_noncommutative
795                                  || is_exactly_a<add>(*it1) || is_exactly_a<add>(*it2)
796                                  || is_exactly_a<mul>(*it1) || is_exactly_a<mul>(*it2)
797                                  || is_exactly_a<ncmul>(*it1) || is_exactly_a<ncmul>(*it2)) {
798
799                                         // One of the factors became a sum or product:
800                                         // re-expand expression and run again
801                                         // Non-commutative products are always re-expanded to give
802                                         // eval_ncmul() the chance to re-order and canonicalize
803                                         // the product
804                                         ex r = (non_commutative ? ex(ncmul(v, true)) : ex(mul(v)));
805                                         return simplify_indexed(r, free_indices, dummy_indices, sp);
806                                 }
807
808                                 // Both objects may have new indices now or they might
809                                 // even not be indexed objects any more, so we have to
810                                 // start over
811                                 something_changed = true;
812                                 goto try_again;
813                         }
814                 }
815         }
816
817         // Find free indices (concatenate them all and call find_free_and_dummy())
818         // and all dummy indices that appear
819         exvector un, individual_dummy_indices;
820         for (it1 = v.begin(), itend = v.end(); it1 != itend; ++it1) {
821                 exvector free_indices_of_factor;
822                 if (is_a<indexed>(*it1)) {
823                         exvector dummy_indices_of_factor;
824                         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);
825                         individual_dummy_indices.insert(individual_dummy_indices.end(), dummy_indices_of_factor.begin(), dummy_indices_of_factor.end());
826                 } else
827                         free_indices_of_factor = it1->get_free_indices();
828                 un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
829         }
830         exvector local_dummy_indices;
831         find_free_and_dummy(un, free_indices, local_dummy_indices);
832         local_dummy_indices.insert(local_dummy_indices.end(), individual_dummy_indices.begin(), individual_dummy_indices.end());
833
834         // Filter out the dummy indices with variance
835         exvector variant_dummy_indices;
836         find_variant_indices(local_dummy_indices, variant_dummy_indices);
837
838         // Any indices with variance present at all?
839         if (!variant_dummy_indices.empty()) {
840
841                 // Yes, bring the product into a canonical order that only depends on
842                 // the base expressions of indexed objects
843                 if (!non_commutative)
844                         std::sort(v.begin(), v.end(), ex_base_is_less());
845
846                 exvector moved_indices;
847
848                 // Iterate over all indexed objects in the product
849                 for (it1 = v.begin(), itend = v.end(); it1 != itend; ++it1) {
850                         if (!is_a<indexed>(*it1))
851                                 continue;
852
853                         if (reposition_dummy_indices(*it1, variant_dummy_indices, moved_indices))
854                                 something_changed = true;
855                 }
856         }
857
858         ex r;
859         if (something_changed)
860                 r = non_commutative ? ex(ncmul(v, true)) : ex(mul(v));
861         else
862                 r = e;
863
864         // The result should be symmetric with respect to exchange of dummy
865         // indices, so if the symmetrization vanishes, the whole expression is
866         // zero. This detects things like eps.i.j.k * p.j * p.k = 0.
867         if (local_dummy_indices.size() >= 2) {
868                 exvector dummy_syms;
869                 dummy_syms.reserve(local_dummy_indices.size());
870                 for (exvector::const_iterator it = local_dummy_indices.begin(); it != local_dummy_indices.end(); ++it)
871                         dummy_syms.push_back(it->op(0));
872                 if (symmetrize(r, dummy_syms).is_zero()) {
873                         free_indices.clear();
874                         return _ex0;
875                 }
876         }
877
878         // Dummy index renaming
879         r = rename_dummy_indices(r, dummy_indices, local_dummy_indices);
880
881         // Product of indexed object with a scalar?
882         if (is_exactly_a<mul>(r) && r.nops() == 2
883          && is_exactly_a<numeric>(r.op(1)) && is_a<indexed>(r.op(0)))
884                 return ex_to<basic>(r.op(0).op(0)).scalar_mul_indexed(r.op(0), ex_to<numeric>(r.op(1)));
885         else
886                 return r;
887 }
888
889 /** This structure stores the original and symmetrized versions of terms
890  *  obtained during the simplification of sums. */
891 class terminfo {
892 public:
893         terminfo(const ex & orig_, const ex & symm_) : orig(orig_), symm(symm_) {}
894
895         ex orig; /**< original term */
896         ex symm; /**< symmtrized term */
897 };
898
899 class terminfo_is_less {
900 public:
901         bool operator() (const terminfo & ti1, const terminfo & ti2) const
902         {
903                 return (ti1.symm.compare(ti2.symm) < 0);
904         }
905 };
906
907 /** This structure stores the individual symmetrized terms obtained during
908  *  the simplification of sums. */
909 class symminfo {
910 public:
911         symminfo() : num(0) {}
912
913         symminfo(const ex & symmterm_, const ex & orig_, size_t num_) : orig(orig_), num(num_)
914         {
915                 if (is_exactly_a<mul>(symmterm_) && is_exactly_a<numeric>(symmterm_.op(symmterm_.nops()-1))) {
916                         coeff = symmterm_.op(symmterm_.nops()-1);
917                         symmterm = symmterm_ / coeff;
918                 } else {
919                         coeff = 1;
920                         symmterm = symmterm_;
921                 }
922         }
923
924         ex symmterm;  /**< symmetrized term */
925         ex coeff;     /**< coefficient of symmetrized term */
926         ex orig;      /**< original term */
927         size_t num; /**< how many symmetrized terms resulted from the original term */
928 };
929
930 class symminfo_is_less_by_symmterm {
931 public:
932         bool operator() (const symminfo & si1, const symminfo & si2) const
933         {
934                 return (si1.symmterm.compare(si2.symmterm) < 0);
935         }
936 };
937
938 class symminfo_is_less_by_orig {
939 public:
940         bool operator() (const symminfo & si1, const symminfo & si2) const
941         {
942                 return (si1.orig.compare(si2.orig) < 0);
943         }
944 };
945
946 /** Simplify indexed expression, return list of free indices. */
947 ex simplify_indexed(const ex & e, exvector & free_indices, exvector & dummy_indices, const scalar_products & sp)
948 {
949         // Expand the expression
950         ex e_expanded = e.expand();
951
952         // Simplification of single indexed object: just find the free indices
953         // and perform dummy index renaming/repositioning
954         if (is_a<indexed>(e_expanded)) {
955
956                 // Find the dummy indices
957                 const indexed &i = ex_to<indexed>(e_expanded);
958                 exvector local_dummy_indices;
959                 find_free_and_dummy(i.seq.begin() + 1, i.seq.end(), free_indices, local_dummy_indices);
960
961                 // Filter out the dummy indices with variance
962                 exvector variant_dummy_indices;
963                 find_variant_indices(local_dummy_indices, variant_dummy_indices);
964
965                 // Any indices with variance present at all?
966                 if (!variant_dummy_indices.empty()) {
967
968                         // Yes, reposition them
969                         exvector moved_indices;
970                         reposition_dummy_indices(e_expanded, variant_dummy_indices, moved_indices);
971                 }
972
973                 // Rename the dummy indices
974                 return rename_dummy_indices(e_expanded, dummy_indices, local_dummy_indices);
975         }
976
977         // Simplification of sum = sum of simplifications, check consistency of
978         // free indices in each term
979         if (is_exactly_a<add>(e_expanded)) {
980                 bool first = true;
981                 ex sum;
982                 free_indices.clear();
983
984                 for (size_t i=0; i<e_expanded.nops(); i++) {
985                         exvector free_indices_of_term;
986                         ex term = simplify_indexed(e_expanded.op(i), free_indices_of_term, dummy_indices, sp);
987                         if (!term.is_zero()) {
988                                 if (first) {
989                                         free_indices = free_indices_of_term;
990                                         sum = term;
991                                         first = false;
992                                 } else {
993                                         if (!indices_consistent(free_indices, free_indices_of_term)) {
994                                                 std::ostringstream s;
995                                                 s << "simplify_indexed: inconsistent indices in sum: ";
996                                                 s << exprseq(free_indices) << " vs. " << exprseq(free_indices_of_term);
997                                                 throw (std::runtime_error(s.str()));
998                                         }
999                                         if (is_a<indexed>(sum) && is_a<indexed>(term))
1000                                                 sum = ex_to<basic>(sum.op(0)).add_indexed(sum, term);
1001                                         else
1002                                                 sum += term;
1003                                 }
1004                         }
1005                 }
1006
1007                 // If the sum turns out to be zero, we are finished
1008                 if (sum.is_zero()) {
1009                         free_indices.clear();
1010                         return sum;
1011                 }
1012
1013                 // More than one term and more than one dummy index?
1014                 size_t num_terms_orig = (is_exactly_a<add>(sum) ? sum.nops() : 1);
1015                 if (num_terms_orig < 2 || dummy_indices.size() < 2)
1016                         return sum;
1017
1018                 // Yes, construct vector of all dummy index symbols
1019                 exvector dummy_syms;
1020                 dummy_syms.reserve(dummy_indices.size());
1021                 for (exvector::const_iterator it = dummy_indices.begin(); it != dummy_indices.end(); ++it)
1022                         dummy_syms.push_back(it->op(0));
1023
1024                 // Chop the sum into terms and symmetrize each one over the dummy
1025                 // indices
1026                 std::vector<terminfo> terms;
1027                 for (size_t i=0; i<sum.nops(); i++) {
1028                         const ex & term = sum.op(i);
1029                         ex term_symm = symmetrize(term, dummy_syms);
1030                         if (term_symm.is_zero())
1031                                 continue;
1032                         terms.push_back(terminfo(term, term_symm));
1033                 }
1034
1035                 // Sort by symmetrized terms
1036                 std::sort(terms.begin(), terms.end(), terminfo_is_less());
1037
1038                 // Combine equal symmetrized terms
1039                 std::vector<terminfo> terms_pass2;
1040                 for (std::vector<terminfo>::const_iterator i=terms.begin(); i!=terms.end(); ) {
1041                         size_t num = 1;
1042                         std::vector<terminfo>::const_iterator j = i + 1;
1043                         while (j != terms.end() && j->symm == i->symm) {
1044                                 num++;
1045                                 j++;
1046                         }
1047                         terms_pass2.push_back(terminfo(i->orig * num, i->symm * num));
1048                         i = j;
1049                 }
1050
1051                 // If there is only one term left, we are finished
1052                 if (terms_pass2.size() == 1)
1053                         return terms_pass2[0].orig;
1054
1055                 // Chop the symmetrized terms into subterms
1056                 std::vector<symminfo> sy;
1057                 for (std::vector<terminfo>::const_iterator i=terms_pass2.begin(); i!=terms_pass2.end(); ++i) {
1058                         if (is_exactly_a<add>(i->symm)) {
1059                                 size_t num = i->symm.nops();
1060                                 for (size_t j=0; j<num; j++)
1061                                         sy.push_back(symminfo(i->symm.op(j), i->orig, num));
1062                         } else
1063                                 sy.push_back(symminfo(i->symm, i->orig, 1));
1064                 }
1065
1066                 // Sort by symmetrized subterms
1067                 std::sort(sy.begin(), sy.end(), symminfo_is_less_by_symmterm());
1068
1069                 // Combine equal symmetrized subterms
1070                 std::vector<symminfo> sy_pass2;
1071                 exvector result;
1072                 for (std::vector<symminfo>::const_iterator i=sy.begin(); i!=sy.end(); ) {
1073
1074                         // Combine equal terms
1075                         std::vector<symminfo>::const_iterator j = i + 1;
1076                         if (j != sy.end() && j->symmterm == i->symmterm) {
1077
1078                                 // More than one term, collect the coefficients
1079                                 ex coeff = i->coeff;
1080                                 while (j != sy.end() && j->symmterm == i->symmterm) {
1081                                         coeff += j->coeff;
1082                                         j++;
1083                                 }
1084
1085                                 // Add combined term to result
1086                                 if (!coeff.is_zero())
1087                                         result.push_back(coeff * i->symmterm);
1088
1089                         } else {
1090
1091                                 // Single term, store for second pass
1092                                 sy_pass2.push_back(*i);
1093                         }
1094
1095                         i = j;
1096                 }
1097
1098                 // Were there any remaining terms that didn't get combined?
1099                 if (sy_pass2.size() > 0) {
1100
1101                         // Yes, sort by their original terms
1102                         std::sort(sy_pass2.begin(), sy_pass2.end(), symminfo_is_less_by_orig());
1103
1104                         for (std::vector<symminfo>::const_iterator i=sy_pass2.begin(); i!=sy_pass2.end(); ) {
1105
1106                                 // How many symmetrized terms of this original term are left?
1107                                 size_t num = 1;
1108                                 std::vector<symminfo>::const_iterator j = i + 1;
1109                                 while (j != sy_pass2.end() && j->orig == i->orig) {
1110                                         num++;
1111                                         j++;
1112                                 }
1113
1114                                 if (num == i->num) {
1115
1116                                         // All terms left, then add the original term to the result
1117                                         result.push_back(i->orig);
1118
1119                                 } else {
1120
1121                                         // Some terms were combined with others, add up the remaining symmetrized terms
1122                                         std::vector<symminfo>::const_iterator k;
1123                                         for (k=i; k!=j; k++)
1124                                                 result.push_back(k->coeff * k->symmterm);
1125                                 }
1126
1127                                 i = j;
1128                         }
1129                 }
1130
1131                 // Add all resulting terms
1132                 ex sum_symm = (new add(result))->setflag(status_flags::dynallocated);
1133                 if (sum_symm.is_zero())
1134                         free_indices.clear();
1135                 return sum_symm;
1136         }
1137
1138         // Simplification of products
1139         if (is_exactly_a<mul>(e_expanded)
1140          || is_exactly_a<ncmul>(e_expanded)
1141          || (is_exactly_a<power>(e_expanded) && is_a<indexed>(e_expanded.op(0)) && e_expanded.op(1).is_equal(_ex2)))
1142                 return simplify_indexed_product(e_expanded, free_indices, dummy_indices, sp);
1143
1144         // Cannot do anything
1145         free_indices.clear();
1146         return e_expanded;
1147 }
1148
1149 /** Simplify/canonicalize expression containing indexed objects. This
1150  *  performs contraction of dummy indices where possible and checks whether
1151  *  the free indices in sums are consistent.
1152  *
1153  *  @param options Simplification options (currently unused)
1154  *  @return simplified expression */
1155 ex ex::simplify_indexed(unsigned options) const
1156 {
1157         exvector free_indices, dummy_indices;
1158         scalar_products sp;
1159         return GiNaC::simplify_indexed(*this, free_indices, dummy_indices, sp);
1160 }
1161
1162 /** Simplify/canonicalize expression containing indexed objects. This
1163  *  performs contraction of dummy indices where possible, checks whether
1164  *  the free indices in sums are consistent, and automatically replaces
1165  *  scalar products by known values if desired.
1166  *
1167  *  @param sp Scalar products to be replaced automatically
1168  *  @param options Simplification options (currently unused)
1169  *  @return simplified expression */
1170 ex ex::simplify_indexed(const scalar_products & sp, unsigned options) const
1171 {
1172         exvector free_indices, dummy_indices;
1173         return GiNaC::simplify_indexed(*this, free_indices, dummy_indices, sp);
1174 }
1175
1176 /** Symmetrize expression over its free indices. */
1177 ex ex::symmetrize() const
1178 {
1179         return GiNaC::symmetrize(*this, get_free_indices());
1180 }
1181
1182 /** Antisymmetrize expression over its free indices. */
1183 ex ex::antisymmetrize() const
1184 {
1185         return GiNaC::antisymmetrize(*this, get_free_indices());
1186 }
1187
1188 /** Symmetrize expression by cyclic permutation over its free indices. */
1189 ex ex::symmetrize_cyclic() const
1190 {
1191         return GiNaC::symmetrize_cyclic(*this, get_free_indices());
1192 }
1193
1194 //////////
1195 // helper classes
1196 //////////
1197
1198 spmapkey::spmapkey(const ex & v1_, const ex & v2_, const ex & dim_) : dim(dim_)
1199 {
1200         // If indexed, extract base objects
1201         ex s1 = is_a<indexed>(v1_) ? v1_.op(0) : v1_;
1202         ex s2 = is_a<indexed>(v2_) ? v2_.op(0) : v2_;
1203
1204         // Enforce canonical order in pair
1205         if (s1.compare(s2) > 0) {
1206                 v1 = s2;
1207                 v2 = s1;
1208         } else {
1209                 v1 = s1;
1210                 v2 = s2;
1211         }
1212 }
1213
1214 bool spmapkey::operator==(const spmapkey &other) const
1215 {
1216         if (!v1.is_equal(other.v1))
1217                 return false;
1218         if (!v2.is_equal(other.v2))
1219                 return false;
1220         if (is_a<wildcard>(dim) || is_a<wildcard>(other.dim))
1221                 return true;
1222         else
1223                 return dim.is_equal(other.dim);
1224 }
1225
1226 bool spmapkey::operator<(const spmapkey &other) const
1227 {
1228         int cmp = v1.compare(other.v1);
1229         if (cmp)
1230                 return cmp < 0;
1231         cmp = v2.compare(other.v2);
1232         if (cmp)
1233                 return cmp < 0;
1234
1235         // Objects are equal, now check dimensions
1236         if (is_a<wildcard>(dim) || is_a<wildcard>(other.dim))
1237                 return false;
1238         else
1239                 return dim.compare(other.dim) < 0;
1240 }
1241
1242 void spmapkey::debugprint() const
1243 {
1244         std::cerr << "(" << v1 << "," << v2 << "," << dim << ")";
1245 }
1246
1247 void scalar_products::add(const ex & v1, const ex & v2, const ex & sp)
1248 {
1249         spm[spmapkey(v1, v2)] = sp;
1250 }
1251
1252 void scalar_products::add(const ex & v1, const ex & v2, const ex & dim, const ex & sp)
1253 {
1254         spm[spmapkey(v1, v2, dim)] = sp;
1255 }
1256
1257 void scalar_products::add_vectors(const lst & l, const ex & dim)
1258 {
1259         // Add all possible pairs of products
1260         for (lst::const_iterator it1 = l.begin(); it1 != l.end(); ++it1)
1261                 for (lst::const_iterator it2 = l.begin(); it2 != l.end(); ++it2)
1262                         add(*it1, *it2, *it1 * *it2);
1263 }
1264
1265 void scalar_products::clear()
1266 {
1267         spm.clear();
1268 }
1269
1270 /** Check whether scalar product pair is defined. */
1271 bool scalar_products::is_defined(const ex & v1, const ex & v2, const ex & dim) const
1272 {
1273         return spm.find(spmapkey(v1, v2, dim)) != spm.end();
1274 }
1275
1276 /** Return value of defined scalar product pair. */
1277 ex scalar_products::evaluate(const ex & v1, const ex & v2, const ex & dim) const
1278 {
1279         return spm.find(spmapkey(v1, v2, dim))->second;
1280 }
1281
1282 void scalar_products::debugprint() const
1283 {
1284         std::cerr << "map size=" << spm.size() << std::endl;
1285         spmap::const_iterator i = spm.begin(), end = spm.end();
1286         while (i != end) {
1287                 const spmapkey & k = i->first;
1288                 std::cerr << "item key=";
1289                 k.debugprint();
1290                 std::cerr << ", value=" << i->second << std::endl;
1291                 ++i;
1292         }
1293 }
1294
1295 /** Returns all dummy indices from the exvector */
1296 exvector get_all_dummy_indices(const ex & e)
1297 {
1298         exvector p;
1299         bool nc;
1300         product_to_exvector(e, p, nc);
1301         exvector::const_iterator ip = p.begin(), ipend = p.end();
1302         exvector v, v1;
1303         while (ip != ipend) {
1304                 if (is_a<indexed>(*ip)) {
1305                         v1 = ex_to<indexed>(*ip).get_dummy_indices();
1306                         v.insert(v.end(), v1.begin(), v1.end());
1307                         exvector::const_iterator ip1 = ip+1;
1308                         while (ip1 != ipend) {
1309                                 if (is_a<indexed>(*ip1)) {
1310                                         v1 = ex_to<indexed>(*ip).get_dummy_indices(ex_to<indexed>(*ip1));
1311                                         v.insert(v.end(), v1.begin(), v1.end());
1312                                 }
1313                                 ++ip1;
1314                         }
1315                 }
1316                 ++ip;
1317         }
1318         return v;
1319 }
1320
1321 ex rename_dummy_indices_uniquely(const ex & a, const ex & b)
1322 {
1323         exvector va = get_all_dummy_indices(a), vb = get_all_dummy_indices(b), common_indices;
1324         set_intersection(va.begin(), va.end(), vb.begin(), vb.end(), std::back_insert_iterator<exvector>(common_indices), ex_is_less());
1325         if (common_indices.empty()) {
1326                 return b;
1327         } else {
1328                 exvector new_indices, old_indices;
1329                 old_indices.reserve(2*common_indices.size());
1330                 new_indices.reserve(2*common_indices.size());
1331                 exvector::const_iterator ip = common_indices.begin(), ipend = common_indices.end();
1332                 while (ip != ipend) {
1333                         if (is_a<varidx>(*ip)) {
1334                                 varidx mu((new symbol)->setflag(status_flags::dynallocated), ex_to<varidx>(*ip).get_dim(), ex_to<varidx>(*ip).is_covariant());
1335                                 old_indices.push_back(*ip);
1336                                 new_indices.push_back(mu);
1337                                 old_indices.push_back(ex_to<varidx>(*ip).toggle_variance());
1338                                 new_indices.push_back(mu.toggle_variance());
1339                         } else {
1340                                 old_indices.push_back(*ip);
1341                                 new_indices.push_back(idx((new symbol)->setflag(status_flags::dynallocated), ex_to<varidx>(*ip).get_dim()));
1342                         }
1343                         ++ip;
1344                 }
1345                 return b.subs(lst(old_indices.begin(), old_indices.end()), lst(new_indices.begin(), new_indices.end()), subs_options::no_pattern);
1346         }
1347 }
1348
1349 ex expand_dummy_sum(const ex & e, bool subs_idx)
1350 {
1351         ex e_expanded = e.expand();
1352         pointer_to_map_function_1arg<bool> fcn(expand_dummy_sum, subs_idx);
1353         if (is_a<add>(e_expanded) || is_a<lst>(e_expanded) || is_a<matrix>(e_expanded)) {
1354                 return e_expanded.map(fcn);
1355         } else if (is_a<ncmul>(e_expanded) || is_a<mul>(e_expanded) || is_a<power>(e_expanded)) {
1356                 exvector v = get_all_dummy_indices(e_expanded);
1357                 exvector::const_iterator it = v.begin(), itend = v.end();
1358                 while (it != itend) {
1359                         varidx nu = ex_to<varidx>(*it);
1360                         if (nu.is_dim_numeric()) {
1361                                 ex en = 0;
1362                                 for (int i=0; i < ex_to<numeric>(nu.get_dim()).to_int(); i++) {
1363                                         if (is_a<varidx>(nu) && !subs_idx) {
1364                                                 en += e_expanded.subs(lst(nu == varidx(i, nu.get_dim(), true), nu.toggle_variance() == varidx(i, nu.get_dim())));
1365                                         } else {
1366                                                 en += e_expanded.subs(lst(nu == idx(i, nu.get_dim()), nu.toggle_variance() == idx(i, nu.get_dim())));
1367                                         }
1368                                 }
1369                                 return expand_dummy_sum(en, subs_idx);
1370                         } 
1371                         ++it;
1372                 }
1373                 return e;
1374         } else if (is_a<indexed>(e_expanded)) {
1375                 exvector v = ex_to<indexed>(e_expanded).get_dummy_indices();
1376                 exvector::const_iterator it = v.begin(), itend = v.end();
1377                 while (it != itend) {
1378                         varidx nu = ex_to<varidx>(*it);
1379                         if (nu.is_dim_numeric()) {
1380                                 ex en = 0;
1381                                 for (int i=0; i < ex_to<numeric>(nu.get_dim()).to_int(); i++) {
1382                                         if (is_a<varidx>(nu) && !subs_idx) {
1383                                                 en += e_expanded.subs(lst(nu == varidx(i, nu.get_dim(), true), nu.toggle_variance() == varidx(i, nu.get_dim())));
1384                                         } else {
1385                                                 en += e_expanded.subs(lst(nu == idx(i, nu.get_dim()), nu.toggle_variance() == idx(i, nu.get_dim())));
1386                                         }
1387                                 }
1388                                 return expand_dummy_sum(en, subs_idx);
1389                         } 
1390                         ++it;
1391                 }
1392                 return e;
1393         } else {
1394                 return e;
1395         }
1396 }
1397
1398 } // namespace GiNaC