GiNaC  1.6.2
idx.cpp
Go to the documentation of this file.
00001 
00005 /*
00006  *  GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program; if not, write to the Free Software
00020  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021  */
00022 
00023 #include "idx.h"
00024 #include "symbol.h"
00025 #include "lst.h"
00026 #include "relational.h"
00027 #include "operators.h"
00028 #include "archive.h"
00029 #include "utils.h"
00030 #include "hash_seed.h"
00031 
00032 #include <iostream>
00033 #include <sstream>
00034 #include <stdexcept>
00035 
00036 namespace GiNaC {
00037 
00038 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(idx, basic,
00039   print_func<print_context>(&idx::do_print).
00040   print_func<print_latex>(&idx::do_print_latex).
00041   print_func<print_csrc>(&idx::do_print_csrc).
00042   print_func<print_tree>(&idx::do_print_tree))
00043 
00044 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(varidx, idx,
00045   print_func<print_context>(&varidx::do_print).
00046   print_func<print_latex>(&varidx::do_print_latex).
00047   print_func<print_tree>(&varidx::do_print_tree))
00048 
00049 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(spinidx, varidx,
00050   print_func<print_context>(&spinidx::do_print).
00051   print_func<print_latex>(&spinidx::do_print_latex).
00052   print_func<print_tree>(&spinidx::do_print_tree))
00053 
00055 // default constructor
00057 
00058 idx::idx() {}
00059 
00060 varidx::varidx() : covariant(false)
00061 {
00062 }
00063 
00064 spinidx::spinidx() : dotted(false)
00065 {
00066 }
00067 
00069 // other constructors
00071 
00072 idx::idx(const ex & v, const ex & d) :  value(v), dim(d)
00073 {
00074     if (is_dim_numeric())
00075         if (!dim.info(info_flags::posint))
00076             throw(std::invalid_argument("dimension of space must be a positive integer"));
00077 }
00078 
00079 varidx::varidx(const ex & v, const ex & d, bool cov) : inherited(v, d), covariant(cov)
00080 {
00081 }
00082 
00083 spinidx::spinidx(const ex & v, const ex & d, bool cov, bool dot) : inherited(v, d, cov), dotted(dot)
00084 {
00085 }
00086 
00088 // archiving
00090 
00091 void idx::read_archive(const archive_node& n, lst& sym_lst) 
00092 {
00093     inherited::read_archive(n, sym_lst);
00094     n.find_ex("value", value, sym_lst);
00095     n.find_ex("dim", dim, sym_lst);
00096 }
00097 GINAC_BIND_UNARCHIVER(idx);
00098 
00099 void varidx::read_archive(const archive_node& n, lst& sym_lst)
00100 {
00101     inherited::read_archive(n, sym_lst);
00102     n.find_bool("covariant", covariant);
00103 }
00104 GINAC_BIND_UNARCHIVER(varidx);
00105 
00106 void spinidx::read_archive(const archive_node& n, lst& sym_lst)
00107 {
00108     inherited::read_archive(n, sym_lst);
00109     n.find_bool("dotted", dotted);
00110 }
00111 GINAC_BIND_UNARCHIVER(spinidx);
00112 
00113 void idx::archive(archive_node &n) const
00114 {
00115     inherited::archive(n);
00116     n.add_ex("value", value);
00117     n.add_ex("dim", dim);
00118 }
00119 
00120 void varidx::archive(archive_node &n) const
00121 {
00122     inherited::archive(n);
00123     n.add_bool("covariant", covariant);
00124 }
00125 
00126 void spinidx::archive(archive_node &n) const
00127 {
00128     inherited::archive(n);
00129     n.add_bool("dotted", dotted);
00130 }
00131 
00133 // functions overriding virtual functions from base classes
00135 
00136 void idx::print_index(const print_context & c, unsigned level) const
00137 {
00138     bool need_parens = !(is_exactly_a<numeric>(value) || is_a<symbol>(value));
00139     if (need_parens)
00140         c.s << "(";
00141     value.print(c);
00142     if (need_parens)
00143         c.s << ")";
00144     if (c.options & print_options::print_index_dimensions) {
00145         c.s << "[";
00146         dim.print(c);
00147         c.s << "]";
00148     }
00149 }
00150 
00151 void idx::do_print(const print_context & c, unsigned level) const
00152 {
00153     c.s << ".";
00154     print_index(c, level);
00155 }
00156 
00157 void idx::do_print_latex(const print_latex & c, unsigned level) const
00158 {
00159     c.s << "{";
00160     print_index(c, level);
00161     c.s << "}";
00162 }
00163 
00164 void idx::do_print_csrc(const print_csrc & c, unsigned level) const
00165 {
00166     c.s << "[";
00167     if (value.info(info_flags::integer))
00168         c.s << ex_to<numeric>(value).to_int();
00169     else
00170         value.print(c);
00171     c.s << "]";
00172 }
00173 
00174 void idx::do_print_tree(const print_tree & c, unsigned level) const
00175 {
00176     c.s << std::string(level, ' ') << class_name() << " @" << this
00177         << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
00178         << std::endl;
00179     value.print(c, level +  c.delta_indent);
00180     dim.print(c, level + c.delta_indent);
00181 }
00182 
00183 void varidx::do_print(const print_context & c, unsigned level) const
00184 {
00185     if (covariant)
00186         c.s << ".";
00187     else
00188         c.s << "~";
00189     print_index(c, level);
00190 }
00191 
00192 void varidx::do_print_tree(const print_tree & c, unsigned level) const
00193 {
00194     c.s << std::string(level, ' ') << class_name() << " @" << this
00195         << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
00196         << (covariant ? ", covariant" : ", contravariant")
00197         << std::endl;
00198     value.print(c, level + c.delta_indent);
00199     dim.print(c, level + c.delta_indent);
00200 }
00201 
00202 void spinidx::do_print(const print_context & c, unsigned level) const
00203 {
00204     if (covariant)
00205         c.s << ".";
00206     else
00207         c.s << "~";
00208     if (dotted)
00209         c.s << "*";
00210     print_index(c, level);
00211 }
00212 
00213 void spinidx::do_print_latex(const print_latex & c, unsigned level) const
00214 {
00215     if (dotted)
00216         c.s << "\\dot{";
00217     else
00218         c.s << "{";
00219     print_index(c, level);
00220     c.s << "}";
00221 }
00222 
00223 void spinidx::do_print_tree(const print_tree & c, unsigned level) const
00224 {
00225     c.s << std::string(level, ' ') << class_name() << " @" << this
00226         << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec
00227         << (covariant ? ", covariant" : ", contravariant")
00228         << (dotted ? ", dotted" : ", undotted")
00229         << std::endl;
00230     value.print(c, level + c.delta_indent);
00231     dim.print(c, level + c.delta_indent);
00232 }
00233 
00234 bool idx::info(unsigned inf) const
00235 {
00236     switch(inf) {
00237         case info_flags::idx:
00238         case info_flags::has_indices:
00239             return true;
00240     }
00241     return inherited::info(inf);
00242 }
00243 
00244 size_t idx::nops() const
00245 {
00246     // don't count the dimension as that is not really a sub-expression
00247     return 1;
00248 }
00249 
00250 ex idx::op(size_t i) const
00251 {
00252     GINAC_ASSERT(i == 0);
00253     return value;
00254 }
00255 
00256 ex idx::map(map_function & f) const
00257 {
00258     const ex &mapped_value = f(value);
00259     if (are_ex_trivially_equal(value, mapped_value))
00260         return *this;
00261     else {
00262         idx *copy = duplicate();
00263         copy->setflag(status_flags::dynallocated);
00264         copy->clearflag(status_flags::hash_calculated);
00265         copy->value = mapped_value;
00266         return *copy;
00267     }
00268 }
00269 
00272 int idx::compare_same_type(const basic & other) const
00273 {
00274     GINAC_ASSERT(is_a<idx>(other));
00275     const idx &o = static_cast<const idx &>(other);
00276 
00277     int cmpval = value.compare(o.value);
00278     if (cmpval)
00279         return cmpval;
00280     return dim.compare(o.dim);
00281 }
00282 
00283 bool idx::match_same_type(const basic & other) const
00284 {
00285     GINAC_ASSERT(is_a<idx>(other));
00286     const idx &o = static_cast<const idx &>(other);
00287 
00288     return dim.is_equal(o.dim);
00289 }
00290 
00291 int varidx::compare_same_type(const basic & other) const
00292 {
00293     GINAC_ASSERT(is_a<varidx>(other));
00294     const varidx &o = static_cast<const varidx &>(other);
00295 
00296     int cmpval = inherited::compare_same_type(other);
00297     if (cmpval)
00298         return cmpval;
00299 
00300     // Check variance last so dummy indices will end up next to each other
00301     if (covariant != o.covariant)
00302         return covariant ? -1 : 1;
00303 
00304     return 0;
00305 }
00306 
00307 bool varidx::match_same_type(const basic & other) const
00308 {
00309     GINAC_ASSERT(is_a<varidx>(other));
00310     const varidx &o = static_cast<const varidx &>(other);
00311 
00312     if (covariant != o.covariant)
00313         return false;
00314 
00315     return inherited::match_same_type(other);
00316 }
00317 
00318 int spinidx::compare_same_type(const basic & other) const
00319 {
00320     GINAC_ASSERT(is_a<spinidx>(other));
00321     const spinidx &o = static_cast<const spinidx &>(other);
00322 
00323     // Check dottedness first so dummy indices will end up next to each other
00324     if (dotted != o.dotted)
00325         return dotted ? -1 : 1;
00326 
00327     int cmpval = inherited::compare_same_type(other);
00328     if (cmpval)
00329         return cmpval;
00330 
00331     return 0;
00332 }
00333 
00334 bool spinidx::match_same_type(const basic & other) const
00335 {
00336     GINAC_ASSERT(is_a<spinidx>(other));
00337     const spinidx &o = static_cast<const spinidx &>(other);
00338 
00339     if (dotted != o.dotted)
00340         return false;
00341     return inherited::match_same_type(other);
00342 }
00343 
00344 unsigned idx::calchash() const
00345 {
00346     // NOTE: The code in simplify_indexed() assumes that canonically
00347     // ordered sequences of indices have the two members of dummy index
00348     // pairs lying next to each other. The hash values for indices must
00349     // be devised accordingly. The easiest (only?) way to guarantee the
00350     // desired ordering is to make indices with the same value have equal
00351     // hash keys. That is, the hash values must not depend on the index
00352     // dimensions or other attributes (variance etc.).
00353     // The compare_same_type() methods will take care of the rest.
00354     unsigned v = make_hash_seed(typeid(*this));
00355     v = rotate_left(v);
00356     v ^= value.gethash();
00357 
00358     // Store calculated hash value only if object is already evaluated
00359     if (flags & status_flags::evaluated) {
00360         setflag(status_flags::hash_calculated);
00361         hashvalue = v;
00362     }
00363 
00364     return v;
00365 }
00366 
00369 ex idx::evalf(int level) const
00370 {
00371     return *this;
00372 }
00373 
00374 ex idx::subs(const exmap & m, unsigned options) const
00375 {
00376     // First look for index substitutions
00377     exmap::const_iterator it = m.find(*this);
00378     if (it != m.end()) {
00379 
00380         // Substitution index->index
00381         if (is_a<idx>(it->second) || (options & subs_options::really_subs_idx))
00382             return it->second;
00383 
00384         // Otherwise substitute value
00385         idx *i_copy = duplicate();
00386         i_copy->value = it->second;
00387         i_copy->clearflag(status_flags::hash_calculated);
00388         return i_copy->setflag(status_flags::dynallocated);
00389     }
00390 
00391     // None, substitute objects in value (not in dimension)
00392     const ex &subsed_value = value.subs(m, options);
00393     if (are_ex_trivially_equal(value, subsed_value))
00394         return *this;
00395 
00396     idx *i_copy = duplicate();
00397     i_copy->value = subsed_value;
00398     i_copy->clearflag(status_flags::hash_calculated);
00399     return i_copy->setflag(status_flags::dynallocated);
00400 }
00401 
00405 ex idx::derivative(const symbol & s) const
00406 {
00407     return _ex0;
00408 }
00409 
00411 // new virtual functions
00413 
00414 bool idx::is_dummy_pair_same_type(const basic & other) const
00415 {
00416     const idx &o = static_cast<const idx &>(other);
00417 
00418     // Only pure symbols form dummy pairs, "2n+1" doesn't
00419     if (!is_a<symbol>(value))
00420         return false;
00421 
00422     // Value must be equal, of course
00423     if (!value.is_equal(o.value))
00424         return false;
00425 
00426     // Dimensions need not be equal but must be comparable (so we can
00427     // determine the minimum dimension of contractions)
00428     if (dim.is_equal(o.dim))
00429         return true;
00430 
00431     return is_exactly_a<numeric>(dim) || is_exactly_a<numeric>(o.dim);
00432 }
00433 
00434 bool varidx::is_dummy_pair_same_type(const basic & other) const
00435 {
00436     const varidx &o = static_cast<const varidx &>(other);
00437 
00438     // Variance must be opposite
00439     if (covariant == o.covariant)
00440         return false;
00441 
00442     return inherited::is_dummy_pair_same_type(other);
00443 }
00444 
00445 bool spinidx::is_dummy_pair_same_type(const basic & other) const
00446 {
00447     const spinidx &o = static_cast<const spinidx &>(other);
00448 
00449     // Dottedness must be the same
00450     if (dotted != o.dotted)
00451         return false;
00452 
00453     return inherited::is_dummy_pair_same_type(other);
00454 }
00455 
00456 
00458 // non-virtual functions
00460 
00461 ex idx::replace_dim(const ex & new_dim) const
00462 {
00463     idx *i_copy = duplicate();
00464     i_copy->dim = new_dim;
00465     i_copy->clearflag(status_flags::hash_calculated);
00466     return i_copy->setflag(status_flags::dynallocated);
00467 }
00468 
00469 ex idx::minimal_dim(const idx & other) const
00470 {
00471     return GiNaC::minimal_dim(dim, other.dim);
00472 }
00473 
00474 ex varidx::toggle_variance() const
00475 {
00476     varidx *i_copy = duplicate();
00477     i_copy->covariant = !i_copy->covariant;
00478     i_copy->clearflag(status_flags::hash_calculated);
00479     return i_copy->setflag(status_flags::dynallocated);
00480 }
00481 
00482 ex spinidx::toggle_dot() const
00483 {
00484     spinidx *i_copy = duplicate();
00485     i_copy->dotted = !i_copy->dotted;
00486     i_copy->clearflag(status_flags::hash_calculated);
00487     return i_copy->setflag(status_flags::dynallocated);
00488 }
00489 
00490 ex spinidx::toggle_variance_dot() const
00491 {
00492     spinidx *i_copy = duplicate();
00493     i_copy->covariant = !i_copy->covariant;
00494     i_copy->dotted = !i_copy->dotted;
00495     i_copy->clearflag(status_flags::hash_calculated);
00496     return i_copy->setflag(status_flags::dynallocated);
00497 }
00498 
00500 // global functions
00502 
00503 bool is_dummy_pair(const idx & i1, const idx & i2)
00504 {
00505     // The indices must be of exactly the same type
00506     if (typeid(i1) != typeid(i2))
00507         return false;
00508 
00509     // Same type, let the indices decide whether they are paired
00510     return i1.is_dummy_pair_same_type(i2);
00511 }
00512 
00513 bool is_dummy_pair(const ex & e1, const ex & e2)
00514 {
00515     // The expressions must be indices
00516     if (!is_a<idx>(e1) || !is_a<idx>(e2))
00517         return false;
00518 
00519     return is_dummy_pair(ex_to<idx>(e1), ex_to<idx>(e2));
00520 }
00521 
00522 void find_free_and_dummy(exvector::const_iterator it, exvector::const_iterator itend, exvector & out_free, exvector & out_dummy)
00523 {
00524     out_free.clear();
00525     out_dummy.clear();
00526 
00527     // No indices? Then do nothing
00528     if (it == itend)
00529         return;
00530 
00531     // Only one index? Then it is a free one if it's not numeric
00532     if (itend - it == 1) {
00533         if (ex_to<idx>(*it).is_symbolic())
00534             out_free.push_back(*it);
00535         return;
00536     }
00537 
00538     // Sort index vector. This will cause dummy indices come to lie next
00539     // to each other (because the sort order is defined to guarantee this).
00540     exvector v(it, itend);
00541     shaker_sort(v.begin(), v.end(), ex_is_less(), ex_swap());
00542 
00543     // Find dummy pairs and free indices
00544     it = v.begin(); itend = v.end();
00545     exvector::const_iterator last = it++;
00546     while (it != itend) {
00547         if (is_dummy_pair(*it, *last)) {
00548             out_dummy.push_back(*last);
00549             it++;
00550             if (it == itend)
00551                 return;
00552         } else {
00553             if (!it->is_equal(*last) && ex_to<idx>(*last).is_symbolic())
00554                 out_free.push_back(*last);
00555         }
00556         last = it++;
00557     }
00558     if (ex_to<idx>(*last).is_symbolic())
00559         out_free.push_back(*last);
00560 }
00561 
00562 ex minimal_dim(const ex & dim1, const ex & dim2)
00563 {
00564     if (dim1.is_equal(dim2) || dim1 < dim2 || (is_exactly_a<numeric>(dim1) && !is_a<numeric>(dim2)))
00565         return dim1;
00566     else if (dim1 > dim2 || (!is_a<numeric>(dim1) && is_exactly_a<numeric>(dim2)))
00567         return dim2;
00568     else {
00569         std::ostringstream s;
00570         s << "minimal_dim(): index dimensions " << dim1 << " and " << dim2 << " cannot be ordered";
00571         throw (std::runtime_error(s.str()));
00572     }
00573 }
00574 
00575 } // namespace GiNaC

This page is part of the GiNaC developer's reference. It was generated automatically by doxygen. For an introduction, see the tutorial.