Project

General

Profile

« Previous | Next » 

Revision a75b2d32

Added by Leszek Koltunski 10 months ago

progress with algorithmic solvers

View differences:

src/main/java/org/distorted/objectlib/algsolvers/MitmTable.java
21 21

  
22 22
///////////////////////////////////////////////////////////////////////////////////////////////////
23 23

  
24
  MitmTable(int bytesPerEntry)
24
  MitmTable(int numCubits, int numQuats)
25 25
    {
26
    mBytesPerEntry = bytesPerEntry;
26
    double tmp = Math.log(numQuats) / Math.log(2);
27
    double numBytes = numCubits*tmp/8;
28
    mBytesPerEntry = (int)Math.ceil(numBytes);  // this many bytes will be needed to store one position
29

  
27 30
    mData = new HashSet<>();
28 31
    }
29 32

  
......
38 41

  
39 42
  void build(SolvedObject object, int len)
40 43
    {
44
    int branchingFactor = object.getBranchingFactor();
41 45
    mData.clear();
42

  
43
    // TODO
46
    buildRecursive(object,branchingFactor,-1,len);
44 47
    }
45 48

  
46 49
///////////////////////////////////////////////////////////////////////////////////////////////////
47 50
// having built the MiTM table, try to reach it working backwards from each of the positions
48 51
// described by 'endQuats'.
49 52

  
50
  int[][] tryReaching(SolvedObject object, int[][] endQuats, int len, OperatingSystemInterface osi)
53
  int[][] tryReaching(SolvedObject object, int[][] endQuats, int len)
51 54
    {
52
    // TODO
55
    int numQuats = endQuats.length;
56
    int[] indices = new int[numQuats];
57
    boolean thereIsNext;
58

  
59
    do
60
      {
61
      int[][] ret = tryReachingRecursive(object,endQuats,indices,len);
62
      if( ret!=null ) return ret;
63
      thereIsNext = getNext(endQuats,indices);
64
      }
65
    while( thereIsNext );
53 66

  
54 67
    return null;
55 68
    }
69

  
70
///////////////////////////////////////////////////////////////////////////////////////////////////
71

  
72
  int[][] tryReachingRecursive(SolvedObject object, int[][] endQuats, int[] indices, int len)
73
    {
74
    object.setUpStartingQuats(endQuats,indices);
75

  
76

  
77
    }
78

  
79
///////////////////////////////////////////////////////////////////////////////////////////////////
80

  
81
  private void buildRecursive(SolvedObject object, int branching, int previousMove, int len)
82
    {
83
    int[] quats = object.getCubitQuats();
84
    byte[] signature = computeSignature(quats);
85
    mData.add(signature);
86

  
87
    if( len>0 )
88
      for(int m=0; m<branching; m++)
89
        if( object.movesDontClash(m,previousMove) )
90
          {
91
          object.makeMove(m);
92
          buildRecursive(object,branching,m,len-1);
93
          object.backMove(m);
94
          }
95
    }
96

  
97
///////////////////////////////////////////////////////////////////////////////////////////////////
98

  
99
  private boolean getNext(int[][] quats, int[] indices)
100
    {
101

  
102
    }
103

  
104
///////////////////////////////////////////////////////////////////////////////////////////////////
105

  
106
  private byte[] computeSignature(int[] quats)
107
    {
108
    byte[] ret = new byte[mBytesPerEntry];
109

  
110
    // TODO
111

  
112
    return ret;
113
    }
114

  
56 115
}
src/main/java/org/distorted/objectlib/algsolvers/PhaseSolutionFinder.java
29 29
  public PhaseSolutionFinder(SolvedObject object)
30 30
    {
31 31
    mObject = object;
32

  
33 32
    Static4D[] quats = object.getQuats();
34 33
    int numQuats = quats.length;
35 34
    int numCubits = mObject.getCubitPositions().length;
36
    double tmp = Math.log(numQuats) / Math.log(2);
37
    double numBytes = numCubits*tmp/8;
38
    int bytesPerEntry = (int)Math.ceil(numBytes);  // this many bytes will be needed to store
39
                                                   // one position in the MiTM table
40
    mTable  = new MitmTable(bytesPerEntry);
35
    mTable = new MitmTable(numCubits, numQuats);
41 36
    }
