1 /**
2  *
3  */
4 package student1522.project;
6 import java.util.Arrays;
7 import java.util.HashMap;
10 /**
11  * @author mvws1302
12  *
13  */
14 public class PolyaMagic {
16         /**
17          * contains the orbits trees. Each tree contains a representative element of its orbit
18          * and all elements of the equivalence class as child nodes.
19          * TODO
20          * - explain which element is representative
21          * - order of children at a given level in the tree
22          */
23         public LinkedList< PolyaTree > orbits;
25         private int[] numberOfColours;
27         private LinkedList< Permutation > generators;
29         private int[] numberOfNodesEdgesFaces;
31         public PolyaMagic(      int idxOfMathObject,
32                                                 int[] numberOfColours, //position 0/1/2: number of colours of nodes/edges/faces
33                                                 boolean withReflection ){
34                 this.numberOfNodesEdgesFaces = calculateNodesEdgesFaces( idxOfMathObject );
35                 this.numberOfColours    = numberOfColours;
36                 this.generators                 = calculateGenerators( idxOfMathObject, withReflection );
37                 this.orbits                     = calculatePolyaTrees( idxOfMathObject );
40         }
42         private int[] calculateNodesEdgesFaces(int idxOfMathObject) {
43                 int[] nodesEdgesFaces = new int[3];
44                 switch( idxOfMathObject ){
45                 case 1: // math object = tetrahedron
46                         nodesEdgesFaces[0] = 4;
47                         nodesEdgesFaces[1] = 6;
48                         nodesEdgesFaces[2] = 4;
49                         break;
50                 case 2: // math object = cube
51                         nodesEdgesFaces[0] = 8;
52                         nodesEdgesFaces[1] = 12;
53                         nodesEdgesFaces[2] = 6;
54                         break;
55                 case 3: // math object = octahedron
56                         break;
57                 case 4: // math object = dodecahedron
58                         break;
59                 }
60                 return nodesEdgesFaces;
61         }
63         private LinkedList<PolyaTree> calculatePolyaTrees( int idxMathObject ) {
65                 int numberOfColourings = 0;
66                 switch( idxMathObject ){
67                 case 1: // math object = tetrahedron
68                         numberOfColourings =    (int) Math.round( Math.pow(this.numberOfColours[0], 4) *
69                                         Math.pow(this.numberOfColours[1], 6) *
70                                         Math.pow(this.numberOfColours[2], 4) );
71                         break;
72                 case 2: // math object = cube
73                         numberOfColourings =    (int) Math.round( Math.pow(this.numberOfColours[0], 8) *
74                                                                 Math.pow(this.numberOfColours[1], 12) *
75                                                                 Math.pow(this.numberOfColours[2], 6) );
77                         break;
78                 case 3: // math object = octahedron
79                         break;
80                 case 4: // math object = dodecahedron
81                         break;
82                 }
83                 boolean[] isInTree = new boolean[ numberOfColourings ];
84 //              System.out.println( isInTree[0] );
85                 int numberOfElementsinTrees = 0;
87                 int currIdx = 0;
88                 while( numberOfElementsinTrees < numberOfColourings ){
89                         while( isInTree[ currIdx ] ){
90                                 currIdx++;
91                         }
92                         Permutation representativePerm = unrank( currIdx );
93 //                      System.out.println( rank(colouredObject) );
94 //                      System.out.println( (unrank( currIdx ) ));
95                         PolyaTree tree = new PolyaTree( representativePerm );
96                         isInTree[ currIdx ] = true;
97                         numberOfElementsinTrees++;
98                         // use generators to create full tree
99                         Permutation currPermutation;
100                         // Queue
103                         while ( !nodesToConsider.isEmpty() ){
104                                 for (int i = 0; i < this.generators.size(); i++) {
105                                         PolyaTreeNode currNode = nodesToConsider.getFirst();
106                                         currPermutation = currNode.colouring.clone();
107                                         currPermutation.permuteBy( this.generators.get( i ) );
108                                         // check if permutation is already in tree
109                                         if (!isInTree[ rank(currPermutation) ]){
110                                                 PolyaTreeNode nodeToAdd = new PolyaTreeNode( currPermutation, i );
112 //                                              System.out.println("\t" +  currPermutation );
114                                                 isInTree[ rank(currPermutation) ] = true;
115                                                 numberOfElementsinTrees++;
117                                         }
118                                 }
119                                 nodesToConsider.removeFirst();
122                         }
124                 }
126                 return trees;
127         }
129         private Permutation unrank( int number ) {
130                 int cf = this.numberOfColours[ 2 ];
131                 int ce = this.numberOfColours[ 1 ];
132                 int cn = this.numberOfColours[ 0 ];
134                 int nf = this.numberOfNodesEdgesFaces[ 2 ];
135                 int ne = this.numberOfNodesEdgesFaces[ 1 ];
136                 int nn = this.numberOfNodesEdgesFaces[ 0 ];
138                 int[] colours = new int[ nn + ne +nf ];
139                 while( number > cf -1){
140                         int numberToCompare = cf;
141                         int idx = 1;
142                         while( number >= numberToCompare && idx < nf ){
143                                 numberToCompare *= cf;
144                                 idx++;
145                         }
146                         while( number >= numberToCompare && idx >= nf && idx < nf + ne ){
147                                 numberToCompare *= ce;
148                                 idx++;
149                         }
150                         while( number >= numberToCompare && idx >= nf + ne  ){
151                                 numberToCompare *= cn;
152                                 idx++;
153                         }
155                         // move one step back
156                         if( idx <= nf ){
157                                 numberToCompare = numberToCompare / cf;
158                         }
159                         if( idx > nf && idx <= nf + ne ){
160                                 numberToCompare = numberToCompare / ce;
161                         }
162                         if( idx > nf + ne ){
163                                 numberToCompare = numberToCompare / cn;
164                         }
165                         int coeff = number / numberToCompare;
166                         colours[ colours.length - idx ] = coeff;
168                         number = number % numberToCompare;
169                 }
170                 colours[ colours.length - 1 ] = number;
171                 return new Permutation( colours );
172         }
174         private int rank( Permutation colouring ){
175                 int cf = this.numberOfColours[ 2 ];
176                 int ce = this.numberOfColours[ 1 ];
177                 int cn = this.numberOfColours[ 0 ];
179                 int nf = this.numberOfNodesEdgesFaces[ 2 ];
180                 int ne = this.numberOfNodesEdgesFaces[ 1 ];
181                 int nn = this.numberOfNodesEdgesFaces[ 0 ];
182                 int n = nf + ne + nn;
184                 int rank = 0;
185                 for (int i = 0; i < nf; i++) {
186                         rank += colouring.perm[ n - 1 - i ] * Math.pow( cf, i );
187                 }
188                 for (int i = 0; i < ne; i++) {
189                         rank += colouring.perm[ n - nf - 1 - i ] * Math.pow( ce, i ) * Math.pow( cf, nf ) ;
190                 }
191                 for (int i = 0; i < nn; i++) {
192                         rank += colouring.perm[ n - nf - ne - 1 - i ] * Math.pow( cn, i ) * Math.pow( ce, ne ) * Math.pow( cf, nf ) ;
193                 }
194                 return rank;
195         }
197         private LinkedList< Permutation > calculateGenerators(  int idxOfMathObject,
198                                                                                                                         boolean withReflection) {
199                 LinkedList< Permutation > gens = null;
200                 String[] fromIntToString = null;
201                 HashMap< String, Integer > fromStringToInt = null;
202                 Permutation nodePermutation = null;
203                 Permutation transformation = null;
205                 switch ( idxOfMathObject ){
206                 case 1: // math object = tetrahedron
207                         gens = new LinkedList< Permutation >();
208                         fromIntToString = new String[]{"1","2","3","4",
209                                         "12","13","14","23", "24", "34",
210                                         "123", "234", "124", "134"};
211                         fromStringToInt = new HashMap< String, Integer>();
212                         for ( int i = 1; i<= fromIntToString.length; i++ ) {
213                                 fromStringToInt.put( fromIntToString[ i-1 ], i);
214                         }
216                         nodePermutation = new Permutation( new int[]{1,4,2,3} );
217                         transformation = calcPermutationFromFunction( fromIntToString.clone(), fromStringToInt, nodePermutation );
220                         nodePermutation = new Permutation( new int[]{2,1,4,3} );
221                         transformation = calcPermutationFromFunction( fromIntToString.clone(), fromStringToInt, nodePermutation );
224                         if ( withReflection ){
225 //                              nodePermutation = new Permutation( new int[]{5,6,7,8,1,2,3,4} );
226 //                              transformation = calcPermutationFromFunction( fromIntToString.clone(), fromStringToInt, nodePermutation );
228                         }
230                         break;
231                 case 2: // math object = cube
232                         gens = new LinkedList< Permutation >();
233                         //nodes: 1->1, 2->4, 3->8 ,4->5, 5->2, 6->3, 7->7, 8->6
234 //                      Permutation rotationv1v7 = new Permutation( new int[]
235 //                                      {1, 4, 8, 5, 2, 3, 7, 6,
236 //                                      10, 11, 9, 16, 14, 18, 20, 17, 12, 13, 15, 19,
237 //                                      23, 21, 22, 25, 26, 24} );
239                         fromIntToString = new String[]{"1","2","3","4","5","6","7","8",
240                                                                                 "12","14","15","23", "26", "34", "37", "48", "56", "58","67","78",
241                                                                                 "1234", "1256", "1458", "2367", "3478", "5678"};
242                         fromStringToInt = new HashMap< String, Integer>();
243                         for ( int i = 1; i<= fromIntToString.length; i++ ) {
244                                 fromStringToInt.put( fromIntToString[ i-1 ], i);
245                         }
246                         nodePermutation = new Permutation( new int[]{1,4,8,5,2,3,7,6} );
247                         transformation = calcPermutationFromFunction( fromIntToString.clone(), fromStringToInt, nodePermutation );
249 //                      System.out.println( rotation.toString() );
251                         nodePermutation = new Permutation( new int[]{2,3,4,1,6,7,8,5} );
252                         transformation = calcPermutationFromFunction( fromIntToString.clone(), fromStringToInt, nodePermutation );
254 //                      System.out.println( rotation.toString() );
257                         if ( withReflection ){
258                                 nodePermutation = new Permutation( new int[]{5,6,7,8,1,2,3,4} );
259                                 transformation = calcPermutationFromFunction( fromIntToString.clone(), fromStringToInt, nodePermutation );
261                         }
263                         break;
264                 case 3: // math object = octahedron
265                         break;
266                 case 4: // math object = dodecahedron
267                         break;
268                 }
269                 return gens;
270         }
272         private Permutation calcPermutationFromFunction(        String[] fromIntToString,
273                                                                                                                 HashMap<String, Integer> fromStringToInt,
274                                                                                                                 Permutation nodePermutation) {
275                 int[] values = new int[ fromIntToString.length ];
276                 for ( int i = 0; i < fromIntToString.length; i++ ) {
277                         String str = fromIntToString[ i ];
278                         char[] chars = str.toCharArray();
279                         for (int j = 0; j < chars.length; j++) {
280                                 //System.out.println( chars[ j ]);
281                                 chars[ j ] =  fromIntToString[ nodePermutation.perm[ fromStringToInt.get( ""+chars[j]) - 1 ] - 1 ].charAt( 0 ) ;
282                         }
284                         Arrays.sort( chars );
285                         str = new String( chars );
286                         values[i] = fromStringToInt.get( str );
287                 }
288                 return new Permutation( values );
289         }
291         public static void main( String[] args ){
292                 PolyaMagic magic = new PolyaMagic( 2, new int[]{1,1,2}, false);
293         }
295 }