|
GiNaC
1.6.2
|
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