Browse Source

perf: cal core for FastCal

legacy
Dnomd343 2 years ago
parent
commit
abdaae9a83
  1. 2
      src/fast_cal/CMakeLists.txt
  2. 93
      src/fast_cal/cal_core.cc
  3. 168
      src/fast_cal/fast_cal.cc
  4. 32
      src/fast_cal/fast_cal.h

2
src/fast_cal/CMakeLists.txt

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.0)
add_library(fast_cal fast_cal.cc) add_library(fast_cal cal_core.cc fast_cal.cc)
target_link_libraries(fast_cal core) target_link_libraries(fast_cal core)

93
src/fast_cal/cal_core.cc

@ -0,0 +1,93 @@
#include "core.h"
#include "fast_cal.h"
Core FastCal::init(uint64_t code) { // initialize process
/// clear working data
cases.clear();
std::queue<fast_cal_t*>{}.swap(cache);
// TODO: test the speed without hashmap reserve
cases.reserve(65536);
/// insert root node
cache.emplace(&cases.emplace(code, fast_cal_t {
.code = code,
.mask = 0,
.last = nullptr, // without parent node
}).first->second);
/// import klotski core
return Core(
[this](auto &&code, auto &&mask) { // lambda as function pointer
new_case(std::forward<decltype(code)>(code), std::forward<decltype(mask)>(mask));
}
);
}
/// callback function for new case
void FastCal::new_case(uint64_t code, uint64_t mask) {
auto current = cases.find(code);
if (current != cases.end()) { // find existed case
current->second.mask |= mask; // update mask info
return;
}
cache.emplace(&cases.emplace(code, fast_cal_t { // record new case
.code = code,
.mask = mask,
.last = cache.front(), // link parent case
}).first->second);
}
/// found first matched target
uint64_t FastCal::target(uint64_t code, const check_t &match) {
auto core = init(code);
while (!cache.empty()) { // bfs search
if (match(cache.front()->code)) {
return cache.front()->code; // match target
}
core.next_cases(cache.front()->code, cache.front()->mask);
cache.pop();
}
return FastCal::NOT_FOUND; // target not found
}
/// found multi-targets matched in first same layer
std::vector<uint64_t> FastCal::target_multi(uint64_t code, const check_t &match) {
auto core = init(code);
auto layer_end = cache.back();
std::vector<uint64_t> matched; // matched list
while (!cache.empty()) { // bfs search
if (match(cache.front()->code)) { // match target
matched.emplace_back(cache.front()->code);
}
core.next_cases(cache.front()->code, cache.front()->mask);
if (cache.front() == layer_end) { // reach layer ending
if (!matched.empty()) {
return matched; // stop at first matched layer
}
layer_end = cache.back(); // reset layer ending
}
cache.pop();
}
return std::vector<uint64_t>{}; // no target found
}
/// found all of the furthest cases
std::vector<uint64_t> FastCal::furthest(uint64_t code) {
auto core = init(code);
auto layer_end = cache.back();
std::vector<uint64_t> layer_cases;
while (!cache.empty()) { // bfs search
core.next_cases(cache.front()->code, cache.front()->mask);
layer_cases.emplace_back(cache.front()->code); // record layer cases
if (cache.front() == layer_end) { // reach layer ending
if (cache.size() == 1) {
break; // stop loop at last layer
}
layer_cases.clear();
layer_end = cache.back(); // reset layer ending
}
cache.pop();
}
return layer_cases; // release latest layer cases
}

168
src/fast_cal/fast_cal.cc

