Browse Source

perf: avoid building single group

master
Dnomd343 5 days ago
parent
commit
38f06d555c
  1. 175
      src/core/group/internal/group.cc
  2. 2
      src/core/main.cc
  3. 2
      src/core/utils/utility.h

175
src/core/group/internal/group.cc

@ -1,11 +1,9 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include <parallel_hashmap/phmap.h>
#include "group/group.h" #include "group/group.h"
#include "mover/mover.h"
#include <mover/mover.h>
#include <parallel_hashmap/phmap.h>
using klotski::codec::RawCode; using klotski::codec::RawCode;
using klotski::codec::CommonCode; using klotski::codec::CommonCode;
@ -19,76 +17,45 @@ using klotski::mover::MaskMover;
using klotski::group::GROUP_DATA; using klotski::group::GROUP_DATA;
using klotski::group::PATTERN_DATA; using klotski::group::PATTERN_DATA;
// NOTE: This code implements two time-consuming functions: template <typename Func>
// 1. Calculate all cases included in Group based on type_id/pattern_id/toward. KLSK_NOINLINE static RangesUnion group_extend(RawCode seed, const size_t reserve, Func add_mirror) {
// 2. Calculate the Group information it belongs to based on RawCode.
/// Spawn all the unsorted codes of the current group.
// static std::vector<RawCode> Group_extend_for_cases(RawCode raw_code, uint32_t reserve) {
// std::vector<RawCode> codes;
// phmap::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
// codes.reserve(reserve);
// cases.reserve(reserve * 1.56);
//
// auto core = MaskMover([&codes, &cases](RawCode code, uint64_t mask) {
// if (const auto match = cases.find(code.unwrap()); match != cases.end()) {
// match->second |= mask; // update mask
// return;
// }
// cases.emplace(code, mask);
// codes.emplace_back(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(RawCode::unsafe_create(curr), cases.find(curr)->second);
// }
// return codes;
// }
template <typename R>
static RangesUnion extend_next_(RawCode seed, size_t reserve, R func) {
std::vector<RawCode> codes; std::vector<RawCode> codes;
std::vector<RawCode> mirrors; std::vector<RawCode> mirrors;
phmap::flat_hash_map<RawCode, uint64_t> cases; // <code, hint> phmap::flat_hash_map<RawCode, uint64_t> cases; // <code, hint>
codes.reserve(reserve); codes.reserve(reserve);
mirrors.reserve(reserve); // TODO: cal max size-coff mirrors.reserve(reserve); // TODO: cal max size-coff
cases.reserve(reserve * 1.56); cases.reserve(static_cast<size_t>(reserve * 1.56));
auto core = MaskMover([&codes, &cases, &mirrors, func](RawCode code, uint64_t hint) { auto core = MaskMover([&codes, &cases, &mirrors, add_mirror](RawCode code, uint64_t hint) {
if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) {
iter->second |= hint; // update hint iter->second |= hint; // update hint
return; return;
} }
codes.emplace_back(code); // new case codes.emplace_back(code);
add_mirror(code, [&cases, &mirrors](RawCode mirror) {
func(code, [&cases, &mirrors](RawCode kk) { cases.emplace(mirror, 0);
cases.emplace(kk, 0); // TODO: contain check mirrors.emplace_back(mirror);
mirrors.emplace_back(kk);
}); });
}); });
uint64_t offset = 0; uint64_t offset = 0;
codes.emplace_back(seed); codes.emplace_back(seed);
cases.emplace(seed, 0); // without hint cases.emplace(seed, 0); // without hint
add_mirror(seed, [&mirrors, &cases](RawCode mirror) {
func(seed, [&mirrors, &cases](RawCode pp) { cases.emplace(mirror, 0);
cases.emplace(pp, 0); mirrors.emplace_back(mirror);
mirrors.emplace_back(pp);
}); });
while (offset != codes.size()) { while (offset != codes.size()) {
auto curr = codes[offset++]; const auto curr = codes[offset++];
core.next_cases(curr, cases.find(curr)->second); core.next_cases(curr, cases.find(curr)->second);
} }
// std::cout << std::format("{:.5f}\n", static_cast<double>(codes.size()) / reserve);
RangesUnion result {}; RangesUnion result {};
// TODO: how to reserve // TODO: how to reserve
for (auto raw_code : codes) { // TODO: using `std::views::concat` in new std library for (auto raw_code : codes) {
const auto code = raw_code.to_common_code().unwrap(); const auto code = raw_code.to_common_code().unwrap();
result.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code)); result.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code));
} }
@ -99,132 +66,70 @@ static RangesUnion extend_next_(RawCode seed, size_t reserve, R func) {
return result; return result;
} }
__attribute__((noinline)) static RangesUnion extend_type_common(RawCode seed, size_t reserve) { static RangesUnion extend_type_common(RawCode seed, size_t reserve) {
return extend_next_(seed, reserve, [](RawCode code, auto callback) {}); return group_extend(seed, reserve, [](RawCode, auto) {});
} }
// TODO: without `__attribute__((noinline))` will make it faster
static RangesUnion extend_type_hor(RawCode seed, size_t reserve) { static RangesUnion extend_type_hor(RawCode seed, size_t reserve) {
return extend_next_(seed, reserve, [](RawCode code, auto callback) { return group_extend(seed, reserve, [](const RawCode code, auto callback) {
const auto k1 = code.to_horizontal_mirror(); if (const auto mirror = code.to_horizontal_mirror(); mirror != code) {
if (k1 != code) { callback(mirror);
callback(k1);
} }
}); });
} }
__attribute__((noinline)) static RangesUnion extend_type_ver(RawCode seed, size_t reserve) { static RangesUnion extend_type_ver(RawCode seed, size_t reserve) {
return extend_next_(seed, reserve, [](RawCode code, auto callback) { return group_extend(seed, reserve, [](const RawCode code, auto callback) {
const auto k1 = code.to_vertical_mirror(); callback(code.to_vertical_mirror());
// if (k1 != code) {
callback(k1);
// }
}); });
} }
__attribute__((noinline)) static RangesUnion extend_type_diag(RawCode seed, size_t reserve) { static RangesUnion extend_type_diag(RawCode seed, size_t reserve) {
return extend_next_(seed, reserve, [](RawCode code, auto callback) { return group_extend(seed, reserve, [](const RawCode code, auto callback) {
const auto k1 = code.to_vertical_mirror().to_horizontal_mirror(); if (const auto mirror = code.to_diagonal_mirror(); mirror != code) {
if (k1 != code) { callback(mirror);
callback(k1);
} }
}); });
} }
__attribute__((noinline)) static RangesUnion extend_type_x(RawCode seed, size_t reserve) { static RangesUnion extend_type_x(RawCode seed, size_t reserve) {
return extend_next_(seed, reserve, [](RawCode code, auto callback) { return group_extend(seed, reserve, [](const RawCode code, auto callback) {
const auto k1 = code.to_vertical_mirror(); const auto mirror_1 = code.to_vertical_mirror();
callback(k1); callback(mirror_1);
const auto k2 = code.to_horizontal_mirror(); if (const auto mirror_2 = code.to_horizontal_mirror(); mirror_2 != code) {
if (k2 != code) { callback(mirror_2);
callback(k2); callback(mirror_1.to_horizontal_mirror());
const auto p3 = k1.to_horizontal_mirror();
callback(p3);
} }
}); });
} }
RangesUnion Group::cases() const { RangesUnion Group::cases() const {
if (const auto gu = GroupUnion::unsafe_create(type_id()); gu.group_num() == 1) {
// TODO: add white list for single-group unions return gu.cases();
// return GroupUnion::cases directly }
auto seed = CommonCode::unsafe_create(PATTERN_DATA[flat_id()] >> 23).to_raw_code(); auto seed = CommonCode::unsafe_create(PATTERN_DATA[flat_id()] >> 23).to_raw_code();
// NOTE: convert as RawCode directly
if (toward_ == Toward::B) { if (toward_ == Toward::B) {
seed = seed.to_horizontal_mirror(); seed = seed.to_horizontal_mirror();
} else if (toward_ == Toward::C) { } else if (toward_ == Toward::C) {
seed = seed.to_vertical_mirror(); seed = seed.to_vertical_mirror();
} else if (toward_ == Toward::D) { } else if (toward_ == Toward::D) {
// NOTE: avoid multi convert seed = seed.to_diagonal_mirror();
seed = seed.to_vertical_mirror().to_horizontal_mirror();
} }
RangesUnion data; RangesUnion data;
if (mirror_type() == MirrorType::Full) { if (mirror_type() == MirrorType::Full) {
data = extend_type_x(seed, size()); data = extend_type_x(seed, size());
} else if (mirror_type() == MirrorType::Horizontal) { } else if (mirror_type() == MirrorType::Horizontal) {
data = extend_type_hor(seed, size()); data = extend_type_hor(seed, size());
// auto lambda = [](RawCode code, phmap::flat_hash_map<RawCode, uint64_t> &cases, std::vector<RawCode> &mirrors) {
// const auto k1 = code.to_horizontal_mirror();
// if (k1 != code) {
// cases.emplace(k1, 0); // TODO: contain check
// mirrors.emplace_back(k1);
// }
// };
//
// data = extend_next<lambda>(seed, size());
// data = extend_next(seed, size(), [](RawCode code, phmap::flat_hash_map<RawCode, uint64_t> &cases, std::vector<RawCode> &mirrors) {
// const auto k1 = code.to_horizontal_mirror();
// if (k1 != code) {
// cases.emplace(k1, 0); // TODO: contain check
// mirrors.emplace_back(k1);
// }
// });
// data = extend_next(seed, size(), [](RawCode code, auto callback) {
// const auto k1 = code.to_horizontal_mirror();
// if (k1 != code) {
// callback(k1);
// }
// });
} else if (mirror_type() == MirrorType::Vertical) { } else if (mirror_type() == MirrorType::Vertical) {
data = extend_type_ver(seed, size()); data = extend_type_ver(seed, size());
// data = extend_next_(seed, size(), [](RawCode code, auto callback) {
// const auto k1 = code.to_vertical_mirror();
// if (k1 != code) { // TODO: without check
// callback(k1);
// }
// });
} else if (mirror_type() == MirrorType::Centro) { } else if (mirror_type() == MirrorType::Centro) {
data = extend_type_diag(seed, size()); data = extend_type_diag(seed, size());
// data = extend_next_(seed, size(), [](RawCode code, auto callback) {
// const auto k1 = code.to_vertical_mirror().to_horizontal_mirror();
// if (k1 != code) {
// callback(k1);
// }
// });
} else { } else {
data = extend_type_common(seed, size()); data = extend_type_common(seed, size());
} }
// auto raw_data = Group_extend_for_cases(seed, size());
// RangesUnion data {};
// for (auto raw_code : raw_data) {
// auto common_code = raw_code.to_common_code().unwrap();
// data.ranges(common_code >> 32).emplace_back(static_cast<uint32_t>(common_code));
// }
for (int head = 0; head < 16; ++head) { for (int head = 0; head < 16; ++head) {
std::stable_sort(data.ranges(head).begin(), data.ranges(head).end()); std::stable_sort(data.ranges(head).begin(), data.ranges(head).end());
} }

2
src/core/main.cc

@ -62,6 +62,8 @@ int main() {
for (auto group : GroupUnion::unsafe_create(type_id).groups()) { for (auto group : GroupUnion::unsafe_create(type_id).groups()) {
// if (group.is_horizontal_mirror()) { // if (group.is_horizontal_mirror()) {
// if (group.is_vertical_mirror()) { // if (group.is_vertical_mirror()) {
// if (group.mirror_type() == Group::MirrorType::Horizontal) {
// if (group.mirror_type() == Group::MirrorType::Vertical) {
// if (group.mirror_type() == Group::MirrorType::Centro) { // if (group.mirror_type() == Group::MirrorType::Centro) {
// if (group.mirror_type() == Group::MirrorType::Full) { // if (group.mirror_type() == Group::MirrorType::Full) {
// if (group.mirror_type() == Group::MirrorType::Ordinary) { // if (group.mirror_type() == Group::MirrorType::Ordinary) {

2
src/core/utils/utility.h

@ -36,8 +36,10 @@
/// Force function declaration to be inline. /// Force function declaration to be inline.
#if defined(__clang__) #if defined(__clang__)
#define KLSK_INLINE __attribute__ ((always_inline)) #define KLSK_INLINE __attribute__ ((always_inline))
#define KLSK_NOINLINE __attribute__((noinline))
#else #else
#define KLSK_INLINE // NOTE: make sure that function can be inline #define KLSK_INLINE // NOTE: make sure that function can be inline
#define KLSK_NOINLINE
#endif #endif
#define KLSK_INLINE_H KLSK_INLINE inline #define KLSK_INLINE_H KLSK_INLINE inline
#define KLSK_INLINE_CE KLSK_INLINE constexpr #define KLSK_INLINE_CE KLSK_INLINE constexpr

Loading…
Cancel
Save