public void EoEquatorCoordinateTest() { bool found; for (int expanded = 0; expanded < NumEquatorDistributions * NumEdgeOrientations; expanded++) { found = false; int reduced = SymmetryReduction.ReduceEoEquatorCoordinate[expanded]; int expandedSym = SymmetryReduction.ExpandEoEquatorCoordinate[reduced]; CubieCube expandedCube = CubieCube.CreateSolved(); SetEdgeOrientation(expandedCube, expanded % 2048); SetEquatorDistribution(expandedCube, expanded / 2048); for (int sym = 0; sym < NumSymmetriesDh4; sym++) { CubieCube symCube = Symmetries.SymmetryCubes[sym].Clone(); symCube.MultiplyEdges(expandedCube); symCube.MultiplyEdges(Symmetries.SymmetryCubes[Symmetries.InverseIndex[sym]]); if (expandedSym % 2048 == GetEdgeOrientation(symCube) && expandedSym / 2048 == GetEquatorDistribution(symCube)) { found = true; break; } } if (!found) { Assert.Fail(); } } }
/// <summary> /// Create a move table for U- and D-edge order. Only valid for cubes /// in the subgroup G1. /// </summary> /// <returns> /// A move table for U- and D-edge order. /// </returns> public static ushort[,] CreateUdEdgeOrderMoveTable() { ushort[,] udEdgeOrderMoveTable = new ushort[Coordinates.NumUdEdgeOrders, TwoPhaseConstants.NumMovesPhase2]; //invalidate table for (int udEdgeOrder = 0; udEdgeOrder < Coordinates.NumUdEdgeOrders; udEdgeOrder++) { for (int move = 0; move < TwoPhaseConstants.NumMovesPhase2; move++) { udEdgeOrderMoveTable[udEdgeOrder, move] = ushort.MaxValue; } } //populate table for (int udEdgeOrder = 0; udEdgeOrder < Coordinates.NumCornerPermutations; udEdgeOrder++) { for (int face = 0; face < NumFaces; face++) { CubieCube cube = CubieCube.CreateSolved(); Coordinates.SetUdEdgeOrder(cube, udEdgeOrder); for (int move = 0; move < 3; move++) { cube.MultiplyEdges(CubieCube.MovesArray[face * 3]); if (TwoPhaseConstants.Phase2Moves.Contains((Move)(face * 3 + move))) { udEdgeOrderMoveTable[udEdgeOrder, Phase1IndexToPhase2Index[face * 3 + move]] = (ushort)Coordinates.GetUdEdgeOrder(cube); } } } } return(udEdgeOrderMoveTable); }
/// <summary> /// Create a move table for edge orientation. /// </summary> /// <returns> /// A move table for edge orientation. /// </returns> public static short[,] CreateEdgeOrientationMoveTable() { CubieCube cube = CubieCube.CreateSolved(); short[,] edgeOrientationMoveTable = new short[Coordinates.NumEdgeOrientations, NumMoves]; //invalidate table for (int edgeOrientation = 0; edgeOrientation < Coordinates.NumEdgeOrientations; edgeOrientation++) { for (int move = 0; move < NumMoves; move++) { edgeOrientationMoveTable[edgeOrientation, move] = -1; } } //populate table for (int edgeOrientation = 0; edgeOrientation < Coordinates.NumEdgeOrientations; edgeOrientation++) { for (int face = 0; face < NumFaces; face++) { Coordinates.SetEdgeOrientation(cube, edgeOrientation); for (int move = 0; move < 3; move++) { cube.MultiplyEdges(CubieCube.MovesArray[face * 3]); edgeOrientationMoveTable[edgeOrientation, face * 3 + move] = (short)Coordinates.GetEdgeOrientation(cube); } } } return(edgeOrientationMoveTable); }
//TODO remove redundant indexes /// <summary> /// Create a move table for equator order. Only valid for cubes in the /// subgroup G1. /// </summary> /// <returns> /// A move table for equator order. /// </returns> public static sbyte[,] CreateEquatorOrderMoveTable() { sbyte[,] equatorOrderMoveTable = new sbyte[Coordinates.NumEquatorOrders, NumMoves]; //invalidate table for (int equatorOrder = 0; equatorOrder < Coordinates.NumEquatorOrders; equatorOrder++) { for (int move = 0; move < NumMoves; move++) { equatorOrderMoveTable[equatorOrder, move] = -1; } } //populate table for (int equatorOrder = 0; equatorOrder < Coordinates.NumEquatorOrders; equatorOrder++) { for (int face = 0; face < NumFaces; face++) { CubieCube cube = CubieCube.CreateSolved(); Coordinates.SetEquatorOrder(cube, equatorOrder); for (int move = 0; move < 3; move++) { cube.MultiplyEdges(CubieCube.MovesArray[face * 3]); if (TwoPhaseConstants.Phase2Moves.Contains((Move)(face * 3 + move))) { equatorOrderMoveTable[equatorOrder, face * 3 + move] = (sbyte)Coordinates.GetEquatorOrder(cube); } } } } return(equatorOrderMoveTable); }
static SymmetryReduction() { //avoid naming conflicts CubieCube cube; int reducedEoEquator, reducedCornerPermutation; #region initialize ConjugateCoCoordinate ConjugateCornerOrientationCoordinate = new int[NumCornerOrientations, NumSymmetriesDh4]; //invalidate for (int cornerOrientation = 0; cornerOrientation < NumCornerOrientations; cornerOrientation++) { for (int symmetryIndex = 0; symmetryIndex < NumSymmetriesDh4; symmetryIndex++) { ConjugateCornerOrientationCoordinate[cornerOrientation, symmetryIndex] = -1; } } //populate cube = CubieCube.CreateSolved(); for (int cornerOrientation = 0; cornerOrientation < NumCornerOrientations; cornerOrientation++) { cube.IsMirrored = false; //TEST if necessary SetCornerOrientation(cube, cornerOrientation); for (int symmetryIndex = 0; symmetryIndex < NumSymmetriesDh4; symmetryIndex++) { //conjugate cube CubieCube symmetryCube = SymmetryCubes[symmetryIndex].Clone(); symmetryCube.MultiplyCorners(cube); symmetryCube.MultiplyCorners(SymmetryCubes[InverseIndex[symmetryIndex]]); //store result ConjugateCornerOrientationCoordinate[cornerOrientation, symmetryIndex] = GetCornerOrientation(symmetryCube); } } #endregion initialize ConjugateCoCoordinate //TODO simplify #region initialize ReduceEoEquatorCoordinate, ExpandEoEquatorCoordinate and EoEquatorReductionSymmetry //initialize and invalidate ReduceEoEquatorCoordinate = Enumerable.Repeat(-1, NumEquatorDistributions * NumEdgeOrientations) .ToArray(); ExpandEoEquatorCoordinate = Enumerable.Repeat(-1, NumEoEquatorSymmetryClasses) .ToArray(); EoEquatorReductionSymmetry = Enumerable.Repeat(-1, NumEquatorDistributions * NumEdgeOrientations) .ToArray(); //populate cube = CubieCube.CreateSolved(); reducedEoEquator = 0; for (int equatorDistribution = 0; equatorDistribution < NumEquatorDistributions; equatorDistribution++) { SetEquatorDistribution(cube, equatorDistribution); for (int edgeOrientation = 0; edgeOrientation < NumEdgeOrientations; edgeOrientation++) { int eoEquator = NumEdgeOrientations * equatorDistribution + edgeOrientation; if (ReduceEoEquatorCoordinate[eoEquator] == -1) { SetEdgeOrientation(cube, edgeOrientation); //store representative ReduceEoEquatorCoordinate[eoEquator] = reducedEoEquator; EoEquatorReductionSymmetry[eoEquator] = 0; ExpandEoEquatorCoordinate[reducedEoEquator] = eoEquator; //go through all symmetries of the current cube and set //their reduced index to the same full index for (int symmetryIndex = 0; symmetryIndex < NumSymmetriesDh4; symmetryIndex++) { //symmetry ^ -1 * cube * symmetry CubieCube symCube = SymmetryCubes[InverseIndex[symmetryIndex]].Clone(); symCube.MultiplyEdges(cube); symCube.MultiplyEdges(SymmetryCubes[symmetryIndex]); //store int newEdgeOrientation = GetEdgeOrientation(symCube); int newEquatorDistribution = GetEquatorDistribution(symCube); int newEoEquator = NumEdgeOrientations * newEquatorDistribution + newEdgeOrientation; //TODO test if necessary if (ReduceEoEquatorCoordinate[newEoEquator] == -1) { ReduceEoEquatorCoordinate[newEoEquator] = reducedEoEquator; EoEquatorReductionSymmetry[newEoEquator] = symmetryIndex; } } reducedEoEquator++; } } } #endregion initialize ReduceEoEquatorCoordinate, ExpandEoEquatorCoordinate and EoEquatorReductionSymmetry #region initialize EoEquatorSymmetries //initialize and invalidate EoEquatorSymmetries = Enumerable.Repeat(0, NumEoEquatorSymmetryClasses) .ToArray(); //populate cube = CubieCube.CreateSolved(); for (reducedEoEquator = 0; reducedEoEquator < NumEoEquatorSymmetryClasses; reducedEoEquator++) { //set cube to the representative of the reduced index int eoEquator = ExpandEoEquatorCoordinate[reducedEoEquator]; SetEoEquatorCoord(cube, eoEquator); //find all symmetries of the cube for (int symmetryIndex = 0; symmetryIndex < NumSymmetriesDh4; symmetryIndex++) { //symmetry * cube * symmetry ^ -1 CubieCube symmetryCube = SymmetryCubes[symmetryIndex].Clone(); symmetryCube.MultiplyEdges(cube); symmetryCube.MultiplyEdges(SymmetryCubes[InverseIndex[symmetryIndex]]); //set flag if symmetrical int newEoEquator = GetEoEquatorCoord(symmetryCube); if (eoEquator == newEoEquator) { EoEquatorSymmetries[reducedEoEquator] |= 1 << symmetryIndex; } } } #endregion initialize EoEoquatorSymmetries #region initialize ConjugateUdEdgeOrderCoordinate ConjugateUdEdgeOrderCoordinate = new int[NumUdEdgeOrders, NumSymmetriesDh4]; //invalidate for (int udEdgeOrders = 0; udEdgeOrders < NumUdEdgeOrders; udEdgeOrders++) { for (int symmetryIndex = 0; symmetryIndex < NumSymmetriesDh4; symmetryIndex++) { ConjugateUdEdgeOrderCoordinate[udEdgeOrders, symmetryIndex] = -1; } } //populate cube = CubieCube.CreateSolved(); for (int udEdgePermutation = 0; udEdgePermutation < NumUdEdgeOrders; udEdgePermutation++) { SetUdEdgeOrder(cube, udEdgePermutation); for (int symmetryIndex = 0; symmetryIndex < NumSymmetriesDh4; symmetryIndex++) { //conjugate cube CubieCube symmetryCube = SymmetryCubes[symmetryIndex].Clone(); symmetryCube.MultiplyEdges(cube); symmetryCube.MultiplyEdges(SymmetryCubes[InverseIndex[symmetryIndex]]); //store result ConjugateUdEdgeOrderCoordinate[udEdgePermutation, symmetryIndex] = GetUdEdgeOrder(symmetryCube); } } #endregion initialize ConjugateUdEdgeOrderCoordinate #region initialize ReduceCpCoordinate, ExpandCpCoordinate and CpReductionSymmetry //initialize and invalidate ReduceCornerPermutationCoordinate = Enumerable.Repeat(-1, NumCornerPermutations) .ToArray(); ExpandCornerPermutationCoordinate = Enumerable.Repeat(-1, NumCornerPermutationSymmetryClasses) .ToArray(); CornerPermutationReductionSymmetry = Enumerable.Repeat(-1, NumCornerPermutations) .ToArray(); //populate cube = CubieCube.CreateSolved(); reducedCornerPermutation = 0; for (int cornerPermutation = 0; cornerPermutation < NumCornerPermutations; cornerPermutation++) { if (ReduceCornerPermutationCoordinate[cornerPermutation] == -1) { cube.IsMirrored = false; //TEST if necessary SetCornerPermutation(cube, cornerPermutation); //store representative ReduceCornerPermutationCoordinate[cornerPermutation] = reducedCornerPermutation; CornerPermutationReductionSymmetry[cornerPermutation] = 0; ExpandCornerPermutationCoordinate[reducedCornerPermutation] = cornerPermutation; //go through all symmetries of the current cube and set //their reduced index to the same full index for (int symmetryIndex = 0; symmetryIndex < NumSymmetriesDh4; symmetryIndex++) { //symmetry ^ -1 * cube * symmetry CubieCube symmetryCube = SymmetryCubes[InverseIndex[symmetryIndex]].Clone(); symmetryCube.MultiplyCorners(cube); symmetryCube.MultiplyCorners(SymmetryCubes[symmetryIndex]); //store int newCornerPermutation = GetCornerPermutation(symmetryCube); //TODO test if necessary if (ReduceCornerPermutationCoordinate[newCornerPermutation] == -1) { ReduceCornerPermutationCoordinate[newCornerPermutation] = reducedCornerPermutation; CornerPermutationReductionSymmetry[newCornerPermutation] = symmetryIndex; } } reducedCornerPermutation++; } } #endregion initialize ReduceCpCoordinate, ExpandCpCoordinate and CpReductionSymmetry #region initialize CpSymmetries CornerPermutationSymmetries = Enumerable.Repeat(0, NumCornerPermutationSymmetryClasses) .ToArray(); cube = CubieCube.CreateSolved(); for (reducedCornerPermutation = 0; reducedCornerPermutation < NumCornerPermutationSymmetryClasses; reducedCornerPermutation++) { //set cube to the representative of the reduced index int cornerPermutation = ExpandCornerPermutationCoordinate[reducedCornerPermutation]; SetCornerPermutation(cube, cornerPermutation); //find all symmetries of the cube for (int symmetryIndex = 0; symmetryIndex < NumSymmetriesDh4; symmetryIndex++) { //symmetry * cube * symmetry ^ -1 CubieCube symmetryCube = SymmetryCubes[symmetryIndex].Clone(); symmetryCube.MultiplyCorners(cube); symmetryCube.MultiplyCorners(SymmetryCubes[InverseIndex[symmetryIndex]]); //set flag if symmetrical int newCornerPermutation = GetCornerPermutation(symmetryCube); if (cornerPermutation == newCornerPermutation) { CornerPermutationSymmetries[reducedCornerPermutation] |= 1 << symmetryIndex; } } } #endregion initialize CpSymmetries }