@ -7,33 +7,16 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
Core FastCal::init() { // initialization process uint64_t FastCal::solve(uint64_t code) {
/// clear working data return FastCal::target(code, [](uint64_t code) {
cases.clear(); return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // check 2x2 block address
std::queue<fast_cal_t*>{}.swap(cache); });
// TODO: test the speed without hashmap reserve
cases.reserve(65536);
/// import klotski core
return Core(
[this](auto &&code, auto &&mask) { // lambda as function pointer
new_case(std::forward<decltype(code)>(code), std::forward<decltype(mask)>(mask));
}
);
} }
void FastCal::new_case(uint64_t code, uint64_t mask) { // callback function for new case std::vector<uint64_t> FastCal::solve_multi(uint64_t code) {
auto current = cases.find(code); return FastCal::target_multi(code, [](uint64_t code) {
if (current != cases.end()) { // find existed case return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // check 2x2 block address
current->second.mask |= mask; // update mask info });
return;
}
cache.emplace(&cases.emplace(code, fast_cal_t { // record new case
.code = code,
.mask = mask,
.last = cache.front(), // link parent case
}).first->second);
} }
std::vector<uint64_t> FastCal::backtrack(uint64_t code) { std::vector<uint64_t> FastCal::backtrack(uint64_t code) {
@ -52,138 +35,7 @@ std::vector<uint64_t> FastCal::backtrack(uint64_t code) {
} }
uint64_t FastCal::solve(uint64_t code) {
return FastCal::target(code, [](uint64_t code) {
return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // check 2x2 block address
});
}
std::vector<uint64_t> FastCal::solve_multi(uint64_t code) {
return FastCal::target_multi(code, [](uint64_t code) {
return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // check 2x2 block address
});
}
uint64_t FastCal::target(uint64_t code, const check_t &match) {
auto core = init();
cache.emplace(&cases.emplace(code, fast_cal_t {
.code = code,
.mask = 0,
.last = nullptr, // without parent node
}).first->second);
while (!cache.empty()) {
if (match(cache.front()->code)) {
return cache.front()->code; // match target
}
core.next_cases(cache.front()->code, cache.front()->mask);
cache.pop();
}
return FastCal::NOT_FOUND; // target not found
}
std::vector<uint64_t> FastCal::target_multi(uint64_t code, const FastCal::check_t &match) {
auto core = init();
cache.emplace(&cases.emplace(code, fast_cal_t {
.code = code,
.mask = 0,
.last = nullptr, // without parent node
}).first->second);
auto layer_end = cache.back();
int layer_num = 0;
// bool matched = false;
std::vector<uint64_t> matched;
while (!cache.empty()) {
if (match(cache.front()->code)) {
// matched = true;
matched.emplace_back(cache.front()->code);
// std::cout << "found: " << std::endl;
// std::cout << RawCode(cache.front()->code);
}
core.next_cases(cache.front()->code, cache.front()->mask);
if (cache.front() == layer_end) {
if (!matched.empty()) {
std::cout << "layer " << layer_num << " end -> exit search" << std::endl;
return matched;
}
std::cout << "reach layer " << layer_num << " ending" << std::endl;
++layer_num;
layer_end = cache.back();
}
cache.pop();
}
return std::vector<uint64_t>{}; // no target found
}
std::vector<uint64_t> FastCal::furthest(uint64_t code) {
auto core = init();
cache.emplace(&cases.emplace(code, fast_cal_t {
.code = code,
.mask = 0,
.last = nullptr, // without parent node
}).first->second);
auto layer_end = cache.back();
int layer_num = 0;
std::vector<uint64_t> layer_cases;
while (!cache.empty()) {
core.next_cases(cache.front()->code, cache.front()->mask);
layer_cases.emplace_back(cache.front()->code);
if (cache.front() == layer_end) {
std::cout << "layer size -> " << layer_cases.size() << std::endl;
std::cout << "reach layer " << layer_num << " ending -> " << cache.size() << std::endl;
if (cache.size() == 1) { // almost exit -> last layer
break;
// return layer_cases;
}
layer_cases.clear();
++layer_num;
layer_end = cache.back();
}
cache.pop();
}
return layer_cases;
}
uint32_t FastCal::step_num(uint64_t code) { uint32_t FastCal::step_num(uint64_t code) {
@ -198,7 +50,3 @@ uint32_t FastCal::step_num(uint64_t code) {
return num; return num;
} }

32
src/fast_cal/fast_cal.h

@ -1,41 +1,28 @@
#pragma once #pragma once
#include <queue> #include <queue>
#include <vector>
#include <cstdint> #include <cstdint>
#include <unordered_map> #include <unordered_map>
#include <vector>
class FastCal { class FastCal {
public: public:
typedef std::function<bool(uint64_t)> check_t;
const static auto NOT_FOUND = (uint64_t)0; const static auto NOT_FOUND = (uint64_t)0;
typedef std::function<bool(uint64_t)> check_t;
// explicit FastCal(uint64_t code) : root(code) {}
// search resolve
// search all min-step resolve
// search the furthest cases
// search target by code
// search target by lambda
/// xxx_multi only search until same layer /// xxx_multi only search until same layer
// solve_multi // TODO: shall we use RawCode instead of uint64_t?
// TODO: shall we using RawCode instead of uint64_t?
uint64_t solve(uint64_t code); uint64_t solve(uint64_t code);
uint64_t target(uint64_t code, const check_t &match); uint64_t target(uint64_t code, const check_t &match);
std::vector<uint64_t> furthest(uint64_t code);
std::vector<uint64_t> solve_multi(uint64_t code); std::vector<uint64_t> solve_multi(uint64_t code);
std::vector<uint64_t> target_multi(uint64_t code, const check_t &match); std::vector<uint64_t> target_multi(uint64_t code, const check_t &match);
std::vector<uint64_t> furthest(uint64_t code); // TODO: search / search_multi / resolve / resolve_multi
// TODO: static furthest function
std::vector<uint64_t> backtrack(uint64_t code); std::vector<uint64_t> backtrack(uint64_t code);
@ -51,14 +38,9 @@ private:
fast_cal_t *last; fast_cal_t *last;
}; };
// uint64_t root;
std::queue<fast_cal_t*> cache; std::queue<fast_cal_t*> cache;
std::unordered_map<uint64_t, fast_cal_t> cases; std::unordered_map<uint64_t, fast_cal_t> cases;
Core init(); Core init(uint64_t code);
void new_case(uint64_t code, uint64_t mask); void new_case(uint64_t code, uint64_t mask);
}; };

Loading…
Cancel
Save