Spaces:
Sleeping
Sleeping
add ability to compute changes associated with a sequence of moves
Browse files- README.md +6 -5
- notebooks/dev.ipynb +14 -4
- src/rubik/action.py +11 -2
- 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 |
-
|
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
|
62 |
-
- ⬜ Find sequences of moves satisfying input constrains.
|
|
|
|
|
63 |
|
64 |
#### Base solvers following rule-based policies
|
65 |
|
66 |
-
|
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 |
-
"
|
60 |
-
"
|
61 |
-
"print(
|
62 |
-
"print(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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(
|
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(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
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 =
|
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 |
-
|
|
|
|
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)
|