|
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 "symmetry.h" 00024 #include "lst.h" 00025 #include "add.h" 00026 #include "numeric.h" // for factorial() 00027 #include "operators.h" 00028 #include "archive.h" 00029 #include "utils.h" 00030 #include "hash_seed.h" 00031 00032 #include <functional> 00033 #include <iostream> 00034 #include <limits> 00035 #include <stdexcept> 00036 00037 namespace GiNaC { 00038 00039 GINAC_IMPLEMENT_REGISTERED_CLASS_OPT(symmetry, basic, 00040 print_func<print_context>(&symmetry::do_print). 00041 print_func<print_tree>(&symmetry::do_print_tree)) 00042 00043 /* 00044 Some notes about the structure of a symmetry tree: 00045 - The leaf nodes of the tree are of type "none", have one index, and no 00046 children (of course). They are constructed by the symmetry(unsigned) 00047 constructor. 00048 - Leaf nodes are the only nodes that only have one index. 00049 - Container nodes contain two or more children. The "indices" set member 00050 is the set union of the index sets of all children, and the "children" 00051 vector stores the children themselves. 00052 - The index set of each child of a "symm", "anti" or "cycl" node must 00053 have the same size. It follows that the children of such a node are 00054 either all leaf nodes, or all container nodes with two or more indices. 00055 */ 00056 00057 00058 // default constructor 00060 00061 symmetry::symmetry() : type(none) 00062 { 00063 setflag(status_flags::evaluated | status_flags::expanded); 00064 } 00065 00067 // other constructors 00069 00070 symmetry::symmetry(unsigned i) : type(none) 00071 { 00072 indices.insert(i); 00073 setflag(status_flags::evaluated | status_flags::expanded); 00074 } 00075 00076 symmetry::symmetry(symmetry_type t, const symmetry &c1, const symmetry &c2) : type(t) 00077 { 00078 add(c1); add(c2); 00079 setflag(status_flags::evaluated | status_flags::expanded); 00080 } 00081 00083 // archiving 00085 00087 void symmetry::read_archive(const archive_node &n, lst &sym_lst) 00088 { 00089 inherited::read_archive(n, sym_lst); 00090 unsigned t; 00091 if (!(n.find_unsigned("type", t))) 00092 throw (std::runtime_error("unknown symmetry type in archive")); 00093 type = (symmetry_type)t; 00094 00095 unsigned i = 0; 00096 while (true) { 00097 ex e; 00098 if (n.find_ex("child", e, sym_lst, i)) 00099 add(ex_to<symmetry>(e)); 00100 else 00101 break; 00102 i++; 00103 } 00104 00105 if (i == 0) { 00106 while (true) { 00107 unsigned u; 00108 if (n.find_unsigned("index", u, i)) 00109 indices.insert(u); 00110 else 00111 break; 00112 i++; 00113 } 00114 } 00115 } 00116 GINAC_BIND_UNARCHIVER(symmetry); 00117 00119 void symmetry::archive(archive_node &n) const 00120 { 00121 inherited::archive(n); 00122 00123 n.add_unsigned("type", type); 00124 00125 if (children.empty()) { 00126 std::set<unsigned>::const_iterator i = indices.begin(), iend = indices.end(); 00127 while (i != iend) { 00128 n.add_unsigned("index", *i); 00129 i++; 00130 } 00131 } else { 00132 exvector::const_iterator i = children.begin(), iend = children.end(); 00133 while (i != iend) { 00134 n.add_ex("child", *i); 00135 i++; 00136 } 00137 } 00138 } 00139 00141 // functions overriding virtual functions from base classes 00143 00144 int symmetry::compare_same_type(const basic & other) const 00145 { 00146 GINAC_ASSERT(is_a<symmetry>(other)); 00147 00148 // For archiving purposes we need to have an ordering of symmetries. 00149 const symmetry &othersymm = ex_to<symmetry>(other); 00150 00151 // Compare type. 00152 if (type > othersymm.type) 00153 return 1; 00154 if (type < othersymm.type) 00155 return -1; 00156 00157 // Compare the index set. 00158 size_t this_size = indices.size(); 00159 size_t that_size = othersymm.indices.size(); 00160 if (this_size > that_size) 00161 return 1; 00162 if (this_size < that_size) 00163 return -1; 00164 typedef std::set<unsigned>::const_iterator set_it; 00165 set_it end = indices.end(); 00166 for (set_it i=indices.begin(),j=othersymm.indices.begin(); i!=end; ++i,++j) { 00167 if(*i < *j) 00168 return 1; 00169 if(*i > *j) 00170 return -1; 00171 } 00172 00173 // Compare the children. 00174 if (children.size() > othersymm.children.size()) 00175 return 1; 00176 if (children.size() < othersymm.children.size()) 00177 return -1; 00178 for (size_t i=0; i<children.size(); ++i) { 00179 int cmpval = ex_to<symmetry>(children[i]) 00180 .compare_same_type(ex_to<symmetry>(othersymm.children[i])); 00181 if (cmpval) 00182 return cmpval; 00183 } 00184 00185 return 0; 00186 } 00187 00188 unsigned symmetry::calchash() const 00189 { 00190 unsigned v = make_hash_seed(typeid(*this)); 00191 00192 if (type == none) { 00193 v = rotate_left(v); 00194 if (!indices.empty()) 00195 v ^= *(indices.begin()); 00196 } else { 00197 for (exvector::const_iterator i=children.begin(); i!=children.end(); ++i) 00198 { 00199 v = rotate_left(v); 00200 v ^= i->gethash(); 00201 } 00202 } 00203 00204 if (flags & status_flags::evaluated) { 00205 setflag(status_flags::hash_calculated); 00206 hashvalue = v; 00207 } 00208 00209 return v; 00210 } 00211 00212 void symmetry::do_print(const print_context & c, unsigned level) const 00213 { 00214 if (children.empty()) { 00215 if (indices.size() > 0) 00216 c.s << *(indices.begin()); 00217 else 00218 c.s << "none"; 00219 } else { 00220 switch (type) { 00221 case none: c.s << '!'; break; 00222 case symmetric: c.s << '+'; break; 00223 case antisymmetric: c.s << '-'; break; 00224 case cyclic: c.s << '@'; break; 00225 default: c.s << '?'; break; 00226 } 00227 c.s << '('; 00228 size_t num = children.size(); 00229 for (size_t i=0; i<num; i++) { 00230 children[i].print(c); 00231 if (i != num - 1) 00232 c.s << ","; 00233 } 00234 c.s << ')'; 00235 } 00236 } 00237 00238 void symmetry::do_print_tree(const print_tree & c, unsigned level) const 00239 { 00240 c.s << std::string(level, ' ') << class_name() << " @" << this 00241 << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec 00242 << ", type="; 00243 00244 switch (type) { 00245 case none: c.s << "none"; break; 00246 case symmetric: c.s << "symm"; break; 00247 case antisymmetric: c.s << "anti"; break; 00248 case cyclic: c.s << "cycl"; break; 00249 default: c.s << "<unknown>"; break; 00250 } 00251 00252 c.s << ", indices=("; 00253 if (!indices.empty()) { 00254 std::set<unsigned>::const_iterator i = indices.begin(), end = indices.end(); 00255 --end; 00256 while (i != end) 00257 c.s << *i++ << ","; 00258 c.s << *i; 00259 } 00260 c.s << ")\n"; 00261 00262 exvector::const_iterator i = children.begin(), end = children.end(); 00263 while (i != end) { 00264 i->print(c, level + c.delta_indent); 00265 ++i; 00266 } 00267 } 00268 00270 // non-virtual functions in this class 00272 00273 bool symmetry::has_nonsymmetric() const 00274 { 00275 if (type == antisymmetric || type == cyclic) 00276 return true; 00277 00278 for (exvector::const_iterator i=children.begin(); i!=children.end(); ++i) 00279 if (ex_to<symmetry>(*i).has_nonsymmetric()) 00280 return true; 00281 00282 return false; 00283 } 00284 00285 bool symmetry::has_cyclic() const 00286 { 00287 if (type == cyclic) 00288 return true; 00289 00290 for (exvector::const_iterator i=children.begin(); i!=children.end(); ++i) 00291 if (ex_to<symmetry>(*i).has_cyclic()) 00292 return true; 00293 00294 return false; 00295 } 00296 00297 symmetry &symmetry::add(const symmetry &c) 00298 { 00299 // All children must have the same number of indices 00300 if (type != none && !children.empty()) { 00301 GINAC_ASSERT(is_exactly_a<symmetry>(children[0])); 00302 if (ex_to<symmetry>(children[0]).indices.size() != c.indices.size()) 00303 throw (std::logic_error("symmetry:add(): children must have same number of indices")); 00304 } 00305 00306 // Compute union of indices and check whether the two sets are disjoint 00307 std::set<unsigned> un; 00308 set_union(indices.begin(), indices.end(), c.indices.begin(), c.indices.end(), inserter(un, un.begin())); 00309 if (un.size() != indices.size() + c.indices.size()) 00310 throw (std::logic_error("symmetry::add(): the same index appears in more than one child")); 00311 00312 // Set new index set 00313 indices.swap(un); 00314 00315 // Add child node 00316 children.push_back(c); 00317 return *this; 00318 } 00319 00320 void symmetry::validate(unsigned n) 00321 { 00322 if (indices.upper_bound(n - 1) != indices.end()) 00323 throw (std::range_error("symmetry::verify(): index values are out of range")); 00324 if (type != none && indices.empty()) { 00325 for (unsigned i=0; i<n; i++) 00326 add(i); 00327 } 00328 } 00329 00331 // global functions 00333 00334 static const symmetry & index0() 00335 { 00336 static ex s = (new symmetry(0))->setflag(status_flags::dynallocated); 00337 return ex_to<symmetry>(s); 00338 } 00339 00340 static const symmetry & index1() 00341 { 00342 static ex s = (new symmetry(1))->setflag(status_flags::dynallocated); 00343 return ex_to<symmetry>(s); 00344 } 00345 00346 static const symmetry & index2() 00347 { 00348 static ex s = (new symmetry(2))->setflag(status_flags::dynallocated); 00349 return ex_to<symmetry>(s); 00350 } 00351 00352 static const symmetry & index3() 00353 { 00354 static ex s = (new symmetry(3))->setflag(status_flags::dynallocated); 00355 return ex_to<symmetry>(s); 00356 } 00357 00358 const symmetry & not_symmetric() 00359 { 00360 static ex s = (new symmetry)->setflag(status_flags::dynallocated); 00361 return ex_to<symmetry>(s); 00362 } 00363 00364 const symmetry & symmetric2() 00365 { 00366 static ex s = (new symmetry(symmetry::symmetric, index0(), index1()))->setflag(status_flags::dynallocated); 00367 return ex_to<symmetry>(s); 00368 } 00369 00370 const symmetry & symmetric3() 00371 { 00372 static ex s = (new symmetry(symmetry::symmetric, index0(), index1()))->add(index2()).setflag(status_flags::dynallocated); 00373 return ex_to<symmetry>(s); 00374 } 00375 00376 const symmetry & symmetric4() 00377 { 00378 static ex s = (new symmetry(symmetry::symmetric, index0(), index1()))->add(index2()).add(index3()).setflag(status_flags::dynallocated); 00379 return ex_to<symmetry>(s); 00380 } 00381 00382 const symmetry & antisymmetric2() 00383 { 00384 static ex s = (new symmetry(symmetry::antisymmetric, index0(), index1()))->setflag(status_flags::dynallocated); 00385 return ex_to<symmetry>(s); 00386 } 00387 00388 const symmetry & antisymmetric3() 00389 { 00390 static ex s = (new symmetry(symmetry::antisymmetric, index0(), index1()))->add(index2()).setflag(status_flags::dynallocated); 00391 return ex_to<symmetry>(s); 00392 } 00393 00394 const symmetry & antisymmetric4() 00395 { 00396 static ex s = (new symmetry(symmetry::antisymmetric, index0(), index1()))->add(index2()).add(index3()).setflag(status_flags::dynallocated); 00397 return ex_to<symmetry>(s); 00398 } 00399 00400 class sy_is_less : public std::binary_function<ex, ex, bool> { 00401 exvector::iterator v; 00402 00403 public: 00404 sy_is_less(exvector::iterator v_) : v(v_) {} 00405 00406 bool operator() (const ex &lh, const ex &rh) const 00407 { 00408 GINAC_ASSERT(is_exactly_a<symmetry>(lh)); 00409 GINAC_ASSERT(is_exactly_a<symmetry>(rh)); 00410 GINAC_ASSERT(ex_to<symmetry>(lh).indices.size() == ex_to<symmetry>(rh).indices.size()); 00411 std::set<unsigned>::const_iterator ait = ex_to<symmetry>(lh).indices.begin(), aitend = ex_to<symmetry>(lh).indices.end(), bit = ex_to<symmetry>(rh).indices.begin(); 00412 while (ait != aitend) { 00413 int cmpval = v[*ait].compare(v[*bit]); 00414 if (cmpval < 0) 00415 return true; 00416 else if (cmpval > 0) 00417 return false; 00418 ++ait; ++bit; 00419 } 00420 return false; 00421 } 00422 }; 00423 00424 class sy_swap : public std::binary_function<ex, ex, void> { 00425 exvector::iterator v; 00426 00427 public: 00428 bool &swapped; 00429 00430 sy_swap(exvector::iterator v_, bool &s) : v(v_), swapped(s) {} 00431 00432 void operator() (const ex &lh, const ex &rh) 00433 { 00434 GINAC_ASSERT(is_exactly_a<symmetry>(lh)); 00435 GINAC_ASSERT(is_exactly_a<symmetry>(rh)); 00436 GINAC_ASSERT(ex_to<symmetry>(lh).indices.size() == ex_to<symmetry>(rh).indices.size()); 00437 std::set<unsigned>::const_iterator ait = ex_to<symmetry>(lh).indices.begin(), aitend = ex_to<symmetry>(lh).indices.end(), bit = ex_to<symmetry>(rh).indices.begin(); 00438 while (ait != aitend) { 00439 v[*ait].swap(v[*bit]); 00440 ++ait; ++bit; 00441 } 00442 swapped = true; 00443 } 00444 }; 00445 00446 int canonicalize(exvector::iterator v, const symmetry &symm) 00447 { 00448 // Less than two elements? Then do nothing 00449 if (symm.indices.size() < 2) 00450 return std::numeric_limits<int>::max(); 00451 00452 // Canonicalize children first 00453 bool something_changed = false; 00454 int sign = 1; 00455 exvector::const_iterator first = symm.children.begin(), last = symm.children.end(); 00456 while (first != last) { 00457 GINAC_ASSERT(is_exactly_a<symmetry>(*first)); 00458 int child_sign = canonicalize(v, ex_to<symmetry>(*first)); 00459 if (child_sign == 0) 00460 return 0; 00461 if (child_sign != std::numeric_limits<int>::max()) { 00462 something_changed = true; 00463 sign *= child_sign; 00464 } 00465 first++; 00466 } 00467 00468 // Now reorder the children 00469 first = symm.children.begin(); 00470 switch (symm.type) { 00471 case symmetry::symmetric: 00472 // Sort the children in ascending order 00473 shaker_sort(first, last, sy_is_less(v), sy_swap(v, something_changed)); 00474 break; 00475 case symmetry::antisymmetric: 00476 // Sort the children in ascending order, keeping track of the signum 00477 sign *= permutation_sign(first, last, sy_is_less(v), sy_swap(v, something_changed)); 00478 if (sign == 0) 00479 return 0; 00480 break; 00481 case symmetry::cyclic: 00482 // Permute the smallest child to the front 00483 cyclic_permutation(first, last, min_element(first, last, sy_is_less(v)), sy_swap(v, something_changed)); 00484 break; 00485 default: 00486 break; 00487 } 00488 return something_changed ? sign : std::numeric_limits<int>::max(); 00489 } 00490 00491 00492 // Symmetrize/antisymmetrize over a vector of objects 00493 static ex symm(const ex & e, exvector::const_iterator first, exvector::const_iterator last, bool asymmetric) 00494 { 00495 // Need at least 2 objects for this operation 00496 unsigned num = last - first; 00497 if (num < 2) 00498 return e; 00499 00500 // Transform object vector to a lst (for subs()) 00501 lst orig_lst(first, last); 00502 00503 // Create index vectors for permutation 00504 unsigned *iv = new unsigned[num], *iv2; 00505 for (unsigned i=0; i<num; i++) 00506 iv[i] = i; 00507 iv2 = (asymmetric ? new unsigned[num] : NULL); 00508 00509 // Loop over all permutations (the first permutation, which is the 00510 // identity, is unrolled) 00511 exvector sum_v; 00512 sum_v.push_back(e); 00513 while (std::next_permutation(iv, iv + num)) { 00514 lst new_lst; 00515 for (unsigned i=0; i<num; i++) 00516 new_lst.append(orig_lst.op(iv[i])); 00517 ex term = e.subs(orig_lst, new_lst, subs_options::no_pattern|subs_options::no_index_renaming); 00518 if (asymmetric) { 00519 memcpy(iv2, iv, num * sizeof(unsigned)); 00520 term *= permutation_sign(iv2, iv2 + num); 00521 } 00522 sum_v.push_back(term); 00523 } 00524 ex sum = (new add(sum_v))->setflag(status_flags::dynallocated); 00525 00526 delete[] iv; 00527 delete[] iv2; 00528 00529 return sum / factorial(numeric(num)); 00530 } 00531 00532 ex symmetrize(const ex & e, exvector::const_iterator first, exvector::const_iterator last) 00533 { 00534 return symm(e, first, last, false); 00535 } 00536 00537 ex antisymmetrize(const ex & e, exvector::const_iterator first, exvector::const_iterator last) 00538 { 00539 return symm(e, first, last, true); 00540 } 00541 00542 ex symmetrize_cyclic(const ex & e, exvector::const_iterator first, exvector::const_iterator last) 00543 { 00544 // Need at least 2 objects for this operation 00545 unsigned num = last - first; 00546 if (num < 2) 00547 return e; 00548 00549 // Transform object vector to a lst (for subs()) 00550 lst orig_lst(first, last); 00551 lst new_lst = orig_lst; 00552 00553 // Loop over all cyclic permutations (the first permutation, which is 00554 // the identity, is unrolled) 00555 ex sum = e; 00556 for (unsigned i=0; i<num-1; i++) { 00557 ex perm = new_lst.op(0); 00558 new_lst.remove_first().append(perm); 00559 sum += e.subs(orig_lst, new_lst, subs_options::no_pattern|subs_options::no_index_renaming); 00560 } 00561 return sum / num; 00562 } 00563 00565 ex ex::symmetrize(const lst & l) const 00566 { 00567 exvector v(l.begin(), l.end()); 00568 return symm(*this, v.begin(), v.end(), false); 00569 } 00570 00572 ex ex::antisymmetrize(const lst & l) const 00573 { 00574 exvector v(l.begin(), l.end()); 00575 return symm(*this, v.begin(), v.end(), true); 00576 } 00577 00580 ex ex::symmetrize_cyclic(const lst & l) const 00581 { 00582 exvector v(l.begin(), l.end()); 00583 return GiNaC::symmetrize_cyclic(*this, v.begin(), v.end()); 00584 } 00585 00586 } // namespace GiNaC