]> www.ginac.de Git - ginac.git/blob - ginac/idx.cpp
* Headers only include <iosfwd> from now on, since that contains all the
[ginac.git] / ginac / idx.cpp
1 /** @file idx.cpp
2  *
3  *  Implementation of GiNaC's indices. */
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 <iostream>
24 #include <stdexcept>
25
26 #include "idx.h"
27 #include "symbol.h"
28 #include "lst.h"
29 #include "print.h"
30 #include "archive.h"
31 #include "utils.h"
32
33 namespace GiNaC {
34
35 GINAC_IMPLEMENT_REGISTERED_CLASS(idx, basic)
36 GINAC_IMPLEMENT_REGISTERED_CLASS(varidx, idx)
37 GINAC_IMPLEMENT_REGISTERED_CLASS(spinidx, varidx)
38
39 //////////
40 // default ctor, dtor, copy ctor, assignment operator and helpers
41 //////////
42
43 idx::idx() : inherited(TINFO_idx) {}
44
45 varidx::varidx() : covariant(false)
46 {
47         tinfo_key = TINFO_varidx;
48 }
49
50 spinidx::spinidx() : dotted(false)
51 {
52         tinfo_key = TINFO_spinidx;
53 }
54
55 void idx::copy(const idx & other)
56 {
57         inherited::copy(other);
58         value = other.value;
59         dim = other.dim;
60 }
61
62 void varidx::copy(const varidx & other)
63 {
64         inherited::copy(other);
65         covariant = other.covariant;
66 }
67
68 void spinidx::copy(const spinidx & other)
69 {
70         inherited::copy(other);
71         dotted = other.dotted;
72 }
73
74 DEFAULT_DESTROY(idx)
75 DEFAULT_DESTROY(varidx)
76 DEFAULT_DESTROY(spinidx)
77
78 //////////
79 // other constructors
80 //////////
81
82 idx::idx(const ex & v, const ex & d) : inherited(TINFO_idx), value(v), dim(d)
83 {
84         if (is_dim_numeric())
85                 if (!dim.info(info_flags::posint))
86                         throw(std::invalid_argument("dimension of space must be a positive integer"));
87 }
88
89 varidx::varidx(const ex & v, const ex & d, bool cov) : inherited(v, d), covariant(cov)
90 {
91         tinfo_key = TINFO_varidx;
92 }
93
94 spinidx::spinidx(const ex & v, const ex & d, bool cov, bool dot) : inherited(v, d, cov), dotted(dot)
95 {
96         tinfo_key = TINFO_spinidx;
97 }
98
99 //////////
100 // archiving
101 //////////
102
103 idx::idx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
104 {
105         n.find_ex("value", value, sym_lst);
106         n.find_ex("dim", dim, sym_lst);
107 }
108
109 varidx::varidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
110 {
111         n.find_bool("covariant", covariant);
112 }
113
114 spinidx::spinidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
115 {
116         n.find_bool("dotted", dotted);
117 }
118
119 void idx::archive(archive_node &n) const
120 {
121         inherited::archive(n);
122         n.add_ex("value", value);
123         n.add_ex("dim", dim);
124 }
125
126 void varidx::archive(archive_node &n) const
127 {
128         inherited::archive(n);
129         n.add_bool("covariant", covariant);
130 }
131
132 void spinidx::archive(archive_node &n) const
133 {
134         inherited::archive(n);
135         n.add_bool("dotted", dotted);
136 }
137
138 DEFAULT_UNARCHIVE(idx)
139 DEFAULT_UNARCHIVE(varidx)
140 DEFAULT_UNARCHIVE(spinidx)
141
142 //////////
143 // functions overriding virtual functions from base classes
144 //////////
145
146 void idx::print(const print_context & c, unsigned level) const
147 {
148         if (is_of_type(c, print_tree)) {
149
150                 c.s << std::string(level, ' ') << class_name()
151                     << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
152                     << std::endl;
153                 unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
154                 value.print(c, level + delta_indent);
155                 dim.print(c, level + delta_indent);
156
157         } else {
158
159                 if (!is_of_type(c, print_latex))
160                         c.s << ".";
161                 bool need_parens = !(is_ex_exactly_of_type(value, numeric) || is_ex_of_type(value, symbol));
162                 if (need_parens)
163                         c.s << "(";
164                 value.print(c);
165                 if (need_parens)
166                         c.s << ")";
167         }
168 }
169
170 void varidx::print(const print_context & c, unsigned level) const
171 {
172         if (is_of_type(c, print_tree)) {
173
174                 c.s << std::string(level, ' ') << class_name()
175                     << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
176                     << (covariant ? ", covariant" : ", contravariant")
177                     << std::endl;
178                 unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
179                 value.print(c, level + delta_indent);
180                 dim.print(c, level + delta_indent);
181
182         } else {
183
184                 if (!is_of_type(c, print_latex)) {
185                         if (covariant)
186                                 c.s << ".";
187                         else
188                                 c.s << "~";
189                 }
190                 bool need_parens = !(is_ex_exactly_of_type(value, numeric) || is_ex_of_type(value, symbol));
191                 if (need_parens)
192                         c.s << "(";
193                 value.print(c);
194                 if (need_parens)
195                         c.s << ")";
196         }
197 }
198
199 void spinidx::print(const print_context & c, unsigned level) const
200 {
201         if (is_of_type(c, print_tree)) {
202
203                 c.s << std::string(level, ' ') << class_name()
204                     << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
205                     << (covariant ? ", covariant" : ", contravariant")
206                     << (dotted ? ", dotted" : ", undotted")
207                     << std::endl;
208                 unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
209                 value.print(c, level + delta_indent);
210                 dim.print(c, level + delta_indent);
211
212         } else {
213
214                 bool is_tex = is_of_type(c, print_latex);
215                 if (!is_tex) {
216                         if (covariant)
217                                 c.s << ".";
218                         else
219                                 c.s << "~";
220                 }
221                 if (dotted) {
222                         if (is_tex)
223                                 c.s << "\\dot{";
224                         else
225                                 c.s << "*";
226                 }
227                 bool need_parens = !(is_ex_exactly_of_type(value, numeric) || is_ex_of_type(value, symbol));
228                 if (need_parens)
229                         c.s << "(";
230                 value.print(c);
231                 if (need_parens)
232                         c.s << ")";
233                 if (is_tex && dotted)
234                         c.s << "}";
235         }
236 }
237
238 bool idx::info(unsigned inf) const
239 {
240         if (inf == info_flags::idx)
241                 return true;
242         return inherited::info(inf);
243 }
244
245 unsigned idx::nops() const
246 {
247         // don't count the dimension as that is not really a sub-expression
248         return 1;
249 }
250
251 ex & idx::let_op(int i)
252 {
253         GINAC_ASSERT(i == 0);
254         return value;
255 }
256
257 /** Returns order relation between two indices of the same type. The order
258  *  must be such that dummy indices lie next to each other. */
259 int idx::compare_same_type(const basic & other) const
260 {
261         GINAC_ASSERT(is_a<idx>(other));
262         const idx &o = static_cast<const idx &>(other);
263
264         int cmpval = value.compare(o.value);
265         if (cmpval)
266                 return cmpval;
267         return dim.compare(o.dim);
268 }
269
270 bool idx::match_same_type(const basic & other) const
271 {
272         GINAC_ASSERT(is_a<idx>(other));
273         const idx &o = static_cast<const idx &>(other);
274
275         return dim.is_equal(o.dim);
276 }
277
278 int varidx::compare_same_type(const basic & other) const
279 {
280         GINAC_ASSERT(is_a<varidx>(other));
281         const varidx &o = static_cast<const varidx &>(other);
282
283         int cmpval = inherited::compare_same_type(other);
284         if (cmpval)
285                 return cmpval;
286
287         // Check variance last so dummy indices will end up next to each other
288         if (covariant != o.covariant)
289                 return covariant ? -1 : 1;
290         return 0;
291 }
292
293 bool varidx::match_same_type(const basic & other) const
294 {
295         GINAC_ASSERT(is_a<varidx>(other));
296         const varidx &o = static_cast<const varidx &>(other);
297
298         if (covariant != o.covariant)
299                 return false;
300         return inherited::match_same_type(other);
301 }
302
303 int spinidx::compare_same_type(const basic & other) const
304 {
305         GINAC_ASSERT(is_a<spinidx>(other));
306         const spinidx &o = static_cast<const spinidx &>(other);
307
308         // Check dottedness first so dummy indices will end up next to each other
309         if (dotted != o.dotted)
310                 return dotted ? -1 : 1;
311
312         int cmpval = inherited::compare_same_type(other);
313         if (cmpval)
314                 return cmpval;
315
316         return 0;
317 }
318
319 bool spinidx::match_same_type(const basic & other) const
320 {
321         GINAC_ASSERT(is_a<spinidx>(other));
322         const spinidx &o = static_cast<const spinidx &>(other);
323
324         if (dotted != o.dotted)
325                 return false;
326         return inherited::match_same_type(other);
327 }
328
329 /** By default, basic::evalf would evaluate the index value but we don't want
330  *  a.1 to become a.(1.0). */
331 ex idx::evalf(int level) const
332 {
333         return *this;
334 }
335
336 ex idx::subs(const lst & ls, const lst & lr, bool no_pattern) const
337 {
338         GINAC_ASSERT(ls.nops() == lr.nops());
339
340         // First look for index substitutions
341         for (unsigned i=0; i<ls.nops(); i++) {
342                 if (is_equal(ex_to<basic>(ls.op(i)))) {
343
344                         // Substitution index->index
345                         if (is_ex_of_type(lr.op(i), idx))
346                                 return lr.op(i);
347
348                         // Otherwise substitute value
349                         idx *i_copy = static_cast<idx *>(duplicate());
350                         i_copy->value = lr.op(i);
351                         i_copy->clearflag(status_flags::hash_calculated);
352                         return i_copy->setflag(status_flags::dynallocated);
353                 }
354         }
355
356         // None, substitute objects in value (not in dimension)
357         const ex &subsed_value = value.subs(ls, lr, no_pattern);
358         if (are_ex_trivially_equal(value, subsed_value))
359                 return *this;
360
361         idx *i_copy = static_cast<idx *>(duplicate());
362         i_copy->value = subsed_value;
363         i_copy->clearflag(status_flags::hash_calculated);
364         return i_copy->setflag(status_flags::dynallocated);
365 }
366
367 /** Implementation of ex::diff() for an index always returns 0.
368  *
369  *  @see ex::diff */
370 ex idx::derivative(const symbol & s) const
371 {
372         return _ex0;
373 }
374
375 //////////
376 // new virtual functions
377 //////////
378
379 bool idx::is_dummy_pair_same_type(const basic & other) const
380 {
381         const idx &o = static_cast<const idx &>(other);
382
383         // Only pure symbols form dummy pairs, "2n+1" doesn't
384         if (!is_ex_of_type(value, symbol))
385                 return false;
386
387         // Value must be equal, of course
388         if (!value.is_equal(o.value))
389                 return false;
390
391         // Also the dimension
392         return dim.is_equal(o.dim);
393 }
394
395 bool varidx::is_dummy_pair_same_type(const basic & other) const
396 {
397         const varidx &o = static_cast<const varidx &>(other);
398
399         // Variance must be opposite
400         if (covariant == o.covariant)
401                 return false;
402
403         return inherited::is_dummy_pair_same_type(other);
404 }
405
406 bool spinidx::is_dummy_pair_same_type(const basic & other) const
407 {
408         const spinidx &o = static_cast<const spinidx &>(other);
409
410         // Dottedness must be the same
411         if (dotted != o.dotted)
412                 return false;
413
414         return inherited::is_dummy_pair_same_type(other);
415 }
416
417
418 //////////
419 // non-virtual functions
420 //////////
421
422 ex varidx::toggle_variance(void) const
423 {
424         varidx *i_copy = static_cast<varidx *>(duplicate());
425         i_copy->covariant = !i_copy->covariant;
426         i_copy->clearflag(status_flags::hash_calculated);
427         return i_copy->setflag(status_flags::dynallocated);
428 }
429
430 ex spinidx::toggle_dot(void) const
431 {
432         spinidx *i_copy = static_cast<spinidx *>(duplicate());
433         i_copy->dotted = !i_copy->dotted;
434         i_copy->clearflag(status_flags::hash_calculated);
435         return i_copy->setflag(status_flags::dynallocated);
436 }
437
438 ex spinidx::toggle_variance_dot(void) const
439 {
440         spinidx *i_copy = static_cast<spinidx *>(duplicate());
441         i_copy->covariant = !i_copy->covariant;
442         i_copy->dotted = !i_copy->dotted;
443         i_copy->clearflag(status_flags::hash_calculated);
444         return i_copy->setflag(status_flags::dynallocated);
445 }
446
447 //////////
448 // global functions
449 //////////
450
451 bool is_dummy_pair(const idx & i1, const idx & i2)
452 {
453         // The indices must be of exactly the same type
454         if (i1.tinfo() != i2.tinfo())
455                 return false;
456
457         // Same type, let the indices decide whether they are paired
458         return i1.is_dummy_pair_same_type(i2);
459 }
460
461 bool is_dummy_pair(const ex & e1, const ex & e2)
462 {
463         // The expressions must be indices
464         if (!is_ex_of_type(e1, idx) || !is_ex_of_type(e2, idx))
465                 return false;
466
467         return is_dummy_pair(ex_to<idx>(e1), ex_to<idx>(e2));
468 }
469
470 void find_free_and_dummy(exvector::const_iterator it, exvector::const_iterator itend, exvector & out_free, exvector & out_dummy)
471 {
472         out_free.clear();
473         out_dummy.clear();
474
475         // No indices? Then do nothing
476         if (it == itend)
477                 return;
478
479         // Only one index? Then it is a free one if it's not numeric
480         if (itend - it == 1) {
481                 if (ex_to<idx>(*it).is_symbolic())
482                         out_free.push_back(*it);
483                 return;
484         }
485
486         // Sort index vector. This will cause dummy indices come to lie next
487         // to each other (because the sort order is defined to guarantee this).
488         exvector v(it, itend);
489         shaker_sort(v.begin(), v.end(), ex_is_less(), ex_swap());
490
491         // Find dummy pairs and free indices
492         it = v.begin(); itend = v.end();
493         exvector::const_iterator last = it++;
494         while (it != itend) {
495                 if (is_dummy_pair(*it, *last)) {
496                         out_dummy.push_back(*last);
497                         it++;
498                         if (it == itend)
499                                 return;
500                 } else {
501                         if (!it->is_equal(*last) && ex_to<idx>(*last).is_symbolic())
502                                 out_free.push_back(*last);
503                 }
504                 last = it++;
505         }
506         if (ex_to<idx>(*last).is_symbolic())
507                 out_free.push_back(*last);
508 }
509
510 } // namespace GiNaC