Univariate Hensel lifting now uses upoly.
[ginac.git] / ginac / symmetry.h
1 /** @file symmetry.h
2  *
3  *  Interface to GiNaC's symmetry definitions. */
4
5 /*
6  *  GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany
7  *
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.
12  *
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.
17  *
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #ifndef __GINAC_SYMMETRY_H__
24 #define __GINAC_SYMMETRY_H__
25
26 #include <set>
27
28 #include "ex.h"
29 #include "archive.h"
30
31 namespace GiNaC {
32
33
34 class sy_is_less;
35 class sy_swap;
36
37 /** This class describes the symmetry of a group of indices. These objects
38  *  can be grouped into a tree to form complex mixed symmetries. */
39 class symmetry : public basic
40 {
41         friend class sy_is_less;
42         friend class sy_swap;
43         friend int canonicalize(exvector::iterator v, const symmetry &symm);
44
45         GINAC_DECLARE_REGISTERED_CLASS(symmetry, basic)
46
47         // types
48 public:
49         /** Type of symmetry */
50         typedef enum {
51                 none,          /**< no symmetry properties */
52                 symmetric,     /**< totally symmetric */
53                 antisymmetric, /**< totally antisymmetric */
54                 cyclic         /**< cyclic symmetry */
55         } symmetry_type;
56
57         // other constructors
58 public:
59         /** Create leaf node that represents one index. */
60         symmetry(unsigned i);
61
62         /** Create node with two children. */
63         symmetry(symmetry_type t, const symmetry &c1, const symmetry &c2);
64
65         // non-virtual functions in this class
66 public:
67         /** Get symmetry type. */
68         symmetry_type get_type() const {return type;}
69
70         /** Set symmetry type. */
71         void set_type(symmetry_type t) {type = t;}
72
73         /** Add child node, check index sets for consistency. */
74         symmetry &add(const symmetry &c);
75
76         /** Verify that all indices of this node are in the range [0..n-1].
77          *  This function throws an exception if the verification fails.
78          *  If the top node has a type != none and no children, add all indices
79          *  in the range [0..n-1] as children. */
80         void validate(unsigned n);
81
82         /** Check whether this node actually represents any kind of symmetry. */
83         bool has_symmetry() const {return type != none || !children.empty(); }
84         /** Check whether this node involves a cyclic symmetry. */
85         bool has_cyclic() const;
86
87         /** Save (a.k.a. serialize) object into archive. */
88         void archive(archive_node& n) const;
89         /** Read (a.k.a. deserialize) object from archive. */
90         void read_archive(const archive_node& n, lst& syms);
91 protected:
92         void do_print(const print_context & c, unsigned level) const;
93         void do_print_tree(const print_tree & c, unsigned level) const;
94         unsigned calchash() const;
95
96         // member variables
97 private:
98         /** Type of symmetry described by this node. */
99         symmetry_type type;
100
101         /** Sorted union set of all indices handled by this node. */
102         std::set<unsigned> indices;
103
104         /** Vector of child nodes. */
105         exvector children;
106 };
107 GINAC_DECLARE_UNARCHIVER(symmetry); 
108
109
110 // global functions
111
112 inline symmetry sy_none() { return symmetry(); }
113 inline symmetry sy_none(const symmetry &c1, const symmetry &c2) { return symmetry(symmetry::none, c1, c2); }
114 inline symmetry sy_none(const symmetry &c1, const symmetry &c2, const symmetry &c3) { return symmetry(symmetry::none, c1, c2).add(c3); }
115 inline symmetry sy_none(const symmetry &c1, const symmetry &c2, const symmetry &c3, const symmetry &c4) { return symmetry(symmetry::none, c1, c2).add(c3).add(c4); }
116
117 inline symmetry sy_symm() { symmetry s; s.set_type(symmetry::symmetric); return s; }
118 inline symmetry sy_symm(const symmetry &c1, const symmetry &c2) { return symmetry(symmetry::symmetric, c1, c2); }
119 inline symmetry sy_symm(const symmetry &c1, const symmetry &c2, const symmetry &c3) { return symmetry(symmetry::symmetric, c1, c2).add(c3); }
120 inline symmetry sy_symm(const symmetry &c1, const symmetry &c2, const symmetry &c3, const symmetry &c4) { return symmetry(symmetry::symmetric, c1, c2).add(c3).add(c4); }
121
122 inline symmetry sy_anti() { symmetry s; s.set_type(symmetry::antisymmetric); return s; }
123 inline symmetry sy_anti(const symmetry &c1, const symmetry &c2) { return symmetry(symmetry::antisymmetric, c1, c2); }
124 inline symmetry sy_anti(const symmetry &c1, const symmetry &c2, const symmetry &c3) { return symmetry(symmetry::antisymmetric, c1, c2).add(c3); }
125 inline symmetry sy_anti(const symmetry &c1, const symmetry &c2, const symmetry &c3, const symmetry &c4) { return symmetry(symmetry::antisymmetric, c1, c2).add(c3).add(c4); }
126
127 inline symmetry sy_cycl() { symmetry s; s.set_type(symmetry::cyclic); return s; }
128 inline symmetry sy_cycl(const symmetry &c1, const symmetry &c2) { return symmetry(symmetry::cyclic, c1, c2); }
129 inline symmetry sy_cycl(const symmetry &c1, const symmetry &c2, const symmetry &c3) { return symmetry(symmetry::cyclic, c1, c2).add(c3); }
130 inline symmetry sy_cycl(const symmetry &c1, const symmetry &c2, const symmetry &c3, const symmetry &c4) { return symmetry(symmetry::cyclic, c1, c2).add(c3).add(c4); }
131
132 // These return references to preallocated common symmetries (similar to
133 // the numeric flyweights).
134 const symmetry & not_symmetric();
135 const symmetry & symmetric2();
136 const symmetry & symmetric3();
137 const symmetry & symmetric4();
138 const symmetry & antisymmetric2();
139 const symmetry & antisymmetric3();
140 const symmetry & antisymmetric4();
141
142 /** Canonicalize the order of elements of an expression vector, according to
143  *  the symmetry properties defined in a symmetry tree.
144  *
145  *  @param v Start of expression vector
146  *  @param symm Root node of symmetry tree
147  *  @return the overall sign introduced by the reordering (+1, -1 or 0)
148  *          or numeric_limits<int>::max() if nothing changed */
149 extern int canonicalize(exvector::iterator v, const symmetry &symm);
150
151 /** Symmetrize expression over a set of objects (symbols, indices). */
152 ex symmetrize(const ex & e, exvector::const_iterator first, exvector::const_iterator last);
153
154 /** Symmetrize expression over a set of objects (symbols, indices). */
155 inline ex symmetrize(const ex & e, const exvector & v)
156 {
157         return symmetrize(e, v.begin(), v.end());
158 }
159
160 /** Antisymmetrize expression over a set of objects (symbols, indices). */
161 ex antisymmetrize(const ex & e, exvector::const_iterator first, exvector::const_iterator last);
162
163 /** Antisymmetrize expression over a set of objects (symbols, indices). */
164 inline ex antisymmetrize(const ex & e, const exvector & v)
165 {
166         return antisymmetrize(e, v.begin(), v.end());
167 }
168
169 /** Symmetrize expression by cyclic permuation over a set of objects
170  *  (symbols, indices). */
171 ex symmetrize_cyclic(const ex & e, exvector::const_iterator first, exvector::const_iterator last);
172
173 /** Symmetrize expression by cyclic permutation over a set of objects
174  *  (symbols, indices). */
175 inline ex symmetrize_cyclic(const ex & e, const exvector & v)
176 {
177         return symmetrize(e, v.begin(), v.end());
178 }
179
180 } // namespace GiNaC
181
182 #endif // ndef __GINAC_SYMMETRY_H__