Browse Source

perf: enhance Analyse module

master
Dnomd343 2 years ago
parent
commit
8914b2b492
  1. 108
      src/analyse/analyse.cc
  2. 43
      src/analyse/analyse.h
  3. 5
      src/fast_cal/cal_core.cc
  4. 1
      src/fast_cal/fast_cal.cc
  5. 2
      src/fast_cal/fast_cal.h
  6. 59
      src/main.cc

108
src/analyse/analyse.cc

@ -1,13 +1,21 @@
#include <queue> #include <queue>
#include "core.h"
#include "analyse.h" #include "analyse.h"
#include <list> Core Analyse::init(uint64_t code) {
#include <iostream> /// reset working data
#include "raw_code.h" cases.clear();
#include "common.h" cases.reserve(ANY_MAP_RESERVE); // hashmap pre-reserve
std::queue<analyse_t*>{}.swap(cache);
Core Analyse::init() { /// insert root node
cache.emplace(&cases.emplace(code, analyse_t {
.code = code,
.mask = 0,
.step = 0,
.src = std::list<analyse_t*>{}, // without parent node
}).first->second);
/// import klotski core
return Core( return Core(
[this](auto &&code, auto &&mask) { // lambda as function pointer [this](auto &&code, auto &&mask) { // lambda as function pointer
new_case(std::forward<decltype(code)>(code), std::forward<decltype(mask)>(mask)); new_case(std::forward<decltype(code)>(code), std::forward<decltype(mask)>(mask));
@ -15,95 +23,49 @@ Core Analyse::init() {
); );
} }
/// callback function for new case
void Analyse::new_case(uint64_t code, uint64_t mask) {
auto current = cases.find(code);
if (current != cases.end()) { // new case already exist
if (current->second.step == cache.front()->step + 1) { // new case at next layer
current->second.mask |= mask; // update mask info
current->second.src.emplace_back(cache.front()); // link more parent case
}
} else { // new case not exist
cache.emplace(&cases.emplace(code, analyse_t { // record new case
.code = code,
.mask = mask,
.step = cache.front()->step + 1,
.src = std::list<analyse_t*>{cache.front()}, // link parent case
}).first->second);
}
}
void Analyse::build(uint64_t code) { void Analyse::build(uint64_t code) {
auto core = init(code);
auto core = init();
cases.clear();
cases.reserve(65536);
std::queue<analyse_t*>{}.swap(cache);
cache.emplace(&cases.emplace(code, analyse_t {
.code = code,
.mask = 0,
.step = 0,
.src = std::list<analyse_t*>{},
}).first->second);
while (!cache.empty()) { while (!cache.empty()) {
core.next_cases(cache.front()->code, cache.front()->mask); core.next_cases(cache.front()->code, cache.front()->mask);
cache.pop(); cache.pop();
} }
std::cout << "size: " << cases.size() << std::endl;
} }
std::vector<uint64_t> Analyse::build_until(uint64_t code, const Analyse::match_t &match) { std::vector<uint64_t> Analyse::build_until(uint64_t code, const match_t &match) {
auto core = init(code);
auto core = init();
cases.clear();
cases.reserve(65536);
std::queue<analyse_t*>{}.swap(cache);
cache.emplace(&cases.emplace(code, analyse_t {
.code = code,
.mask = 0,
.step = 0,
.src = std::list<analyse_t*>{},
}).first->second);
auto layer_end = cache.back(); auto layer_end = cache.back();
std::vector<uint64_t> matched; // matched list std::vector<uint64_t> matched; // matched list
/// start BFS search
while (!cache.empty()) { while (!cache.empty()) {
if (match(cache.front()->code)) { // match target if (match(cache.front()->code)) { // match target
matched.emplace_back(cache.front()->code); matched.emplace_back(cache.front()->code);
} }
core.next_cases(cache.front()->code, cache.front()->mask); core.next_cases(cache.front()->code, cache.front()->mask);
if (cache.front() == layer_end) { // reach layer ending if (cache.front() == layer_end) { // reach layer ending
if (!matched.empty()) { if (!matched.empty()) {
std::cout << "size: " << cases.size() << std::endl;
return matched; // stop at first matched layer return matched; // stop at first matched layer
} }
layer_end = cache.back(); // reset layer ending layer_end = cache.back(); // reset layer ending
} }
cache.pop(); cache.pop();
} }
std::cout << "size: " << cases.size() << std::endl;
return std::vector<uint64_t>{}; // no target found return std::vector<uint64_t>{}; // no target found
}
void Analyse::new_case(uint64_t code, uint64_t mask) {
auto current = cases.find(code);
if (current != cases.end()) { // new case already exist
if (current->second.step == cache.front()->step + 1) { // new case at next layer
current->second.mask |= mask; // update mask info
current->second.src.emplace_back(cache.front()); // link more parent case
}
} else { // new case not exist
cache.emplace(&cases.emplace(code, analyse_t { // record new case
.code = code,
.mask = mask,
.step = cache.front()->step + 1,
.src = std::list<analyse_t*>{cache.front()}, // link parent case
}).first->second);
}
} }

