Browse Source

test: perf test suites of Ranges

legacy
Dnomd343 7 months ago
parent
commit
ccae5abce2
  1. 5
      src/core_test/CMakeLists.txt
  2. 49
      src/core_test/cases/helper/cases.h
  3. 23
      src/core_test/cases/helper/impl.cc
  4. 138
      src/core_test/cases/ranges.cc

5
src/core_test/CMakeLists.txt

@ -20,10 +20,11 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../core/common_code)
# ------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------ #
set(KLSK_TEST_CASES_SRC set(KLSK_TEST_CASES_SRC
cases/all_cases.cc cases/ranges.cc
cases/basic_ranges.cc cases/basic_ranges.cc
cases/all_cases.cc
cases/group_union.cc cases/group_union.cc
cases/ranges.cc cases/helper/impl.cc
) )
add_executable(test_klotski_cases ${KLSK_TEST_CASES_SRC}) add_executable(test_klotski_cases ${KLSK_TEST_CASES_SRC})

49
src/core_test/cases/helper/cases.h

@ -0,0 +1,49 @@
#pragma once
#include <array>
#include <algorithm>
#include "group/group.h"
#include "all_cases/all_cases.h"
using klotski::cases::Ranges;
using klotski::cases::AllCases;
using klotski::codec::CommonCode;
using klotski::cases::BasicRanges;
using klotski::cases::RangesUnion;
using klotski::array_sum;
using klotski::range_reverse;
using klotski::cases::BLOCK_NUM;
using klotski::cases::ALL_CASES_NUM;
using klotski::cases::ALL_CASES_NUM;
using klotski::cases::BASIC_RANGES_NUM;
using klotski::cases::BASIC_RANGES_NUM_;
/// All valid klotski heads.
constexpr auto Heads = std::to_array({
0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14
});
/// Assert that Ranges are sorted and unique.
#define EXPECT_SORTED_AND_UNIQUE(R) \
EXPECT_TRUE(std::ranges::is_sorted(R.begin(), R.end())); \
EXPECT_EQ(std::ranges::adjacent_find(R.begin(), R.end()), R.end()) // no duplicates
/// Assert that two ordered arrays are in a containment relationship.
#define EXPECT_SUBSET(R1, R2) \
EXPECT_TRUE(std::ranges::includes(R1.begin(), R1.end(), R2.begin(), R2.end()))
/// Assert that all CommonCodes generated from head and Ranges are valid.
#define EXPECT_COMMON_CODES(head, ranges) \
for (const auto range : ranges) \
EXPECT_TRUE(CommonCode::check(static_cast<uint64_t>(head) << 32 | range))
struct block_num_t {
int n_1x1;
int n_1x2;
int n_2x1;
};
block_num_t get_block_num(uint32_t range);

23
src/core_test/cases/helper/impl.cc

@ -0,0 +1,23 @@
#include <cstdint>
#include "cases.h"
#include "utils/utility.h"
block_num_t get_block_num(uint32_t range) {
block_num_t result {};
range = klotski::range_reverse(range);
for (; range; range >>= 2) {
switch (range & 0b11) {
case 0b01: // 1x2 block
++result.n_1x2;
continue;
case 0b10: // 2x1 block
++result.n_2x1;
continue;
case 0b11: // 1x1 block
++result.n_1x1;
continue;
}
}
return result;
}

138
src/core_test/cases/ranges.cc

