Browse Source

feat: function implementation of Group module

master
Dnomd343 5 months ago
parent
commit
e28d717c3c
  1. 2
      src/core/CMakeLists.txt
  2. 25
      src/core/benchmark/group.cc
  3. 15
      src/core/group/group.h
  4. 16
      src/core/group/internal/constant/group.h
  5. 4
      src/core/group/internal/constant/group_union.h
  6. 0
      src/core/group/internal/constant/seeds.inc
  7. 1
      src/core/group/internal/constant/sizes.inc
  8. 76
      src/core/group/internal/group.cc
  9. 29
      src/core/group/internal/group.inl
  10. 30
      src/core/group/internal/group_union.inl
  11. 39
      src/core/main.cc

2
src/core/CMakeLists.txt

@ -45,7 +45,7 @@ target_compile_options(codec_benchmark PRIVATE -fno-rtti -fno-exceptions)
target_link_libraries(codec_benchmark PRIVATE klotski::core benchmark::benchmark_main)
add_executable(group_benchmark benchmark/group.cc)
target_compile_options(group_benchmark PRIVATE -fno-rtti -fno-exceptions)
target_compile_options(group_benchmark PRIVATE -fno-rtti -fno-exceptions -fno-access-control)
target_link_libraries(group_benchmark PRIVATE klotski::core benchmark::benchmark_main)
add_executable(bm_all_cases benchmark/all_cases.cc)

25
src/core/benchmark/group.cc

