Browse Source

update: several fixes and improvements

master
Dnomd343 1 month ago
parent
commit
d7eb0526d8
  1. 1
      src/core/CMakeLists.txt
  2. 24
      src/core/group/group.h
  3. 24
      src/core/group/internal/group.cc
  4. 119
      src/core/group/internal/group_union.cc
  5. 36
      src/core/group/internal/group_union.inl
  6. 3178
      src/core/group/internal/seeds.inc
  7. 9
      src/core/ranges/internal/derive.cc
  8. 3
      src/core/ranges/ranges.h
  9. 1
      src/core_test/CMakeLists.txt
  10. 183
      src/core_test/cases/group_union.cc

1
src/core/CMakeLists.txt

@ -22,6 +22,7 @@ set(KLOTSKI_CORE_SRC
fast_cal/internal/cal_core.cc
fast_cal/internal/fast_cal.cc
group/internal/group_union.cc
group/internal/group.cc
ranges/internal/ranges.cc

24
src/core/group/group.h

@ -75,10 +75,10 @@ namespace klotski::cases {
constexpr uint32_t TYPE_ID_LIMIT = 203;
constexpr uint32_t ALL_GROUP_NUM = 25422;
uint32_t common_code_to_type_id(uint64_t common_code);
uint32_t raw_code_to_type_id(uint64_t raw_code);
// uint32_t common_code_to_type_id(uint64_t common_code);
// uint32_t raw_code_to_type_id(uint64_t raw_code);
std::vector<uint64_t> group_extend_from_seed(uint64_t raw_code);
// std::vector<uint64_t> group_extend_from_seed(uint64_t raw_code);
class Group;
@ -109,6 +109,8 @@ public:
/// Get the upper limit of the group size.
[[nodiscard]] uint32_t max_group_size() const;
[[nodiscard]] RangesUnion cases() const;
/// Get all group instances under the current type id.
[[nodiscard]] std::vector<Group> groups() const;
@ -155,14 +157,9 @@ public:
/// Create Group with validity check.
static std::optional<Group> create(uint32_t type_id, uint32_t group_id);
// TODO: fetch group size directly
[[nodiscard]] uint32_t size() const;
void build();
// TODO: maybe define CommonCodes here
// TODO: get all cases from current Group
const CommonCodes& cases();
[[nodiscard]] RangesUnion cases() const;
static Group from_raw_code(codec::RawCode raw_code);
static Group from_common_code(codec::CommonCode common_code);
@ -170,6 +167,10 @@ public:
private:
uint32_t type_id_;
uint32_t group_id_;
[[nodiscard]] uint32_t flat_id() const;
static std::vector<uint64_t> extend(codec::RawCode raw_code);
};
class GroupCase {
@ -197,12 +198,9 @@ private:
static std::mutex building_;
static codec::CommonCode fast_decode(const info_t &info);
static codec::CommonCode tiny_decode(const info_t &info);
static info_t fast_encode(const codec::CommonCode &common_code);
static info_t tiny_encode(const codec::CommonCode &common_code);
};
} // namespace klotski::cases
#include "internal/group.inl"
#include "internal/group_union.inl"

24
src/core/group/internal/group.cc

