GiNaC  1.6.2
symmetry.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 "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

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