diff options
| author | Sebastiano Tronto <sebastiano@tronto.net> | 2024-10-01 19:20:16 +0200 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano@tronto.net> | 2024-10-01 19:20:16 +0200 |
| commit | 8d3fe446815a1631876e4170747bc6cb03a6bbf8 (patch) | |
| tree | ae83f73e14d3699c6cf89cbf812ed1c8a9956698 | |
| parent | e3d0efaebd00af412602ae71062d24d7977e443a (diff) | |
| download | nissy-core-8d3fe446815a1631876e4170747bc6cb03a6bbf8.tar.gz nissy-core-8d3fe446815a1631876e4170747bc6cb03a6bbf8.zip | |
Updated h48 doc
Diffstat (limited to '')
| -rw-r--r-- | doc/h48.md | 103 |
1 files changed, 81 insertions, 22 deletions
| @@ -132,7 +132,7 @@ The H48 solver uses a target group that is invariant under all 48 | |||
| 132 | symmetries. This group is defined as follows: | 132 | symmetries. This group is defined as follows: |
| 133 | 133 | ||
| 134 | * Each corner is placed in the *corner tetrad* it belongs to, and it | 134 | * Each corner is placed in the *corner tetrad* it belongs to, and it |
| 135 | is oriented. Here by corner tetrad we means one of the two sets of | 135 | is oriented. Here by corner tetrad we mean one of the two sets of |
| 136 | corners {UFR, UBL, DFL, DBR} and {UFL, UBR, DFR, DBL}. For a corner | 136 | corners {UFR, UBL, DFL, DBR} and {UFL, UBR, DFR, DBL}. For a corner |
| 137 | that is placed in its own tetrad, the orientation does not depend on | 137 | that is placed in its own tetrad, the orientation does not depend on |
| 138 | the reference axis chosen, and an oriented corner can be defined | 138 | the reference axis chosen, and an oriented corner can be defined |
| @@ -171,17 +171,17 @@ is a little too much for most personal computers. | |||
| 171 | 171 | ||
| 172 | One can wonder if it is possible to use a coordinate that considers | 172 | One can wonder if it is possible to use a coordinate that considers |
| 173 | the orientation of only *some* of the edges, which we may call **h1** | 173 | the orientation of only *some* of the edges, which we may call **h1** |
| 174 | to **h10**. Such coordinates do exist, but it is not invariant under the | 174 | to **h10**. Such coordinates do exist, but they are not invariant under |
| 175 | full symmetry group: indeed an edge whose orientation we keep track of | 175 | the full symmetry group: indeed an edge whose orientation we keep track |
| 176 | could be moved to any of the untracked edges' positions by one of the | 176 | of could be moved to any of the untracked edges' positions by one of |
| 177 | symmetries, making the whole coordinate ill-defined. | 177 | the symmetries, making the whole coordinate ill-defined. |
| 178 | 178 | ||
| 179 | It is however possible to compute the symmetry-reduced pruning tables | 179 | It is however possible to compute the symmetry-reduced pruning tables |
| 180 | for these coordinates. One way to construct them is by taking the **h11** | 180 | for these coordinates. One way to construct them is by taking the **h11** |
| 181 | pruning table and "forgetting" about some of the edge orientation values, | 181 | pruning table and "forgetting" about some of the edge orientation values, |
| 182 | collapsing 2 (or a power thereof) values to one by taking the minimum. | 182 | collapsing 2 (or a power thereof) values to one by taking the minimum. |
| 183 | It is also possible to compute these tables directly, as explained in | 183 | It is also possible to compute these tables directly, as explained in |
| 184 | the **Pruning table computation** section below (work in progress). | 184 | the **Pruning table computation** section below. |
| 185 | 185 | ||
| 186 | ### Coordinate computation for pruning value estimation | 186 | ### Coordinate computation for pruning value estimation |
| 187 | 187 | ||
| @@ -220,9 +220,6 @@ Once we have computed the full h0 coordinate, we can access the correct | |||
| 220 | entry in the full pruning table. As mentioned above, the pruning table | 220 | entry in the full pruning table. As mentioned above, the pruning table |
| 221 | can be one of three kinds: | 221 | can be one of three kinds: |
| 222 | 222 | ||
| 223 | (Work in progress - the only kind of table currently implemented is | ||
| 224 | the 4 bits per entry table) | ||
| 225 | |||
| 226 | * 4 bits per entry, or `k4`: In this case the pruning value (between 0 | 223 | * 4 bits per entry, or `k4`: In this case the pruning value (between 0 |
| 227 | and 15) can be simply read off the table. | 224 | and 15) can be simply read off the table. |
| 228 | * 2 bits per entry, or `k2`: Tables of this kind work as described by | 225 | * 2 bits per entry, or `k2`: Tables of this kind work as described by |
| @@ -236,7 +233,6 @@ the 4 bits per entry table) | |||
| 236 | cannot take b as a lower bount. Instead we have to use a pruning value from | 233 | cannot take b as a lower bount. Instead we have to use a pruning value from |
| 237 | another table, for example the corner-only table mentioned in the previous | 234 | another table, for example the corner-only table mentioned in the previous |
| 238 | section, or a completely new one. | 235 | section, or a completely new one. |
| 239 | (Work in progress - `k2` tables not available in the code yet) | ||
| 240 | * 1 bit per entry, or `k1`: With one bit per entry, the only information we | 236 | * 1 bit per entry, or `k1`: With one bit per entry, the only information we |
| 241 | can get from the pruning table is wether or not the current position | 237 | can get from the pruning table is wether or not the current position |
| 242 | requires more or fewer moves than a fixed base value b. This can still be | 238 | requires more or fewer moves than a fixed base value b. This can still be |
| @@ -249,8 +245,6 @@ the 4 bits per entry table) | |||
| 249 | After computing the pruning value, there are a number of different tricks | 245 | After computing the pruning value, there are a number of different tricks |
| 250 | that can be used to improve the estimation. | 246 | that can be used to improve the estimation. |
| 251 | 247 | ||
| 252 | (Work in progress - the following techniques are not implemented yet) | ||
| 253 | |||
| 254 | #### Inverse estimate | 248 | #### Inverse estimate |
| 255 | 249 | ||
| 256 | A cube position and its inverse will, in general, give a different | 250 | A cube position and its inverse will, in general, give a different |
| @@ -299,8 +293,6 @@ Other possible (low-level) optimizations include: | |||
| 299 | is expensive. We can avoid doing that (for the inverse pruning value | 293 | is expensive. We can avoid doing that (for the inverse pruning value |
| 300 | estimate) if we bring along both the normal and the inverse cube during | 294 | estimate) if we bring along both the normal and the inverse cube during |
| 301 | the search, and we use *premoves* to apply moves to the inverse scramble. | 295 | the search, and we use *premoves* to apply moves to the inverse scramble. |
| 302 | (Work in progress - premoves are not implemented yet, but it will take | ||
| 303 | little work to add them) | ||
| 304 | * **Multi-threading (multiple scrambles)**: It is easy to parallelize this | 296 | * **Multi-threading (multiple scrambles)**: It is easy to parallelize this |
| 305 | algorithm when solving multiple cubes at once, by firing up multiple | 297 | algorithm when solving multiple cubes at once, by firing up multiple |
| 306 | instances of the solver. It is important to make sure that the same | 298 | instances of the solver. It is important to make sure that the same |
| @@ -314,17 +306,84 @@ Other possible (low-level) optimizations include: | |||
| 314 | 306 | ||
| 315 | ## Pruning table computation | 307 | ## Pruning table computation |
| 316 | 308 | ||
| 317 | ### The h0 table | 309 | ### 4 bits tables for h0 and h11 |
| 310 | |||
| 311 | Computing the pruning table for a "real" h48 coordinate, that **h0** | ||
| 312 | or **h11**, using 4 bits per entry is quite simple. The method currently | ||
| 313 | implemented works as follows. | ||
| 314 | |||
| 315 | First, we set the value of the solved cube's coordinate to 0 and every | ||
| 316 | other entry to 15, the largest 4-bit integer. Then we iteratively scan | ||
| 317 | through the table and compute the coordinates at depth n+1 from those at | ||
| 318 | depth n as follows: for each coordinate at depth n, we compute a valid | ||
| 319 | representative for it, we apply each of the possible 18 moves to it, and | ||
| 320 | we set their value to n+1. Once the table is filled or we have reached | ||
| 321 | depth 15, we stop (there are no **h0** coordinates at depth 16 or more, | ||
| 322 | but I currently don't know if this is the case for **h11**). | ||
| 323 | |||
| 324 | Unfortunately what I described above is an oversimplification: one | ||
| 325 | also must take into account the case where the corner coordinate is | ||
| 326 | self-symmetric, and handle it accordingly by making sure that every | ||
| 327 | symmetric variation of the same coordinate has its value set at the | ||
| 328 | right iteration. | ||
| 329 | |||
| 330 | When this algorithm reaches the last few iterations, the coordinates at | ||
| 331 | depth n are many more than those whose depth is still unknown. Therefore | ||
| 332 | it is convenient to look at the unset coordinate and check if they have | ||
| 333 | any neighbor whose depth is i; if so, we can set such a coordinate to i+1. | ||
| 334 | Thanks to [torchlight](https://github.com/torchlight) for suggesting | ||
| 335 | this optimization. | ||
| 336 | |||
| 337 | Finally, this algorithm can be easily parallelized by dividing the set | ||
| 338 | of coordinates into separate sections, but one must take into account | ||
| 339 | that a coordinate and its neighbors are usually not in the same section. | ||
| 340 | |||
| 341 | This method is currently implemented only for **h0**, since the 4 bits | ||
| 342 | table for **h11** would require around 115GB of RAM to compute, and I | ||
| 343 | don't have this much memory. | ||
| 344 | |||
| 345 | ### 2 bits tables with for h0 and h11 | ||
| 346 | |||
| 347 | (Work in progress - currently I there is no specialized routine for | ||
| 348 | computing 2 bits table for "real" coordinates; instead, an optimized | ||
| 349 | version of the generic method explained below is used) | ||
| 318 | 350 | ||
| 319 | TODO - short explanation of how this is computed | 351 | ### A generic method for intermediate coordinates (from h1 to h10) |
| 320 | 352 | ||
| 321 | ### The intermediate tables (h1, ... h10) | 353 | (Work in progress - this method is quite slow and it may be replaced |
| 354 | by a better algorithm in the future) | ||
| 322 | 355 | ||
| 323 | TODO - explain why these are more complicated (if one does not | 356 | Computing the pruning tables for intermediate coordinates is not as |
| 324 | want to compute the full **h11** table first) | 357 | simple. The reason is that these coordinates are not invariant under |
| 358 | the 48 transformations of the cube, but we are treating them as such. | ||
| 359 | Take for example the case of **h10**. Each **h10** coordinate is | ||
| 360 | represented by either of two **h11** coordinates: the one where the 11th | ||
| 361 | edge is correctly oriented and the one where this edge is flipped (of | ||
| 362 | course, the orientation of the 12th edge can be deduced from the parity | ||
| 363 | of the orientation of the other 11). We can take any cube whose **h11** | ||
| 364 | coordinate is one of these two to represent our **h10** coordinate, but | ||
| 365 | the set of neighbors will change depending on which representative we | ||
| 366 | picked. In other words: if I take one of the two cubes and make a move, | ||
| 367 | the position reached is not necessarily obtainable by applying a move | ||
| 368 | to the other cube. This means that the same algorithm that we described | ||
| 369 | for the "real coordinate" case cannot be applied here. | ||
| 325 | 370 | ||
| 326 | Work in progress - these tables are not implemented yet. | 371 | It is still possible to do a brute-force depth-first seach to fill |
| 372 | these tables. To make it reasonably fast, we apply a couple of | ||
| 373 | optimizations. First of all, we restrict ourselves to computing a 2 bits | ||
| 374 | table, so we can stop the search early. | ||
| 327 | 375 | ||
| 328 | ### The h11 table | 376 | The second optimization we employ consists in pre-computing all possible |
| 377 | **h11** coordinates at a fixed depth, and storing their depth in a hash | ||
| 378 | map indexed by their **h11** coordinate value. This way we do not have | ||
| 379 | to brute-force our way through from depth 0, and it make this method | ||
| 380 | considerably faster. Unfortunately, since the number of coordinates | ||
| 381 | at a certain depth increases exponentially with the depth, we are for | ||
| 382 | now limited at storing the coordinates at depth 8. (Work in progress - | ||
| 383 | we may experiment with depth 9 in the future) | ||
| 329 | 384 | ||
| 330 | Work in progress - this tables is not implemented yet. | 385 | This method works for the "real" coordinates **h0** and **h11** as well. |
| 386 | Moreover, in this case one can optimize it further by avoiding to repeat | ||
| 387 | the search from a coordinate that has already been visited. (Work | ||
| 388 | in progress - this method will be replaced in the future by a more | ||
| 389 | efficient one) | ||
