Browse Source

test: refactor no-deps builder for Group

legacy
Dnomd343 3 months ago
parent
commit
75e6fc197b
  1. 53
      src/core_test/cases/group_union.cc
  2. 29
      src/core_test/cases/helper/block_num.cc
  3. 112
      src/core_test/cases/helper/group_impl.cc

53
src/core_test/cases/group_union.cc

@ -1,14 +1,10 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <format>
#include <cstdint> #include <cstdint>
#include <algorithm> #include <algorithm>
#include <ranges> #include <ranges>
// TODO: only for debug
#include <iostream>
#include "group/group.h" #include "group/group.h"
#include "helper/cases.h" #include "helper/cases.h"
#include "common_code/common_code.h" #include "common_code/common_code.h"
@ -21,6 +17,7 @@ using klotski::cases::ALL_GROUP_NUM;
TEST(GroupUnion, basic) { TEST(GroupUnion, basic) {
// TODO: loop for all
EXPECT_TRUE(GroupUnion::create(0).has_value()); EXPECT_TRUE(GroupUnion::create(0).has_value());
EXPECT_EQ(GroupUnion::create(0).value().unwrap(), 0); EXPECT_EQ(GroupUnion::create(0).value().unwrap(), 0);
EXPECT_FALSE(GroupUnion::create(TYPE_ID_LIMIT).has_value()); EXPECT_FALSE(GroupUnion::create(TYPE_ID_LIMIT).has_value());
@ -76,60 +73,18 @@ TEST(GroupUnion, size) {
} }
TEST(GroupUnion, group_num) { TEST(GroupUnion, group_num) {
for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) { for (uint32_t type_id = 0; type_id < TYPE_ID_LIMIT; ++type_id) {
EXPECT_EQ(GroupUnion::unsafe_create(type_id).group_num(), group_num(type_id)); EXPECT_EQ(GroupUnion::unsafe_create(type_id).group_num(), group_num(type_id));
} }
} }
TEST(GroupUnion, cases) { TEST(GroupUnion, cases) {
for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) { for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) {
auto cases = group_union_cases(type_id); auto cases = group_union_cases(type_id);
EXPECT_EQ(cases, klotski::cases::GroupUnion::unsafe_create(type_id).cases().codes()); EXPECT_EQ(cases, GroupUnion::unsafe_create(type_id).cases().codes());
} }
} }
TEST(GroupUnion, demo) { // TODO: test max_group_size
// for (auto i = 0; i < block_nums().size(); ++i) {
// std::cout << block_nums()[i].n_2x1 + block_nums()[i].n_1x2 << ", ";
// std::cout << block_nums()[i].n_2x1 << ", ";
// std::cout << block_nums()[i].n_1x1 << std::endl;
// }
std::vector<std::vector<uint64_t>> pp;
pp.resize(block_nums().size());
for (uint64_t head = 0; head < 16; ++head) {
for (auto range : 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);
}
}
for (uint32_t type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) {
auto cases = klotski::cases::GroupUnion::unsafe_create(type_id).cases();
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;
EXPECT_EQ(extend, pp[type_id]);
}
} // TODO: verify from_raw_code / from_short_code / from_common_code

29
src/core_test/cases/helper/block_num.cc