@ -8,28 +8,10 @@
#include <core/core.h>
static KLSK_INLINE uint32_t type_id(const int n, const int n_2x1, const int n_1x1) {
constexpr int offset[8] = {0, 15, 41, 74, 110, 145, 175, 196};
return offset[n] + (15 - n * 2) * n_2x1 + n_1x1;
}
uint32_t klotski::cases::common_code_to_type_id(const uint64_t common_code) {
const auto range = static_cast<uint32_t>(common_code);
const auto n_1x1 = std::popcount((range >> 1) & range & 0x55555555);
const auto n_2x1 = std::popcount((range >> 1) & ~range & 0x55555555);
return type_id(std::popcount(range) - n_1x1 * 2, n_2x1, n_1x1);
}
uint32_t klotski::cases::raw_code_to_type_id(const uint64_t raw_code) {
const auto n = std::popcount(((raw_code >> 1) ^ raw_code) & 0x0249249249249249);
const auto n_2x1 = std::popcount((raw_code >> 1) & ~raw_code & 0x0249249249249249);
const auto n_1x1 = std::popcount((raw_code >> 1) & raw_code & 0x0249249249249249) - n - 3;
return type_id(n, n_2x1, n_1x1);
}
std::vector<uint64_t> klotski::cases::group_extend_from_seed(uint64_t raw_code) {
std::vector<uint64_t> klotski::cases::Group::extend(codec::RawCode raw_code) {
auto max_size = GroupUnion::create(raw_code_to_type_id(raw_code))->max_group_size();
auto max_size = GroupUnion::from_raw_code(raw_code).max_group_size();
// auto max_size = GroupUnion::create(raw_code_to_type_id(raw_code))->max_group_size();
uint64_t offset = 0;
std::vector<uint64_t> results;

119
src/core/group/internal/group_union.cc

@ -0,0 +1,119 @@
#include "group/group.h"
// #include <queue>
// #include <absl/container/btree_set.h>
// #include <absl/container/flat_hash_map.h>
// #include <absl/container/node_hash_map.h>
#include <iostream>
#include <core/core.h>
static KLSK_INLINE uint32_t type_id(const int n, const int n_2x1, const int n_1x1) {
constexpr int offset[8] = {0, 15, 41, 74, 110, 145, 175, 196};
return offset[n] + (15 - n * 2) * n_2x1 + n_1x1;
}
static uint32_t common_code_to_type_id(const uint64_t common_code) {
const auto range = static_cast<uint32_t>(common_code);
const auto n_1x1 = std::popcount((range >> 1) & range & 0x55555555);
const auto n_2x1 = std::popcount((range >> 1) & ~range & 0x55555555);
return type_id(std::popcount(range) - n_1x1 * 2, n_2x1, n_1x1);
}
static uint32_t raw_code_to_type_id(const uint64_t raw_code) {
const auto n = std::popcount(((raw_code >> 1) ^ raw_code) & 0x0249249249249249);
const auto n_2x1 = std::popcount((raw_code >> 1) & ~raw_code & 0x0249249249249249);
const auto n_1x1 = std::popcount((raw_code >> 1) & raw_code & 0x0249249249249249) - n - 3;
return type_id(n, n_2x1, n_1x1);
}
uint32_t klotski::cases::GroupUnion::type_id(codec::CommonCode common_code) {
return common_code_to_type_id(common_code.unwrap());
}
uint32_t klotski::cases::GroupUnion::type_id(codec::RawCode raw_code) {
return raw_code_to_type_id(raw_code.unwrap());
}
// TODO: using {n, n_2x1, n_1x1} for CPU cache-line perf.
constexpr int TYPE_ID_N_NUM[203] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7,
};
constexpr int TYPE_ID_N_2x1_NUM[203] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1,
1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
2, 2, 2, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 0, 0,
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
4, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 0,
0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5,
5, 6, 6, 6, 0, 1, 2, 3, 4, 5, 6,
};
constexpr int TYPE_ID_N_1x1_NUM[203] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
1, 2, 3, 4, 5, 6, 7, 0, 8, 8, 9, 1, 9, 10, 10, 2,
11, 3, 11, 12, 12, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6,
7, 8, 8, 0, 9, 1, 9, 2, 10, 10, 3, 4, 5, 6, 7, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 2, 3, 4, 5,
6, 7, 8, 8, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3,
4, 5, 6, 7, 0, 8, 8, 1, 2, 3, 4, 5, 6, 7, 0, 1,
2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3,
4, 5, 6, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5,
6, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4,
0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0,
1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1,
2, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0,
};
klotski::cases::RangesUnion klotski::cases::GroupUnion::cases() const {
Ranges ranges {};
int n = TYPE_ID_N_NUM[type_id_];
int n_2x1 = TYPE_ID_N_2x1_NUM[type_id_];
int n_1x1 = TYPE_ID_N_1x1_NUM[type_id_]; // TODO: cal from type_id
ranges.spawn(n, n_2x1, n_1x1);
for (auto &x : ranges) {
x = klotski::range_reverse(x);
}
// std::cout << "start derive" << std::endl;
RangesUnion cases;
ranges.derive(0x0, cases[0x0]);
ranges.derive(0x1, cases[0x1]);
ranges.derive(0x2, cases[0x2]);
ranges.derive(0x4, cases[0x4]);
ranges.derive(0x5, cases[0x5]);
ranges.derive(0x6, cases[0x6]);
ranges.derive(0x8, cases[0x8]);
ranges.derive(0x9, cases[0x9]);
ranges.derive(0xA, cases[0xA]);
ranges.derive(0xC, cases[0xC]);
ranges.derive(0xD, cases[0xD]);
ranges.derive(0xE, cases[0xE]);
return cases;
}

