JBAujogue commited on
Commit
b24b865
·
1 Parent(s): 4145e1a

add ability to compute changes associated with a sequence of moves

Browse files
Files changed (4) hide show
  1. README.md +6 -5
  2. notebooks/dev.ipynb +14 -4
  3. src/rubik/action.py +11 -2
  4. src/rubik/cube.py +14 -3
README.md CHANGED
@@ -7,7 +7,7 @@ This project uses `uv 0.7` as environment & dependency manager, and `python 3.11
7
 
8
  ```shell
9
  uv venv
10
- (Activate env)
11
  uv sync
12
  pre-commit install
13
  ```
@@ -54,16 +54,17 @@ cube.rotate('X2 X1i Y1i Z1i Y0 Z0i X2 X1i Y1i Z1i Y0 Z0i')
54
  - ☑️ Tensorized states.
55
  - ☑️ Tensorized actions.
56
  - ☑️ Interface for performing actions.
57
- - ⬜ Tensor operations moved to cuda.
58
 
59
  #### Movement explorer
60
 
61
- - ⬜ Explore result of an input sequences of moves.
62
- - ⬜ Find sequences of moves satisfying input constrains.
 
 
63
 
64
  #### Base solvers following rule-based policies
65
 
66
- #### Visualization interface
67
 
68
 
69
  ## Related projects
 
7
 
8
  ```shell
9
  uv venv
10
+ -- Activate env --
11
  uv sync
12
  pre-commit install
13
  ```
 
54
  - ☑️ Tensorized states.
55
  - ☑️ Tensorized actions.
56
  - ☑️ Interface for performing actions.
 
57
 
58
  #### Movement explorer
59
 
60
+ - ⬜ Explore changes resulting from a sequences of moves.
61
+ - ⬜ Find least sequences of moves satisfying some input constrains.
62
+
63
+ #### Visualization interface
64
 
65
  #### Base solvers following rule-based policies
66
 
67
+
68
 
69
 
70
  ## Related projects
notebooks/dev.ipynb CHANGED
@@ -56,10 +56,20 @@
56
  "metadata": {},
57
  "outputs": [],
58
  "source": [
59
- "cubis_cpu = copy.deepcopy(cube)\n",
60
- "cubis_cpu.shuffle(2000, seed=0)\n",
61
- "print(cubis_cpu)\n",
62
- "print(cubis_cpu.history)"
 
 
 
 
 
 
 
 
 
 
63
  ]
64
  },
65
  {
 
56
  "metadata": {},
57
  "outputs": [],
58
  "source": [
59
+ "cubis = copy.deepcopy(cube)\n",
60
+ "cubis.shuffle(2000, seed=0)\n",
61
+ "print(cubis)\n",
62
+ "print(cubis.history)"
63
+ ]
64
+ },
65
+ {
66
+ "cell_type": "code",
67
+ "execution_count": null,
68
+ "id": "cb29c742",
69
+ "metadata": {},
70
+ "outputs": [],
71
+ "source": [
72
+ "cubis.compute_changes(\"X2 X1i Y1i Z1i Y0 Z0i X2 X1i Y1i Z1i Y0 Z0i \")"
73
  ]
74
  },
75
  {
src/rubik/action.py CHANGED
@@ -123,14 +123,23 @@ def build_action_tensor(size: int, axis: int, slice: int, inverse: int) -> torch
123
  return torch.sparse_coo_tensor(indices=perm_indices, values=perm_values, size=perm_size, dtype=torch.int8)
124
 
125
 
126
- def parse_action_str(name: str) -> tuple[int, ...]:
127
  """
128
  Convert the name of an action into a triple (axis, slice, inverse).
129
  Examples:
130
  'X1' -> (0, 1, 0)
131
  'X2i' -> (0, 2, 1)
132
  """
133
- return ("XYZ".index(name[0]), int(name[1]), int(len(name) >= 3))
 
 
 
 
 
 
 
 
 
134
 
135
 
136
  def sample_actions_str(num_moves: int, size: int, seed: int = 0) -> str:
 
123
  return torch.sparse_coo_tensor(indices=perm_indices, values=perm_values, size=perm_size, dtype=torch.int8)
124
 
125
 
126
+ def parse_action_str(move: str) -> tuple[int, ...]:
127
  """
128
  Convert the name of an action into a triple (axis, slice, inverse).
129
  Examples:
130
  'X1' -> (0, 1, 0)
131
  'X2i' -> (0, 2, 1)
132
  """
133
+ return ("XYZ".index(move[0]), int(move[1]), int(len(move) >= 3))
134
+
135
+
136
+ def parse_actions_str(moves: str) -> list[tuple[int, ...]]:
137
+ """
138
+ Convert a sequence of actions in a string into a list of triples (axis, slice, inverse).
139
+ Examples:
140
+ 'X1 X2i' -> [(0, 1, 0), (0, 2, 1)]
141
+ """
142
+ return [parse_action_str(move) for move in moves.strip().split()]
143
 
144
 
145
  def sample_actions_str(num_moves: int, size: int, seed: int = 0) -> str:
src/rubik/cube.py CHANGED
@@ -1,9 +1,10 @@
 
1
  from loguru import logger
2
 
3
  import torch
4
  import torch.nn.functional as F
5
 
6
- from rubik.action import build_actions_tensor, parse_action_str, sample_actions_str
7
  from rubik.display import stringify
8
  from rubik.tensor_utils import build_cube_tensor
9
 
@@ -63,7 +64,7 @@ class Cube:
63
  """
64
  Apply a sequence of moves (defined as plain string) to the cube.
65
  """
66
- actions = [parse_action_str(move) for move in moves.strip().split()]
67
  for action in actions:
68
  self.rotate_once(*action)
69
  return
@@ -77,6 +78,15 @@ class Cube:
77
  self.history.append([axis, slice, inverse])
78
  return
79
 
 
 
 
 
 
 
 
 
 
80
  def solve(self, policy: str) -> None:
81
  """
82
  Apply the specified solving policy to the cube.
@@ -87,4 +97,5 @@ class Cube:
87
  """
88
  Compute a string representation of a cube.
89
  """
90
- return stringify(self.state.argmax(dim=-1).to(device="cpu", dtype=torch.int8), self.colors, self.size)
 
 
1
+ from functools import reduce
2
  from loguru import logger
3
 
4
  import torch
5
  import torch.nn.functional as F
6
 
7
+ from rubik.action import build_actions_tensor, parse_actions_str, sample_actions_str
8
  from rubik.display import stringify
9
  from rubik.tensor_utils import build_cube_tensor
10
 
 
64
  """
65
  Apply a sequence of moves (defined as plain string) to the cube.
66
  """
67
+ actions = parse_actions_str(moves)
68
  for action in actions:
69
  self.rotate_once(*action)
70
  return
 
78
  self.history.append([axis, slice, inverse])
79
  return
80
 
81
+ def compute_changes(self, moves: str) -> dict[int, int]:
82
+ """
83
+ combine a sequence of moves and return the resulting changes.
84
+ """
85
+ actions = parse_actions_str(moves)
86
+ tensors = [self.actions[*action].to(torch.float32) for action in actions]
87
+ result = reduce(lambda A, B: A @ B, tensors).to(torch.int8)
88
+ return dict(result.indices().transpose(0, 1).tolist())
89
+
90
  def solve(self, policy: str) -> None:
91
  """
92
  Apply the specified solving policy to the cube.
 
97
  """
98
  Compute a string representation of a cube.
99
  """
100
+ state = self.state.argmax(dim=-1).to(device="cpu", dtype=torch.int8)
101
+ return stringify(state, self.colors, self.size)