Browse Source

update: perf speed of BasicRanges module

master
Dnomd343 2 years ago
parent
commit
fbbecd2664
  1. 4
      src/CMakeLists.txt
  2. 177
      src/all_cases/basic_ranges.cc
  3. 10
      src/all_cases/basic_ranges.h
  4. 5
      src/main.cc

4
src/CMakeLists.txt

@ -28,8 +28,8 @@ add_subdirectory(analyse)
################################
#add_executable(klotski main.cc)
add_executable(klotski main.cc basic_ranges_demo.cc)
add_executable(klotski main.cc)
#add_executable(klotski main.cc basic_ranges_demo.cc)
################################

177
src/all_cases/basic_ranges.cc

@ -1,3 +1,4 @@
#include <queue>
#include <algorithm>
#include "common.h"
#include "basic_ranges.h"
@ -45,84 +46,140 @@ void BasicRanges::build() { // ensure that basic ranges available
}
}
#include <iostream>
void BasicRanges::sort_data(std::vector<int> &flags, std::vector<uint32_t> &raw) {
struct heap_node {
uint32_t value;
int index;
int limit;
};
struct compare {
bool operator() (heap_node n1, heap_node n2) {
return n1.value > n2.value;
}
};
std::priority_queue<heap_node, std::vector<heap_node>, compare> min_heap;
for (auto i = 0; i < flags.size() - 1; ++i) {
min_heap.push({
.value = raw[flags[i]],
.index = flags[i],
.limit = flags[i + 1] - 1,
});
}
while (!min_heap.empty()) {
auto current = min_heap.top();
min_heap.pop();
data.emplace_back(current.value);
if (current.index != current.limit) {
min_heap.push({
.value = raw[current.index + 1],
.index = current.index + 1,
.limit = current.limit,
});
}
}
}
void BasicRanges::build_data() { // build basic ranges
BasicRanges::data.reserve(BASIC_RANGES_SIZE); // memory pre-allocated
std::vector<uint32_t> raw_data;
raw_data.reserve(BASIC_RANGES_SIZE);
std::vector<int> start_points;
for (int n = 0; n <= 7; ++n) { // number of 1x2 and 2x1 block -> 0 ~ 7
for (int n_2x1 = 0; n_2x1 <= n; ++n_2x1) { // number of 2x1 block -> 0 ~ n
for (int n_1x1 = 0; n_1x1 <= (14 - n * 2); ++n_1x1) { // number of 1x1 block -> 0 ~ (14 - 2n)
int n_1x2 = n - n_2x1;
int n_space = 16 - n * 2 - n_1x1;
generate(n_space, n_1x2, n_2x1, n_1x1); // generate target ranges
/// 0x0 -> 00 | 1x2 -> 01 | 2x1 -> 10 | 1x1 -> 11
start_points.emplace_back(raw_data.size());
generate(raw_data, generate_t { // generate target ranges
.n1 = 16 - n * 2 - n_1x1, /// space -> 00
.n2 = n - n_2x1, /// 1x2 -> 01
.n3 = n_2x1, /// 2x1 -> 10
.n4 = n_1x1, /// 1x1 -> 11
});
}
}
}
std::sort(BasicRanges::data.begin(), BasicRanges::data.end()); // sort basic ranges
start_points.emplace_back(raw_data.size());
// std::sort(BasicRanges::data.begin(), BasicRanges::data.end()); // sort basic ranges
BasicRanges::sort_data(start_points, raw_data);
std::cout << "size: " << BasicRanges::data.size() << std::endl;
// std::sort(raw_data.begin(), raw_data.end());
// std::cout << raw_data.size() << std::endl;
// for (auto &range : BasicRanges::data) {
// range = Common::range_reverse(range); // basic ranges reverse
// }
}
void BasicRanges::generate(int n1, int n2, int n3, int n4) { // generate specific basic ranges
int len, limit;
constexpr uint32_t MASK_01 = 0b01 << 30;
constexpr uint32_t MASK_10 = 0b10 << 30;
constexpr uint32_t MASK_11 = 0b11 << 30;
std::vector<uint32_t> cache_1, cache_2;
len = n1 + n2;
limit = 0b1 << len;
for (uint32_t bin = 0; bin < limit; ++bin) {
if (binary_count(bin) != n2) { // skip binary without `n2` non-zero bits
continue;
}
uint32_t range = 0;
for (int i = 0; i < len; ++i) { // generate range base on binary value
range >>= 2;
if ((bin >> i) & 0b1) { // non-zero bit
range |= MASK_01;
}
void BasicRanges::generate(std::vector<uint32_t> &release, generate_t info) { // generate specific basic ranges
constexpr uint32_t MASK_01 = (uint32_t)0b01 << 30;
constexpr uint32_t MASK_10 = (uint32_t)0b10 << 30;
constexpr uint32_t MASK_11 = (uint32_t)0b11 << 30;
/// n4 n3 n2 n1
/// 00000000 00000000 00000000 00000000 (32-bits)
struct build_t {
uint32_t nx;
uint32_t prefix;
int offset;
};
std::queue<build_t> cache;
cache.emplace(build_t {
.nx = static_cast<uint32_t>(info.n1 | info.n2 << 8 | info.n3 << 16 | info.n4 << 24),
.prefix = 0x00000000,
.offset = 0,
});
while (!cache.empty()) { // queue without elements
auto current = cache.front();
if (!current.nx) { // both n1, n2, n3, n4 -> 0
release.emplace_back(current.prefix); // release prefix as basic range
cache.pop();
continue; // skip search
}
cache_1.emplace_back(range); // insert into first layer
}
len += n3;
limit <<= n3;
for (uint32_t bin = 0; bin < limit; ++bin) {
if (binary_count(bin) != n3) { // skip binary without `n3` non-zero bits
continue;
if (current.nx & 0xFF) { // n1 -> `00`
cache.emplace(build_t {
.nx = current.nx - 0x01, // --n1
.prefix = current.prefix,
.offset = current.offset + 2,
});
}
for (uint32_t base : cache_1) { // traverse first layer
uint32_t range = 0;
for (int i = 0; i < len; ++i) { // generate range base on binary value
if ((bin >> i) & 0b1) { // non-zero bit
(range >>= 2) |= MASK_10;
continue;
}
(range >>= 2) |= base & MASK_11;
base <<= 2;
}
cache_2.emplace_back(range); // insert into second layer
if (current.nx & 0xFF00) { // n2 -> `01`
cache.emplace(build_t {
.nx = current.nx - 0x0100, // --n2
.prefix = current.prefix | (MASK_01 >> current.offset),
.offset = current.offset + 2,
});
}
}
len += n4;
limit <<= n4;
for (uint32_t bin = 0; bin < limit; ++bin) {
if (binary_count(bin) != n4) { // skip binary without `n4` non-zero bits
continue;
if (current.nx & 0xFF0000) { // n3 -> `10`
cache.emplace(build_t {
.nx = current.nx - 0x010000, // --n3
.prefix = current.prefix | (MASK_10 >> current.offset),
.offset = current.offset + 2,
});
}
for (uint32_t base : cache_2) { // traverse second layer
uint32_t range = 0;
for (int i = 0; i < len; ++i) { // generate range base on binary value
if ((bin >> i) & 0b1) { // non-zero bit
(range >>= 2) |= MASK_11;
continue;
}
(range >>= 2) |= base & MASK_11;
base <<= 2;
}
BasicRanges::data.emplace_back(range); // insert into release data
if (current.nx & 0xFF000000) { // n4 -> `11`
cache.emplace(build_t {
.nx = current.nx - 0x01000000, // --n4
.prefix = current.prefix | (MASK_11 >> current.offset),
.offset = current.offset + 2,
});
}
cache.pop(); // remove searched case
}
}

10
src/all_cases/basic_ranges.h

@ -18,10 +18,18 @@ public:
static const std::vector<uint32_t>* fetch();
private:
struct generate_t {
int n1; // number of `00`
int n2; // number of `01`
int n3; // number of `10`
int n4; // number of `11`
};
static bool available;
static std::mutex building;
static std::vector<uint32_t> data;
static void build_data();
static void generate(int n1, int n2, int n3, int n4);
static void sort_data(std::vector<int> &flags, std::vector<uint32_t> &raw);
static void generate(std::vector<uint32_t> &release, generate_t info);
};

5
src/main.cc

@ -242,9 +242,8 @@ int main() {
// }
load_ranges();
// BasicRanges::build();
// load_ranges();
BasicRanges::build();
std::cerr << (clock() - start_time) * 1000 / CLOCKS_PER_SEC << "ms" << std::endl;
// std::cerr << (clock() - start_time) * 1000000 / CLOCKS_PER_SEC << "us" << std::endl;

Loading…
Cancel
Save