36
src/core/group/internal/group.inl → src/core/group/internal/group_union.inl

@ -93,11 +93,19 @@ inline uint32_t GroupUnion::max_group_size() const {
}
inline std::vector<Group> GroupUnion::groups() const {
return {};
std::vector<Group> groups;
groups.reserve(group_num());
for (uint32_t group_id = 0; group_id < group_num(); ++group_id) {
groups.emplace_back(Group::unsafe_create(type_id_, group_id));
}
return groups;
}
inline std::optional<Group> GroupUnion::group(const uint32_t group_id) const {
if (group_id < GROUP_NUM[group_id]) {
if (group_id < group_num()) {
return Group::unsafe_create(type_id_, group_id);
}
return std::nullopt;
@ -120,27 +128,3 @@ inline GroupUnion GroupUnion::from_common_code(const codec::CommonCode common_co
// ------------------------------------------------------------------------------------- //
} // namespace klotski::cases
namespace klotski::cases::internal {
class GroupImpl {
public:
explicit GroupImpl(const int flat_id) : flat_id_(flat_id) {}
const std::vector<codec::CommonCode>& cases();
int flat_id_;
bool available_;
std::mutex building_;
// static constexpr std::array<GroupImpl, ALL_GROUP_NUM> ins() {
// return std::array<GroupImpl, ALL_GROUP_NUM> {};
// }
};
} // namespace klotski::cases::internal
// inline const std::vector<codec::CommonCode>& Group::cases() {
// static auto kk = internal::GroupImpl::ins();
// return kk[0].cases();
// }

3178
src/core/group/internal/seeds.inc

File diff suppressed because it is too large

9
src/core/ranges/internal/derive.cc

@ -39,8 +39,13 @@ void Ranges::derive(const int head, Ranges &output) const {
/// ( xx xx xx ) xx xx xx ... [reversed range]
/// +1 00 00 00 ... (delta)
tmp += range_reverse((*this)[index]) & ~(tmp - 1);
while (range_reverse((*this)[++index]) < tmp) {} // located next range
--index;
// TODO: overflow here in some type_id
// TODO: -> tmp > range[-1]
// TODO: maybe using binary search here
// while (range_reverse((*this)[++index]) < tmp) {} // located next range
// --index;
continue;
}
output.emplace_back(range_reverse((*this)[index])); // release valid case

3
src/core/ranges/ranges.h

@ -14,4 +14,7 @@ public:
void derive(int head, Ranges &output) const;
};
// TODO: add RangesUnion here
// TODO: -> spawn from Ranges / export std::vector<CommonCode>
} // namespace klotski::cases

1
src/core_test/CMakeLists.txt

@ -22,6 +22,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../core/common_code)
set(KLSK_TEST_CASES_SRC
cases/all_cases.cc
cases/basic_ranges.cc
cases/group_union.cc
)
add_executable(test_klotski_cases ${KLSK_TEST_CASES_SRC})

183
src/core_test/cases/group_union.cc

