├── .gitignore
├── tests
├── RunAllTests.cpp
├── MoveSeqTest.cpp
├── CMakeLists.txt
├── test_util.h
├── Cube6Test.cpp
├── EdgeCubeTest.cpp
├── NxPruneTest.cpp
└── CubeTest.cpp
├── src
├── alloc.h
├── nxsolve.cpp
├── types.h
├── cube6.h
├── alloc.cpp
├── sse_cube.h
├── util.cpp
├── util.h
├── nxprune.cpp
├── gen-const-cubes.cpp
├── const-cubes.h
├── nxsolve.h
├── nxprune_generator.h
├── cube.cpp
├── avx2_cube.h
├── nxprune.h
├── vc-optimal.cpp
└── cube.h
├── CMakeLists.txt
├── test64.txt
├── README.md
├── doc
└── speffz.md
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | /vc-optimal
2 | /gen-const-cubes
3 | /tests/check
4 |
5 | CMakeCache.txt
6 | CMakeFiles
7 | CMakeScripts
8 | Testing
9 | Makefile
10 | cmake_install.cmake
11 | install_manifest.txt
12 | compile_commands.json
13 | CTestTestfile.cmake
14 |
15 | .*.swp
16 | *.a
17 |
--------------------------------------------------------------------------------
/tests/RunAllTests.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #include "CppUTest/CommandLineTestRunner.h"
20 | #include "test_util.h"
21 |
22 | decltype(t::rng) t::rng;
23 |
24 | int main(int argc, char **argv) {
25 | t::setup();
26 | return CommandLineTestRunner::RunAllTests(argc, argv);
27 | }
28 |
--------------------------------------------------------------------------------
/tests/MoveSeqTest.cpp:
--------------------------------------------------------------------------------
1 | #include "util.h"
2 |
3 | #include "CppUTest/TestHarness.h"
4 |
5 | using namespace vcube;
6 |
7 | TEST_GROUP(MoveSeq) {
8 | void check_parse(const std::string &s, const moveseq_t &expected) {
9 | CHECK(moveseq_t::parse(s) == expected);
10 | }
11 | };
12 |
13 | TEST(MoveSeq, Parse) {
14 | check_parse("", {});
15 | check_parse("URFDLB", { 0, 3, 6, 9, 12, 15 });
16 | check_parse("U1R1F1D1L1B1", { 0, 3, 6, 9, 12, 15 });
17 | check_parse("U2R2F2D2L2B2", { 1, 4, 7, 10, 13, 16 });
18 | check_parse("U'R'F'D'L'B'", { 2, 5, 8, 11, 14, 17 });
19 | check_parse("UUURRRFFF", { 0, 0, 0, 3, 3, 3, 6, 6, 6 });
20 | }
21 |
22 | TEST(MoveSeq, ParseLowercase) {
23 | check_parse("urfdlb", { 0, 3, 6, 9, 12, 15 });
24 | check_parse("u1r1f1d1l1b1", { 0, 3, 6, 9, 12, 15 });
25 | check_parse("u2r2f2d2l2b2", { 1, 4, 7, 10, 13, 16 });
26 | check_parse("u'r'f'd'l'b'", { 2, 5, 8, 11, 14, 17 });
27 | }
28 |
29 | TEST(MoveSeq, ParseDelimited) {
30 | check_parse(" U2?R1,XF2\tD' L B ", { 1, 3, 7, 11, 12, 15 });
31 | }
32 |
33 | TEST(MoveSeq, ParseMalformedInput) {
34 | check_parse("U2 U 2", { 1, 0 });
35 | check_parse("U321", { 2 });
36 | check_parse("1", {});
37 | check_parse("2", {});
38 | check_parse("3", {});
39 | check_parse("'", {});
40 | }
41 |
--------------------------------------------------------------------------------
/src/alloc.h:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #ifndef VCUBE_ALLOC_H
20 | #define VCUBE_ALLOC_H
21 |
22 | #include
23 | #include
24 |
25 | namespace vcube {
26 |
27 | class alloc {
28 | public:
29 | template
30 | static T * huge(size_t n) {
31 | return (T *) huge_impl(n * sizeof(T));
32 | }
33 |
34 | template
35 | static T * shared(size_t n, uint32_t key, bool rdwr) {
36 | return (T *) shared_impl(n * sizeof(T), key, rdwr);
37 | }
38 |
39 | private:
40 | static void * huge_impl(size_t n);
41 | static void * shared_impl(size_t n, uint32_t key, bool rdwr);
42 | };
43 |
44 | }
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/src/nxsolve.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #include
20 | #include "nxsolve.h"
21 |
22 | using namespace vcube;
23 | using namespace vcube::nx;
24 |
25 | decltype(solver_base::depth4) solver_base::depth4;
26 |
27 | void solver_base::init() {
28 | std::set seen = { cube() };
29 | std::vector prev = { { cube(), 0, 0xff } };
30 |
31 | // Find all cubes at depth 4 (there are 43,239 of them)
32 | for (int depth = 0; depth < 4; depth++) {
33 | depth4.clear();
34 | for (const auto &q : prev) {
35 | for (int m = 0; m < N_MOVES; m++) {
36 | cube6 c6 = q.c6.move(m);
37 | if (seen.insert(c6[0]).second) {
38 | depth4.emplace_back(c6, (q.moves << 8) | m, m / 3);
39 | }
40 | }
41 | }
42 | prev.swap(depth4);
43 | }
44 |
45 | prev.swap(depth4);
46 | }
47 |
--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of vcube.
2 | #
3 | # Copyright (C) 2018 Andrew Skalski
4 | #
5 | # vcube is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # vcube is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with vcube. If not, see .
17 |
18 | if(DEFINED ENV{CPPUTEST_HOME})
19 | message(STATUS "Using CppUTest found in $ENV{CPPUTEST_HOME}")
20 | set(CPPUTEST_INCLUDE_DIRS $ENV{CPPUTEST_HOME}/include)
21 | set(CPPUTEST_LIBRARIES $ENV{CPPUTEST_HOME}/lib)
22 | set(CPPUTEST_LDFLAGS CppUTest CppUTestExt)
23 | else()
24 | find_package(PkgConfig REQUIRED)
25 | pkg_search_module(CPPUTEST REQUIRED cpputest>=3.8)
26 | message(STATUS "Found CppUTest version ${CPPUTEST_VERSION}")
27 | endif()
28 |
29 | include_directories(${CPPUTEST_INCLUDE_DIRS} ../src/)
30 | link_directories(${CPPUTEST_LIBRARIES})
31 |
32 | add_executable(check
33 | RunAllTests.cpp
34 | CubeTest.cpp
35 | Cube6Test.cpp
36 | EdgeCubeTest.cpp
37 | MoveSeqTest.cpp
38 | NxPruneTest.cpp
39 | )
40 | target_link_libraries(check vcube ${CPPUTEST_LDFLAGS})
41 | add_custom_command(TARGET check COMMAND ./check POST_BUILD)
42 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file is part of vcube.
2 | #
3 | # Copyright (C) 2018 Andrew Skalski
4 | #
5 | # vcube is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # vcube is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with vcube. If not, see .
17 |
18 | cmake_minimum_required (VERSION 3.5)
19 |
20 | project(vcube)
21 |
22 | # Need -std=c++17 for proper alignment of AVX variables in std::vector
23 | set(CMAKE_BUILD_TYPE Release)
24 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mlzcnt -mbmi -mbmi2 -mavx2 -flax-vector-conversions -std=c++17")
25 |
26 | # The Clang compiler currently produces faster code than GCC for this project
27 | set(CMAKE_C_COMPILER "clang" CACHE STRING "clang compiler" FORCE)
28 | set(CMAKE_CXX_COMPILER "clang++" CACHE STRING "clang++ compiler" FORCE)
29 |
30 | add_executable(gen-const-cubes
31 | src/gen-const-cubes.cpp
32 | )
33 |
34 | add_library(vcube
35 | src/alloc.cpp
36 | src/cube.cpp
37 | src/nxprune.cpp
38 | src/nxsolve.cpp
39 | src/util.cpp
40 | )
41 |
42 | add_executable(vc-optimal
43 | src/vc-optimal.cpp
44 | )
45 | target_link_libraries(vc-optimal vcube pthread)
46 |
47 | add_subdirectory(tests)
48 |
--------------------------------------------------------------------------------
/tests/test_util.h:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #include "cube.h"
20 | #include
21 |
22 | using namespace vcube;
23 |
24 | struct t {
25 | public:
26 | static void setup() {
27 | rng.seed(rng.default_seed);
28 | }
29 |
30 | static int rand(int max) {
31 | std::uniform_int_distribution<> dis(0, max - 1);
32 | return dis(rng);
33 | }
34 |
35 | static uint8_t * to_array(cube &c) {
36 | return reinterpret_cast(&c);
37 | }
38 |
39 | static const uint8_t * to_array(const cube &c) {
40 | return reinterpret_cast(&c);
41 | }
42 |
43 | static cube random_cube() {
44 | cube c;
45 | c.setEdgePerm(rand(N_EPERM));
46 | c.setEdgeOrient(rand(N_EORIENT));
47 | c.setCornerPerm(rand(N_CPERM));
48 | c.setCornerOrient(rand(N_CORIENT));
49 | if (c.parity()) {
50 | std::swap(to_array(c)[0], to_array(c)[1]);
51 | }
52 | return c;
53 | }
54 |
55 | private:
56 | static std::mt19937 rng;
57 | };
58 |
--------------------------------------------------------------------------------
/src/types.h:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #ifndef VCUBE_TYPES_H
20 | #define VCUBE_TYPES_H
21 |
22 | #include
23 |
24 | namespace vcube {
25 |
26 | using eorient_t = uint32_t;
27 | static constexpr eorient_t N_EORIENT = 2048;
28 |
29 | using e8orient_t = uint32_t;
30 | static constexpr e8orient_t N_E8ORIENT = 256;
31 |
32 | using e4orient_t = uint32_t;
33 | static constexpr e4orient_t N_E4ORIENT = 16;
34 |
35 | using corient_t = uint32_t;
36 | static constexpr corient_t N_CORIENT = 2187;
37 |
38 | using eperm_t = uint32_t;
39 | static constexpr eperm_t N_EPERM = 479001600;
40 |
41 | using cperm_t = uint32_t;
42 | static constexpr cperm_t N_CPERM = 40320;
43 |
44 | using c4comb_t = uint32_t;
45 | static constexpr c4comb_t N_C4COMB = 70;
46 |
47 | using e4comb_t = uint32_t;
48 | static constexpr e4comb_t N_E4COMB = 495;
49 |
50 | using e4perm_t = uint32_t;
51 | static constexpr e4perm_t N_E4PERM = 24;
52 |
53 | using eud4comb_t = uint32_t;
54 | static constexpr eud4comb_t N_EUD4COMB = 70;
55 |
56 | static constexpr int N_MOVES = 18;
57 |
58 | }
59 |
60 | #endif
61 |
--------------------------------------------------------------------------------
/src/cube6.h:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #ifndef VCUBE_CUBE6_H
20 | #define VCUBE_CUBE6_H
21 |
22 | #include
23 | #include "cube.h"
24 |
25 | namespace vcube {
26 |
27 | class cube6 {
28 | public:
29 | cube6() : ca() {
30 | }
31 |
32 | cube6(const cube &c) {
33 | cube ci = ~c;
34 | ca = {
35 | c,
36 | S_URF3 * c * S_URF3i,
37 | S_URF3i * c * S_URF3,
38 | ci,
39 | S_URF3 * ci * S_URF3i,
40 | S_URF3i * ci * S_URF3
41 | };
42 | }
43 |
44 | const cube & operator [] (size_t idx) const { return ca[idx]; }
45 | bool operator == (const cube &c) const { return ca[0] == c; }
46 | bool operator != (const cube &c) const { return ca[0] != c; }
47 |
48 | cube6 operator * (const cube6 &o) const {
49 | return {{
50 | ca[0] * o.ca[0],
51 | ca[1] * o.ca[1],
52 | ca[2] * o.ca[2],
53 | o.ca[3] * ca[3],
54 | o.ca[4] * ca[4],
55 | o.ca[5] * ca[5]
56 | }};
57 | }
58 |
59 | cube6 move(uint8_t m0) const {
60 | auto &m = move_sym6[m0];
61 | return {{
62 | ca[0].move( m0),
63 | ca[1].move( m[1]),
64 | ca[2].move( m[2]),
65 | ca[3].premove(m[3]),
66 | ca[4].premove(m[4]),
67 | ca[5].premove(m[5])
68 | }};
69 | }
70 |
71 | cube6 premove(uint8_t m0) const {
72 | auto &m = move_sym6[m0];
73 | return {{
74 | ca[0].premove(m0),
75 | ca[1].premove(m[1]),
76 | ca[2].premove(m[2]),
77 | ca[3].move( m[3]),
78 | ca[4].move( m[4]),
79 | ca[5].move( m[5])
80 | }};
81 | }
82 |
83 | private:
84 | std::array ca;
85 |
86 | cube6(const decltype(ca) &ca)
87 | : ca(ca)
88 | {
89 | }
90 | };
91 |
92 | }
93 |
94 | #endif
95 |
--------------------------------------------------------------------------------
/tests/Cube6Test.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 |
20 | #include "cube6.h"
21 |
22 | #include "test_util.h"
23 | #include "CppUTest/TestHarness.h"
24 |
25 | using namespace vcube;
26 |
27 | TEST_GROUP(Cube6) {
28 | bool equal(const cube6 &a, const cube6 &b) {
29 | for (int i = 0; i < 6; i++) {
30 | if (a[i] != b[i]) {
31 | return false;
32 | }
33 | }
34 | return true;
35 | }
36 | };
37 |
38 | TEST(Cube6, CubeConstructor) {
39 | cube c = t::random_cube();
40 | cube6 c6(c);
41 |
42 | CHECK(c6[0] == c);
43 | CHECK(c6[1] == vcube::S_URF3 * c6[0] * ~vcube::S_URF3);
44 | CHECK(c6[2] == ~vcube::S_URF3 * c6[0] * vcube::S_URF3);
45 | CHECK(c6[3] == ~c);
46 | CHECK(c6[4] == vcube::S_URF3 * c6[3] * ~vcube::S_URF3);
47 | CHECK(c6[5] == ~vcube::S_URF3 * c6[3] * vcube::S_URF3);
48 | }
49 |
50 | TEST(Cube6, Handedness) {
51 | CHECK(cube6(cube::from_moves("U "))[0] == cube::from_moves("U"));
52 | CHECK(cube6(cube::from_moves("R "))[1] == cube::from_moves("U"));
53 | CHECK(cube6(cube::from_moves("F "))[2] == cube::from_moves("U"));
54 | CHECK(cube6(cube::from_moves("U'"))[3] == cube::from_moves("U"));
55 | CHECK(cube6(cube::from_moves("R'"))[4] == cube::from_moves("U"));
56 | CHECK(cube6(cube::from_moves("F'"))[5] == cube::from_moves("U"));
57 | }
58 |
59 | TEST(Cube6, Equality) {
60 | // Unlikely for them to be the same
61 | cube c = t::random_cube(), d = t::random_cube();
62 |
63 | cube6 c6(c);
64 |
65 | CHECK(c6 == c);
66 | CHECK_FALSE(c6 != c);
67 |
68 | CHECK(c6 != d);
69 | CHECK_FALSE(c6 == d);
70 | }
71 |
72 | TEST(Cube6, Move) {
73 | cube c = t::random_cube();
74 | for (int m = 0; m < N_MOVES; m++) {
75 | CHECK(equal(c.move(m), cube6(c).move(m)));
76 | CHECK(equal(c.premove(m), cube6(c).premove(m)));
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/tests/EdgeCubeTest.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #include "cube.h"
20 |
21 | #include
22 | #include "test_util.h"
23 | #include "CppUTest/TestHarness.h"
24 |
25 | using namespace vcube;
26 |
27 | TEST_GROUP(EdgeCube) {
28 | bool equivalent(const edgecube &ec, const cube &c) {
29 | return !memcmp(&ec, &c, sizeof(ec));
30 | }
31 | };
32 |
33 | TEST(EdgeCube, Constructor) {
34 | LONGS_EQUAL(sizeof(edgecube), 16);
35 |
36 | for (int i = 0; i < 1000; i++) {
37 | cube c = t::random_cube();
38 | CHECK(equivalent(edgecube(c), c));
39 | }
40 | }
41 |
42 | TEST(EdgeCube, Compose) {
43 | for (int i = 0; i < 1000; i++) {
44 | cube a = t::random_cube();
45 | cube b = t::random_cube();
46 | CHECK(equivalent(edgecube(a).compose(edgecube(b)), a.compose(b)));
47 | }
48 | }
49 |
50 | TEST(EdgeCube, Move) {
51 | for (int m = 0; m < 18; m++) {
52 | cube c = t::random_cube();
53 | CHECK(equivalent(edgecube(c).move(m), c.move(m)));
54 | CHECK(equivalent(edgecube(c).premove(m), c.premove(m)));
55 | }
56 | }
57 |
58 | TEST(EdgeCube, SymConjugate) {
59 | for (int s = 0; s < 48; s++) {
60 | cube c = t::random_cube();
61 | CHECK(equivalent(edgecube(c).symConjugate(s), c.symConjugate(s)));
62 | }
63 | }
64 |
65 | TEST(EdgeCube, GetEdgeOrient) {
66 | LONGS_EQUAL(0, edgecube().getEdgeOrientRaw());
67 |
68 | for (int i = 0; i < 1000; i++) {
69 | cube c = t::random_cube();
70 | LONGS_EQUAL(edgecube(c).getEdgeOrientRaw(), c.getEdgeOrientRaw());
71 | }
72 | }
73 |
74 | TEST(EdgeCube, SetEdgeOrient) {
75 | edgecube ec;
76 | for (int i = 0; i < 1000; i++) {
77 | cube c = t::random_cube();
78 |
79 | auto eo = c.getEdgeOrient();
80 | auto e8o = c.getEdge8Orient();
81 | auto e4o = c.getEdge4Orient();
82 |
83 | c.setEdgeOrient(0);
84 | edgecube ec(c);
85 |
86 | CHECK(equivalent(ec.setEdgeOrient(eo), c.setEdgeOrient(eo)));
87 | CHECK(equivalent(ec.setEdge8Orient(e8o), c.setEdge8Orient(e8o)));
88 | CHECK(equivalent(ec.setEdge4Orient(e4o), c.setEdge4Orient(e4o)));
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/alloc.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include "alloc.h"
23 |
24 | // Missing in the header
25 | #ifndef SHM_HUGE_SHIFT
26 | #define SHM_HUGE_SHIFT MAP_HUGE_SHIFT
27 | #endif
28 |
29 | using namespace vcube;
30 |
31 | static size_t num_pages(size_t n, size_t page_size) {
32 | size_t mask = (1LL << page_size) - 1;
33 | return (n >> page_size) + !!(n & mask);
34 | }
35 |
36 | static void * map_huge(size_t n, size_t page_size, int prot, int flags) {
37 | if (page_size) {
38 | n = num_pages(n, page_size);
39 | flags |= MAP_HUGETLB | (page_size << MAP_HUGE_SHIFT);
40 | }
41 | void *mem = mmap(NULL, n << page_size, prot, flags, -1, 0);
42 | return (mem == MAP_FAILED) ? NULL : mem;
43 | }
44 |
45 | void * alloc::huge_impl(size_t n) {
46 | int prot = PROT_READ | PROT_WRITE;
47 | int flags = MAP_PRIVATE | MAP_ANONYMOUS;
48 |
49 | void *mem = map_huge(n, 30, prot, flags); // 1GB pages
50 | if (!mem) {
51 | mem = map_huge(n, 21, prot, flags); // 2MB pages
52 | }
53 | if (!mem) {
54 | mem = map_huge(n, 0, prot, flags); // Standard pages
55 | }
56 |
57 | return mem;
58 | }
59 |
60 | static void * map_shared(size_t n, uint32_t key, bool rdwr, size_t page_size) {
61 | int flags = 0600;
62 | if (rdwr) {
63 | flags |= IPC_CREAT | IPC_EXCL;
64 | }
65 | if (page_size) {
66 | n = num_pages(n, page_size);
67 | flags |= SHM_HUGETLB | (page_size << SHM_HUGE_SHIFT);
68 | }
69 | int shm = shmget(key, n << page_size, flags);
70 | if (shm == -1) {
71 | return NULL;
72 | }
73 | void *mem = shmat(shm, NULL, rdwr ? 0 : SHM_RDONLY);
74 | return (mem == (void *) -1) ? NULL : mem;
75 | }
76 |
77 | void * alloc::shared_impl(size_t n, uint32_t key, bool rdwr) {
78 | void *mem = NULL;
79 | if (rdwr) {
80 | // Huge page setting is relevant only on create
81 | mem = map_shared(n, key, rdwr, 30); // 1GB pages
82 | if (!mem) {
83 | mem = map_shared(n, key, rdwr, 21); // 2MB pages
84 | }
85 | }
86 | if (!mem) {
87 | mem = map_shared(n, key, rdwr, 0);
88 | }
89 | return mem;
90 | }
91 |
--------------------------------------------------------------------------------
/src/sse_cube.h:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #ifndef VCUBE_SSE_CUBE_H
20 | #define VCUBE_SSE_CUBE_H
21 |
22 | #include
23 | #include
24 | #include "types.h"
25 | #include "util.h"
26 |
27 | namespace vcube {
28 |
29 | struct sse {
30 | //static const __m128i identity = _mm_set_epi64x(
31 | // 0x0f0e0d0c0b0a0908, 0x0706050403020100);
32 | static constexpr __m128i identity = (__m128i) {
33 | 0x0706050403020100, 0x0f0e0d0c0b0a0908
34 | };
35 |
36 | static uint32_t bitmask(__m128i v, int b) {
37 | return _mm_movemask_epi8(_mm_slli_epi32(v, 7 - b));
38 | }
39 |
40 | static bool equals(__m128i a, __m128i b) {
41 | return _mm_movemask_epi8(_mm_cmpeq_epi8(a, b)) == -1;
42 | }
43 |
44 | static bool less_than(__m128i a, __m128i b) {
45 | // See avx2_cube.h
46 | #if 1
47 | uint32_t gt = _mm_movemask_epi8(_mm_cmpgt_epi8(a, b));
48 | uint32_t lt = _mm_movemask_epi8(_mm_cmpgt_epi8(b, a));
49 | return gt < lt;
50 | #else
51 | uint32_t eq = _mm_movemask_epi8(_mm_cmpeq_epi8(a, b));
52 | uint32_t lt = _mm_movemask_epi8(_mm_cmpgt_epi8(b, a));
53 | uint32_t sum = (lt << 1) + eq;
54 | return sum < lt;
55 | #endif
56 | }
57 |
58 | static __m128i edge_compose(__m128i a, __m128i b) {
59 | __m128i vperm = _mm_shuffle_epi8(a, b);
60 | __m128i vorient = _mm_and_si128(b, _mm_set1_epi8(0xf0));
61 | return _mm_xor_si128(vperm, vorient);
62 | }
63 |
64 | static __m128i xor_edge_orient(__m128i v, eorient_t eorient) {
65 | __m128i vorient = _mm_shuffle_epi8(
66 | _mm_set1_epi32(eorient),
67 | _mm_set_epi64x(0xffffffff01010101, 0));
68 | vorient = _mm_or_si128(vorient, _mm_set1_epi64x(~0x8040201008040201));
69 | vorient = _mm_cmpeq_epi8(vorient, _mm_set1_epi64x(-1));
70 | vorient = _mm_and_si128(vorient, _mm_set1_epi8(0x10));
71 | return _mm_xor_si128(v, vorient);
72 | }
73 |
74 | static corient_t corner_orient(__m128i v) {
75 | // Mask the corner orientation bits and convert to 16-bit vector
76 | auto vorient = _mm_and_si128(v, _mm_set1_epi8(0x30));
77 | vorient = _mm_unpacklo_epi8(vorient, _mm_setzero_si128());
78 |
79 | // Multiply each corner by its place value, add adjacent pairs
80 | vorient = _mm_madd_epi16(vorient, _mm_set_epi16(729, 243, 81, 27, 9, 3, 1, 0));
81 |
82 | // Finish the horizontal sum
83 | uint64_t r = _mm_extract_epi64(vorient, 0) + _mm_extract_epi64(vorient, 1);
84 | r += r >> 32;
85 |
86 | // Shift the result into the correct position
87 | return r >> 4;
88 | }
89 | };
90 |
91 | }
92 |
93 | #endif
94 |
--------------------------------------------------------------------------------
/src/util.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #include "util.h"
20 |
21 | using namespace vcube;
22 |
23 | // Parse a move sequence loosely; supports multiple formats such as
24 | // "U R2 F'", "U1R2F3", "URRFFF". Input is not validated, and anything
25 | // unexpected is treated as a delimiter.
26 | moveseq_t moveseq_t::parse(const std::string &s) {
27 | moveseq_t moves;
28 |
29 | int face = -1;
30 | for (auto ch : s) {
31 | int f = -1, power = -1;
32 | switch (ch) {
33 | case 'u': case 'U': f = 0; break;
34 | case 'r': case 'R': f = 3; break;
35 | case 'f': case 'F': f = 6; break;
36 | case 'd': case 'D': f = 9; break;
37 | case 'l': case 'L': f = 12; break;
38 | case 'b': case 'B': f = 15; break;
39 | case '3': case '\'': power = 2; break;
40 | case '2': power = 1; break;
41 | case '1': power = 0; break;
42 | default: power = 0;
43 | }
44 |
45 | if (f != -1) {
46 | if (face != -1) {
47 | moves.push_back(face);
48 | }
49 | face = f;
50 | } else if (power != -1 && face != -1) {
51 | moves.push_back(face + power);
52 | face = -1;
53 | }
54 | }
55 |
56 | if (face != -1) {
57 | moves.push_back(face);
58 | }
59 |
60 | return moves;
61 | }
62 |
63 | moveseq_t moveseq_t::canonical() const {
64 | if (empty()) {
65 | return {};
66 | }
67 |
68 | moveseq_t canon = *this;
69 |
70 | // Append a dummy move different from the final axis to ensure
71 | // the final moves are flushed
72 | canon.push_back(canon.back() + 3);
73 |
74 | uint8_t last_axis = 0, power[2] = { 0, 0 };
75 | auto tail = canon.begin();
76 | for (auto m : canon) {
77 | auto axis = (m / 3) % 3;
78 | if (axis != last_axis) {
79 | for (int pole = 0; pole < 2; pole++) {
80 | if (power[pole] %= 4) {
81 | *tail++ = (last_axis * 3 + pole * 9) + (power[pole] % 4) - 1;
82 | }
83 | power[pole] = 0;
84 | }
85 | last_axis = axis;
86 | }
87 | power[m >= 9] += (m % 3) + 1;
88 | }
89 |
90 | canon.resize(tail - canon.begin());
91 |
92 | return canon;
93 | }
94 |
95 | std::string moveseq_t::to_string(style_t style) const {
96 | const char *face = "URFDLB";
97 | const char *power = (style == FIXED) ? "123" : " 2'";
98 | bool delim = (style != FIXED);
99 |
100 | std::string s;
101 | for (auto m : *this) {
102 | s.push_back(face[m / 3]);
103 | s.push_back(power[m % 3]);
104 | if (delim) {
105 | s.push_back(' ');
106 | }
107 | }
108 |
109 | while (!s.empty() && s.back() == ' ') {
110 | s.pop_back();
111 | }
112 |
113 | return s;
114 | }
115 |
--------------------------------------------------------------------------------
/src/util.h:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #ifndef VCUBE_UTIL_H
20 | #define VCUBE_UTIL_H
21 |
22 | #include
23 | #include
24 | #include
25 | #include "types.h"
26 |
27 | namespace vcube {
28 |
29 | namespace {
30 | template
31 | constexpr auto init_NcR_rank() {
32 | auto tbl = std::array();
33 | T rank = 0;
34 | for (int32_t i = (1 << N) - 1; i >= 0; i--) {
35 | if (__builtin_popcountl(i) == R) {
36 | tbl[i] = rank++;
37 | }
38 | }
39 | return tbl;
40 | }
41 |
42 | template
43 | constexpr auto init_NcR_unrank() {
44 | auto tbl = std::array();
45 | T rank = 0;
46 | size_t idx = 0;
47 | for (int32_t i = (1 << N) - 1; i >= 0; i--) {
48 | if (__builtin_popcountl(i) == R) {
49 | tbl[idx++] = i;
50 | }
51 | }
52 | return tbl;
53 | }
54 |
55 | template
56 | extern inline T rank_nCr(T bits) {
57 | static constexpr auto tbl = init_NcR_rank();
58 | return tbl[bits];
59 | }
60 |
61 | template
62 | extern inline T unrank_nCr(T idx) {
63 | static constexpr auto tbl = init_NcR_unrank();
64 | return tbl[idx];
65 | }
66 |
67 | static constexpr auto init_4perm_rank_oddeven() {
68 | /* To accommodate 'movemask' extraction of the permutation,
69 | * the lookup table index has "odd-even" bit order: 75316420
70 | */
71 | constexpr int fc[] = { 6, 2, 1 };
72 | std::array tbl = { };
73 | for (int perm = 0; perm < 24; perm++) {
74 | uint32_t table = 0x3210;
75 | uint8_t index = 0;
76 | for (int i = 0; i < 3; i++) {
77 | int shift = perm / fc[i] % (4 - i) * 4;
78 | uint8_t value = (table >> shift) & 3;
79 | table ^= (table ^ (table >> 4)) & (0xffffU << shift);
80 | index |= (value & 1) << i;
81 | index |= (value & 2) << (i + 3);
82 | }
83 | index |= (table & 1) << 3;
84 | index |= (table & 2) << 6;
85 | tbl[index] = perm;
86 | }
87 | return tbl;
88 | }
89 | }
90 |
91 | extern inline auto rank_8C4(uint8_t bits) {
92 | return rank_nCr(bits);
93 | }
94 |
95 | extern inline auto rank_12C4(uint16_t bits) {
96 | return rank_nCr(bits);
97 | }
98 |
99 | extern inline auto unrank_8C4(uint8_t idx) {
100 | return unrank_nCr(idx);
101 | }
102 |
103 | extern inline auto unrank_12C4(uint16_t idx) {
104 | return unrank_nCr(idx);
105 | }
106 |
107 | /* Set the orientation of the 12th edge based on parity of the other 11 */
108 | extern inline eorient_t set_eorient_parity(eorient_t eorient) {
109 | // Faster than popcnt because of instruction latency
110 | eorient_t parity = eorient ^ (eorient << 6);
111 | parity ^= parity << 3;
112 | parity ^= (parity << 2) ^ (parity << 1);
113 | return eorient ^ (parity & 0x800);
114 | }
115 |
116 | extern inline auto rank_4perm_oddeven(uint8_t bits) {
117 | constexpr auto tbl = init_4perm_rank_oddeven();
118 | return tbl[bits];
119 | }
120 |
121 | struct moveseq_t : public std::vector {
122 | enum style_t { SINGMASTER, FIXED };
123 |
124 | using std::vector::vector;
125 |
126 | static moveseq_t parse(const std::string &);
127 |
128 | moveseq_t canonical() const;
129 | std::string to_string(style_t style = SINGMASTER) const;
130 | };
131 |
132 | }
133 |
134 | #endif
135 |
--------------------------------------------------------------------------------
/test64.txt:
--------------------------------------------------------------------------------
1 | B3L3D3F1D3B2L3B1L3F1U1D2F2B2R1L2U3L2D1R1D1F1D2R1B2D2F2R3U3B1L1D1B3L2F2
2 | R3L1D1F2L3U2R1F1U1D2F1L2B1L1B2R1L2D1B3U2B2R2U2L2U2B2U2F2L2D2R3B3D1F2B3
3 | R1L3U2F3D2L2F1L3B3R1B2U2B2D1R1F3B1L2B2D2L3U3L3U2L1U2D2L1D1R3B3L1B2D3F1
4 | F1R3B2R3D1B3L2U3B2U2R2D3B2R3B1L3B2R3F3U1R1L1U3B3R2D1F2L1U3D1F2R1U1F1L3
5 | F3D3B2U1B3D2R3L2D2F3L2D3B3R2U1D2F1L2F2R2B2R3U1D2B3L1B3U1F2R2B3R2U1B3D1
6 | B2R3L2B1D3L2F2D1B2D3R2F3D2L1F3U1B3D2R2B1U3B1R1L1U1D1R2L2D3F2U3L3D2B1R1
7 | U2R2U3B1D3L1F3R1D1B2R1L3B3D3F3U1D3L3U3F1B2U2D1F1B1D1R3U2F1U2B2D1L3B2R1
8 | R2U1L1U3D2B1D3R2D1L3B2U1F3R1F2B1L1B1L1B3R2B2D1R2U2L2U2R3D2R1D1L3F3L2F3
9 | F1D2F3U3R3F1R2B2U2R1F2U2F3R3D1B1L3D3R2U2F3U2B2U2F2B3D1F3U2D2B3L1B1D1R1
10 | D1F2R1L1U1D1B2R2F2B2L1F2R1F1L1B3U2D1R3B1D2F1U3R1U3F2D3R3B3U1L3B2U3R3U3
11 | B2R1L1B3U2F3L2B1L1F1B1L2F2R2D1B3U1L2U2F2D2L3U1D2R1U3F2L1U1B1R3F1D3L1U2
12 | U3F2R2F1D2R2F3U3R2F2L2F2R1U3R2D3F1D2R1U1B2R1F2B3L1U1R2D1L2U2L3D3F3R3U1
13 | B2D2R1B1U2R2F3R3U1B1R1B1L2D1F2U2F3D3R2B3L3F3B3R2F3B2U2L1B1U2L2D1L3U3R3
14 | F3U3B2R3F1L1D1L2U2D1B3L1F3L3D2L3D3B3R2L1B1R1F2D3L3F3D3B2U1B3U1F1R2L2D1
15 | U2R1L1D2L3B2D3R3B2R1D1B1U3F3D3F3B1L3F1U1D2R1B3R2L3B3R2L1U3D3F2D1L2U2F3
16 | U3B3L2F3R1F2L3D1B1D1B3D2B1L1U3D3L3D2B1L3D1B1L3U3B3R1F3D2R2U2R1U3L3U3D2
17 | R3B2R3D2R2L3U3D3B3U2R2B2D3L3F1L2D1R1D3B2U1L3B1L1F3D2R2F3R3D1L1D2R1L3U2
18 | L1U2L1F3B3R3L2D3L1F2D1B3L3B3U1R1U1D3B3R2B3L1D3B3R3U2B3R2L1D2R2B3L2B2D2
19 | B3L2D2F2R1D2F1R1L1U1B3R1D1F2B2L3D1R3L1D3F1L2F3B2L3U2R1U2L1F1D1B1L3U3R1
20 | D3L2D2B1U2B1D3F1B1U2D2R3F2U3D2B2R3L2D3B1D2F1U3D3B3U1F3R1D2F1L3B3U2B2L2
21 | F2D1F2L3B1D1R3F2L1F3U3L3U3R3B2U3F1D3R2L2F1U3F1R2D3L3F1R1L3F3D1F3L3B2D3
22 | D3R1F3U3L1U2R2B3D2F1B1D1B3L1D1F1B2L3F2L3F3B2R1D2F2D3R1B2L2F2B2D1F2B2L2
23 | B3U1L3B2R2L1F2U3D3B2L2D2F3U3F1B1U1R1B2U3L3F1U3R2U1R2L3F2D3L2F2D2L2D1F2
24 | B1D2F2L2U2R1L1D1R1U3R2B3R1U2F3B2D2L3F2R2D2R2U1B1U1R2B3U1D2L2B2R3D2R2F1
25 | U1B2D3L3D2L3F1R3D2L1B1L1F1R2U3F1B3D1F3U2B1D1L3F1L3D1B1D1B3R3L3F2L1F3L3
26 | F3R2U1L1D2R1F1L3B1L1U3F2U3F3L3B1D2L2B3L3U2B2U2B2U1F2B1U3L3U1L2U1D2F2U3
27 | F2L1D3F1B1D2B3U1R3D1B1D3F2R2F1D2F1R3U1L1D3F2B2D3L1U1F1R2L3D2L1D3F2R3F1
28 | D2L3U3R1D3F2B2U3R2D3B2U3R2L3B1U1L2B3R3D3B1L1U3B1U2F3R1B3D1R3U2R3D3B3U2
29 | U2L2U3D1R3F1L2D3B2L1F2U3F3L2F1R2L3F2L1U1D2L2D1F1R3L2U2F2U3D2R1B1R1B2D3
30 | D3B2D3R3F1D3B1D3F3L1B1R3D1B1R2D2R3U3F1D1F3R3U3D1B3R2U1B1L1U3R1D1F2D2F1
31 | L3B1U3L3D2L1B2D2B3L1F3R2L3B2R2D2R2B1D3B2R1D1F2U3R3L3B1D3F2L2U3D1L3U1R2
32 | F3U3L1U2R3U2B1U3B3L1D3L1F3R1B3D3F1R3L1U1D2F2D1L3D2R3B1R1L2F2D2L1D1B3D3
33 | F1L2F2D3B2L3F1B1R2L2U2F1B3U1D3F3R3L2B2R1B3D1F1U1R3D2L1F2L3U2R1L3B1D1B2
34 | U2F3D1L1D2F1R3F3D2B1D3R2F2U2D2B1R2D2B1D1R1F3D1B3U3R2F2R2F3D1F3L3D2B1R2
35 | D1F1B3R3L3B2L1D1B1D3R2B3R2F2U2L1F1D3L3F1B3L1B1D2B1U2D1F3B3U3F2U2L1U3F1
36 | B2D1L2D1R2F2L2U2D2B1L2F2U3B3L1F1U2D2R1L3B3L2U2B2L2F3B3L2U2B1L1F3U3R3F2
37 | D1F2L3B1L1D2L3U3D3R1F3L2D2R2U2R2U2R1L3U2F3L2F2B2L3B3L1D1F1B2U2D1F1U2D3
38 | R3L1U3F3L1B1D1R1F1U1D1L2F2R1D2L3U2F2B2L3F3L1D2L3F2L2D3R1U3F2D3L1B1D2L3
39 | U1L3F1R1F1U3L1B3L2D3L3B2L2U3L1U1L2F3B2U1R1L1U2D1L3B3D1B2R2L1B2U2R1L3U2
40 | D1F2L1U2B2R1D2F1L3F3D2B1R2D1F1D1B2U3F2B3D2F1U3B2U3L2F3L2U2B2R2D1R2D3L3
41 | B3U1L3D2R3B1R3B2D1B1D2F3D1F2L1U1B3U3L2B1D3F3D3F1L2F1B3L3U3B3R2L2F3L3B1
42 | L3F3R2B1L2F2D2B3U3D1B1D3F2L3B1D3R2U3R3U2B3L1D2B3U1F2D1L1B1D3R2L3D2L2F1
43 | U3L2D2B3U3R2D1B3U3L3U2R1F2L1F3L2F2D2B1U1D1R2D1F1D1F3B3U1L1U1F3L3F3L1F1
44 | F3B3L2U1D1R2D1F3U3B1L3F1D3L2U3R3U1B3R2D2F2R3D1R1L1U2L3U3F2U2R2D1B2U1L3
45 | D1L2B2U2B1L3B3D2R1B2D1L3F3L2U3B1U2L3B3R2U2R3D1F2D2L1F2U1L1B3L3D2B2L3D2
46 | B2D2L3D2L2B3D1R1U2F2R2L2U3L1B1U3D3R2F2L2F1U3D3B1R3F2D2L3D3B1U1F3B3R3B3
47 | L1B2L1D2B2L3B3L2B1L2U2R3L1F1D1B2U2R3D1R3F2D3L3B2R2B2R1D2B2D1B3D2R2F1R1
48 | B3U2B2L1D2F3B1R2D1L3B2U3L1F1B2D3L3F2D3L2F1B3D3R1U3D3F3L1F3U2L2B2L2B3U2
49 | F2B2R1B1U3F2R1B3L3D3B1D2F3U1R2F3B1R2B2D1F1U3B1D3B1U2B2D3B1L3D2F1L1B3D1
50 | R1L1F2U1B1U1D2L1F3B1L3F3U2B1U3R3B3L2U3D3B3R2L1D2R3U1B2D1F3R1B1L2F3D3L1
51 | L3U3R3F3D3F2B3R2D3R2D2B3L1U2R2B3D3F2L2D2L1F1B2L3D1B1U1L3D1L1F2R1L1D1R1
52 | D2F3R2D3F2U2B1U3F3U2D1F2B1D1B1D2B2U1D1R1F1L3F3R1L3B3L3F2D3B2U3L2F2R2D1
53 | L3F1L1D2F3L3F1U1L1U3R1D2B1R3D3R2F3U3R2B1U2B2D3B2D3B2R3F3U2B1R3B2R3B2U1
54 | L2D1F3R1U3D3L2F2U2R3F3B1U3L1U1B3U3L2B2R3B1R2B1L2D2L2B2L3B2R2B2L3U2D1B3
55 | R3L1F3B2R2F3B1L2U2F2B2U1F3D3R3F3B2L2D2F2D2B1D2F1L1D1F3D2F3D3R1L3U3B3D1
56 | D3B1U1R3F2B1L2D3R1D3B1U1L3B2L3B1D2B2D1B1L3D1F1U3L3F1U3D3R2L2B2R3F2U3B1
57 | L1F3B2D2L3F2B1U2L1D3L1U2L3U1B2D2R1U3R3D3F2B1D1L2F2R2B3U3L2F2U2F3D2B2R3
58 | F3L2F3R1D1R1D1R1D3B2D2L2U2R2U2L3F1L1D3B3U3L2U1B1D3L1U1D1B3R3D1F1B1R3B2
59 | F2L1B2U1B1D2B2L2F2B2U1B1U1B1D2B1R1B1L1D3R3F1B1R1L3B3D2B1U2D2R2L3D3R1B1
60 | L3F2B1U3B3D2F2R2U3R1U2D1R3L3B3D2L2F2B3U3D2L2B1U3L3D2L3B2L2F3U2L1U2D3R3
61 | B1U3D2B1U3F2R2F3D3L1F1D1L2F3U2L1B3U1D3L2B2L2D3F2L1B1R1B2L3U3D2F2U1R3L2
62 | U3R2D3B2D3B3R1B1U2L3D1R3B2L2U1F2R2B3U1D1F2D3R3B1R2D2L1B3U2L3B2R3L1D2L3
63 | R2D1R3F1D1L2B2U1B1U1F3R3F1L2D2R3B1D3R3L3U3L3F2U3L1B3R2L3U1F3L1B2R2B3R2
64 | B1U3R2D2F3R3B3D3F3R3B3L1B1U1D1R2D1B3R2U2L2D1R3D1F2U1R1U2B1R3D2L2F1D2B3
65 |
--------------------------------------------------------------------------------
/src/nxprune.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include "nxprune.h"
25 | #include "alloc.h"
26 |
27 | using namespace vcube::nx;
28 |
29 | prune_base::prune_base(size_t stride) : os_unique(), index(), stride(stride) {
30 | os_unique_t os_tmp;
31 | auto os_next = os_unique.begin();
32 | decltype(index_t::base) next_symcoord = 0;
33 | uint8_t _ignore_;
34 |
35 | for (corient_t corient = 0; corient < N_CORIENT; corient++) {
36 | // Find the representative corient by symmetry
37 | cube c;
38 | c.setCornerOrient(corient);
39 | auto corient_s = ccoord::rep(c, _ignore_).getCornerOrient();
40 |
41 | // If this is a new representative, set base to a new coordinate;
42 | // otherwise copy base from the representative
43 | auto &idx = index[corient], &idx_s = index[corient_s];
44 | idx.base = (corient == corient_s) ? next_symcoord : idx_s.base;
45 |
46 | // Fill in the offsets and symmetries
47 | decltype(offset_sym_t::offset) offset = 0;
48 | for (c4comb_t c4comb = 0; c4comb < N_C4COMB; c4comb++) {
49 | c.setCorner4Comb(c4comb);
50 | c.setCornerOrient(corient);
51 |
52 | auto &os = os_tmp[c4comb];
53 | auto c4comb_s = ccoord::rep(c, os.sym).getCorner4Comb();
54 | auto &os_s = idx_s.os[c4comb_s];
55 |
56 | if (corient != corient_s) {
57 | os.offset = os_s.offset;
58 | } else if (c4comb != c4comb_s) {
59 | os.offset = os_tmp[c4comb_s].offset;
60 | } else {
61 | os.offset = offset++;
62 | }
63 | }
64 |
65 | next_symcoord += offset;
66 |
67 | // Deduplicate
68 | auto os_found = std::find(os_unique.begin(), os_next, os_tmp);
69 | if (os_found == os_next) {
70 | *os_next++ = os_tmp;
71 | }
72 |
73 | idx.os = &(*os_found)[0];
74 | }
75 | }
76 |
77 | void prune_base::setPrune(decltype(index_t::prune) p) {
78 | for (auto &idx : index) {
79 | idx.prune = p + idx.base * stride;
80 | }
81 | }
82 |
83 | bool prune_base::save(const std::string &filename) const {
84 | auto dir = filename;
85 | (void) mkdir(dirname(dir.data()), 0777);
86 |
87 | auto tmpname = filename + ".tmp";
88 | FILE *fp = fopen(tmpname.c_str(), "w");
89 | if (!fp) {
90 | return false;
91 | }
92 | size_t n = fwrite(index[0].prune, stride, N_CORNER_SYM, fp);
93 | if (fclose(fp)) {
94 | return false;
95 | }
96 | if (n != N_CORNER_SYM) {
97 | return false;
98 | }
99 | return rename(tmpname.c_str(), filename.c_str()) == 0;
100 | }
101 |
102 | bool prune_base::load(const std::string &filename) {
103 | size_t sz = stride * N_CORNER_SYM;
104 |
105 | FILE *fp = fopen(filename.c_str(), "r");
106 | if (!fp) {
107 | return false;
108 | }
109 |
110 | auto mem = alloc::huge(sz);
111 | if (!mem) {
112 | fclose(fp);
113 | return false;
114 | }
115 |
116 | size_t n = fread(mem, stride, N_CORNER_SYM, fp);
117 | if (fclose(fp)) {
118 | return false;
119 | }
120 |
121 | if (n != N_CORNER_SYM) {
122 | return false;
123 | }
124 |
125 | setPrune(mem);
126 |
127 | return true;
128 | }
129 |
130 | bool prune_base::loadShared(uint32_t key, const std::string &filename) {
131 | size_t sz = stride * N_CORNER_SYM;
132 |
133 | auto mem = alloc::shared(sz, key, false);
134 | if (!mem) {
135 | if (filename.empty()) {
136 | return false;
137 | }
138 |
139 | mem = alloc::shared(sz, key, true);
140 | if (!mem) {
141 | return false;
142 | }
143 |
144 | FILE *fp = fopen(filename.c_str(), "r");
145 | if (!fp) {
146 | return false;
147 | }
148 |
149 | size_t n = fread(mem, stride, N_CORNER_SYM, fp);
150 | if (fclose(fp)) {
151 | return false;
152 | }
153 |
154 | if (n != N_CORNER_SYM) {
155 | return false;
156 | }
157 | }
158 |
159 | setPrune(mem);
160 |
161 | return true;
162 | }
163 |
164 | std::vector prune_base::getCornerRepresentatives() const {
165 | std::vector cv;
166 | for (corient_t corient = 0; corient < N_CORIENT; corient++) {
167 | auto &idx = index[corient];
168 | for (c4comb_t c4comb = 0; c4comb < N_C4COMB; c4comb++) {
169 | auto &os = idx.os[c4comb];
170 | if (os.sym == 0) {
171 | cube c;
172 | c.setCorner4Comb(c4comb);
173 | c.setCornerOrient(corient);
174 | cv.push_back(c);
175 | }
176 | }
177 | }
178 | return cv;
179 | }
180 |
--------------------------------------------------------------------------------
/src/gen-const-cubes.cpp:
--------------------------------------------------------------------------------
1 | /* This file is part of vcube.
2 | *
3 | * Copyright (C) 2018 Andrew Skalski
4 | *
5 | * vcube is free software: you can redistribute it and/or modify
6 | * it under the terms of the GNU General Public License as published by
7 | * the Free Software Foundation, either version 3 of the License, or
8 | * (at your option) any later version.
9 | *
10 | * vcube is distributed in the hope that it will be useful,
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | * GNU General Public License for more details.
14 | *
15 | * You should have received a copy of the GNU General Public License
16 | * along with vcube. If not, see .
17 | */
18 |
19 | #define GENERATE_CONST_CUBES
20 | namespace vcube {
21 | class cube;
22 | static cube *moves = 0;
23 | static cube *sym = 0;
24 | static int *sym_inv = 0;
25 | static int move_sym6[18][8];
26 | }
27 |
28 | #include
29 | #include