From 37112680b05d3a32f2bb52e772f31c9dca5a0622 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 18 Jan 2025 18:19:24 +0800 Subject: [PATCH] update: using mirror function template --- src/core/benchmark/group.cc | 4 +- src/core/group/internal/group.cc | 409 ++++++++----------------------- src/core/main.cc | 3 +- 3 files changed, 110 insertions(+), 306 deletions(-) diff --git a/src/core/benchmark/group.cc b/src/core/benchmark/group.cc index be69e05..e731e9b 100644 --- a/src/core/benchmark/group.cc +++ b/src/core/benchmark/group.cc @@ -114,7 +114,9 @@ static void GroupExtend(benchmark::State &state) { // auto src = klotski::codec::RawCode::from_common_code(0x1A9BF0C00).value(); - const auto group = Group::unsafe_create(169, 0, Group::Toward::C); + // const auto group = Group::unsafe_create(169, 0, Group::Toward::C); + // const auto group = Group::create(5, 0, Group::Toward::A).value(); + const auto group = Group::create(186, 0, Group::Toward::A).value(); for (auto _ : state) { diff --git a/src/core/group/internal/group.cc b/src/core/group/internal/group.cc index bbd4fc9..c6bd3f0 100644 --- a/src/core/group/internal/group.cc +++ b/src/core/group/internal/group.cc @@ -24,148 +24,33 @@ using klotski::group::PATTERN_DATA; // 2. Calculate the Group information it belongs to based on RawCode. /// Spawn all the unsorted codes of the current group. -static std::vector Group_extend_for_cases(RawCode raw_code, uint32_t reserve) { - std::vector codes; - phmap::flat_hash_map cases; // - 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; -} - -// TODO: maybe we can send callback here (for GroupCases `data_1` builder) - -static RangesUnion extend_demo(Group group, RawCode seed, size_t reserve) { // TODO: group param only for test - std::vector codes; - // TODO: key type of flat_hash_map can using `RawCode` directly - phmap::flat_hash_map cases; // - codes.reserve(reserve); - cases.reserve(reserve * 1.56); - - std::vector mirror_codes; - mirror_codes.reserve(reserve); // TODO: cal max size-coff - - auto core = MaskMover([&codes, &cases, &mirror_codes](RawCode code, uint64_t mask) { - // TODO: using `try_emplace` interface - 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 - - auto k1 = code.to_horizontal_mirror(); - if (k1 != code) { - bool ret = cases.try_emplace(k1.unwrap(), 0).second; - if (!ret) { - std::cout << "!!! get unexpect case" << std::endl; // TODO: can we confirm it? - } else { - mirror_codes.emplace_back(k1); - } - } - - // auto k2 = code.to_vertical_mirror(); - // if (k2 != code && cases.try_emplace(k2.unwrap(), 0).second) { - // mirror_codes.emplace_back(k2); - // } - - // auto k3 = k2.to_horizontal_mirror(); - // if (k3 != code && cases.try_emplace(k3.unwrap(), 0).second) { - // mirror_codes.emplace_back(k3); - // } - }); - - uint64_t offset = 0; - codes.emplace_back(seed); - cases.emplace(seed, 0); // without mask - - auto p1 = seed.to_horizontal_mirror(); - if (p1 != seed) { - mirror_codes.emplace_back(p1); - cases.emplace(p1, 0); - } - - std::cout << std::format("{} vs {}\n", codes.size(), mirror_codes.size()); - - // auto p2 = seed.to_vertical_mirror(); - // if (p2 != seed) { - // mirror_codes.emplace_back(p2); - // cases.emplace(p2, 0); - // } - - // auto p3 = p2.to_horizontal_mirror(); - // if (p3 != p2) { - // mirror_codes.emplace_back(p3); - // cases.emplace(p3, 0); - // } - - while (offset != codes.size()) { - auto curr = codes[offset++].unwrap(); - core.next_cases(RawCode::unsafe_create(curr), cases.find(curr)->second); - } - - std::cout << std::format("{}: {}+{}/{} ({})\n", group.to_string(), codes.size(), mirror_codes.size(), cases.size(), codes.size() + mirror_codes.size() == cases.size()); - - // TODO: we can emplace mirrored code into another vector - - RangesUnion result {}; - for (auto [raw_code, _] : cases) { - auto common_code = RawCode::unsafe_create(raw_code).to_common_code().unwrap(); - result.ranges(common_code >> 32).emplace_back(static_cast(common_code)); - } - return result; -} - -static RangesUnion extend_type_common(RawCode seed, size_t reserve) { - std::vector codes; - phmap::flat_hash_map cases; // - - codes.reserve(reserve); - cases.reserve(reserve * 1.56); - - auto core = MaskMover([&codes, &cases](RawCode code, uint64_t hint) { - if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { - iter->second |= hint; // update hint - return; - } - codes.emplace_back(code); // new case - }); - - uint64_t offset = 0; - codes.emplace_back(seed); - cases.emplace(seed, 0); // without hint - - while (offset != codes.size()) { - auto curr = codes[offset++]; - core.next_cases(curr, cases.find(curr)->second); - } - - RangesUnion result {}; - // TODO: how to reserve - for (auto raw_code : codes) { // TODO: using `std::views::concat` in new std library - const auto code = raw_code.to_common_code().unwrap(); - result.ranges(code >> 32).emplace_back(static_cast(code)); - } - return result; -} - -static RangesUnion extend_type_hor(RawCode seed, size_t reserve) { +// static std::vector Group_extend_for_cases(RawCode raw_code, uint32_t reserve) { +// std::vector codes; +// phmap::flat_hash_map cases; // +// 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 +static RangesUnion extend_next_(RawCode seed, size_t reserve, R func) { std::vector codes; std::vector mirrors; phmap::flat_hash_map cases; // @@ -174,29 +59,27 @@ static RangesUnion extend_type_hor(RawCode seed, size_t reserve) { mirrors.reserve(reserve); // TODO: cal max size-coff cases.reserve(reserve * 1.56); - auto core = MaskMover([&codes, &cases, &mirrors](RawCode code, uint64_t hint) { + auto core = MaskMover([&codes, &cases, &mirrors, func](RawCode code, uint64_t hint) { if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { iter->second |= hint; // update hint return; } codes.emplace_back(code); // new case - const auto k1 = code.to_horizontal_mirror(); - if (k1 != code) { - cases.emplace(k1, 0); // TODO: contain check - mirrors.emplace_back(k1); - } + func(code, [&cases, &mirrors](RawCode kk) { + cases.emplace(kk, 0); // TODO: contain check + mirrors.emplace_back(kk); + }); }); uint64_t offset = 0; codes.emplace_back(seed); cases.emplace(seed, 0); // without hint - const auto p1 = seed.to_horizontal_mirror(); - if (p1 != seed) { - mirrors.emplace_back(p1); - cases.emplace(p1, 0); - } + func(seed, [&mirrors, &cases](RawCode pp) { + cases.emplace(pp, 0); + mirrors.emplace_back(pp); + }); while (offset != codes.size()) { auto curr = codes[offset++]; @@ -216,172 +99,51 @@ static RangesUnion extend_type_hor(RawCode seed, size_t reserve) { return result; } -static RangesUnion extend_type_ver(RawCode seed, size_t reserve) { - std::vector codes; - std::vector mirrors; - phmap::flat_hash_map cases; // - - codes.reserve(reserve); - mirrors.reserve(reserve); // TODO: cal max size-coff - cases.reserve(reserve * 1.56); - - auto core = MaskMover([&codes, &cases, &mirrors](RawCode code, uint64_t hint) { - if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { - iter->second |= hint; // update hint - return; - } - codes.emplace_back(code); // new case +__attribute__((noinline)) static RangesUnion extend_type_common(RawCode seed, size_t reserve) { + return extend_next_(seed, reserve, [](RawCode code, auto callback) {}); +} - const auto k1 = code.to_vertical_mirror(); +// TODO: without `__attribute__((noinline))` will make it faster +static RangesUnion extend_type_hor(RawCode seed, size_t reserve) { + return extend_next_(seed, reserve, [](RawCode code, auto callback) { + const auto k1 = code.to_horizontal_mirror(); if (k1 != code) { - cases.emplace(k1, 0); // TODO: contain check - mirrors.emplace_back(k1); + callback(k1); } }); - - uint64_t offset = 0; - codes.emplace_back(seed); - cases.emplace(seed, 0); // without hint - - const auto p1 = seed.to_vertical_mirror(); - if (p1 != seed) { - mirrors.emplace_back(p1); - cases.emplace(p1, 0); - } - - while (offset != codes.size()) { - auto curr = codes[offset++]; - core.next_cases(curr, cases.find(curr)->second); - } - - RangesUnion result {}; - // TODO: how to reserve - for (auto raw_code : codes) { // TODO: using `std::views::concat` in new std library - const auto code = raw_code.to_common_code().unwrap(); - result.ranges(code >> 32).emplace_back(static_cast(code)); - } - for (auto raw_code : mirrors) { - const auto code = raw_code.to_common_code().unwrap(); - result.ranges(code >> 32).emplace_back(static_cast(code)); - } - return result; } -static RangesUnion extend_type_diag(RawCode seed, size_t reserve) { - std::vector codes; - std::vector mirrors; - phmap::flat_hash_map cases; // - - codes.reserve(reserve); - mirrors.reserve(reserve); // TODO: cal max size-coff - cases.reserve(reserve * 1.56); - - auto core = MaskMover([&codes, &cases, &mirrors](RawCode code, uint64_t hint) { - if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { - iter->second |= hint; // update hint - return; - } - codes.emplace_back(code); // new case +__attribute__((noinline)) static RangesUnion extend_type_ver(RawCode seed, size_t reserve) { + return extend_next_(seed, reserve, [](RawCode code, auto callback) { + const auto k1 = code.to_vertical_mirror(); + // if (k1 != code) { + callback(k1); + // } + }); +} +__attribute__((noinline)) static RangesUnion extend_type_diag(RawCode seed, size_t reserve) { + return extend_next_(seed, reserve, [](RawCode code, auto callback) { const auto k1 = code.to_vertical_mirror().to_horizontal_mirror(); if (k1 != code) { - cases.emplace(k1, 0); // TODO: contain check - mirrors.emplace_back(k1); + callback(k1); } }); - - uint64_t offset = 0; - codes.emplace_back(seed); - cases.emplace(seed, 0); // without hint - - const auto p1 = seed.to_vertical_mirror().to_horizontal_mirror(); - if (p1 != seed) { - mirrors.emplace_back(p1); - cases.emplace(p1, 0); - } - - while (offset != codes.size()) { - auto curr = codes[offset++]; - core.next_cases(curr, cases.find(curr)->second); - } - - RangesUnion result {}; - // TODO: how to reserve - for (auto raw_code : codes) { // TODO: using `std::views::concat` in new std library - const auto code = raw_code.to_common_code().unwrap(); - result.ranges(code >> 32).emplace_back(static_cast(code)); - } - for (auto raw_code : mirrors) { - const auto code = raw_code.to_common_code().unwrap(); - result.ranges(code >> 32).emplace_back(static_cast(code)); - } - return result; } -static RangesUnion extend_type_x(RawCode seed, size_t reserve) { - std::vector codes; - std::vector mirrors; - phmap::flat_hash_map cases; // - - codes.reserve(reserve); - mirrors.reserve(reserve); // TODO: cal max size-coff - cases.reserve(reserve * 1.56); - - auto core = MaskMover([&codes, &cases, &mirrors](RawCode code, uint64_t hint) { - if (const auto [iter, ret] = cases.try_emplace(code, hint); !ret) { - iter->second |= hint; // update hint - return; - } - codes.emplace_back(code); // new case - +__attribute__((noinline)) static RangesUnion extend_type_x(RawCode seed, size_t reserve) { + return extend_next_(seed, reserve, [](RawCode code, auto callback) { const auto k1 = code.to_vertical_mirror(); - mirrors.emplace_back(k1); - cases.emplace(k1, 0); + callback(k1); const auto k2 = code.to_horizontal_mirror(); if (k2 != code) { - mirrors.emplace_back(k2); - cases.emplace(k2, 0); + callback(k2); const auto p3 = k1.to_horizontal_mirror(); - mirrors.emplace_back(p3); - cases.emplace(p3, 0); + callback(p3); } }); - - uint64_t offset = 0; - codes.emplace_back(seed); - cases.emplace(seed, 0); // without hint - - const auto p1 = seed.to_vertical_mirror(); - mirrors.emplace_back(p1); - cases.emplace(p1, 0); - const auto p2 = seed.to_horizontal_mirror(); - if (p2 != seed) { - mirrors.emplace_back(p2); - cases.emplace(p2, 0); - const auto p3 = p1.to_horizontal_mirror(); - mirrors.emplace_back(p3); - cases.emplace(p3, 0); - } - - while (offset != codes.size()) { - auto curr = codes[offset++]; - core.next_cases(curr, cases.find(curr)->second); - } - - RangesUnion result {}; - // TODO: how to reserve - for (auto raw_code : codes) { // TODO: using `std::views::concat` in new std library - const auto code = raw_code.to_common_code().unwrap(); - result.ranges(code >> 32).emplace_back(static_cast(code)); - } - for (auto raw_code : mirrors) { - const auto code = raw_code.to_common_code().unwrap(); - result.ranges(code >> 32).emplace_back(static_cast(code)); - } - return result; } -// TODO: maybe we can perf with mirror cases RangesUnion Group::cases() const { // TODO: add white list for single-group unions @@ -399,22 +161,61 @@ RangesUnion Group::cases() const { seed = seed.to_vertical_mirror().to_horizontal_mirror(); } - // auto data = extend_type_hor(seed, size()); - // auto data = extend_type_ver(seed, size()); - // auto data = extend_type_diag(seed, size()); - // auto data = extend_type_x(seed, size()); - RangesUnion data; if (mirror_type() == MirrorType::Full) { data = extend_type_x(seed, size()); + } else if (mirror_type() == MirrorType::Horizontal) { data = extend_type_hor(seed, size()); + + // auto lambda = [](RawCode code, phmap::flat_hash_map &cases, std::vector &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()); + + // data = extend_next(seed, size(), [](RawCode code, phmap::flat_hash_map &cases, std::vector &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) { 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) { 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 { data = extend_type_common(seed, size()); + } // auto raw_data = Group_extend_for_cases(seed, size()); @@ -425,7 +226,7 @@ RangesUnion Group::cases() const { // } for (int head = 0; head < 16; ++head) { - std::stable_sort(data.ranges(head).begin(), data.ranges(head).end()); // TODO: maybe using quick_sort + std::stable_sort(data.ranges(head).begin(), data.ranges(head).end()); } return data; } diff --git a/src/core/main.cc b/src/core/main.cc index b8cfb14..3c2cd0b 100644 --- a/src/core/main.cc +++ b/src/core/main.cc @@ -64,7 +64,8 @@ int main() { // if (group.is_vertical_mirror()) { // if (group.mirror_type() == Group::MirrorType::Centro) { // if (group.mirror_type() == Group::MirrorType::Full) { - // std::cout << group.to_string() << std::endl; + // if (group.mirror_type() == Group::MirrorType::Ordinary) { + // std::cout << std::format("{} ({})\n", group.to_string(), group.size()); volatile auto kk = group.cases(); // std::cout << group.size() << std::endl; // }