@ -0,0 +1,183 @@
#include <algorithm>
#include <common_code.h>
#include <cstdint>
#include <iostream>
#include <format>
#include <utility.h>
#include <group/group.h>
#include <gtest/gtest.h>
struct block_num_t {
int n_1x1;
int n_1x2;
int n_2x1;
};
template <>
struct std::hash<block_num_t> {
size_t operator()(const block_num_t val) const noexcept {
return std::hash<int>()(val.n_1x1) ^ std::hash<int>()(val.n_1x2) ^ std::hash<int>()(val.n_2x1);
}
};
bool operator==(const block_num_t &lhs, const block_num_t &rhs) {
return lhs.n_1x1 == rhs.n_1x1 && lhs.n_1x2 == rhs.n_1x2 && lhs.n_2x1 == rhs.n_2x1;
}
uint32_t cal_flag(const block_num_t &block_num) {
return ((block_num.n_1x2 + block_num.n_2x1) << 7) | (block_num.n_2x1 << 3) | block_num.n_1x1;
}
std::vector<block_num_t> block_nums() {
std::vector<std::pair<uint32_t, block_num_t>> tmp;
for (int n = 0; n <= 7; ++n) {
for (int n_1x2 = 0; n_1x2 <= n; ++n_1x2) {
if (n == 7 && n_1x2 == 0) {
continue;
}
for (int n_1x1 = 0; n_1x1 <= (20 - 4 - 2 - n * 2); ++n_1x1) {
auto num = block_num_t {
.n_1x1 = n_1x1,
.n_1x2 = n_1x2,
.n_2x1 = n - n_1x2,
};
auto flag = cal_flag(num);
tmp.emplace_back(flag, num);
// std::cout << flag << std::endl;
}
}
}
std::sort(tmp.begin(), tmp.end(), [](const auto val1, const auto val2) {
return val1.first < val2.first;
});
// for (auto [x, _] : tmp) {
// std::cout << x << std::endl;
// }
std::vector<block_num_t> results;
std::ranges::transform(tmp, std::back_inserter(results), [](const auto val) {
return val.second;
});
// for (auto x : results) {
// std::cout << std::format("n_1x1 = {} / n_1x2 = {} / n_2x1 = {}", x.n_1x1, x.n_1x2, x.n_2x1) << std::endl;
// }
return results;
}
block_num_t cal_block_num(const uint64_t common_code) noexcept {
block_num_t result {};
auto range = klotski::range_reverse(static_cast<uint32_t>(common_code));
for (; range; range >>= 2) {
switch (range & 0b11) {
case 0b01: // 1x2 block
++result.n_1x2;
continue;
case 0b10: // 2x1 block
++result.n_2x1;
continue;
case 0b11: // 1x1 block
++result.n_1x1;
continue;
}
}
return result;
}
uint32_t to_type_id(block_num_t block_num) {
auto f = []() {
auto ret = block_nums();
std::unordered_map<block_num_t, uint32_t> kk;
for (auto i = 0; i < ret.size(); ++i) {
kk.emplace(ret[i], i);
}
return kk;
};
static auto data = f();
return data[block_num];
}
TEST(GroupUnion, demo) {
// kk();
auto kk = cal_block_num(0x1A9BF0C00);
std::cout << to_type_id(kk) << std::endl;
// for (auto i = 0; i < block_nums().size(); ++i) {
// // std::cout << block_nums()[i].n_2x1 + block_nums()[i].n_1x2 << std::endl;
//
// // std::cout << block_nums()[i].n_2x1 << std::endl;
//
// std::cout << block_nums()[i].n_1x1 << std::endl;
// }
//
// return;
std::vector<std::vector<uint64_t>> pp;
pp.resize(block_nums().size());
// std::cout << pp.size() << std::endl;
for (uint64_t head = 0; head < 16; ++head) {
for (auto range : klotski::cases::AllCases::instance().fetch()[head]) {
uint64_t common_code = head << 32 | range;
auto type_id = to_type_id(cal_block_num(common_code));
pp[type_id].emplace_back(common_code);
}
}
// std::cout << pp[0].size() << std::endl;
// std::cout << pp[169].size() << std::endl;
for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) {
// std::cout << "start cases cal" << std::endl;
auto cases = klotski::cases::GroupUnion::unsafe_create(type_id).cases();
// std::cout << "end cases cal" << std::endl;
std::vector<uint64_t> extend {};
for (uint64_t head = 0; head < 16; ++head) {
for (auto range : cases[head]) {
extend.emplace_back(head << 32 | range);
}
}
std::cout << "type_id " << type_id << " -> " << extend.size() << std::endl;
// std::cout << std::endl;
EXPECT_EQ(extend, pp[type_id]);
}
}
Loading…
Cancel
Save