43
src/analyse/analyse.h

@ -1,26 +1,39 @@
#pragma once #pragma once
#include <list>
#include <queue> #include <queue>
#include <cstdint> #include <cstdint>
#include <functional>
#include <unordered_map> #include <unordered_map>
#include "core.h"
#include <list> const uint32_t ANY_MAP_RESERVE = 65536;
#include <set>
#include <unordered_set>
class Analyse { class Analyse {
public: public:
typedef std::function<bool(uint64_t)> match_t;
void build(uint64_t code);
std::vector<uint64_t> build_until(uint64_t code, const match_t &match);
private:
struct analyse_t { struct analyse_t {
uint64_t code; uint64_t code;
uint64_t mask; uint64_t mask;
uint32_t step; uint32_t step;
std::list<analyse_t*> src; std::list<analyse_t*> src;
// std::vector<analyse_t*> src;
// std::set<analyse_t*> src;
// std::unordered_set<analyse_t*> src;
}; };
uint64_t root;
std::queue<analyse_t*> cache;
std::unordered_map<uint64_t, analyse_t> cases;
inline Core init(uint64_t code);
void new_case(uint64_t code, uint64_t mask);
/// backtrack definitions
// struct backtrack_t { // struct backtrack_t {
// uint64_t code; // uint64_t code;
// uint32_t layer_num; // uint32_t layer_num;
@ -28,24 +41,8 @@ public:
// std::list<backtrack_t*> next; // std::list<backtrack_t*> next;
// }; // };
std::queue<analyse_t*> cache;
std::unordered_map<uint64_t, analyse_t> cases;
// inline Core new_core();
// TODO: backtrack for multi-codes // TODO: backtrack for multi-codes
// void backtrack(uint64_t code); // void backtrack(uint64_t code);
// void backtrack(const std::vector<uint64_t> &raw_code_list); // void backtrack(const std::vector<uint64_t> &raw_code_list);
typedef std::function<bool(uint64_t)> match_t;
void build(uint64_t code);
std::vector<uint64_t> build_until(uint64_t code, const match_t &match);
// inline Core init(uint64_t code);
inline Core init();
void new_case(uint64_t code, uint64_t mask);
}; };

5
src/fast_cal/cal_core.cc

