3 * Implementation of GiNaC's indices. */
6 * GiNaC Copyright (C) 1999-2002 Johannes Gutenberg University Mainz, Germany
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.
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.
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
35 GINAC_IMPLEMENT_REGISTERED_CLASS(idx, basic)
36 GINAC_IMPLEMENT_REGISTERED_CLASS(varidx, idx)
37 GINAC_IMPLEMENT_REGISTERED_CLASS(spinidx, varidx)
40 // default ctor, dtor, copy ctor, assignment operator and helpers
43 idx::idx() : inherited(TINFO_idx) {}
45 varidx::varidx() : covariant(false)
47 tinfo_key = TINFO_varidx;
50 spinidx::spinidx() : dotted(false)
52 tinfo_key = TINFO_spinidx;
55 void idx::copy(const idx & other)
57 inherited::copy(other);
62 void varidx::copy(const varidx & other)
64 inherited::copy(other);
65 covariant = other.covariant;
68 void spinidx::copy(const spinidx & other)
70 inherited::copy(other);
71 dotted = other.dotted;
75 DEFAULT_DESTROY(varidx)
76 DEFAULT_DESTROY(spinidx)
82 idx::idx(const ex & v, const ex & d) : inherited(TINFO_idx), value(v), dim(d)
85 if (!dim.info(info_flags::posint))
86 throw(std::invalid_argument("dimension of space must be a positive integer"));
89 varidx::varidx(const ex & v, const ex & d, bool cov) : inherited(v, d), covariant(cov)
91 tinfo_key = TINFO_varidx;
94 spinidx::spinidx(const ex & v, const ex & d, bool cov, bool dot) : inherited(v, d, cov), dotted(dot)
96 tinfo_key = TINFO_spinidx;
103 idx::idx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
105 n.find_ex("value", value, sym_lst);
106 n.find_ex("dim", dim, sym_lst);
109 varidx::varidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
111 n.find_bool("covariant", covariant);
114 spinidx::spinidx(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
116 n.find_bool("dotted", dotted);
119 void idx::archive(archive_node &n) const
121 inherited::archive(n);
122 n.add_ex("value", value);
123 n.add_ex("dim", dim);
126 void varidx::archive(archive_node &n) const
128 inherited::archive(n);
129 n.add_bool("covariant", covariant);
132 void spinidx::archive(archive_node &n) const
134 inherited::archive(n);
135 n.add_bool("dotted", dotted);
138 DEFAULT_UNARCHIVE(idx)
139 DEFAULT_UNARCHIVE(varidx)
140 DEFAULT_UNARCHIVE(spinidx)
143 // functions overriding virtual functions from base classes
146 void idx::print(const print_context & c, unsigned level) const
148 if (is_a<print_tree>(c)) {
150 c.s << std::string(level, ' ') << class_name()
151 << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
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);
159 if (is_a<print_latex>(c))
163 bool need_parens = !(is_exactly_a<numeric>(value) || is_a<symbol>(value));
169 if (is_a<print_latex>(c))
174 void varidx::print(const print_context & c, unsigned level) const
176 if (is_a<print_tree>(c)) {
178 c.s << std::string(level, ' ') << class_name()
179 << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
180 << (covariant ? ", covariant" : ", contravariant")
182 unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
183 value.print(c, level + delta_indent);
184 dim.print(c, level + delta_indent);
187 if (is_a<print_latex>(c))
195 bool need_parens = !(is_exactly_a<numeric>(value) || is_a<symbol>(value));
201 if (is_a<print_latex>(c))
206 void spinidx::print(const print_context & c, unsigned level) const
208 if (is_a<print_tree>(c)) {
210 c.s << std::string(level, ' ') << class_name()
211 << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
212 << (covariant ? ", covariant" : ", contravariant")
213 << (dotted ? ", dotted" : ", undotted")
215 unsigned delta_indent = static_cast<const print_tree &>(c).delta_indent;
216 value.print(c, level + delta_indent);
217 dim.print(c, level + delta_indent);
221 bool is_tex = is_a<print_latex>(c);
239 bool need_parens = !(is_exactly_a<numeric>(value) || is_a<symbol>(value));
245 if (is_tex && dotted)
252 bool idx::info(unsigned inf) const
254 if (inf == info_flags::idx)
256 return inherited::info(inf);
259 unsigned idx::nops() const
261 // don't count the dimension as that is not really a sub-expression
265 ex & idx::let_op(int i)
267 GINAC_ASSERT(i == 0);
271 /** Returns order relation between two indices of the same type. The order
272 * must be such that dummy indices lie next to each other. */
273 int idx::compare_same_type(const basic & other) const
275 GINAC_ASSERT(is_a<idx>(other));
276 const idx &o = static_cast<const idx &>(other);
278 int cmpval = value.compare(o.value);
281 return dim.compare(o.dim);
284 bool idx::match_same_type(const basic & other) const
286 GINAC_ASSERT(is_a<idx>(other));
287 const idx &o = static_cast<const idx &>(other);
289 return dim.is_equal(o.dim);
292 int varidx::compare_same_type(const basic & other) const
294 GINAC_ASSERT(is_a<varidx>(other));
295 const varidx &o = static_cast<const varidx &>(other);
297 int cmpval = inherited::compare_same_type(other);
301 // Check variance last so dummy indices will end up next to each other
302 if (covariant != o.covariant)
303 return covariant ? -1 : 1;
307 bool varidx::match_same_type(const basic & other) const
309 GINAC_ASSERT(is_a<varidx>(other));
310 const varidx &o = static_cast<const varidx &>(other);
312 if (covariant != o.covariant)
314 return inherited::match_same_type(other);
317 int spinidx::compare_same_type(const basic & other) const
319 GINAC_ASSERT(is_a<spinidx>(other));
320 const spinidx &o = static_cast<const spinidx &>(other);
322 // Check dottedness first so dummy indices will end up next to each other
323 if (dotted != o.dotted)
324 return dotted ? -1 : 1;
326 int cmpval = inherited::compare_same_type(other);
333 bool spinidx::match_same_type(const basic & other) const
335 GINAC_ASSERT(is_a<spinidx>(other));
336 const spinidx &o = static_cast<const spinidx &>(other);
338 if (dotted != o.dotted)
340 return inherited::match_same_type(other);
343 /** By default, basic::evalf would evaluate the index value but we don't want
344 * a.1 to become a.(1.0). */
345 ex idx::evalf(int level) const
350 ex idx::subs(const lst & ls, const lst & lr, bool no_pattern) const
352 GINAC_ASSERT(ls.nops() == lr.nops());
354 // First look for index substitutions
355 for (unsigned i=0; i<ls.nops(); i++) {
356 if (is_equal(ex_to<basic>(ls.op(i)))) {
358 // Substitution index->index
359 if (is_a<idx>(lr.op(i)))
362 // Otherwise substitute value
363 idx *i_copy = static_cast<idx *>(duplicate());
364 i_copy->value = lr.op(i);
365 i_copy->clearflag(status_flags::hash_calculated);
366 return i_copy->setflag(status_flags::dynallocated);
370 // None, substitute objects in value (not in dimension)
371 const ex &subsed_value = value.subs(ls, lr, no_pattern);
372 if (are_ex_trivially_equal(value, subsed_value))
375 idx *i_copy = static_cast<idx *>(duplicate());
376 i_copy->value = subsed_value;
377 i_copy->clearflag(status_flags::hash_calculated);
378 return i_copy->setflag(status_flags::dynallocated);
381 /** Implementation of ex::diff() for an index always returns 0.
384 ex idx::derivative(const symbol & s) const
390 // new virtual functions
393 bool idx::is_dummy_pair_same_type(const basic & other) const
395 const idx &o = static_cast<const idx &>(other);
397 // Only pure symbols form dummy pairs, "2n+1" doesn't
398 if (!is_a<symbol>(value))
401 // Value must be equal, of course
402 if (!value.is_equal(o.value))
405 // Also the dimension
406 return dim.is_equal(o.dim);
409 bool varidx::is_dummy_pair_same_type(const basic & other) const
411 const varidx &o = static_cast<const varidx &>(other);
413 // Variance must be opposite
414 if (covariant == o.covariant)
417 return inherited::is_dummy_pair_same_type(other);
420 bool spinidx::is_dummy_pair_same_type(const basic & other) const
422 const spinidx &o = static_cast<const spinidx &>(other);
424 // Dottedness must be the same
425 if (dotted != o.dotted)
428 return inherited::is_dummy_pair_same_type(other);
433 // non-virtual functions
436 ex varidx::toggle_variance(void) const
438 varidx *i_copy = static_cast<varidx *>(duplicate());
439 i_copy->covariant = !i_copy->covariant;
440 i_copy->clearflag(status_flags::hash_calculated);
441 return i_copy->setflag(status_flags::dynallocated);
444 ex spinidx::toggle_dot(void) const
446 spinidx *i_copy = static_cast<spinidx *>(duplicate());
447 i_copy->dotted = !i_copy->dotted;
448 i_copy->clearflag(status_flags::hash_calculated);
449 return i_copy->setflag(status_flags::dynallocated);
452 ex spinidx::toggle_variance_dot(void) const
454 spinidx *i_copy = static_cast<spinidx *>(duplicate());
455 i_copy->covariant = !i_copy->covariant;
456 i_copy->dotted = !i_copy->dotted;
457 i_copy->clearflag(status_flags::hash_calculated);
458 return i_copy->setflag(status_flags::dynallocated);
465 bool is_dummy_pair(const idx & i1, const idx & i2)
467 // The indices must be of exactly the same type
468 if (i1.tinfo() != i2.tinfo())
471 // Same type, let the indices decide whether they are paired
472 return i1.is_dummy_pair_same_type(i2);
475 bool is_dummy_pair(const ex & e1, const ex & e2)
477 // The expressions must be indices
478 if (!is_a<idx>(e1) || !is_a<idx>(e2))
481 return is_dummy_pair(ex_to<idx>(e1), ex_to<idx>(e2));
484 void find_free_and_dummy(exvector::const_iterator it, exvector::const_iterator itend, exvector & out_free, exvector & out_dummy)
489 // No indices? Then do nothing
493 // Only one index? Then it is a free one if it's not numeric
494 if (itend - it == 1) {
495 if (ex_to<idx>(*it).is_symbolic())
496 out_free.push_back(*it);
500 // Sort index vector. This will cause dummy indices come to lie next
501 // to each other (because the sort order is defined to guarantee this).
502 exvector v(it, itend);
503 shaker_sort(v.begin(), v.end(), ex_is_less(), ex_swap());
505 // Find dummy pairs and free indices
506 it = v.begin(); itend = v.end();
507 exvector::const_iterator last = it++;
508 while (it != itend) {
509 if (is_dummy_pair(*it, *last)) {
510 out_dummy.push_back(*last);
515 if (!it->is_equal(*last) && ex_to<idx>(*last).is_symbolic())
516 out_free.push_back(*last);
520 if (ex_to<idx>(*last).is_symbolic())
521 out_free.push_back(*last);