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