Browse Source

update: using mirror function template

master
Dnomd343 6 days ago
parent
commit
37112680b0
  1. 4
      src/core/benchmark/group.cc
  2. 397
      src/core/group/internal/group.cc
  3. 3
      src/core/main.cc

4
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(); // 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) { for (auto _ : state) {

397
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. // 2. Calculate the Group information it belongs to based on RawCode.
/// Spawn all the unsorted codes of the current group. /// Spawn all the unsorted codes of the current group.
static std::vector<RawCode> Group_extend_for_cases(RawCode raw_code, uint32_t reserve) { // static std::vector<RawCode> Group_extend_for_cases(RawCode raw_code, uint32_t reserve) {
std::vector<RawCode> codes; // std::vector<RawCode> codes;
phmap::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask> // phmap::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
codes.reserve(reserve); // codes.reserve(reserve);
cases.reserve(reserve * 1.56); // cases.reserve(reserve * 1.56);
//
auto core = MaskMover([&codes, &cases](RawCode code, uint64_t mask) { // auto core = MaskMover([&codes, &cases](RawCode code, uint64_t mask) {
if (const auto match = cases.find(code.unwrap()); match != cases.end()) { // if (const auto match = cases.find(code.unwrap()); match != cases.end()) {
match->second |= mask; // update mask // match->second |= mask; // update mask
return; // 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<RawCode> codes;
// TODO: key type of flat_hash_map can using `RawCode` directly
phmap::flat_hash_map<uint64_t, uint64_t> cases; // <code, mask>
codes.reserve(reserve);
cases.reserve(reserve * 1.56);
std::vector<RawCode> 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);
// } // }
// cases.emplace(code, mask);
// auto k3 = k2.to_horizontal_mirror(); // codes.emplace_back(code); // new case
// if (k3 != code && cases.try_emplace(k3.unwrap(), 0).second) { // });
// mirror_codes.emplace_back(k3); //
// 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;
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()) { template <typename R>
auto curr = codes[offset++].unwrap(); static RangesUnion extend_next_(RawCode seed, size_t reserve, R func) {
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<uint32_t>(common_code));
}
return result;
}
static RangesUnion extend_type_common(RawCode seed, size_t reserve) {
std::vector<RawCode> codes;
phmap::flat_hash_map<RawCode, uint64_t> cases; // <code, hint>
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<uint32_t>(code));
}
return result;
}
static RangesUnion extend_type_hor(RawCode seed, size_t reserve) {
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>
@ -174,29 +59,27 @@ static RangesUnion extend_type_hor(RawCode seed, size_t reserve) {
mirrors.reserve(reserve); // TODO: cal max size-coff mirrors.reserve(reserve); // TODO: cal max size-coff
cases.reserve(reserve * 1.56); 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) { 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); // new case
const auto k1 = code.to_horizontal_mirror(); func(code, [&cases, &mirrors](RawCode kk) {
if (k1 != code) { cases.emplace(kk, 0); // TODO: contain check
cases.emplace(k1, 0); // TODO: contain check mirrors.emplace_back(kk);
mirrors.emplace_back(k1); });
}
}); });
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
const auto p1 = seed.to_horizontal_mirror(); func(seed, [&mirrors, &cases](RawCode pp) {
if (p1 != seed) { cases.emplace(pp, 0);
mirrors.emplace_back(p1); mirrors.emplace_back(pp);
cases.emplace(p1, 0); });
}
while (offset != codes.size()) { while (offset != codes.size()) {
auto curr = codes[offset++]; auto curr = codes[offset++];
@ -216,172 +99,51 @@ static RangesUnion extend_type_hor(RawCode seed, size_t reserve) {
return result; return result;
} }
static RangesUnion extend_type_ver(RawCode seed, size_t reserve) { __attribute__((noinline)) static RangesUnion extend_type_common(RawCode seed, size_t reserve) {
std::vector<RawCode> codes; return extend_next_(seed, reserve, [](RawCode code, auto callback) {});
std::vector<RawCode> mirrors;
phmap::flat_hash_map<RawCode, uint64_t> cases; // <code, hint>
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
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) { if (k1 != code) {
cases.emplace(k1, 0); // TODO: contain check callback(k1);
mirrors.emplace_back(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()) { __attribute__((noinline)) static RangesUnion extend_type_ver(RawCode seed, size_t reserve) {
auto curr = codes[offset++]; return extend_next_(seed, reserve, [](RawCode code, auto callback) {
core.next_cases(curr, cases.find(curr)->second); const auto k1 = code.to_vertical_mirror();
} // if (k1 != code) {
callback(k1);
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<uint32_t>(code));
}
for (auto raw_code : mirrors) {
const auto code = raw_code.to_common_code().unwrap();
result.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code));
}
return result;
}
static RangesUnion extend_type_diag(RawCode seed, size_t reserve) {
std::vector<RawCode> codes;
std::vector<RawCode> mirrors;
phmap::flat_hash_map<RawCode, uint64_t> cases; // <code, hint>
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_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(); const auto k1 = code.to_vertical_mirror().to_horizontal_mirror();
if (k1 != code) { if (k1 != code) {
cases.emplace(k1, 0); // TODO: contain check callback(k1);
mirrors.emplace_back(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<uint32_t>(code));
}
for (auto raw_code : mirrors) {
const auto code = raw_code.to_common_code().unwrap();
result.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code));
}
return result;
} }
static RangesUnion extend_type_x(RawCode seed, size_t reserve) { __attribute__((noinline)) static RangesUnion extend_type_x(RawCode seed, size_t reserve) {
std::vector<RawCode> codes; return extend_next_(seed, reserve, [](RawCode code, auto callback) {
std::vector<RawCode> mirrors;
phmap::flat_hash_map<RawCode, uint64_t> cases; // <code, hint>
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
const auto k1 = code.to_vertical_mirror(); const auto k1 = code.to_vertical_mirror();
mirrors.emplace_back(k1); callback(k1);
cases.emplace(k1, 0);
const auto k2 = code.to_horizontal_mirror(); const auto k2 = code.to_horizontal_mirror();
if (k2 != code) { if (k2 != code) {
mirrors.emplace_back(k2); callback(k2);
cases.emplace(k2, 0);
const auto p3 = k1.to_horizontal_mirror(); const auto p3 = k1.to_horizontal_mirror();
mirrors.emplace_back(p3); callback(p3);
cases.emplace(p3, 0);
} }
}); });
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<uint32_t>(code));
}
for (auto raw_code : mirrors) {
const auto code = raw_code.to_common_code().unwrap();
result.ranges(code >> 32).emplace_back(static_cast<uint32_t>(code));
}
return result;
}
// TODO: maybe we can perf with mirror cases
RangesUnion Group::cases() const { RangesUnion Group::cases() const {
// TODO: add white list for single-group unions // TODO: add white list for single-group unions
@ -399,22 +161,61 @@ RangesUnion Group::cases() const {
seed = seed.to_vertical_mirror().to_horizontal_mirror(); 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; 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()); // auto raw_data = Group_extend_for_cases(seed, size());
@ -425,7 +226,7 @@ RangesUnion Group::cases() const {
// } // }
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()); // TODO: maybe using quick_sort std::stable_sort(data.ranges(head).begin(), data.ranges(head).end());
} }
return data; return data;
} }

3
src/core/main.cc

@ -64,7 +64,8 @@ int main() {
// if (group.is_vertical_mirror()) { // if (group.is_vertical_mirror()) {
// 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) {
// 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(); volatile auto kk = group.cases();
// std::cout << group.size() << std::endl; // std::cout << group.size() << std::endl;
// } // }

Loading…
Cancel
Save