1 // ---------------------------------------------------------------------------
2 //
3 //  This file is part of PermLib.
4 //
5 // Copyright (c) 2009-2011 Thomas Rehn <thomas@carmen76.de>
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 // 1. Redistributions of source code must retain the above copyright
12 //    notice, this list of conditions and the following disclaimer.
13 // 2. Redistributions in binary form must reproduce the above copyright
14 //    notice, this list of conditions and the following disclaimer in the
15 //    documentation and/or other materials provided with the distribution.
16 // 3. The name of the author may not be used to endorse or promote products
17 //    derived from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 // IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 // NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // ---------------------------------------------------------------------------
31 
32 
33 #ifndef PERMUTATIONWORD_H_
34 #define PERMUTATIONWORD_H_
35 
36 #include <permlib/permutation.h>
37 #include <vector>
38 
39 #include <boost/shared_ptr.hpp>
40 #include <boost/foreach.hpp>
41 
42 namespace permlib {
43 
44 typedef boost::shared_ptr<Permutation> PermutationPtr;
45 
46 /// permutation class storing permutations as words of elementary Permutation 's
47 /**
48  * interface compatible with Permutation
49  */
50 class PermutationWord {
51 public:
52 	/// typedef for permutation image
53 	typedef Permutation::perm perm;
54 
55 	/// boost shared_ptr of this class
56 	typedef boost::shared_ptr<PermutationWord> ptr;
57 
58 	/// constructs identity permutation acting on n elements
59 	explicit PermutationWord(unsigned int n);
60 	/// constructs permutation acting on n elements, given by string in cycle form
61 	PermutationWord(unsigned int n, const std::string &cycles);
62 	/// sort of copy constructor
63 	explicit PermutationWord(const perm &p);
64 	/// copy constructor
65 	PermutationWord(const PermutationWord &p);
66 
67 	/// permutation multiplication from the right
68     PermutationWord operator*(const PermutationWord &p) const;
69 	/// permutation inplace multiplication from the right
70 	/**
71 	 * i.e. THIS := THIS * p
72 	 */
73     PermutationWord& operator*=(const PermutationWord &p);
74     /// permutation inplace multiplication from the left
75 	/**
76 	 * i.e. THIS := p * THIS
77 	 */
78     PermutationWord& operator^=(const PermutationWord &p);
79 	/// permutation inversion
80     PermutationWord operator~() const;
81 	/// permutation inplace inversion
82     PermutationWord& invertInplace();
83 	/// equals operator
84     bool operator==(const PermutationWord &p2) const;
85 
86 	/// lets permutation act on val
87 	inline unsigned long operator/(unsigned long val) const { return at(val); }
88 	/// lets permutation act on val
89 	unsigned long at(unsigned long val) const;
90 	/// lets inverse permutation act on val, i.e. compute j such that (this->at(j) == val)
91 	unsigned long operator%(unsigned long val) const;
92 
93 	/// output
94 	friend std::ostream &operator<< (std::ostream &out, const PermutationWord &p);
95 
96 	/// returns true if this permutation is identity
97 	/**
98 	 * This is done by checking the image of every point, so the permutation word is multiplied out.
99 	 * After that the completely computed permutation is added as a new element to the word generator pool
100 	 */
101 	bool isIdentity(bool flush = false) const;
102 
103 	/// force that permutation word is multiplied out
104 	//TODO: it must be the other way round: isIdentity should call flush
flush()105 	inline void flush() { isIdentity(true); }
106 	/// number of points this permutation acts on
size()107 	inline unsigned int size() const { return m_n; }
108 
109 	/// number of generators in the word generator pool
elementsNumber()110 	static unsigned long elementsNumber() { return ms_elements.size(); }
111 
112 	/// deletes all elementary permutations from the storage. use ONLY if there is currently no PermutationWord in use anywhere
113 	static void clearStorage();
114 private:
115 	static std::vector<PermutationPtr> ms_elements;
116 	static std::vector<PermutationPtr> ms_elementsInverse;
117 	static void addElement(const perm &p);
118 	static void addElement(const perm &p, const perm &pInv);
119 	static void addElement(PermutationPtr p);
120 
121 	mutable std::vector<int> m_word;
122 	unsigned int m_n;
123 };
124 
125 std::vector<PermutationPtr> PermutationWord::ms_elements(1);
126 std::vector<PermutationPtr> PermutationWord::ms_elementsInverse(1);
127 
PermutationWord(unsigned int n)128 inline PermutationWord::PermutationWord(unsigned int n)
129 	: m_n(n)
130 { }
131 
PermutationWord(unsigned int n,const std::string & cycles)132 inline PermutationWord::PermutationWord(unsigned int n, const std::string &cycles)
133 	: m_n(n)
134 {
135 	Permutation *pp = new Permutation(n, cycles);
136 	ms_elements.push_back(PermutationPtr(pp));
137 	ms_elementsInverse.push_back(PermutationPtr(new Permutation(~*pp)));
138 	m_word.reserve(2);
139 	m_word.push_back(ms_elements.size()-1);
140 }
141 
PermutationWord(const PermutationWord & p)142 inline PermutationWord::PermutationWord(const PermutationWord &p)
143 	: m_word(p.m_word), m_n(p.m_n)
144 { }
145 
PermutationWord(const perm & p)146 inline PermutationWord::PermutationWord(const perm &p)
147 	: m_n(p.size())
148 {
149 	addElement(p);
150 	m_word.reserve(2);
151 	m_word.push_back(ms_elements.size()-1);
152 }
153 
addElement(const perm & p)154 inline void PermutationWord::addElement(const perm &p) {
155 	PermutationPtr gen(new Permutation(p));
156 	ms_elements.push_back(gen);
157 	PermutationPtr genInv(new Permutation(~*gen));
158 	ms_elementsInverse.push_back(genInv);
159 }
addElement(PermutationPtr p)160 inline void PermutationWord::addElement(PermutationPtr p) {
161 	ms_elements.push_back(p);
162 	PermutationPtr genInv(new Permutation(~*p));
163 	ms_elementsInverse.push_back(genInv);
164 }
165 
addElement(const perm & p,const perm & pInv)166 inline void PermutationWord::addElement(const perm &p, const perm &pInv) {
167 	PermutationPtr gen(new Permutation(p));
168 	ms_elements.push_back(gen);
169 	PermutationPtr genInv(new Permutation(pInv));
170 	ms_elementsInverse.push_back(genInv);
171 }
172 
173 
174 inline PermutationWord PermutationWord::operator*(const PermutationWord &p) const {
175 	PermutationWord res(*this);
176 	res *= p;
177 	return res;
178 }
179 
180 inline PermutationWord& PermutationWord::operator*=(const PermutationWord &p) {
181 	if (m_word.empty()) {
182 		m_word.insert(m_word.end(), p.m_word.begin(), p.m_word.end());
183 		return *this;
184 	} else if (p.m_word.empty())
185 		return *this;
186 
187 	m_word.insert(m_word.end(), p.m_word.begin(), p.m_word.end());
188 	return *this;
189 }
190 
191 inline PermutationWord& PermutationWord::operator^=(const PermutationWord &p) {
192 	if (m_word.empty()) {
193 		m_word.insert(m_word.end(), p.m_word.begin(), p.m_word.end());
194 		return *this;
195 	} else if (p.m_word.empty())
196 		return *this;
197 
198 	m_word.insert(m_word.begin(), p.m_word.begin(), p.m_word.end());
199 	return *this;
200 }
201 
202 
invertInplace()203 inline PermutationWord& PermutationWord::invertInplace() {
204 	std::vector<int> oldWord(m_word);
205 	for (unsigned int i=0; i<oldWord.size(); ++i) {
206 		m_word[i] = -oldWord[oldWord.size() - 1 - i];
207 	}
208 	return *this;
209 }
210 
211 inline PermutationWord PermutationWord::operator~() const {
212 	PermutationWord inv(*this);
213 	for (unsigned int i=0; i<m_word.size(); ++i) {
214 		inv.m_word[i] = -m_word[m_word.size() - 1 - i];
215 	}
216 	return inv;
217 }
218 
at(unsigned long val)219 inline unsigned long PermutationWord::at(unsigned long val) const {
220 	unsigned long ret = val;
221 	BOOST_FOREACH(int e, m_word) {
222 		if (e > 0)
223 			ret = *(ms_elements[e]) / ret;
224 		else
225 			ret = *(ms_elementsInverse[-e]) / ret;
226 	}
227 	return ret;
228 }
229 
230 inline unsigned long PermutationWord::operator%(unsigned long val) const {
231 	unsigned long ret = val;
232 	for (std::vector<int>::reverse_iterator lit = m_word.rbegin(); lit != m_word.rend(); ++lit) {
233 		int e = *lit;
234 		if (e < 0)
235 			ret = *(ms_elements[-e]) / ret;
236 		else
237 			ret = *(ms_elementsInverse[e]) / ret;
238 	}
239 	return ret;
240 }
241 
isIdentity(bool flush_)242 inline bool PermutationWord::isIdentity(bool flush_) const {
243 	if (m_word.empty()) {
244 		return true;
245 	}
246 	if (m_word.size() == 1) {
247 		if (flush_)
248 			return true;
249 		int e = m_word.front();
250 		if (e>0)
251 			return ms_elements[e]->isIdentity();
252 		else
253 			return ms_elementsInverse[-e]->isIdentity();
254 	}
255 
256 	perm mult(m_n);
257 	perm multInv(m_n);
258 
259 	PermutationPtr resMult(new Permutation(m_n));
260 	BOOST_FOREACH(int e, m_word) {
261 		*resMult *= (e > 0)
262 				? *ms_elements[e].get()
263 				: *ms_elementsInverse[-e].get();
264 	}
265 
266 	const bool permIsIdentity = resMult->isIdentity();
267 
268 	if (!permIsIdentity) {
269 		addElement(resMult);
270 		m_word.clear();
271 		m_word.reserve(2);
272 		m_word.push_back(ms_elements.size()-1);
273 	}
274 
275 
276 	return permIsIdentity;
277 }
278 
279 inline std::ostream &operator<< (std::ostream &out, const PermutationWord &p) {
280     out << "W[";
281     BOOST_FOREACH(int g, p.m_word) {
282         out << g << ",";
283     }
284     out << "]";
285     return out;
286 }
287 
288 inline bool PermutationWord::operator==(const PermutationWord &p2) const {
289 	if (m_n != p2.m_n)
290 		return false;
291 
292 	//TODO: is this correct or do we need the old code (below) or keep references to all perm instances?
293     //note: this is not correct: compare result of \inv{g} * g and g * \inv{g}, but this can be fixed by   .... -x x ...... stripping when multiplying
294     // in other cases it might have a good chance to work as intended
295 	//
296 	// NOTE: old code deleted from below during clean-up
297 	return m_word == p2.m_word;
298 }
299 
clearStorage()300 inline void PermutationWord::clearStorage() {
301 	ms_elements.clear();
302 	ms_elements.resize(1);
303 	ms_elementsInverse.clear();
304 	ms_elementsInverse.resize(1);
305 }
306 
307 }
308 
309 #endif // -- PERMUTATIONWORD_H_
310