]> www.ginac.de Git - ginac.git/blob - ginac/indexed.cpp
subs() performs "syntactic substitution" as in Maple; you can substitute
[ginac.git] / ginac / indexed.cpp
1 /** @file indexed.cpp
2  *
3  *  Implementation of GiNaC's indexed expressions. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2001 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <stdexcept>
24
25 #include "indexed.h"
26 #include "idx.h"
27 #include "add.h"
28 #include "mul.h"
29 #include "ncmul.h"
30 #include "power.h"
31 #include "lst.h"
32 #include "archive.h"
33 #include "utils.h"
34 #include "debugmsg.h"
35
36 namespace GiNaC {
37
38 GINAC_IMPLEMENT_REGISTERED_CLASS(indexed, exprseq)
39
40 //////////
41 // default constructor, destructor, copy constructor assignment operator and helpers
42 //////////
43
44 indexed::indexed() : symmetry(unknown)
45 {
46         debugmsg("indexed default constructor", LOGLEVEL_CONSTRUCT);
47         tinfo_key = TINFO_indexed;
48 }
49
50 void indexed::copy(const indexed & other)
51 {
52         inherited::copy(other);
53         symmetry = other.symmetry;
54 }
55
56 DEFAULT_DESTROY(indexed)
57
58 //////////
59 // other constructors
60 //////////
61
62 indexed::indexed(const ex & b) : inherited(b), symmetry(unknown)
63 {
64         debugmsg("indexed constructor from ex", LOGLEVEL_CONSTRUCT);
65         tinfo_key = TINFO_indexed;
66         assert_all_indices_of_type_idx();
67 }
68
69 indexed::indexed(const ex & b, const ex & i1) : inherited(b, i1), symmetry(unknown)
70 {
71         debugmsg("indexed constructor from ex,ex", LOGLEVEL_CONSTRUCT);
72         tinfo_key = TINFO_indexed;
73         assert_all_indices_of_type_idx();
74 }
75
76 indexed::indexed(const ex & b, const ex & i1, const ex & i2) : inherited(b, i1, i2), symmetry(unknown)
77 {
78         debugmsg("indexed constructor from ex,ex,ex", LOGLEVEL_CONSTRUCT);
79         tinfo_key = TINFO_indexed;
80         assert_all_indices_of_type_idx();
81 }
82
83 indexed::indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3) : inherited(b, i1, i2, i3), symmetry(unknown)
84 {
85         debugmsg("indexed constructor from ex,ex,ex,ex", LOGLEVEL_CONSTRUCT);
86         tinfo_key = TINFO_indexed;
87         assert_all_indices_of_type_idx();
88 }
89
90 indexed::indexed(const ex & b, const ex & i1, const ex & i2, const ex & i3, const ex & i4) : inherited(b, i1, i2, i3, i4), symmetry(unknown)
91 {
92         debugmsg("indexed constructor from ex,ex,ex,ex,ex", LOGLEVEL_CONSTRUCT);
93         tinfo_key = TINFO_indexed;
94         assert_all_indices_of_type_idx();
95 }
96
97 indexed::indexed(const ex & b, symmetry_type symm, const ex & i1, const ex & i2) : inherited(b, i1, i2), symmetry(symm)
98 {
99         debugmsg("indexed constructor from ex,symmetry,ex,ex", LOGLEVEL_CONSTRUCT);
100         tinfo_key = TINFO_indexed;
101         assert_all_indices_of_type_idx();
102 }
103
104 indexed::indexed(const ex & b, symmetry_type symm, const ex & i1, const ex & i2, const ex & i3) : inherited(b, i1, i2, i3), symmetry(symm)
105 {
106         debugmsg("indexed constructor from ex,symmetry,ex,ex,ex", LOGLEVEL_CONSTRUCT);
107         tinfo_key = TINFO_indexed;
108         assert_all_indices_of_type_idx();
109 }
110
111 indexed::indexed(const ex & b, symmetry_type symm, const ex & i1, const ex & i2, const ex & i3, const ex & i4) : inherited(b, i1, i2, i3, i4), symmetry(symm)
112 {
113         debugmsg("indexed constructor from ex,symmetry,ex,ex,ex,ex", LOGLEVEL_CONSTRUCT);
114         tinfo_key = TINFO_indexed;
115         assert_all_indices_of_type_idx();
116 }
117
118 indexed::indexed(const ex & b, const exvector & v) : inherited(b), symmetry(unknown)
119 {
120         debugmsg("indexed constructor from ex,exvector", LOGLEVEL_CONSTRUCT);
121         seq.insert(seq.end(), v.begin(), v.end());
122         tinfo_key = TINFO_indexed;
123         assert_all_indices_of_type_idx();
124 }
125
126 indexed::indexed(const ex & b, symmetry_type symm, const exvector & v) : inherited(b), symmetry(symm)
127 {
128         debugmsg("indexed constructor from ex,symmetry,exvector", LOGLEVEL_CONSTRUCT);
129         seq.insert(seq.end(), v.begin(), v.end());
130         tinfo_key = TINFO_indexed;
131         assert_all_indices_of_type_idx();
132 }
133
134 indexed::indexed(symmetry_type symm, const exprseq & es) : inherited(es), symmetry(symm)
135 {
136         debugmsg("indexed constructor from symmetry,exprseq", LOGLEVEL_CONSTRUCT);
137         tinfo_key = TINFO_indexed;
138         assert_all_indices_of_type_idx();
139 }
140
141 indexed::indexed(symmetry_type symm, const exvector & v, bool discardable) : inherited(v, discardable), symmetry(symm)
142 {
143         debugmsg("indexed constructor from symmetry,exvector", LOGLEVEL_CONSTRUCT);
144         tinfo_key = TINFO_indexed;
145         assert_all_indices_of_type_idx();
146 }
147
148 indexed::indexed(symmetry_type symm, exvector * vp) : inherited(vp), symmetry(symm)
149 {
150         debugmsg("indexed constructor from symmetry,exvector *", LOGLEVEL_CONSTRUCT);
151         tinfo_key = TINFO_indexed;
152         assert_all_indices_of_type_idx();
153 }
154
155 //////////
156 // archiving
157 //////////
158
159 indexed::indexed(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
160 {
161         debugmsg("indexed constructor from archive_node", LOGLEVEL_CONSTRUCT);
162         unsigned int symm;
163         if (!(n.find_unsigned("symmetry", symm)))
164                 throw (std::runtime_error("unknown indexed symmetry type in archive"));
165 }
166
167 void indexed::archive(archive_node &n) const
168 {
169         inherited::archive(n);
170         n.add_unsigned("symmetry", symmetry);
171 }
172
173 DEFAULT_UNARCHIVE(indexed)
174
175 //////////
176 // functions overriding virtual functions from bases classes
177 //////////
178
179 void indexed::printraw(std::ostream & os) const
180 {
181         debugmsg("indexed printraw", LOGLEVEL_PRINT);
182         GINAC_ASSERT(seq.size() > 0);
183
184         os << class_name() << "(";
185         seq[0].printraw(os);
186         os << ",indices=";
187         printrawindices(os);
188         os << ",hash=" << hashvalue << ",flags=" << flags << ")";
189 }
190
191 void indexed::printtree(std::ostream & os, unsigned indent) const
192 {
193         debugmsg("indexed printtree", LOGLEVEL_PRINT);
194         GINAC_ASSERT(seq.size() > 0);
195
196         os << std::string(indent, ' ') << class_name() << ", " << seq.size()-1 << " indices";
197         os << ",hash=" << hashvalue << ",flags=" << flags << std::endl;
198         printtreeindices(os, indent);
199 }
200
201 void indexed::print(std::ostream & os, unsigned upper_precedence) const
202 {
203         debugmsg("indexed print", LOGLEVEL_PRINT);
204         GINAC_ASSERT(seq.size() > 0);
205
206         const ex & base = seq[0];
207         bool need_parens = is_ex_exactly_of_type(base, add) || is_ex_exactly_of_type(base, mul)
208                         || is_ex_exactly_of_type(base, ncmul) || is_ex_exactly_of_type(base, power);
209         if (need_parens)
210                 os << "(";
211         os << base;
212         if (need_parens)
213                 os << ")";
214         printindices(os);
215 }
216
217 bool indexed::info(unsigned inf) const
218 {
219         if (inf == info_flags::indexed) return true;
220         if (inf == info_flags::has_indices) return seq.size() > 1;
221         return inherited::info(inf);
222 }
223
224 bool indexed::all_index_values_are(unsigned inf) const
225 {
226         // No indices? Then no property can be fulfilled
227         if (seq.size() < 2)
228                 return false;
229
230         // Check all indices
231         exvector::const_iterator it = seq.begin() + 1, itend = seq.end();
232         while (it != itend) {
233                 GINAC_ASSERT(is_ex_of_type(*it, idx));
234                 if (!ex_to_idx(*it).get_value().info(inf))
235                         return false;
236                 it++;
237         }
238         return true;
239 }
240
241 int indexed::compare_same_type(const basic & other) const
242 {
243         GINAC_ASSERT(is_of_type(other, indexed));
244         return inherited::compare_same_type(other);
245 }
246
247 // The main difference between sort_index_vector() and canonicalize_indices()
248 // is that the latter takes the symmetry of the object into account. Once we
249 // implement mixed symmetries, canonicalize_indices() will only be able to
250 // reorder index pairs with known symmetry properties, while sort_index_vector()
251 // always sorts the whole vector.
252
253 /** Bring a vector of indices into a canonic order (don't care about the
254  *  symmetry of the objects carrying the indices). Dummy indices will lie
255  *  next to each other after the sorting.
256  *
257  *  @param v Index vector to be sorted */
258 static void sort_index_vector(exvector &v)
259 {
260         // Nothing to sort if less than 2 elements
261         if (v.size() < 2)
262                 return;
263
264         // Simple bubble sort algorithm should be sufficient for the small
265         // number of indices expected
266         exvector::iterator it1 = v.begin(), itend = v.end(), next_to_last_idx = itend - 1;
267         while (it1 != next_to_last_idx) {
268                 exvector::iterator it2 = it1 + 1;
269                 while (it2 != itend) {
270                         if (it1->compare(*it2) > 0)
271                                 it1->swap(*it2);
272                         it2++;
273                 }
274                 it1++;
275         }
276 }
277
278 /** Bring a vector of indices into a canonic order. This operation only makes
279  *  sense if the object carrying these indices is either symmetric or totally
280  *  antisymmetric with respect to the indices.
281  *
282  *  @param itbegin Start of index vector
283  *  @param itend End of index vector
284  *  @param antisymm Whether the object is antisymmetric
285  *  @return the sign introduced by the reordering of the indices if the object
286  *          is antisymmetric (or 0 if two equal indices are encountered). For
287  *          symmetric objects, this is always +1. If the index vector was
288  *          already in a canonic order this function returns INT_MAX. */
289 static int canonicalize_indices(exvector::iterator itbegin, exvector::iterator itend, bool antisymm)
290 {
291         bool something_changed = false;
292         int sig = 1;
293
294         // Simple bubble sort algorithm should be sufficient for the small
295         // number of indices expected
296         exvector::iterator it1 = itbegin, next_to_last_idx = itend - 1;
297         while (it1 != next_to_last_idx) {
298                 exvector::iterator it2 = it1 + 1;
299                 while (it2 != itend) {
300                         int cmpval = it1->compare(*it2);
301                         if (cmpval == 1) {
302                                 it1->swap(*it2);
303                                 something_changed = true;
304                                 if (antisymm)
305                                         sig = -sig;
306                         } else if (cmpval == 0 && antisymm) {
307                                 something_changed = true;
308                                 sig = 0;
309                         }
310                         it2++;
311                 }
312                 it1++;
313         }
314
315         return something_changed ? sig : INT_MAX;
316 }
317
318 ex indexed::eval(int level) const
319 {
320         // First evaluate children, then we will end up here again
321         if (level > 1)
322                 return indexed(symmetry, evalchildren(level));
323
324         const ex &base = seq[0];
325
326         // If the base object is 0, the whole object is 0
327         if (base.is_zero())
328                 return _ex0();
329
330         // If the base object is a product, pull out the numeric factor
331         if (is_ex_exactly_of_type(base, mul) && is_ex_exactly_of_type(base.op(base.nops() - 1), numeric)) {
332                 exvector v = seq;
333                 ex f = ex_to_numeric(base.op(base.nops() - 1));
334                 v[0] = seq[0] / f;
335                 return f * thisexprseq(v);
336         }
337
338         // Canonicalize indices according to the symmetry properties
339         if (seq.size() > 2 && (symmetry != unknown && symmetry != mixed)) {
340                 exvector v = seq;
341                 int sig = canonicalize_indices(v.begin() + 1, v.end(), symmetry == antisymmetric);
342                 if (sig != INT_MAX) {
343                         // Something has changed while sorting indices, more evaluations later
344                         if (sig == 0)
345                                 return _ex0();
346                         return ex(sig) * thisexprseq(v);
347                 }
348         }
349
350         // Let the class of the base object perform additional evaluations
351         return base.bp->eval_indexed(*this);
352 }
353
354 int indexed::degree(const ex & s) const
355 {
356         return is_equal(*s.bp) ? 1 : 0;
357 }
358
359 int indexed::ldegree(const ex & s) const
360 {
361         return is_equal(*s.bp) ? 1 : 0;
362 }
363
364 ex indexed::coeff(const ex & s, int n) const
365 {
366         if (is_equal(*s.bp))
367                 return n==1 ? _ex1() : _ex0();
368         else
369                 return n==0 ? ex(*this) : _ex0();
370 }
371
372 ex indexed::thisexprseq(const exvector & v) const
373 {
374         return indexed(symmetry, v);
375 }
376
377 ex indexed::thisexprseq(exvector * vp) const
378 {
379         return indexed(symmetry, vp);
380 }
381
382 ex indexed::expand(unsigned options) const
383 {
384         GINAC_ASSERT(seq.size() > 0);
385
386         if ((options & expand_options::expand_indexed) && is_ex_exactly_of_type(seq[0], add)) {
387
388                 // expand_indexed expands (a+b).i -> a.i + b.i
389                 const ex & base = seq[0];
390                 ex sum = _ex0();
391                 for (unsigned i=0; i<base.nops(); i++) {
392                         exvector s = seq;
393                         s[0] = base.op(i);
394                         sum += thisexprseq(s).expand();
395                 }
396                 return sum;
397
398         } else
399                 return inherited::expand(options);
400 }
401
402 //////////
403 // virtual functions which can be overridden by derived classes
404 //////////
405
406 // none
407
408 //////////
409 // non-virtual functions in this class
410 //////////
411
412 void indexed::printrawindices(std::ostream & os) const
413 {
414         if (seq.size() > 1) {
415                 exvector::const_iterator it=seq.begin() + 1, itend = seq.end();
416                 while (it != itend) {
417                         it->printraw(os);
418                         it++;
419                         if (it != itend)
420                                 os << ",";
421                 }
422         }
423 }
424
425 void indexed::printtreeindices(std::ostream & os, unsigned indent) const
426 {
427         if (seq.size() > 1) {
428                 exvector::const_iterator it=seq.begin() + 1, itend = seq.end();
429                 while (it != itend) {
430                         os << std::string(indent + delta_indent, ' ');
431                         it->printraw(os);
432                         os << std::endl;
433                         it++;
434                 }
435         }
436 }
437
438 void indexed::printindices(std::ostream & os) const
439 {
440         if (seq.size() > 1) {
441                 exvector::const_iterator it=seq.begin() + 1, itend = seq.end();
442                 while (it != itend) {
443                         it->print(os);
444                         it++;
445                 }
446         }
447 }
448
449 /** Check whether all indices are of class idx. This function is used
450  *  internally to make sure that all constructed indexed objects really
451  *  carry indices and not some other classes. */
452 void indexed::assert_all_indices_of_type_idx(void) const
453 {
454         GINAC_ASSERT(seq.size() > 0);
455         exvector::const_iterator it = seq.begin() + 1, itend = seq.end();
456         while (it != itend) {
457                 if (!is_ex_of_type(*it, idx))
458                         throw(std::invalid_argument("indices of indexed object must be of type idx"));
459                 it++;
460         }
461 }
462
463 //////////
464 // global functions
465 //////////
466
467 /** Check whether two sorted index vectors are consistent (i.e. equal). */
468 static bool indices_consistent(const exvector & v1, const exvector & v2)
469 {
470         // Number of indices must be the same
471         if (v1.size() != v2.size())
472                 return false;
473
474         // And also the indices themselves
475         exvector::const_iterator ait = v1.begin(), aitend = v1.end(),
476                                  bit = v2.begin(), bitend = v2.end();
477         while (ait != aitend) {
478                 if (!ait->is_equal(*bit))
479                         return false;
480                 ait++; bit++;
481         }
482         return true;
483 }
484
485 exvector indexed::get_indices(void) const
486 {
487         GINAC_ASSERT(seq.size() >= 1);
488         return exvector(seq.begin() + 1, seq.end());
489 }
490
491 exvector indexed::get_dummy_indices(void) const
492 {
493         exvector free_indices, dummy_indices;
494         find_free_and_dummy(seq.begin() + 1, seq.end(), free_indices, dummy_indices);
495         return dummy_indices;
496 }
497
498 exvector indexed::get_dummy_indices(const indexed & other) const
499 {
500         exvector indices = get_free_indices();
501         exvector other_indices = other.get_free_indices();
502         indices.insert(indices.end(), other_indices.begin(), other_indices.end());
503         exvector dummy_indices;
504         find_dummy_indices(indices, dummy_indices);
505         return dummy_indices;
506 }
507
508 exvector indexed::get_free_indices(void) const
509 {
510         exvector free_indices, dummy_indices;
511         find_free_and_dummy(seq.begin() + 1, seq.end(), free_indices, dummy_indices);
512         return free_indices;
513 }
514
515 exvector add::get_free_indices(void) const
516 {
517         exvector free_indices;
518         for (unsigned i=0; i<nops(); i++) {
519                 if (i == 0)
520                         free_indices = op(i).get_free_indices();
521                 else {
522                         exvector free_indices_of_term = op(i).get_free_indices();
523                         if (!indices_consistent(free_indices, free_indices_of_term))
524                                 throw (std::runtime_error("add::get_free_indices: inconsistent indices in sum"));
525                 }
526         }
527         return free_indices;
528 }
529
530 exvector mul::get_free_indices(void) const
531 {
532         // Concatenate free indices of all factors
533         exvector un;
534         for (unsigned i=0; i<nops(); i++) {
535                 exvector free_indices_of_factor = op(i).get_free_indices();
536                 un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
537         }
538
539         // And remove the dummy indices
540         exvector free_indices, dummy_indices;
541         find_free_and_dummy(un, free_indices, dummy_indices);
542         return free_indices;
543 }
544
545 exvector ncmul::get_free_indices(void) const
546 {
547         // Concatenate free indices of all factors
548         exvector un;
549         for (unsigned i=0; i<nops(); i++) {
550                 exvector free_indices_of_factor = op(i).get_free_indices();
551                 un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
552         }
553
554         // And remove the dummy indices
555         exvector free_indices, dummy_indices;
556         find_free_and_dummy(un, free_indices, dummy_indices);
557         return free_indices;
558 }
559
560 exvector power::get_free_indices(void) const
561 {
562         // Return free indices of basis
563         return basis.get_free_indices();
564 }
565
566 /** Simplify product of indexed expressions (commutative, noncommutative and
567  *  simple squares), return list of free indices. */
568 ex simplify_indexed_product(const ex & e, exvector & free_indices, const scalar_products & sp)
569 {
570         // Remember whether the product was commutative or noncommutative
571         // (because we chop it into factors and need to reassemble later)
572         bool non_commutative = is_ex_exactly_of_type(e, ncmul);
573
574         // Collect factors in an exvector, store squares twice
575         exvector v;
576         v.reserve(e.nops() * 2);
577
578         if (is_ex_exactly_of_type(e, power)) {
579                 // We only get called for simple squares, split a^2 -> a*a
580                 GINAC_ASSERT(e.op(1).is_equal(_ex2()));
581                 v.push_back(e.op(0));
582                 v.push_back(e.op(0));
583         } else {
584                 for (int i=0; i<e.nops(); i++) {
585                         ex f = e.op(i);
586                         if (is_ex_exactly_of_type(f, power) && f.op(1).is_equal(_ex2())) {
587                                 v.push_back(f.op(0));
588                     v.push_back(f.op(0));
589                         } else if (is_ex_exactly_of_type(f, ncmul)) {
590                                 // Noncommutative factor found, split it as well
591                                 non_commutative = true; // everything becomes noncommutative, ncmul will sort out the commutative factors later
592                                 for (int j=0; j<f.nops(); j++)
593                                         v.push_back(f.op(j));
594                         } else
595                                 v.push_back(f);
596                 }
597         }
598
599         // Perform contractions
600         bool something_changed = false;
601         GINAC_ASSERT(v.size() > 1);
602         exvector::iterator it1, itend = v.end(), next_to_last = itend - 1;
603         for (it1 = v.begin(); it1 != next_to_last; it1++) {
604
605 try_again:
606                 if (!is_ex_of_type(*it1, indexed))
607                         continue;
608
609                 // Indexed factor found, get free indices and look for contraction
610                 // candidates
611                 exvector free1, dummy1;
612                 find_free_and_dummy(ex_to_indexed(*it1).seq.begin() + 1, ex_to_indexed(*it1).seq.end(), free1, dummy1);
613
614                 exvector::iterator it2;
615                 for (it2 = it1 + 1; it2 != itend; it2++) {
616
617                         if (!is_ex_of_type(*it2, indexed))
618                                 continue;
619
620                         // Find free indices of second factor and merge them with free
621                         // indices of first factor
622                         exvector un;
623                         find_free_and_dummy(ex_to_indexed(*it2).seq.begin() + 1, ex_to_indexed(*it2).seq.end(), un, dummy1);
624                         un.insert(un.end(), free1.begin(), free1.end());
625
626                         // Check whether the two factors share dummy indices
627                         exvector free, dummy;
628                         find_free_and_dummy(un, free, dummy);
629                         if (dummy.size() == 0)
630                                 continue;
631
632                         // At least one dummy index, is it a defined scalar product?
633                         bool contracted = false;
634                         if (free.size() == 0) {
635                                 if (sp.is_defined(*it1, *it2)) {
636                                         *it1 = sp.evaluate(*it1, *it2);
637                                         *it2 = _ex1();
638                                         goto contraction_done;
639                                 }
640                         }
641
642                         // Contraction of symmetric with antisymmetric object is zero
643                         if ((ex_to_indexed(*it1).symmetry == indexed::symmetric &&
644                              ex_to_indexed(*it2).symmetry == indexed::antisymmetric
645                           || ex_to_indexed(*it1).symmetry == indexed::antisymmetric &&
646                              ex_to_indexed(*it2).symmetry == indexed::symmetric)
647                          && dummy.size() > 1) {
648                                 free_indices.clear();
649                                 return _ex0();
650                         }
651
652                         // Try to contract the first one with the second one
653                         contracted = it1->op(0).bp->contract_with(it1, it2, v);
654                         if (!contracted) {
655
656                                 // That didn't work; maybe the second object knows how to
657                                 // contract itself with the first one
658                                 contracted = it2->op(0).bp->contract_with(it2, it1, v);
659                         }
660                         if (contracted) {
661 contraction_done:
662                                 if (is_ex_exactly_of_type(*it1, add) || is_ex_exactly_of_type(*it2, add)
663                                  || is_ex_exactly_of_type(*it1, mul) || is_ex_exactly_of_type(*it2, mul)) {
664
665                                         // One of the factors became a sum or product:
666                                         // re-expand expression and run again
667                                         ex r = non_commutative ? ex(ncmul(v)) : ex(mul(v));
668                                         return simplify_indexed(r, free_indices, sp);
669                                 }
670
671                                 // Both objects may have new indices now or they might
672                                 // even not be indexed objects any more, so we have to
673                                 // start over
674                                 something_changed = true;
675                                 goto try_again;
676                         }
677                 }
678         }
679
680         // Find free indices (concatenate them all and call find_free_and_dummy())
681         exvector un, dummy_indices;
682         it1 = v.begin(); itend = v.end();
683         while (it1 != itend) {
684                 exvector free_indices_of_factor = it1->get_free_indices();
685                 un.insert(un.end(), free_indices_of_factor.begin(), free_indices_of_factor.end());
686                 it1++;
687         }
688         find_free_and_dummy(un, free_indices, dummy_indices);
689
690         ex r;
691         if (something_changed)
692                 r = non_commutative ? ex(ncmul(v)) : ex(mul(v));
693         else
694                 r = e;
695
696         // Product of indexed object with a scalar?
697         if (is_ex_exactly_of_type(r, mul) && r.nops() == 2
698          && is_ex_exactly_of_type(r.op(1), numeric) && is_ex_of_type(r.op(0), indexed))
699                 return r.op(0).op(0).bp->scalar_mul_indexed(r.op(0), ex_to_numeric(r.op(1)));
700         else
701                 return r;
702 }
703
704 /** Simplify indexed expression, return list of free indices. */
705 ex simplify_indexed(const ex & e, exvector & free_indices, const scalar_products & sp)
706 {
707         // Expand the expression
708         ex e_expanded = e.expand();
709
710         // Simplification of single indexed object: just find the free indices
711         if (is_ex_of_type(e_expanded, indexed)) {
712                 const indexed &i = ex_to_indexed(e_expanded);
713                 exvector dummy_indices;
714                 find_free_and_dummy(i.seq.begin() + 1, i.seq.end(), free_indices, dummy_indices);
715                 return e_expanded;
716         }
717
718         // Simplification of sum = sum of simplifications, check consistency of
719         // free indices in each term
720         if (is_ex_exactly_of_type(e_expanded, add)) {
721                 bool first = true;
722                 ex sum = _ex0();
723                 free_indices.clear();
724
725                 for (unsigned i=0; i<e_expanded.nops(); i++) {
726                         exvector free_indices_of_term;
727                         ex term = simplify_indexed(e_expanded.op(i), free_indices_of_term, sp);
728                         if (!term.is_zero()) {
729                                 if (first) {
730                                         free_indices = free_indices_of_term;
731                                         sum = term;
732                                         first = false;
733                                 } else {
734                                         if (!indices_consistent(free_indices, free_indices_of_term))
735                                                 throw (std::runtime_error("simplify_indexed: inconsistent indices in sum"));
736                                         if (is_ex_of_type(sum, indexed) && is_ex_of_type(term, indexed))
737                                                 sum = sum.op(0).bp->add_indexed(sum, term);
738                                         else
739                                                 sum += term;
740                                 }
741                         }
742                 }
743
744                 return sum;
745         }
746
747         // Simplification of products
748         if (is_ex_exactly_of_type(e_expanded, mul)
749          || is_ex_exactly_of_type(e_expanded, ncmul)
750          || (is_ex_exactly_of_type(e_expanded, power) && is_ex_of_type(e_expanded.op(0), indexed) && e_expanded.op(1).is_equal(_ex2())))
751                 return simplify_indexed_product(e_expanded, free_indices, sp);
752
753         // Cannot do anything
754         free_indices.clear();
755         return e_expanded;
756 }
757
758 ex simplify_indexed(const ex & e)
759 {
760         exvector free_indices;
761         scalar_products sp;
762         return simplify_indexed(e, free_indices, sp);
763 }
764
765 ex simplify_indexed(const ex & e, const scalar_products & sp)
766 {
767         exvector free_indices;
768         return simplify_indexed(e, free_indices, sp);
769 }
770
771 //////////
772 // helper classes
773 //////////
774
775 void scalar_products::add(const ex & v1, const ex & v2, const ex & sp)
776 {
777         spm[make_key(v1, v2)] = sp;
778 }
779
780 void scalar_products::clear(void)
781 {
782         spm.clear();
783 }
784
785 /** Check whether scalar product pair is defined. */
786 bool scalar_products::is_defined(const ex & v1, const ex & v2) const
787 {
788         return spm.find(make_key(v1, v2)) != spm.end();
789 }
790
791 /** Return value of defined scalar product pair. */
792 ex scalar_products::evaluate(const ex & v1, const ex & v2) const
793 {
794         return spm.find(make_key(v1, v2))->second;
795 }
796
797 void scalar_products::debugprint(void) const
798 {
799         std::cerr << "map size=" << spm.size() << std::endl;
800         for (spmap::const_iterator cit=spm.begin(); cit!=spm.end(); ++cit) {
801                 const spmapkey & k = cit->first;
802                 std::cerr << "item key=(" << k.first << "," << k.second;
803                 std::cerr << "), value=" << cit->second << std::endl;
804         }
805 }
806
807 /** Make key from object pair. */
808 spmapkey scalar_products::make_key(const ex & v1, const ex & v2)
809 {
810         // If indexed, extract base objects
811         ex s1 = is_ex_of_type(v1, indexed) ? v1.op(0) : v1;
812         ex s2 = is_ex_of_type(v2, indexed) ? v2.op(0) : v2;
813
814         // Enforce canonical order in pair
815         if (s1.compare(s2) > 0)
816                 return spmapkey(s2, s1);
817         else
818                 return spmapkey(s1, s2);
819 }
820
821 } // namespace GiNaC