@ -1,120 +1,108 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "group/group.h"
#include "helper/cases.h"
#include "ranges/ranges.h" #include "ranges/ranges.h"
#include <algorithm>
#include <group/group.h>
using klotski::cases::Ranges;
static_assert(std::is_base_of_v<std::vector<uint32_t>, Ranges>); static_assert(std::is_base_of_v<std::vector<uint32_t>, Ranges>);
static_assert(std::is_base_of_v<std::array<Ranges, 16>, klotski::cases::RangesUnion>); static_assert(std::is_base_of_v<std::array<Ranges, 16>, RangesUnion>);
TEST(Ranges, demo) { TEST(Ranges, check) {
RangesUnion all_cases;
const auto ranges = BasicRanges::instance().fetch();
for (int type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) { for (const auto head : Heads) {
auto [n, n_2x1, n_1x1] = klotski::cases::BLOCK_NUM[type_id]; for (auto range : ranges) {
if (Ranges::check(head, range_reverse(range)) == 0) {
all_cases[head].emplace_back(range); // valid cases
}
}
}
EXPECT_EQ(all_cases, AllCases::instance().fetch());
}
TEST(Ranges, spawn) {
for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) {
Ranges ranges; Ranges ranges;
ranges.spawn(n, n_2x1, n_1x1); ranges.spawn(n, n_2x1, n_1x1);
EXPECT_SORTED_AND_UNIQUE(ranges);
EXPECT_TRUE(std::ranges::is_sorted(ranges.begin(), ranges.end())); for (const auto range : ranges) {
const auto [val_1x1, val_1x2, val_2x1] = get_block_num(range);
const auto match = std::ranges::adjacent_find(ranges.begin(), ranges.end()); EXPECT_EQ(val_1x1, n_1x1);
EXPECT_EQ(val_2x1, n_2x1);
EXPECT_EQ(match, ranges.end()); EXPECT_EQ(val_1x2 + val_2x1, n);
}
} }
} }
TEST(Ranges, combine) { TEST(Ranges, derive) {
for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) {
Ranges ranges; Ranges ranges;
for (int type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) {
auto [n, n_2x1, n_1x1] = klotski::cases::BLOCK_NUM[type_id];
ranges.spawn(n, n_2x1, n_1x1); ranges.spawn(n, n_2x1, n_1x1);
ranges.reverse();
RangesUnion cases;
for (const auto head : Heads) {
ranges.derive(head, cases[head]);
EXPECT_SORTED_AND_UNIQUE(cases[head]);
EXPECT_COMMON_CODES(head, cases[head]);
} }
std::ranges::stable_sort(ranges.begin(), ranges.end()); ranges.reverse();
for (const auto head : Heads) {
EXPECT_EQ(ranges, klotski::cases::BasicRanges::instance().fetch()); EXPECT_SUBSET(ranges, cases[head]); // subset verify
}
}
} }
TEST(Ranges, reverse) { TEST(Ranges, reverse) {
auto ranges = BasicRanges::instance().fetch();
for (int type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) {
auto [n, n_2x1, n_1x1] = klotski::cases::BLOCK_NUM[type_id];
Ranges ranges;
ranges.spawn(n, n_2x1, n_1x1);
Ranges reverse {ranges}; Ranges reverse {ranges};
for (auto &x : reverse) { for (auto &x : reverse) {
x = klotski::range_reverse(x); x = range_reverse(x); // manual reverse
} }
ranges.reverse(); ranges.reverse();
EXPECT_EQ(ranges, reverse); EXPECT_EQ(ranges, reverse);
ranges.reverse();
EXPECT_EQ(ranges, BasicRanges::instance().fetch());
} }
TEST(Ranges, combine) {
Ranges all_ranges;
RangesUnion all_cases;
all_ranges.reserve(BASIC_RANGES_NUM_); // pre reserve
for (const auto head : Heads) {
all_cases[head].reserve(ALL_CASES_NUM[head]); // pre reserve
} }
TEST(Ranges, derive) { for (auto [n, n_2x1, n_1x1] : BLOCK_NUM) {
for (int type_id = 0; type_id < klotski::cases::TYPE_ID_LIMIT; ++type_id) {
auto [n, n_2x1, n_1x1] = klotski::cases::BLOCK_NUM[type_id];
Ranges ranges; Ranges ranges;
ranges.spawn(n, n_2x1, n_1x1); ranges.spawn(n, n_2x1, n_1x1);
// TODO: add += interface
all_ranges.insert(all_ranges.end(), ranges.begin(), ranges.end());
ranges.reverse(); ranges.reverse();
for (const auto head : Heads) {
auto kk = klotski::cases::GroupUnion::unsafe_create(type_id); ranges.derive(head, all_cases[head]); // derive from sub ranges
klotski::cases::RangesUnion result;
for (int head = 0; head < 16; ++head) {
if (head % 4 == 3) {
continue;
}
ranges.derive(head, result[head]);
} }
EXPECT_EQ(result, kk.cases());
} }
std::ranges::stable_sort(all_ranges.begin(), all_ranges.end());
} for (const auto head : Heads) {
std::ranges::stable_sort(all_cases[head].begin(), all_cases[head].end());
TEST(Ranges, check) {
auto ranges = klotski::cases::BasicRanges::instance().fetch();
klotski::cases::RangesUnion all_cases;
for (int head = 0; head < 16; ++head) {
if (head % 4 == 3) {
continue;
} }
EXPECT_EQ(all_ranges, BasicRanges::instance().fetch()); // verify content
EXPECT_EQ(all_cases, AllCases::instance().fetch()); // verify content
for (auto range : ranges) { all_ranges.reverse();
if (Ranges::check(head, klotski::range_reverse(range)) == 0) { for (const auto head : Heads) {
all_cases[head].emplace_back(range); all_cases[head].clear();
} all_ranges.derive(head, all_cases[head]); // derive from all ranges
} }
} EXPECT_EQ(all_cases, AllCases::instance().fetch()); // verify content
EXPECT_EQ(klotski::cases::AllCases::instance().fetch(), all_cases);
} }
// TODO: export CommonCode // TODO: export CommonCode

Loading…
Cancel
Save