42 37

  
43 38
///////////////////////////////////////////////////////////////////////////////////////////////////
......
93 88
///////////////////////////////////////////////////////////////////////////////////////////////////
94 89
// Only attempt to find solutions which are not longer than maxlen; if not found, return null.
95 90
// Otherwise, return an array of moves; each move is an int[3] (axis,layer,angle)
96
// osi for reporting errors.
97 91
//
98 92
// Algorithm:
99 93
// Meet in the Middle: first, do a depth-first search and remember each position in a table; depth of
......
102 96
// valid endQuats for a given cubit) do a back-search and try to reach any of the positions from the
103 97
// table.
104 98

  
105
  private int[][] solution(int[][] endQuats, int maxlen, OperatingSystemInterface osi)
99
  private int[][] solution(int[][] endQuats, int maxlen)
106 100
    {
107 101
    float tmp = ((float)(mForwardDepth*maxlen))/(mForwardDepth+mBackwardDepth);
108 102
    int tmpForward = (int)Math.ceil(tmp);
109 103
    int tmpBackward= mForwardDepth+mBackwardDepth - tmpForward;
110 104

  
111 105
    mTable.build(mObject,tmpForward);
112
    return mTable.tryReaching(mObject,endQuats,tmpBackward,osi);
106
    return mTable.tryReaching(mObject,endQuats,tmpBackward);
113 107
    }
114 108

  
115 109
///////////////////////////////////////////////////////////////////////////////////////////////////
116 110
// Find solution and modify the non-null initQuats to match the situation after applying it.
117 111

  
118
  private int[][] findSol(int[][] endQuats, int maxlen, OperatingSystemInterface osi)
112
  private int[][] findSol(int[][] endQuats, int maxlen)