@ -1,4 +1,3 @@
#include "core.h"
#include "fast_cal.h" #include "fast_cal.h"
Core FastCal::init(uint64_t code) { // initialize process Core FastCal::init(uint64_t code) { // initialize process
@ -39,7 +38,6 @@ void FastCal::new_case(uint64_t code, uint64_t mask) {
/// build total search tree /// build total search tree
void FastCal::build() { void FastCal::build() {
auto core = init(root); auto core = init(root);
/// start BFS search
while (!cache.empty()) { while (!cache.empty()) {
core.next_cases(cache.front()->code, cache.front()->mask); core.next_cases(cache.front()->code, cache.front()->mask);
cache.pop(); cache.pop();
@ -49,7 +47,6 @@ void FastCal::build() {
/// found first matched target /// found first matched target
RawCode FastCal::target(const match_t &match) { RawCode FastCal::target(const match_t &match) {
auto core = init(root); auto core = init(root);
/// start BFS search
while (!cache.empty()) { while (!cache.empty()) {
if (match(cache.front()->code)) { if (match(cache.front()->code)) {
return RawCode::unsafe_create(cache.front()->code); // match target return RawCode::unsafe_create(cache.front()->code); // match target
@ -84,7 +81,7 @@ std::vector<RawCode> FastCal::furthest() {
} }
/// found multi-targets matched in first same layer /// found multi-targets matched in first same layer
std::vector<RawCode> FastCal::target_multi(const FastCal::match_t &match) { std::vector<RawCode> FastCal::target_multi(const match_t &match) {
auto core = init(root); auto core = init(root);
auto layer_end = cache.back(); auto layer_end = cache.back();
std::vector<RawCode> matched; // matched list std::vector<RawCode> matched; // matched list

1
src/fast_cal/fast_cal.cc

@ -1,5 +1,4 @@
#include <algorithm> #include <algorithm>
#include "core.h"
#include "common.h" #include "common.h"
#include "fast_cal.h" #include "fast_cal.h"
#include "raw_code.h" #include "raw_code.h"

2
src/fast_cal/fast_cal.h

@ -3,7 +3,9 @@
#include <queue> #include <queue>
#include <vector> #include <vector>
#include <cstdint> #include <cstdint>
#include <functional>
#include <unordered_map> #include <unordered_map>
#include "core.h"
#include "raw_code.h" #include "raw_code.h"
const uint32_t FC_MAP_RESERVE = 65536; const uint32_t FC_MAP_RESERVE = 65536;

59
src/main.cc

@ -16,45 +16,46 @@
int main() { int main() {
BasicRanges::build(); BasicRanges::build();
// AllCases::build();
std::vector<RawCode> test_cases; // std::vector<RawCode> test_cases;
{ // {
AllCases::build(); // AllCases::build();
std::vector<uint64_t> all_cases; // std::vector<uint64_t> all_cases;
for (uint64_t head = 0; head < 16; ++head) { // for (uint64_t head = 0; head < 16; ++head) {
for (const auto &range : AllCases::fetch()[head]) { // for (const auto &range : AllCases::fetch()[head]) {
all_cases.emplace_back(head << 32 | range); // all_cases.emplace_back(head << 32 | range);
} // }
} // }
for (uint32_t i = 0; i < 1000; ++i) { // for (uint32_t i = 0; i < 1000; ++i) {
test_cases.emplace_back( // test_cases.emplace_back(
RawCode::from_common_code(all_cases.at(i * 29334)) // RawCode::from_common_code(all_cases.at(i * 29334))
); // );
} // }
} // }
std::cout << "test size -> " << test_cases.size() << std::endl; // std::cout << "test size -> " << test_cases.size() << std::endl;
// std::cout << "wait 3s" << std::endl; // std::cout << "wait 3s" << std::endl;
// sleep(3); // sleep(3);
std::cout << "start benchmark" << std::endl; // std::cout << "start benchmark" << std::endl;
auto start_time = clock(); auto start_time = clock();
// AllCases::build();
// {
// auto fc = FastCal(RawCode::unsafe_create(0));
// for (auto code : test_cases) {
// fc.set_root(code);
// fc.solve();
// }
// }
{
auto fc = FastCal(RawCode::unsafe_create(0));
for (auto code : test_cases) {
fc.set_root(code);
fc.solve();
}
}
auto a = Analyse();
a.build((uint64_t)RawCode::from_common_code("1a9bf0c"));
// auto a = Analyse();
// a.build((uint64_t)RawCode::from_common_code("1a9bf0c"));
// auto ret = a.build_until((uint64_t)RawCode::from_common_code("1a9bf0c"), [](uint64_t code) { // auto ret = a.build_until((uint64_t)RawCode::from_common_code("1a9bf0c"), [](uint64_t code) {
// return ((code >> (3 * 0xD)) & 0b111) == B_2x2; // return ((code >> (3 * 0xD)) & 0b111) == B_2x2;
// }); // });
@ -99,9 +100,9 @@ int main() {
// std::cout << CommonCode::from_short_code("AXCZN") << std::endl; // std::cout << CommonCode::from_short_code("AXCZN") << std::endl;
std::cerr << (clock() - start_time) / CLOCKS_PER_SEC << "s" << std::endl; // std::cerr << (clock() - start_time) / CLOCKS_PER_SEC << "s" << std::endl;
// std::cerr << (clock() - start_time) * 1000 / CLOCKS_PER_SEC << "ms" << std::endl; // std::cerr << (clock() - start_time) * 1000 / CLOCKS_PER_SEC << "ms" << std::endl;
// std::cerr << (clock() - start_time) * 1000000 / CLOCKS_PER_SEC << "us" << std::endl; std::cerr << (clock() - start_time) * 1000000 / CLOCKS_PER_SEC << "us" << std::endl;
std::cout << "complete benchmark" << std::endl; std::cout << "complete benchmark" << std::endl;

Loading…
Cancel
Save