@ -2,14 +2,14 @@
#include <benchmark/benchmark.h>
#define private public
// #define private public
#include "group/group.h"
#include <ranges/ranges.h>
#include "../../../third_party/thread-pool/include/BS_thread_pool.hpp"
#include "all_cases/all_cases.h"
#undef private
// #undef private
using klotski::cases::AllCases;
@ -104,11 +104,11 @@ static void RawCodeToTypeId(benchmark::State &state) {
static void GroupExtend(benchmark::State &state) {
auto src = klotski::codec::RawCode::from_common_code(0x1A9BF0C00)->unwrap();
auto src = klotski::codec::RawCode::from_common_code(0x1A9BF0C00).value();
for (auto _ : state) {
// volatile auto ret = klotski::cases::group_extend_from_seed(src);
volatile auto ret = klotski::cases::Group::extend(src, 0);
// std::cout << ret.size() << std::endl;
}
@ -246,10 +246,21 @@ static void RangesDerive(benchmark::State &state) {
// std::cout << results.size() << " vs " << klotski::cases::ALL_CASES_NUM[5] << std::endl;
}
static void SpawnGroups(benchmark::State &state) {
volatile auto val = 169;
auto group_union = klotski::cases::GroupUnion::create(val).value();
for (auto _ : state) {
volatile auto kk = group_union.groups();
}
}
// BENCHMARK(CommonCodeToTypeId)->Arg(8)->Arg(64)->Arg(256);
// BENCHMARK(RawCodeToTypeId)->Arg(8)->Arg(64)->Arg(256);
// BENCHMARK(GroupExtend)->Unit(benchmark::kMillisecond);
BENCHMARK(GroupExtend)->Unit(benchmark::kMillisecond);
// BENCHMARK(FilterFromAllCases)->Unit(benchmark::kMillisecond);
@ -259,6 +270,8 @@ static void RangesDerive(benchmark::State &state) {
// BENCHMARK(OriginAllCases)->Unit(benchmark::kMillisecond);
BENCHMARK(RangesDerive)->Unit(benchmark::kMillisecond);
// BENCHMARK(RangesDerive)->Unit(benchmark::kMillisecond);
// BENCHMARK(SpawnGroups);
BENCHMARK_MAIN();

15
src/core/group/group.h

@ -151,6 +151,12 @@ public:
// ------------------------------------------------------------------------------------- //
/// Get the original type id.
[[nodiscard]] uint32_t type_id() const;
/// Get the original group id.
[[nodiscard]] uint32_t group_id() const;
/// Create Group without any check.
static Group unsafe_create(uint32_t type_id, uint32_t group_id);
@ -176,10 +182,13 @@ public:
// ------------------------------------------------------------------------------------- //
private:
uint32_t flat_id_;
uint32_t type_id_;
uint32_t group_id_;
[[nodiscard]] uint32_t flat_id() const;
// TODO: maybe we can using `std::vector<RawCode>`
static std::vector<uint64_t> extend(codec::RawCode raw_code);
public:
static std::vector<codec::RawCode> extend(codec::RawCode raw_code, uint32_t reserve = 0);
};
class GroupCase {

16
src/core/group/internal/constant/group.h

@ -0,0 +1,16 @@
#pragma once
#include <array>
namespace klotski::cases {
// TODO: should we try to compress it?
constexpr auto GROUP_SIZE = std::to_array<uint32_t>({
#include "sizes.inc"
});
constexpr auto GROUP_SEED = std::to_array<uint64_t>({
#include "seeds.inc"
});
} // namespace klotski::cases

4
src/core/group/internal/constant/group_union.h

@ -2,6 +2,8 @@
#include <array>
#include "utils/utility.h"
namespace klotski::cases {
/// The number of groups contained in GroupUnion.
@ -21,6 +23,8 @@ constexpr auto GROUP_NUM = std::to_array<uint16_t>({
214, 6 , 18 , 54 , 2 , 44 , 40 , 124 , 84 , 70 , 18 ,
});
constexpr auto GROUP_OFFSET = to_offset<uint16_t, 203>(GROUP_NUM, 0);
/// The maximum Group size in each GroupUnion.
constexpr auto MAX_GROUP_SIZE = std::to_array<uint32_t>({
12 , 192 , 1440 , 6720 , 21840 , 52416 , 96096 , 137280, 154440, 137280, 96096 , 52416 ,

0
src/core/group/internal/seeds.inc → src/core/group/internal/constant/seeds.inc

1
src/core/group/internal/constant/sizes.inc

File diff suppressed because one or more lines are too long

76
src/core/group/internal/group.cc

@ -1,45 +1,59 @@
#include <absl/container/flat_hash_map.h>
#include "core/core.h"
#include "group/group.h"
#include <queue>
using klotski::core::Core;
using klotski::cases::Group;
using klotski::codec::RawCode;
using klotski::codec::CommonCode;
using klotski::cases::RangesUnion;
#include <absl/container/btree_set.h>
#include <absl/container/flat_hash_map.h>
#include <absl/container/node_hash_map.h>
std::vector<RawCode> Group::extend(RawCode raw_code, uint32_t reserve) {
std::vector<RawCode> codes;
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
reserve = reserve ? reserve : GroupUnion::from_raw_code(raw_code).max_group_size();
codes.reserve(reserve);
cases.reserve(reserve);
auto core = Core([&codes, &cases](uint64_t code, uint64_t mask) {
if (const auto match = cases.find(code); match != cases.end()) {
match->second |= mask; // update mask
return;
}
cases.emplace(code, mask);
codes.emplace_back(RawCode::unsafe_create(code)); // new case
});
uint64_t offset = 0;
codes.emplace_back(raw_code);
cases.emplace(raw_code, 0); // without mask
while (offset != codes.size()) {
auto curr = codes[offset++].unwrap();
core.next_cases(curr, cases.find(curr)->second);
}
return codes;
}
#include <core/core.h>
RangesUnion Group::cases() const {
auto seed = CommonCode::unsafe_create(GROUP_SEED[flat_id()]);
std::vector<uint64_t> klotski::cases::Group::extend(codec::RawCode raw_code) {
// std::cout << seed << std::endl;
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();
auto codes = extend(seed.to_raw_code(), size());
uint64_t offset = 0;
std::vector<uint64_t> results;
results.reserve(max_size);
results.emplace_back(raw_code);
// std::cout << codes.size() << std::endl;
absl::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
cases.reserve(max_size);
cases.emplace(raw_code, 0); // without mask
// TODO: how to reserve
auto core = klotski::core::Core(
[&results, &cases](auto code, auto mask) { // callback function
auto current = cases.find(code);
if (current != cases.end()) {
current->second |= mask; // update mask
return;
}
cases.emplace(code, mask);
results.emplace_back(code);
}
);
RangesUnion data;
while (offset != results.size()) {
auto tmp = results[offset];
core.next_cases(tmp, cases.find(tmp)->second);
++offset;
for (auto raw_code : codes) {
auto common_code = raw_code.to_common_code().unwrap();
data[common_code >> 32].emplace_back(static_cast<uint32_t>(common_code));
}
return results;
// TODO: do sort process
return data;
}

29
src/core/group/internal/group.inl

@ -1,5 +1,34 @@
#pragma once
#include "constant/group.h"
namespace klotski::cases {
inline uint32_t Group::size() const {
return GROUP_SIZE[flat_id()];
}
inline uint32_t Group::flat_id() const {
return GROUP_OFFSET[type_id_] + group_id_;
}
inline uint32_t Group::type_id() const {
return type_id_;
}
inline uint32_t Group::group_id() const {
return group_id_;
}
inline Group Group::unsafe_create(const uint32_t type_id, const uint32_t group_id) {
return std::bit_cast<Group>(static_cast<uint64_t>(group_id) << 32 | type_id);
}
inline std::optional<Group> Group::create(const uint32_t type_id, const uint32_t group_id) {
if (type_id < TYPE_ID_LIMIT && group_id < GROUP_NUM[type_id]) {
return unsafe_create(type_id, group_id);
}
return std::nullopt;
}
} // namespace klotski::cases

30
src/core/group/internal/group_union.inl

@ -1,20 +1,22 @@
#pragma once
#include <ranges>
#include "constant/group_union.h"
namespace klotski::cases {
// ------------------------------------------------------------------------------------- //
inline constexpr uint32_t GroupUnion::unwrap() const {
constexpr uint32_t GroupUnion::unwrap() const {
return type_id_;
}
inline constexpr GroupUnion GroupUnion::unsafe_create(const uint32_t type_id) {
constexpr GroupUnion GroupUnion::unsafe_create(const uint32_t type_id) {
return std::bit_cast<GroupUnion>(type_id);
}
inline constexpr std::optional<GroupUnion> GroupUnion::create(const uint32_t type_id) {
constexpr std::optional<GroupUnion> GroupUnion::create(const uint32_t type_id) {
if (type_id < TYPE_ID_LIMIT) {
return unsafe_create(type_id);
}
@ -23,29 +25,25 @@ inline constexpr std::optional<GroupUnion> GroupUnion::create(const uint32_t typ
// ------------------------------------------------------------------------------------- //
inline constexpr uint32_t GroupUnion::size() const {
constexpr uint32_t GroupUnion::size() const {
return GROUP_UNION_SIZE[type_id_];
}
inline constexpr uint32_t GroupUnion::group_num() const {
constexpr uint32_t GroupUnion::group_num() const {
return GROUP_NUM[type_id_];
}
inline constexpr uint32_t GroupUnion::max_group_size() const {
constexpr uint32_t GroupUnion::max_group_size() const {
return MAX_GROUP_SIZE[type_id_];
}
inline std::vector<Group> GroupUnion::groups() const {
// TODO: using `std::iota` helper
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;
auto build = [this](const uint32_t group_id) {
return Group::unsafe_create(type_id_, group_id);
};
return std::views::iota(0U, group_num())
| std::views::transform(build)
| std::ranges::to<std::vector>();
}
inline std::optional<Group> GroupUnion::group(const uint32_t group_id) const {

39
src/core/main.cc

@ -46,13 +46,38 @@ int main() {
// std::cout << group.type_id_ << ", " << group.group_id_ << std::endl;
// }
constexpr auto gu = GroupUnion::unsafe_create(169);
constexpr auto gu_ = GroupUnion::create(169).value();
// constexpr auto gu_ = GroupUnion::create(1169).value();
constexpr auto k1 = gu.unwrap();
constexpr auto k2 = gu.size();
constexpr auto k3 = gu.group_num();
constexpr auto k4 = gu.max_group_size();
// constexpr auto gu = GroupUnion::unsafe_create(169);
// constexpr auto gu_ = GroupUnion::create(169).value();
// // constexpr auto gu_ = GroupUnion::create(1169).value();
// constexpr auto k1 = gu.unwrap();
// constexpr auto k2 = gu.size();
// constexpr auto k3 = gu.group_num();
// constexpr auto k4 = gu.max_group_size();
// auto kk = GroupUnion::unsafe_create(169);
// auto pp = kk.group(0).value();
// std::cout << pp.type_id() << ", " << pp.group_id() << std::endl;
// for (auto group : kk.groups()) {
// std::cout << group.type_id() << ", " << group.group_id() << std::endl;
// }
auto gu = GroupUnion::unsafe_create(169);
// auto cases = gu.group(0).value().cases();
// for (auto &kk : cases) {
// std::cout << kk.size() << std::endl;
// }
klotski::cases::RangesUnion cases;
for (auto group : gu.groups()) {
cases += group.cases();
}
for (auto &kk : cases) {
std::ranges::sort(kk.begin(), kk.end());
}
std::cout << (cases == gu.cases()) << std::endl;
std::cerr << std::chrono::system_clock::now() - start << std::endl;

Loading…
Cancel
Save