119 113
    {
120
    int[][] s = solution(endQuats,maxlen,osi);
114
    int[][] s = solution(endQuats,maxlen);
121 115

  
122 116
    if( s!=null )
123 117
      {
......
144 138
// Here we try to find a single solution in one phase, i.e. solve at once all 'endQuats'.
145 139
// (example: the white cross phase of the beginner's 3x3 - all four edges solved at once)
146 140

  
147
  int[][] findSolution(int[][] endQuats, OperatingSystemInterface osi)
141
  int[][] findSolution(int[][] endQuats)
148 142
    {
149
    return findSol(endQuats,mForwardDepth+mBackwardDepth,osi);
143
    return findSol(endQuats,mForwardDepth+mBackwardDepth);
150 144
    }
151 145

  
152 146
///////////////////////////////////////////////////////////////////////////////////////////////////
......
170 164

  
171 165
    for(; sub<numSubphases; sub++)
172 166
      {
173
      boolean success = solveAnySubphase(endQuats,solved,sub,numSubphases,tmp,solution,whichSubphase,osi);
167
      boolean success = solveAnySubphase(endQuats,solved,sub,numSubphases,tmp,solution,whichSubphase);
174 168

  
175 169
      if( !success )
176 170
        {
......
200 194
///////////////////////////////////////////////////////////////////////////////////////////////////
201 195

  
202 196
  private boolean solveAnySubphase(int[][] endQuats, boolean[] solved, int sub, int numSubphases, int[][] tmp,
203
                                   int[][][] solution, int[] whichSubphase, OperatingSystemInterface osi)
197
                                   int[][][] solution, int[] whichSubphase)
204 198
    {
205 199
    int maxDepth = mForwardDepth + mBackwardDepth;
206 200
    int numQuats = endQuats.length;
......
220 214
            endQuats[q] = (sp==-1 || sp==p || solved[sp]) ? tmp[q] : null;
221 215
            }
222 216

  
223
          solution[sub] = findSol(endQuats, l, osi);
217
          solution[sub] = findSol(endQuats,l);
224 218

  
225 219
          if( solution[sub]!=null )
226 220
            {
src/main/java/org/distorted/objectlib/algsolvers/SolvedObject.java
24 24
  private final float[][] mOrigPos;
25 25
  private final int[][] mBasicAngles;
26 26
  private final boolean[][] mRotateable;
27
  private final int mNumCubits;
28 27
  private final int[][] mQuatMult;
29 28
  private final int mNumQuats;
29
  private final int mBranchingFactor;
30
  private final int[][] mMoveTable;
30 31

  
31 32
///////////////////////////////////////////////////////////////////////////////////////////////////
32 33

  
33 34
  public SolvedObject(TwistyObject object)
34 35
    {
35
    int[] numL    = object.getNumLayers();
36
    mQuats        = object.getQuats();
37
    mOrigPos      = object.getCubitPositions(numL);
38
    mAxis         = object.getRotationAxis();
39
    mBasicAngles  = object.getBasicAngles();
40
    mRotateable   = object.getLayerRotatable(numL);
41
    mNumCubits    = mOrigPos.length;
42
    mNumQuats     = mQuats.length;
36
    int[] numL       = object.getNumLayers();
37
    mQuats           = object.getQuats();
38
    mOrigPos         = object.getCubitPositions(numL);
39
    mAxis            = object.getRotationAxis();
40
    mBasicAngles     = object.getBasicAngles();
41
    mRotateable      = object.getLayerRotatable(numL);
42
    mNumQuats        = mQuats.length;
43
    mBranchingFactor = computeBranchingFactor();
44
    mMoveTable       = computeMoveTable();
45
    int[] quatF     = computeQuatForward();
46
    int[] quatB     = computeQuatBackward();
43 47

  
44 48
    mQuatMult = new int[mNumQuats][mNumQuats];
45 49

  
46 50
    for(int i=0; i<mNumQuats; i++)
47 51
      for(int j=0; j<mNumQuats; j++) mQuatMult[i][j] = mulQuat(i,j);
48 52

  
49
    mCubits = new SolvedObjectCubit(mOrigPos,mAxis,object.getCuts(numL),mQuats);
53
    mCubits = new SolvedObjectCubit(mOrigPos,mAxis,object.getCuts(numL),mQuats,mQuatMult,mMoveTable,quatF,quatB);
50 54
    }
51 55

  
52 56
///////////////////////////////////////////////////////////////////////////////////////////////////
......
62 66
    }
63 67

  
64 68
///////////////////////////////////////////////////////////////////////////////////////////////////
65
// remember about the double cover of unit quaternions!
66 69

  
67
  private int mulQuat(int q1, int q2)
70
  void setUpStartingQuats(int[] quats)
68 71
    {
69
    Static4D result = QuatHelper.quatMultiply( mQuats[q1], mQuats[q2] );
70

  
71
    float rX = result.get0();
72
    float rY = result.get1();
73
    float rZ = result.get2();
74
    float rW = result.get3();
72
    mCubits.setUpQuats(quats);
73
    }
75 74

  
76
    final float MAX_ERROR = 0.1f;
77
    float dX,dY,dZ,dW;
75
///////////////////////////////////////////////////////////////////////////////////////////////////
78 76

  
79
    for(int i=0; i<mNumQuats; i++)
80
      {
81
      dX = mQuats[i].get0() - rX;
82
      dY = mQuats[i].get1() - rY;
83
      dZ = mQuats[i].get2() - rZ;
84
      dW = mQuats[i].get3() - rW;
77
  void rotateAllCubits(int axisIndex, int rowBitmap, int angle)
78
    {
79
    int quatIndex = makeQuaternionIndex(mAxis[axisIndex],angle);
80
    mCubits.rotateAllCubits(axisIndex,rowBitmap,quatIndex);
81
    }
85 82

  
86
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
87
          dY<MAX_ERROR && dY>-MAX_ERROR &&
88
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
89
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
83
///////////////////////////////////////////////////////////////////////////////////////////////////
90 84

  
91
      dX = mQuats[i].get0() + rX;
92
      dY = mQuats[i].get1() + rY;
93
      dZ = mQuats[i].get2() + rZ;
94
      dW = mQuats[i].get3() + rW;
85
  void makeMove(int moveIndex)
86
    {
87
    mCubits.makeMove(moveIndex);
88
    }
95 89

  
96
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
97
          dY<MAX_ERROR && dY>-MAX_ERROR &&
98
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
99
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
100
      }
90
///////////////////////////////////////////////////////////////////////////////////////////////////
101 91

  
102
    return -1;
92
  void backMove(int moveIndex)
93
    {
94
    mCubits.backMove(moveIndex);
103 95
    }
104 96

  
105 97
///////////////////////////////////////////////////////////////////////////////////////////////////
106 98

  
107
  private boolean belongsToRotation( int cubit, int axis, int rowBitmap)
99
  int[] getCubitQuats()
108 100
    {
109
    return (mCubits.getRotationRowBitmap(cubit,axis) & rowBitmap) != 0;
101
    return mCubits.getRotQuats();
110 102
    }
111 103

  
112 104
///////////////////////////////////////////////////////////////////////////////////////////////////
113 105

  
114
  void setUpStartingQuats(int[] quats)
106
  int getBranchingFactor()
115 107
    {
116
    mCubits.setUpQuats(quats);
108
    return mBranchingFactor;
117 109
    }
118 110

  
119 111
///////////////////////////////////////////////////////////////////////////////////////////////////
112
// moves clash iff they are both along the same axis and the same row
120 113

  
121
  void solve()
114
  boolean movesDontClash(int move1, int move2)
122 115
    {
123
    mCubits.solve();
116
    if( move1>=0 && move2>=0 )
117
      {
118
      int[] m1 = mMoveTable[move1];
119
      int[] m2 = mMoveTable[move2];
120

  
121
      return ( m1[0]!=m2[0] || m1[1]!=m2[1] );
122
      }
123

  
124
    return true;
124 125
    }
125 126

  
126 127
///////////////////////////////////////////////////////////////////////////////////////////////////
......
193 194

  
194 195
///////////////////////////////////////////////////////////////////////////////////////////////////
195 196

  
196
  void rotateAllCubits(int axisIndex, int rowBitmap, int angle)
197
  private int[][] computeMoveTable()
197 198
    {
198
    int quatIndex = makeQuaternionIndex(mAxis[axisIndex],angle);
199
    int[][] ret = new int[mBranchingFactor][];
200
    int numAxis = mAxis.length;
201
    int index = 0;
202

  
203
    for(int a=0; a<numAxis; a++)
204
      {
205
      int numL = mRotateable[a].length;
206

  
207
      for(int l=0; l<numL; l++)
208
        if( mRotateable[a][l] )
209
          {
210
          int basicAngle = mBasicAngles[a][l];
211
          int rowBitmap = (1<<l);
212

  
213
          for(int b=1; b<basicAngle; b++)
214
            {
215
            ret[index] = new int[] { a,rowBitmap,b };
216
            index++;
217
            }
218
          }
219
      }
199 220

  
200
    for(int c=0; c<mNumCubits; c++)
201
      if( belongsToRotation(c,axisIndex,rowBitmap) )
202
        mCubits.rotateCubit(c,quatIndex);
221
    return ret;
203 222
    }
204 223

  
205 224
///////////////////////////////////////////////////////////////////////////////////////////////////
206 225

  
207
  int getBranchingFactor()
226
  private int[] computeQuatForward()
227
    {
228
    int[] ret = new int[mBranchingFactor];
229

  
230
    for(int i=0; i<mBranchingFactor; i++)
231
      {
232
      int[] move = mMoveTable[i];
233
      int axis   = move[0];
234
      int angle  = move[2];
235
      ret[i] = makeQuaternionIndex(mAxis[axis],angle);
236
      }
237

  
238
    return ret;
239
    }
240

  
241
///////////////////////////////////////////////////////////////////////////////////////////////////
242

  
243
  private int[] computeQuatBackward()
244
    {
245
    int[] ret = new int[mBranchingFactor];
246

  
247
    for(int i=0; i<mBranchingFactor; i++)
248
      {
249
      int[] move = mMoveTable[i];
250
      int axis   = move[0];
251
      int angle  =-move[2];
252
      ret[i] = makeQuaternionIndex(mAxis[axis],angle);
253
      }
254

  
255
    return ret;
256
    }
257

  
258
///////////////////////////////////////////////////////////////////////////////////////////////////
259

  
260
  private int computeBranchingFactor()
208 261
    {
209 262
    int factor = 0;
210 263
    int numAxis = mAxis.length;
......
223 276

  
224 277
    return factor;
225 278
    }
279

  
280
///////////////////////////////////////////////////////////////////////////////////////////////////
281
// remember about the double cover of unit quaternions!
282

  
283
  private int mulQuat(int q1, int q2)
284
    {
285
    Static4D result = QuatHelper.quatMultiply( mQuats[q1], mQuats[q2] );
286

  
287
    float rX = result.get0();
288
    float rY = result.get1();
289
    float rZ = result.get2();
290
    float rW = result.get3();
291

  
292
    final float MAX_ERROR = 0.1f;
293
    float dX,dY,dZ,dW;
294

  
295
    for(int i=0; i<mNumQuats; i++)
296
      {
297
      dX = mQuats[i].get0() - rX;
298
      dY = mQuats[i].get1() - rY;
299
      dZ = mQuats[i].get2() - rZ;
300
      dW = mQuats[i].get3() - rW;
301

  
302
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
303
          dY<MAX_ERROR && dY>-MAX_ERROR &&
304
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
305
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
306

  
307
      dX = mQuats[i].get0() + rX;
308
      dY = mQuats[i].get1() + rY;
309
      dZ = mQuats[i].get2() + rZ;
310
      dW = mQuats[i].get3() + rW;
311

  
312
      if( dX<MAX_ERROR && dX>-MAX_ERROR &&
313
          dY<MAX_ERROR && dY>-MAX_ERROR &&
314
          dZ<MAX_ERROR && dZ>-MAX_ERROR &&
315
          dW<MAX_ERROR && dW>-MAX_ERROR  ) return i;
316
      }
317

  
318
    return -1;
319
    }
226 320
}
src/main/java/org/distorted/objectlib/algsolvers/SolvedObjectCubit.java
20 20
public class SolvedObjectCubit
21 21
  {
22 22
  private final int mNumCubits;
23
  private final int[][] mQuatMult;
24
  private final int[] mRotQuats;
25
  private final int[][] mMoveTable;
26
  private final int[] mQuatForwardTable;
27
  private final int[] mQuatBackwardTable;
23 28

  
24 29
  private static class CubitData
25 30
    {
26
    int quatIndex;
27
    int[] jumpIndices;
28
    int[] rotationBitmaps;
31
    int[] jumpIndices;      // size=mNumQuats. This cubit, when rotated with Nth quat, moves to
32
                            // position jumpIndices[N]. Its rotRowBitmaps are then in CubitData[jumpIndices[N]]
33
    int[] rotRowBitmaps;    // size=mNumAxis. Bitmaps of rows this cubit is at according to each rot ax.
29 34

  
30
    CubitData(int qi, int[] ji, int[] rb)
35
    CubitData(int[] ji, int[] rb)
31 36
      {
32
      quatIndex       = qi;
33
      jumpIndices     = ji;
34
      rotationBitmaps = rb;
37
      jumpIndices   = ji;
38
      rotRowBitmaps = rb;
35 39
      }
36 40
    };
37 41

  
......
51 55

  
52 56
///////////////////////////////////////////////////////////////////////////////////////////////////
53 57

  
54
  SolvedObjectCubit(float[][] pos, Static3D[] axis, float[][] cuts, Static4D[] quats)
58
  SolvedObjectCubit( float[][] pos, Static3D[] axis, float[][] cuts, Static4D[] quats, int[][] quatMult,
59
                     int[][] moveTable, int[] quatForwardTable, int[] quatBackwardTable )
55 60
    {
56 61
    mNumCubits = pos.length;
62
    mQuatMult  = quatMult;
63
    mRotQuats  = new int[mNumCubits];
64
    mMoveTable = moveTable;
65

  
66
    mQuatForwardTable = quatForwardTable;
67
    mQuatBackwardTable= quatBackwardTable;
68

  
57 69
    prapareData(pos,axis,cuts,quats);
58 70
    }
59 71

  
60 72
///////////////////////////////////////////////////////////////////////////////////////////////////
61 73

  
62
  int getRotationRowBitmap(int cubit, int axisIndex)
74
  void rotateAllCubits(int axisIndex, int rowBitmap, int quatIndex)
75
    {
76
    for(int c=0; c<mNumCubits; c++)
77
      {
78
      int q = mRotQuats[c];
79
      int ji = mData[c].jumpIndices[q];
80
      int bitmap = mData[ji].rotRowBitmaps[axisIndex];
81
      if( (bitmap&rowBitmap) != 0 ) mRotQuats[c] = mQuatMult[quatIndex][q];
82
      }
83
    }
84

  
85
///////////////////////////////////////////////////////////////////////////////////////////////////
86

  
87
  void makeMove(int moveIndex)
63 88
    {
64
    CubitData cd = mData[cubit];
65
    int ji = cd.jumpIndices[cd.quatIndex];
66
    return mData[ji].rotationBitmaps[axisIndex];
89
    int quatIndex = mQuatForwardTable[moveIndex];
90
    int[] move    = mMoveTable[moveIndex];
91
    int axisIndex = move[0];
92
    int rowBitmap = move[1];
93

  
94
    rotateAllCubits(axisIndex,rowBitmap,quatIndex);
67 95
    }
68 96

  
69 97
///////////////////////////////////////////////////////////////////////////////////////////////////
70 98

  
71
  void rotateCubit(int cubit, int quatIndex)
99
  void backMove(int moveIndex)
72 100
    {
73
    mData[cubit].quatIndex = quatIndex;
101
    int quatIndex = mQuatBackwardTable[moveIndex];
102
    int[] move    = mMoveTable[moveIndex];
103
    int axisIndex = move[0];
104
    int rowBitmap = move[1];
105

  
106
    rotateAllCubits(axisIndex,rowBitmap,quatIndex);
74 107
    }
75 108

  
76 109
///////////////////////////////////////////////////////////////////////////////////////////////////
77 110

  
78 111
  void setUpQuats(int[] quats)
79 112
    {
80
    for(int c=0; c<mNumCubits; c++)
81
      {
82
      mData[c].quatIndex = quats[c];
83
      }
113
    for(int c=0; c<mNumCubits; c++) mRotQuats[c] = quats[c];
84 114
    }
85 115

  
86 116
///////////////////////////////////////////////////////////////////////////////////////////////////
87 117

  
88
  void solve()
118
  int[] getRotQuats()
89 119
    {
90
    for(int c=0; c<mNumCubits; c++)
91
      {
92
      mData[c].quatIndex = 0;
93
      }
120
    return mRotQuats;
94 121
    }
95 122

  
96 123
///////////////////////////////////////////////////////////////////////////////////////////////////
97 124

  
98
  int computeRow(Static3D axis, float[] cuts, float[] pos)
125
  private int computeRow(Static3D axis, float[] cuts, float[] pos)
99 126
    {
100 127
    int ret=0;
101 128
    int len = pos.length / 3;
......
253 280
    for(int c=0; c<size; c++)
254 281
      {
255 282
      RotData rd = data.get(c);
256
      mData[c] = new CubitData(0,jumpTable[c],rd.bitmaps);
283
      mData[c] = new CubitData(jumpTable[c],rd.bitmaps);
257 284
      }
258 285
    }
259 286
}

Also available in: Unified diff