diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 50268c9..61ef420 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -37,7 +37,8 @@ set(KLOTSKI_CORE_SRC add_library(klotski_core STATIC ${KLOTSKI_CORE_SRC}) target_compile_options(klotski_core PRIVATE -fno-rtti -fno-exceptions) # option for `-fvisibility=hidden` target_include_directories(klotski_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(klotski_core PRIVATE absl::flat_hash_map phmap) +target_link_libraries(klotski_core PRIVATE absl::flat_hash_map) +target_link_libraries(klotski_core PUBLIC phmap) add_library(klotski::core ALIAS klotski_core) # TODO: just for dev testing diff --git a/src/core/benchmark/fast_cal.cc b/src/core/benchmark/fast_cal.cc index 4d92d2a..d77be45 100644 --- a/src/core/benchmark/fast_cal.cc +++ b/src/core/benchmark/fast_cal.cc @@ -11,6 +11,7 @@ using klotski::codec::CommonCode; static void FastCalBenchmark(benchmark::State &state) { auto code = CommonCode::unsafe_create(0x1A9BF0C00).to_raw_code(); +// auto code = CommonCode::unsafe_create(0x4FEA13400).to_raw_code(); for (auto _ : state) { // auto fc = FastCal(code); diff --git a/src/core/fast_cal/fast_cal.h b/src/core/fast_cal/fast_cal.h index 59aee58..f50d188 100644 --- a/src/core/fast_cal/fast_cal.h +++ b/src/core/fast_cal/fast_cal.h @@ -13,8 +13,14 @@ #include "mover/mover.h" #include "raw_code/raw_code.h" +#include "group/group.h" + // #include +#include + +#include + using klotski::codec::RawCode; using klotski::mover::MaskMover; @@ -69,3 +75,61 @@ private: }; RawCode FastCal_demo(RawCode code); + +namespace klotski { + +template +class LayerQueue { +public: + LayerQueue(size_t reserve, std::initializer_list first_layer); + + void emplace(T item); + + T current() const; + + void next(); + + [[nodiscard]] bool is_ending() const; + + [[nodiscard]] bool is_new_layer() const; + + std::vector layer_cases() const; + +private: + size_t queue_begin_ {0}; + size_t queue_end_ {0}; + + size_t layer_begin_ {0}; + size_t layer_end_ {0}; + + std::vector data_ {}; +}; + +} // namespace klotski + +namespace klotski::fast_cal { + +class FCDemo { +public: + explicit FCDemo(RawCode raw_code); + + std::optional DoCal(); + + std::vector DoCalMulti(); + + std::vector DoCalFurthest(); + +private: + struct data_t { + uint64_t mask; + uint64_t back; + }; + + LayerQueue codes_; + phmap::flat_hash_map cases_; +}; + +} // namespace klotski::fast_cal + +#include "internal/layer_queue.inl" +#include "internal/fast_cal.inl" diff --git a/src/core/fast_cal/internal/demo.cc b/src/core/fast_cal/internal/demo.cc index 973768d..fef2285 100644 --- a/src/core/fast_cal/internal/demo.cc +++ b/src/core/fast_cal/internal/demo.cc @@ -16,186 +16,112 @@ using klotski::cases::RangesUnion; using klotski::mover::MaskMover; using klotski::cases::GroupUnion; -struct data_t { - uint64_t mask; - uint64_t back; -}; - -template -class MyQueue { -public: - explicit MyQueue(size_t reserve) { - data_.resize(reserve); - } - - void emplace_back(T item) { - data_[queue_end_] = item; - ++queue_end_; - } - - T front() { - return data_[queue_begin_]; - } - - void pop_and_try_layer_switch() { - ++queue_begin_; - try_layer_switch(); - } - - [[nodiscard]] bool is_ending() const { - return queue_begin_ == queue_end_; - } +using klotski::fast_cal::FCDemo; + +std::optional FCDemo::DoCal() { + uint64_t result = 0; + auto core = MaskMover([this, &result](uint64_t code, uint64_t mask) { + if (const auto match = cases_.find(code); match != cases_.end()) { + match->second.mask |= mask; // update mask + return; + } + cases_.emplace(code, data_t { + .mask = mask, + .back = codes_.current(), + }); + codes_.emplace(code); - void try_layer_switch() { - if (queue_begin_ == layer_end_ && !is_ending()) { - layer_begin_ = layer_end_; - layer_end_ = queue_end_; + if (((code >> 39) & 0b111) == 0b100) { + result = code; } - } + }); - [[nodiscard]] bool is_layer_switched() const { - return queue_begin_ == layer_begin_; - } + while (!codes_.is_ending()) { + auto curr = codes_.current(); + core.next_cases(curr, cases_.find(curr)->second.mask); - std::vector get_curr_layer() { - std::vector layer_cases; - for (size_t offset = layer_begin_; offset < layer_end_; ++offset) { - layer_cases.emplace_back(data_[offset]); + codes_.next(); + if (result != 0) { + return RawCode::unsafe_create(result); } - return layer_cases; - } - -private: - size_t queue_begin_ {0}; - size_t queue_end_ {0}; - - size_t layer_begin_ {0}; - size_t layer_end_ {1}; - - std::vector data_ {}; -}; - -class FCDemo { -public: - explicit FCDemo(RawCode raw_code) : codes_(GroupUnion::from_raw_code(raw_code).max_group_size()) { - // TODO: build codes_ with reserve size - auto reserve = GroupUnion::from_raw_code(raw_code).max_group_size(); -// codes_.reserve(reserve); -// cases_.reserve(static_cast(reserve * 1.56)); - cases_.reserve(static_cast(25955 * 1.56)); - codes_.emplace_back(raw_code.unwrap()); - cases_.emplace(raw_code, data_t {0, 0}); // without mask } + return std::nullopt; +} - std::optional DoCal() { - uint64_t result = 0; - auto core = MaskMover([this, &result](uint64_t code, uint64_t mask) { - if (const auto match = cases_.find(code); match != cases_.end()) { - match->second.mask |= mask; // update mask - return; - } - cases_.emplace(code, data_t { - .mask = mask, - .back = codes_.front(), - }); - codes_.emplace_back(code); - - if (((code >> 39) & 0b111) == 0b100) { - result = code; - } - }); - - while (!codes_.is_ending()) { - auto curr = codes_.front(); - core.next_cases(curr, cases_.find(curr)->second.mask); +std::vector FCDemo::DoCalMulti() { + bool stop_flag = false; + std::vector results {}; - codes_.pop_and_try_layer_switch(); - if (result != 0) { - return RawCode::unsafe_create(result); - } + auto core = MaskMover([this, &stop_flag, &results](uint64_t code, uint64_t mask) { + if (const auto match = cases_.find(code); match != cases_.end()) { + match->second.mask |= mask; // update mask + return; } - return std::nullopt; - } - - std::vector DoCalMulti() { - bool stop_flag = false; - std::vector results {}; - - auto core = MaskMover([this, &stop_flag, &results](uint64_t code, uint64_t mask) { - if (const auto match = cases_.find(code); match != cases_.end()) { - match->second.mask |= mask; // update mask - return; - } - cases_.emplace(code, data_t { - .mask = mask, - .back = codes_.front(), - }); - codes_.emplace_back(code); - - if (((code >> 39) & 0b111) == 0b100) { - stop_flag = true; - results.emplace_back(RawCode::unsafe_create(code)); - } + cases_.emplace(code, data_t { + .mask = mask, + .back = codes_.current(), }); + codes_.emplace(code); - while (!codes_.is_ending()) { - auto curr = codes_.front(); - core.next_cases(curr, cases_.find(curr)->second.mask); + if (((code >> 39) & 0b111) == 0b100) { + stop_flag = true; + results.emplace_back(RawCode::unsafe_create(code)); + } + }); - codes_.pop_and_try_layer_switch(); - if (codes_.is_layer_switched() && stop_flag) { - return results; - } + while (!codes_.is_ending()) { + auto curr = codes_.current(); + core.next_cases(curr, cases_.find(curr)->second.mask); + codes_.next(); + if (codes_.is_new_layer() && stop_flag) { + // TODO: fix when solutions at last layer + return results; } - return {}; + } + return {}; +} - std::vector DoCalFurthest() { - - auto core = MaskMover([this](uint64_t code, uint64_t mask) { - if (const auto match = cases_.find(code); match != cases_.end()) { - match->second.mask |= mask; // update mask - return; - } - cases_.emplace(code, data_t { - .mask = mask, - .back = codes_.front(), - }); - codes_.emplace_back(code); +std::vector FCDemo::DoCalFurthest() { + auto core = MaskMover([this](uint64_t code, uint64_t mask) { + if (const auto match = cases_.find(code); match != cases_.end()) { + match->second.mask |= mask; // update mask + return; + } + cases_.emplace(code, data_t { + .mask = mask, + .back = codes_.current(), }); - - while (true) { - auto curr = codes_.front(); - core.next_cases(curr, cases_.find(curr)->second.mask); - - codes_.pop_and_try_layer_switch(); - if (codes_.is_ending()) { - return codes_.get_curr_layer() | std::views::transform([](uint64_t code) { - return RawCode::unsafe_create(code); - }) | std::ranges::to(); - } + codes_.emplace(code); + }); + + while (true) { + auto curr = codes_.current(); + core.next_cases(curr, cases_.find(curr)->second.mask); + + codes_.next(); + if (codes_.is_ending()) { + return codes_.layer_cases() | std::views::transform([](uint64_t code) { + return RawCode::unsafe_create(code); + }) | std::ranges::to(); } } - -private: - MyQueue codes_; - phmap::flat_hash_map cases_; -}; +} RawCode FastCal_demo(RawCode raw_code) { - FCDemo fc {raw_code}; - return fc.DoCal().value(); + klotski::fast_cal::FCDemo fc {raw_code}; +// return fc.DoCal().value(); // auto tmp = fc.DoCal(); -// std::cout << tmp.to_common_code() << std::endl; +// std::cout << tmp.value().to_common_code() << std::endl; // auto tmp = fc.DoCalMulti(); // for (const auto x : tmp) { // std::cout << x.to_common_code() << std::endl; // } -// auto tmp = fc.DoCalFurthest(); + auto tmp = fc.DoCalFurthest(); // for (const auto x : tmp) { // std::cout << x.to_common_code() << std::endl; // } diff --git a/src/core/fast_cal/internal/fast_cal.inl b/src/core/fast_cal/internal/fast_cal.inl new file mode 100644 index 0000000..b0c40ba --- /dev/null +++ b/src/core/fast_cal/internal/fast_cal.inl @@ -0,0 +1,12 @@ +#pragma once + +namespace klotski::fast_cal { + +inline FCDemo::FCDemo(RawCode raw_code) : codes_(cases::GroupUnion::from_raw_code(raw_code).max_group_size(), {raw_code.unwrap()}) { +// auto reserve = cases::GroupUnion::from_raw_code(raw_code).max_group_size(); + cases_.reserve(static_cast(25955 * 1.56)); +// cases_.reserve(static_cast(reserve * 1.56)); + cases_.emplace(raw_code, data_t {0, 0}); // without mask +} + +} // namespace klotski::fast_cal diff --git a/src/core/fast_cal/internal/layer_queue.inl b/src/core/fast_cal/internal/layer_queue.inl new file mode 100644 index 0000000..daee16b --- /dev/null +++ b/src/core/fast_cal/internal/layer_queue.inl @@ -0,0 +1,53 @@ +#pragma once + +namespace klotski { + +template +inline LayerQueue::LayerQueue(size_t reserve, std::initializer_list first_layer) { + data_.resize(reserve); + for (auto x : first_layer) { + emplace(x); + } + layer_end_ = first_layer.size(); +} + +template +void LayerQueue::emplace(T item) { + data_[queue_end_] = item; + ++queue_end_; +} + +template +T LayerQueue::current() const { + return data_[queue_begin_]; +} + +template +void LayerQueue::next() { + ++queue_begin_; + if (queue_begin_ == layer_end_ && !is_ending()) { + layer_begin_ = layer_end_; + layer_end_ = queue_end_; + } +} + +template +[[nodiscard]] bool LayerQueue::is_ending() const { + return queue_begin_ == queue_end_; +} + +template +[[nodiscard]] bool LayerQueue::is_new_layer() const { + return queue_begin_ == layer_begin_; +} + +template +std::vector LayerQueue::layer_cases() const { + std::vector layer_cases; + for (size_t offset = layer_begin_; offset < layer_end_; ++offset) { + layer_cases.emplace_back(data_[offset]); + } + return layer_cases; +} + +} // namespace klotski