@ -24,13 +24,26 @@ static std::vector<block_num_t> build_block_nums() {
} }
} }
} }
std::ranges::sort(nums.begin(), nums.end(), [](const auto lhs, const auto rhs) { std::ranges::sort(nums.begin(), nums.end(), [](const auto lhs, const auto rhs) {
return lhs.first < rhs.first; return lhs.first < rhs.first;
}); });
return std::views::all(nums) | std::views::values | std::ranges::to<std::vector>(); return std::views::all(nums) | std::views::values | std::ranges::to<std::vector>();
} }
/// Build the mapping table from block_num to type_id.
static std::unordered_map<block_num_t, uint32_t> build_type_id_map() {
std::unordered_map<block_num_t, uint32_t> ids;
for (uint64_t i = 0; i < block_nums().size(); ++i) {
ids.emplace(block_nums()[i], i); // TODO: using `std::views::enumerate`
}
return ids;
}
const std::vector<block_num_t>& block_nums() {
static auto data = build_block_nums();
return data;
}
block_num_t cal_block_num(uint32_t range) { block_num_t cal_block_num(uint32_t range) {
block_num_t result {}; block_num_t result {};
for (range = range_reverse(range); range; range >>= 2) { for (range = range_reverse(range); range; range >>= 2) {
@ -50,11 +63,6 @@ block_num_t cal_block_num(uint32_t range) {
return result; return result;
} }
const std::vector<block_num_t>& block_nums() {
static auto data = build_block_nums();
return data;
}
block_num_t to_block_num(const uint32_t type_id) { block_num_t to_block_num(const uint32_t type_id) {
if (type_id < block_nums().size()) { if (type_id < block_nums().size()) {
return block_nums()[type_id]; return block_nums()[type_id];
@ -63,14 +71,7 @@ block_num_t to_block_num(const uint32_t type_id) {
} }
uint32_t to_type_id(const block_num_t block_num) { uint32_t to_type_id(const block_num_t block_num) {
static auto data = [] { static auto data = build_type_id_map();
std::unordered_map<block_num_t, uint32_t> map;
for (auto i = 0; i < block_nums().size(); ++i) {
map.emplace(block_nums()[i], i); // TODO: using `std::views::enumerate`
}
return map;
}();
if (const auto match = data.find(block_num); match != data.end()) { if (const auto match = data.find(block_num); match != data.end()) {
return match->second; return match->second;
} }

112
src/core_test/cases/helper/group_impl.cc

@ -1,99 +1,81 @@
#include <iostream>
#include "cases.h" #include "cases.h"
/// Filter cases with different type_id from AllCases. // TODO: multi-threads builder
static std::vector<std::vector<CommonCode>> build_all_cases() {
std::vector<std::vector<CommonCode>> codes;
for (auto code : AllCases::instance().fetch().codes()) {
const auto type_id = to_type_id(cal_block_num(code.unwrap()));
if (type_id >= codes.size()) {
codes.resize(type_id + 1);
}
codes[type_id].emplace_back(code);
}
return codes;
}
std::vector<CommonCode> extend_cases(CommonCode seed) { /// Extend ordered Group from the specified CommonCode seed.
auto raw_codes = klotski::cases::Group::extend(seed.to_raw_code()); // TODO: using inner build process static std::vector<CommonCode> extend_cases(CommonCode seed) {
// TODO: using inner build process
auto raw_codes = klotski::cases::Group::extend(seed.to_raw_code());
std::vector<CommonCode> common_codes {raw_codes.begin(), raw_codes.end()}; std::vector<CommonCode> common_codes {raw_codes.begin(), raw_codes.end()};
std::ranges::sort(common_codes.begin(), common_codes.end()); std::ranges::sort(common_codes.begin(), common_codes.end());
return common_codes; return common_codes;
} }
std::vector<CommonCode> remove_sub(const std::vector<CommonCode> &all, const std::vector<CommonCode> &sub) { /// Split Groups from the specified ordered list of CommonCodes.
std::vector<CommonCode> tmp;
tmp.reserve(all.size() - sub.size());
std::ranges::set_difference(all.begin(), all.end(), sub.begin(), sub.end(), std::back_inserter(tmp));
return tmp;
}
static std::vector<std::vector<CommonCode>> split_groups(std::vector<CommonCode> codes) { static std::vector<std::vector<CommonCode>> split_groups(std::vector<CommonCode> codes) {
std::vector<std::vector<CommonCode>> groups; std::vector<std::vector<CommonCode>> groups;
while (!codes.empty()) { while (!codes.empty()) {
auto sub = extend_cases(codes[0]); auto group = extend_cases(codes[0]); // sorted array
groups.emplace_back(group);
groups.emplace_back(sub); std::vector<CommonCode> remain;
codes = remove_sub(codes, sub); remain.reserve(codes.size() - group.size());
std::ranges::set_difference(codes.begin(), codes.end(), group.begin(), group.end(), std::back_inserter(remain));
codes = remain; // for next loop
} }
std::ranges::stable_sort(groups.begin(), groups.end(), [](const auto &lhs, const auto &rhs) {
std::ranges::stable_sort(groups.begin(), groups.end(), [](const std::vector<CommonCode> &g1, const std::vector<CommonCode> &g2) { return lhs.size() > rhs.size(); // sort with group size
return g1.size() > g2.size();
}); });
return groups; return groups;
}
/// Filter cases with different type_id from AllCases.
static const std::vector<std::vector<CommonCode>>& group_union_data() {
static auto data = [] {
std::vector<std::vector<CommonCode>> codes;
codes.resize(block_nums().size());
for (auto code: AllCases::instance().fetch().codes()) {
codes[to_type_id(cal_block_num(code.unwrap()))].emplace_back(code);
}
return codes;
}();
return data;
} }
// TODO: static data of `build_all_cases` /// Construct all valid klotski Groups in different GroupUnion.
static const std::vector<std::vector<std::vector<CommonCode>>>& group_data() {
static auto data = [] {
std::vector<std::vector<std::vector<CommonCode>>> groups;
groups.reserve(group_union_num());
for (uint32_t type_id = 0; type_id < group_union_num(); ++type_id) {
groups.emplace_back(split_groups(group_union_cases(type_id)));
}
return groups;
}();
return data;
}
uint32_t group_union_num() { uint32_t group_union_num() {
static auto data = build_all_cases(); return group_union_data().size();
return data.size();
} }
const std::vector<CommonCode>& group_union_cases(const uint32_t type_id) { uint32_t group_num(uint32_t type_id) {
static auto data = build_all_cases(); if (type_id < group_data().size()) {
if (type_id < data.size()) { return group_data()[type_id].size();
return data[type_id];
} }
std::abort(); std::abort();
} }
// TODO: multi-threads builder const std::vector<CommonCode>& group_union_cases(const uint32_t type_id) {
if (type_id < group_union_data().size()) {
static std::vector<std::vector<std::vector<CommonCode>>> all_groups_builder() { return group_union_data()[type_id];
std::vector<std::vector<std::vector<CommonCode>>> data;
for (uint32_t type_id = 0; type_id < group_union_num(); ++type_id) {
data.emplace_back(split_groups(group_union_cases(type_id)));
}
return data;
}
uint32_t group_num(uint32_t type_id) {
static auto data = all_groups_builder();
if (type_id < data.size()) {
return data[type_id].size();
} }
std::abort(); std::abort();
} }
const std::vector<CommonCode>& group_cases(uint32_t type_id, uint32_t group_id) { const std::vector<CommonCode>& group_cases(uint32_t type_id, uint32_t group_id) {
if (type_id < group_data().size() && group_id < group_data()[type_id].size()) {
static auto data = all_groups_builder(); return group_data()[type_id][group_id];
if (type_id < data.size() && group_id < data[type_id].size()) {
return data[type_id][group_id];
} }
std::abort(); std::abort();
} }

Loading…
Cancel
Save