1 #include "symmetry.h"
2 
3 #include "printer.h"
4 #include "log.h"
5 #include <iostream>
6 
7 #include <map>
8 using namespace std;
9 
10 class Trie
11 {
12 	class TrieNode
13 	{
14 		typedef map<int,class TrieNode> Map;
15 		Map m;
16 		int value;//used for storing index in vector of permutations
17 	public:
TrieNode()18 		TrieNode():
19 		  value(-1)
20 		{
21 
22 		}
TrieNode(IntegerVector const & v,int i,int value_)23 		TrieNode(IntegerVector const &v, int i, int value_)
24 		{
25 			if(i<v.size())
26 			m[v[i]]=TrieNode(v,i+1,value_);
27 			else
28 			  value=value_;
29 		}
stabilizerSize(IntegerVector const & v,int i) const30 		int stabilizerSize(IntegerVector const &v, int i)const
31 		{
32 		  int ret=0;
33 		  if(i==v.size())return 1;
34                   for(Map::const_iterator j=m.begin();j!=m.end();j++)
35                     {
36                       if(v[i]==v[j->first])
37                         ret+=j->second.stabilizerSize(v,i+1);
38                     }
39                   return ret;
40 		}
search(IntegerVector const & v,IntegerVector & building,IntegerVector & tempPerm,IntegerVector & ret,IntegerVector & optimal,int i,bool & isImproving,int * value_=0) const41 		void search(IntegerVector const &v, IntegerVector  &building, IntegerVector &tempPerm, IntegerVector &ret, IntegerVector &optimal, int i, bool &isImproving, int *value_=0)const
42 		{
43 			if(i==v.size()){ret=tempPerm;optimal=building;isImproving=false;if(value_)*value_=value;return;}
44 			if(isImproving)
45 				building[i]=-0x7fffffff;
46 			else
47 				building[i]=optimal[i];
48 			for(Map::const_iterator j=m.begin();j!=m.end();j++)
49 				if(v[j->first]>building[i])
50 				{
51 					isImproving=true;
52 					building[i]=v[j->first];
53 				}
54 				for(Map::const_iterator j=m.begin();j!=m.end();j++)
55 				if(v[j->first]==building[i])
56 				{
57 					tempPerm[i]=j->first;
58 					j->second.search(v,building,tempPerm,ret,optimal,i+1,isImproving,value_);
59 				}
60 		}
searchStabalizer(IntegerVector const & v,IntegerVector & building,IntegerVector & tempPerm,IntegerVector & ret,IntegerVector & optimal,int i,bool & isImproving,IntegerVector const & toBeFixed) const61 		void searchStabalizer(IntegerVector const &v, IntegerVector  &building, IntegerVector &tempPerm, IntegerVector &ret, IntegerVector &optimal, int i, bool &isImproving, IntegerVector const &toBeFixed)const
62 		{
63 			if(i==v.size())
64 				if(!(SymmetryGroup::compose(tempPerm,v)<optimal))
65 					{
66 					ret=tempPerm;
67 					optimal=SymmetryGroup::compose(tempPerm,v);
68 					return;
69 					}
70 				for(Map::const_iterator j=m.begin();j!=m.end();j++)
71 					if(toBeFixed[i]==toBeFixed[j->first])
72 				{
73 					tempPerm[i]=j->first;
74 					j->second.searchStabalizer(v,building,tempPerm,ret,optimal,i+1,isImproving,toBeFixed);
75 				}
76 		}
77 /* this code contains mistakes		void searchStabalizer(IntegerVector const &v, IntegerVector  &building, IntegerVector &tempPerm, IntegerVector &ret, IntegerVector &optimal, int i, bool &isImproving, IntegerVector const &toBeFixed)const
78 		{
79 			if(i==v.size()){ret=tempPerm;optimal=building;isImproving=false;debug<<"DEEP";return;}
80 			if(isImproving)
81 				building[i]=-0x7fffffff;
82 			else
83 				building[i]=optimal[i];
84 			for(Map::const_iterator j=m.begin();j!=m.end();j++)
85 				if(toBeFixed[i]==toBeFixed[j->first])
86 				if(v[j->first]>building[i])
87 				{
88 					isImproving=true;
89 					building[i]=v[j->first];
90 				}
91 				for(Map::const_iterator j=m.begin();j!=m.end();j++)
92 					if(toBeFixed[i]==toBeFixed[j->first])
93 				if(v[j->first]==building[i])
94 				{
95 					debug.printInteger(i);debug<<":";
96 					debug.printInteger(j->first);debug<<" ";
97 					tempPerm[i]=j->first;
98 					j->second.searchStabalizer(v,building,tempPerm,ret,optimal,i+1,isImproving,toBeFixed);
99 				}
100 		}*/
101 	//	void doubleSearch();
insert(IntegerVector const & v,int i,int value_)102 		void insert(IntegerVector const &v, int i, int value_)
103 		{
104 			if(i==v.size()){value=value_;return;}
105 			if(m.count(v[i]))
106 				m[v[i]].insert(v,i+1,value_);
107 			else
108 				m[v[i]]=		TrieNode(v,i+1,value_);
109 		}
print(int i,int n) const110 		void print(int i, int n)const
111 		{
112 			if(i==n){debug<<"Value:"<<value<<"\n";return;}
113 			for(Map::const_iterator j=m.begin();j!=m.end();j++)
114 			{
115 				{for(int j=0;j<2*i;j++)debug<<" ";}
116 				debug.printInteger(j->first);
117 				debug<<"\n";
118 				j->second.print(i+1,n);
119 			}
120 			}
size(int i,int n) const121 		int size(int i,int n)const
122 		{
123 			if(i==n)return 1;
124 			int ret=0;
125 			for(Map::const_iterator j=m.begin();j!=m.end();j++)
126 				ret+=j->second.size(i+1,n);
127 			return ret;
128 		}
129 	};
130 public:
131 	TrieNode theTree;
132 	int n;
Trie(int n_)133 	Trie(int n_):
134 		n(n_),
135 		theTree(SymmetryGroup::identity(n_),0,0)
136 	{
137 	}
size() const138 	int size()const
139 	{
140 		return theTree.size(0,n);
141 	}
insert(IntegerVector const & v,int value)142 	void insert(IntegerVector const &v, int value)
143 	{
144 		theTree.insert(v,0,value);
145 //		debug<<v;
146 //		theTree.print(0,v.size());
147 
148 //		debug<<"---------------------------------------------\n";
149 	}
150 	/**
151 	 * returns the sigma from the set with sigma(v) maximal in the lexicographic ordering.
152 	 */
search(IntegerVector const & v,int * value=0)153 	IntegerVector search(IntegerVector const &v, int *value=0)
154 	{
155 		IntegerVector tempPerm(v.size());
156 		IntegerVector ret(v.size());
157 		IntegerVector building(v.size());
158 		IntegerVector optimal=v;//the identity is always in the trie
159 		bool isImproving=true;
160 		theTree.search(v,building,tempPerm,ret,optimal,0,isImproving,value);
161 		return ret;
162 	}
searchStabalizer(IntegerVector const & v,IntegerVector const & toBeFixed)163 	IntegerVector searchStabalizer(IntegerVector const &v, IntegerVector const &toBeFixed)
164 	{
165 		IntegerVector tempPerm=SymmetryGroup::identity(v.size());
166 		IntegerVector ret(v.size());
167 		IntegerVector building(v.size());
168 		IntegerVector optimal=v;//the identity is always in the trie
169 		bool isImproving=true;
170 		theTree.searchStabalizer(v,building,tempPerm,ret,optimal,0,isImproving,toBeFixed);
171 		return ret;
172 	}
stabilizerSize(IntegerVector const & v) const173         int stabilizerSize(IntegerVector const &v)const
174         {
175           return theTree.stabilizerSize(v,0);
176         }
177 };
178 
179 
180 
181 
182 
183 
184 
identity(int n)185 IntegerVector SymmetryGroup::identity(int n)
186 {
187   IntegerVector v(n);
188   for(int i=0;i<n;i++)v[i]=i;
189 
190   return v;
191 }
192 
193 
inverse(IntegerVector const & a)194 IntegerVector SymmetryGroup::inverse(IntegerVector const &a)
195 {
196   return composeInverse(a,identity(a.size()));
197 }
198 
199 
SymmetryGroup(int n)200 SymmetryGroup::SymmetryGroup(int n):
201   byteTable(0),
202   trie(0)
203 {
204   elements.push_back(identity(n));
205 }
206 
207 
sizeOfBaseSet() const208 int SymmetryGroup::sizeOfBaseSet()const
209 {
210   assert(!elements.empty());
211   return elements.begin()->size();
212 }
213 /*
214 void SymmetryGroup::computeClosure(IntegerVector const &v) //does this work??
215 {
216   ElementContainer newOnes;
217 
218   newOnes.insert(v);
219 
220   while(!newOnes.empty())
221     {
222       static int i;
223       i++;
224       if((i&127)==0)fprintf(Stderr,"%i\n",i);
225 
226 
227       IntegerVector v=*newOnes.begin();
228       for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)
229 	{
230 	  {
231 	    IntegerVector n(compose(*i,v));
232 	    if(0==elements.count(n))
233 	      newOnes.insert(n);
234 	  }
235 	  {
236 	    IntegerVector n(compose(v,*i));
237 	    if(0==elements.count(n))
238 	      newOnes.insert(n);
239 	  }
240 	}
241       newOnes.erase(v);
242       elements.insert(v);
243     }
244 }
245 */
246 
computeClosure(IntegerVectorList const & l)247 void SymmetryGroup::computeClosure(IntegerVectorList const &l)
248 {
249   //  for(IntegerVectorList::const_iterator i=l.begin();i!=l.end();i++)
250   //  computeClosure(*i);
251 
252   ElementContainer2 elements2;
253   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)elements2.insert(*i);
254 
255   bool growing=true;
256   while(growing)
257     {
258       growing=false;
259       for(ElementContainer2::const_iterator i=elements2.begin();i!=elements2.end();i++)
260 	{
261 	  for(IntegerVectorList::const_iterator j=l.begin();j!=l.end();j++)
262 	    {
263 	      {
264 		IntegerVector n(compose(*i,*j));
265 		growing|=(0==elements2.count(n));
266 		elements2.insert(n);
267 	      }
268 	      {
269 		IntegerVector n(compose(*i,*j));
270 		growing|=(0==elements2.count(n));
271 		elements2.insert(n);
272 	      }
273 	    }
274 	}
275     }
276   elements=ElementContainer();
277   for(ElementContainer2::const_iterator i=elements2.begin();i!=elements2.end();i++)elements.push_back(*i);
278 }
279 
getUniqueGenerators() const280 IntegerVectorList SymmetryGroup::getUniqueGenerators()const
281 {
282   int n=sizeOfBaseSet();
283   IntegerVectorList ret;
284 
285 restart:
286   SymmetryGroup temp(n);
287   temp.computeClosure(ret);
288   ElementContainer::const_iterator j=temp.elements.begin();
289   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++,j++)
290     {
291 	  if(j==temp.elements.end()||*j!=*i)
292       	{
293           ret.push_back(*i);
294           goto restart;
295         }
296     }
297   return ret;
298 }
299 
print(FILE * f)300 void SymmetryGroup::print(FILE *f)
301 {
302   AsciiPrinter P(f);
303   P.printString("Printing SymmetryGroup\n");
304   IntegerVectorList l;
305   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)
306     {
307       //      P.printVector(*i);
308       //      P.printNewLine();
309       l.push_back(*i);
310     }
311   P.printVectorList(l);
312   fprintf(f,"Group order=%i\n",(int)elements.size());
313   P.printString("Done printing SymmetryGroup.\n");
314 }
315 
316 
compose(IntegerVector const & perm,IntegerVector const & b)317 IntegerVector SymmetryGroup::compose(IntegerVector const &perm, IntegerVector const &b)
318 {
319   IntegerVector v(perm);
320   assert(perm.size()==b.size());
321   for(int i=0;i<perm.size();i++)v[i]=b[perm[i]];
322   return v;
323 }
324 
composeAssign(IntegerVector const & perm,IntegerVector const & b,IntegerVector & dest)325 void SymmetryGroup::composeAssign(IntegerVector const &perm, IntegerVector const &b, IntegerVector &dest)
326 {
327   if(dest.size()!=perm.size())dest=IntegerVector(perm.size());
328   assert(perm.size()==b.size());
329   for(int i=0;i<perm.size();i++)dest[i]=b[perm[i]];
330 }
331 
composeInverse(IntegerVector const & perm,IntegerVector const & b)332 IntegerVector SymmetryGroup::composeInverse(IntegerVector const &perm, IntegerVector const &b)
333 {
334   IntegerVector v(perm);
335   assert(perm.size()==b.size());
336   for(int i=0;i<perm.size();i++)v[perm[i]]=b[i];
337   return v;
338 }
339 
340 
permuteInverseIntegerVectorList(IntegerVector const & perm,IntegerVectorList const & l)341 IntegerVectorList SymmetryGroup::permuteInverseIntegerVectorList(IntegerVector const &perm, IntegerVectorList const &l)
342 {
343   IntegerVectorList ret;
344   for(IntegerVectorList::const_iterator i=l.begin();i!=l.end();i++)
345     ret.push_back(composeInverse(perm,*i));
346 
347   return ret;
348 }
349 
350 
permuteIntegerVectorList(IntegerVectorList const & l,IntegerVector const & v)351 IntegerVectorList SymmetryGroup::permuteIntegerVectorList(IntegerVectorList const &l, IntegerVector const &v)
352 {
353   IntegerVectorList ret;
354   for(IntegerVectorList::const_iterator i=l.begin();i!=l.end();i++)
355     ret.push_back(compose(v,*i));
356 
357   return ret;
358 }
359 
360 
appendPermutedIntegerVectorList(IntegerVectorList const & l,IntegerVector const & perm,IntegerVectorList & dest)361 void SymmetryGroup::appendPermutedIntegerVectorList(IntegerVectorList const &l, IntegerVector const &perm, IntegerVectorList &dest)
362 {
363   int n=perm.size();
364   for(IntegerVectorList::const_iterator i=l.begin();i!=l.end();i++)
365     {
366       dest.push_back(IntegerVector(n));
367       IntegerVector & v=dest.back();
368       for(int j=0;j<n;j++)v[j]=i->UNCHECKEDACCESS(perm.UNCHECKEDACCESS(j));
369     }
370 }
371 
permutePolynomial(Polynomial const & p,IntegerVector const & v)372 Polynomial SymmetryGroup::permutePolynomial(Polynomial const &p, IntegerVector const &v)
373 {
374   Polynomial q(p.getRing());
375 
376   for(TermMap::const_iterator i=p.terms.begin();i!=p.terms.end();i++)
377     {
378       q+=Term(i->second,Monomial(p.getRing(),compose(v,i->first.exponent)));
379     }
380 
381   q.mark(Monomial(p.getRing(),compose(v,p.getMarked().m.exponent)));
382 
383   return q;
384 }
385 
386 
permutePolynomialSet(PolynomialSet const & s,IntegerVector const & v)387 PolynomialSet SymmetryGroup::permutePolynomialSet(PolynomialSet const &s, IntegerVector const &v)
388 {
389   PolynomialRing theRing=s.getRing();
390   PolynomialSet ret(theRing);
391   for(PolynomialSet::const_iterator i=s.begin();i!=s.end();i++)
392     {
393       ret.push_back(permutePolynomial(*i,v));
394     }
395 
396   return ret;
397 }
398 
399 
computeUniqueRepresentative(Polynomial p)400 Polynomial SymmetryGroup::computeUniqueRepresentative(Polynomial p)
401 {
402   Polynomial best=p;
403 
404   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)
405     {
406       Polynomial q=permutePolynomial(p,*i);
407       if(PolynomialCompare()(best,q))best=q;
408     }
409   return best;
410 }
411 
412 
orbitRepresentative(IntegerVector const & v,IntegerVector * usedPermutation) const413 IntegerVector SymmetryGroup::orbitRepresentative(IntegerVector const &v, IntegerVector *usedPermutation)const
414 {
415 	if(trie){
416 		  if(usedPermutation)
417 			  {
418 			  *usedPermutation=trie->search(v);
419 				return compose(*usedPermutation,v);
420 			  }
421 		return compose(trie->search(v),v);
422 	}
423   IntegerVector ret=v;
424   ElementContainer::const_iterator usedPerm;
425   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)
426     {
427       IntegerVector q=compose(*i,v);
428       if(! (q<ret))//negation to make sure that usedPerm is set
429 	{
430 	  usedPerm=i;
431 	  ret=q;
432 	}
433     }
434 
435   if(usedPermutation)*usedPermutation=*usedPerm;
436 
437   if(trie)
438   {
439 //	  debug<<"Input"<<v<<"\n";
440 //	  debug<<"Bruteforce"<<ret<<"\n";
441 	  IntegerVector triePerm=trie->search(v);
442 //	  debug<<"Trie"<<compose(triePerm,v)<<"\n";
443 	  assert((compose(triePerm,v)-ret).isZero());
444   }
445 
446   return ret;
447 }
448 
orbitRepresentative(IntegerVector const & v,int & usedPermutationIndex) const449 IntegerVector SymmetryGroup::orbitRepresentative(IntegerVector const &v, int &usedPermutationIndex)const
450 {
451   if(trie){
452 //      return compose(trie->search(v,&usedPermutationIndex),v);
453       IntegerVector temp=compose(trie->search(v,&usedPermutationIndex),v);
454       assert((temp-compose(elements[usedPermutationIndex],v)).isZero());
455       return temp;
456   }
457   IntegerVector ret=v;
458   ElementContainer::const_iterator usedPerm;
459   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)
460     {
461       IntegerVector q=compose(*i,v);
462       if(! (q<ret))//negation to make sure that usedPerm is set
463         {
464           usedPerm=i;
465           ret=q;
466         }
467     }
468 
469   usedPermutationIndex=usedPerm-elements.begin();
470 
471   return ret;
472 }
473 
474 
referenceToIthVector(int index) const475 IntegerVector const &SymmetryGroup::referenceToIthVector(int index)const
476 {
477   return elements[index];
478 }
479 
480 
orbitRepresentativeFixing(IntegerVector const & v,IntegerVector const & fixed) const481 IntegerVector SymmetryGroup::orbitRepresentativeFixing(IntegerVector const &v, IntegerVector const &fixed)const
482 {
483 	if(trie){
484 		return compose(trie->searchStabalizer(v,fixed),v);
485 	}
486   IntegerVector ret=v;
487 
488   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)
489     if(compose(*i,fixed)==fixed)
490       {
491 	IntegerVector q=compose(*i,v);
492 	if(ret<q)ret=q;
493       }
494 	if(trie){
495 		IntegerVector temp=compose(trie->searchStabalizer(v,fixed),v);
496 //		debug<<"Input"<<v;
497 //		debug<<"Brute"<<ret;
498 //		debug<<"Quick"<<temp;
499 		assert((temp-ret).isZero());
500 //		return compose(trie->searchStabalizer(v,fixed),v);
501 	}
502   return ret;
503 }
504 
isPermutation(IntegerVector const & a)505 bool SymmetryGroup::isPermutation(IntegerVector const &a)
506 {
507   int n=a.size();
508   IntegerVector temp(n);
509   for(int i=0;i<n;i++)temp[i]=-1;
510   for(int i=0;i<n;i++)
511     {
512       if(a[i]<0 || a[i]>=n)return false;
513       temp[i]=i;
514     }
515   for(int i=0;i<n;i++)if(temp[i]<0)return false;
516   return true;
517 }
518 
519 
combinePermutationAndSignChanges(IntegerVector const & permutation,IntegerVector const & signChanges)520 IntegerVector SymmetryGroup::combinePermutationAndSignChanges(IntegerVector const &permutation, IntegerVector const &signChanges)
521 {
522 	assert(isPermutation(permutation));
523 	int n=permutation.size();
524 	assert(n==signChanges.size());
525 	IntegerVector ret(2*n);
526 	for(int i=0;i<n;i++)
527 		if(signChanges[i]==1)
528 		{
529 			ret[i]=permutation[i];
530 			ret[i+n]=n+permutation[i];
531 		}
532 		else
533 		{
534 			ret[i]=n+permutation[i];
535 			ret[i+n]=permutation[i];
536 		}
537 	return ret;
538 }
539 
extractPermuationAndSignChanges(IntegerVector const & v,IntegerVector & permutation,IntegerVector & signChanges)540 void SymmetryGroup::extractPermuationAndSignChanges(IntegerVector const &v, IntegerVector &permutation, IntegerVector &signChanges)
541 {
542 	int n=v.size()/2;
543 	permutation=IntegerVector(n);
544 	signChanges=IntegerVector(n);
545 
546 	for(int i=0;i<n;i++)
547 	{
548 		permutation[i]=v[i]%n;
549 		if(v[i]<n)
550 			signChanges[i]=1;
551 		else
552 			signChanges[i]=-1;
553 	}
554 }
555 
556 
orbitSize(IntegerVector const & stable) const557 int SymmetryGroup::orbitSize(IntegerVector const &stable)const
558 {
559   int groupSize=elements.size();
560 
561   int n=stable.size();
562   int numFixed=0;
563 
564   if(trie)
565     {
566       numFixed=trie->stabilizerSize(stable);
567     }
568   else
569     {
570       for(SymmetryGroup::ElementContainer::const_iterator j=elements.begin();j!=elements.end();j++)
571         {
572           bool doesFix=true;
573 
574           for(int i=0;i<n;i++)
575             if(stable[i]!=stable[(*j)[i]])
576               {
577                 doesFix=false;
578                 break;
579               }
580           if(doesFix)numFixed++;
581         }
582     }
583   return groupSize/numFixed;
584 }
585 
586 
fundamentalDomainInequality(IntegerVector const & perm,bool alternative)587 IntegerVector SymmetryGroup::fundamentalDomainInequality(IntegerVector const &perm, bool alternative)
588 {
589   if(alternative)return identity(perm.size())-perm;
590   for(int i=0;i<perm.size();i++)
591     if(perm[i]!=i)
592       return IntegerVector::standardVector(perm.size(),i)-IntegerVector::standardVector(perm.size(),perm[i]);
593       //      return -IntegerVector::standardVector(perm.size(),i)-IntegerVector::standardVector(perm.size(),perm[i]);//USE this for 4x4 of 5x5
594   return IntegerVector(perm.size());
595 }
596 
597 
fundamentalDomainInequalities(bool alternative) const598 IntegerVectorList SymmetryGroup::fundamentalDomainInequalities(bool alternative)const
599 {
600   set<IntegerVector> ret2;
601   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)
602     ret2.insert(fundamentalDomainInequality(*i,alternative));
603 
604   IntegerVectorList ret;
605   for(set<IntegerVector>::const_iterator i=ret2.begin();i!=ret2.end();i++)
606     if(!i->isZero())ret.push_back(*i);
607 
608   return ret;
609 }
610 
611 
createByteTable()612 void SymmetryGroup::createByteTable()
613 {
614   assert(!byteTable);
615   int n=sizeOfBaseSet();
616   byteTableHeight=elements.size();
617   byteTable=(unsigned char*)malloc(n*byteTableHeight*sizeof(unsigned char));
618   assert(byteTable);
619   int j=0;
620   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++,j++)
621     {
622       for(int k=0;k<n;k++)
623 	byteTable[j*n+k]=(*i)[k];
624     }
625 }
626 
createTrie()627 void SymmetryGroup::createTrie()
628 {
629 	log1 debug<<"Creating symmetry trie.\n";
630 	trie=new Trie(sizeOfBaseSet());
631 	int I=0;
632 	for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++,I++)
633 		trie->insert(*i,I);
634 	log2 debug<<"Number of elements";log2 debug.printInteger(trie->size());log2 debug<<"\n";
635 	log1 debug<<"Done creating symmetry trie.\n";
636 
637 	if(0)
638 	  {
639 	    trie->theTree.print(0,elements[0].size());
640 	    I=0;
641 	    for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++,I++)
642 	      {
643 	        debug<<I<<*i<<"\n";
644 	      }
645 	  }
646 }
647 
648 
getByteTable() const649 unsigned char * SymmetryGroup::getByteTable()const
650 {
651   return byteTable;
652 }
653 
654 
getByteTableHeight() const655 int  SymmetryGroup::getByteTableHeight()const
656 {
657   return byteTableHeight;
658 }
659 
660 
isTrivial() const661 bool SymmetryGroup::isTrivial()const
662 {
663 	ElementContainer::const_iterator i=elements.begin();
664 	assert(i!=elements.end());
665 	i++;
666 	return i==elements.end();
667 }
668 
stabilizer(IntegerVector const & v) const669 IntegerVectorList SymmetryGroup::stabilizer(IntegerVector const &v)const
670 {
671   IntegerVectorList ret;
672   for(ElementContainer::const_iterator i=elements.begin();i!=elements.end();i++)
673     if((compose(*i,v)-v).isZero())ret.push_back(*i);
674   return ret;
675 }
676 
677 
mergeSortRek(IntegerVector & v,int begin,int end,IntegerVector & temp)678 static int mergeSortRek(IntegerVector &v, int begin, int end, IntegerVector &temp)
679 {
680   if(end-begin<2)return 0;
681   int med=(begin+end)>>1;
682   int nswaps=mergeSortRek(v,begin,med,temp);
683   nswaps+=mergeSortRek(v,med,end,temp);
684 
685   {
686     int Astart=begin;
687     int Alength=med-begin;
688     int Bstart=med;
689     int Blength=end-med;
690     int nextFree=begin;
691     while(nextFree!=end)
692       {
693 //        debug<<"Astart:"<<Astart<<"Alength:"<<Alength<<"Bstart:"<<Bstart<<"Blength:"<<Blength<<"nextFree:"<<nextFree<<"\n";
694         if(Blength==0 || (Alength!=0 && v[Astart]<v[Bstart]))
695           {
696             temp[nextFree++]=v[Astart++];
697             Alength--;
698           }
699         else
700           {
701             temp[nextFree++]=v[Bstart++];
702             nswaps+=Alength;
703             Blength--;
704           }
705       }
706     for(int i=begin;i!=end;i++)v[i]=temp[i];
707   }
708 //debug<<"return\n";
709   return nswaps;
710 }
711 
mergeSort(IntegerVector & v)712 int mergeSort(IntegerVector &v)
713 {
714   IntegerVector temp(v.size());
715   return mergeSortRek(v,0,v.size(),temp);
716 }
717 
718