-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1c4e242
commit 6a17ae2
Showing
3 changed files
with
143 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#pragma once | ||
#include <cstddef> | ||
#include <type_traits> | ||
#include <utility> | ||
#include <vector> | ||
|
||
/// Floyd's Tortoise and Hare Algorithm | ||
template <class T> | ||
class CycleFinder { | ||
uint32_t _until_cycle_start; | ||
uint32_t _cycle_len; | ||
std::vector<T> nf; // nf[i] := `start` から `f` を `i` 回適用した結果 | ||
|
||
public: | ||
CycleFinder() = default; | ||
|
||
template <class Fn, std::enable_if_t<std::is_invocable_r_v<T, Fn, T>, std::nullptr_t> = nullptr> | ||
CycleFinder(T start, Fn&& f, std::size_t capacity = 512) : _until_cycle_start(0), _cycle_len(0) { | ||
T tortoise = start, hare = start; | ||
do { | ||
tortoise = f(tortoise); | ||
hare = f(f(hare)); | ||
} while (tortoise != hare); | ||
|
||
nf.reserve(capacity); | ||
nf.push_back(start); | ||
tortoise = start; | ||
while (tortoise != hare) { | ||
hare = f(hare); | ||
tortoise = f(tortoise); | ||
nf.push_back(tortoise); | ||
++_until_cycle_start; | ||
} | ||
|
||
do { | ||
tortoise = f(tortoise); | ||
nf.push_back(tortoise); | ||
++_cycle_len; | ||
} while (tortoise != hare); | ||
} | ||
|
||
/// mapping[x] を写像 f(x) とみなす | ||
template < | ||
class IndexAccessible, | ||
class = std::void_t<decltype(std::declval<IndexAccessible>()[0])>> | ||
CycleFinder(T start, IndexAccessible const& mapping) | ||
: CycleFinder( | ||
start, | ||
[&](T x) { return (T)mapping[x]; }, | ||
mapping.size() + 1 | ||
) {} | ||
|
||
inline uint32_t until_cycle_start() const { | ||
return _until_cycle_start; | ||
} | ||
|
||
inline uint32_t cycle_len() const { | ||
return _cycle_len; | ||
} | ||
|
||
/// start に f を n 回適用した結果を O(1) で求める。 | ||
inline const T apply_repeat(uint64_t n) const { | ||
if (n <= _until_cycle_start + _cycle_len) return nf[n]; | ||
return nf[_until_cycle_start + (n - _until_cycle_start) % _cycle_len]; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
#include <armkn/algo/mapping/cycle_finder.hpp> | ||
#include <catch2/catch_test_macros.hpp> | ||
|
||
#include <vector> | ||
|
||
TEST_CASE("CycleFinder") { | ||
std::vector<int> f(7); | ||
f[0] = 1; | ||
f[1] = 2; | ||
f[2] = 3; | ||
f[3] = 4; | ||
f[4] = 5; | ||
f[5] = 3; | ||
f[6] = 6; | ||
|
||
SECTION("start=1") { | ||
auto cf = CycleFinder(1, f); | ||
CHECK(cf.until_cycle_start() == 2); | ||
CHECK(cf.cycle_len() == 3); | ||
CHECK(cf.apply_repeat(0) == 1); | ||
CHECK(cf.apply_repeat(1) == 2); | ||
CHECK(cf.apply_repeat(2) == 3); | ||
CHECK(cf.apply_repeat(3) == 4); | ||
CHECK(cf.apply_repeat(4) == 5); | ||
CHECK(cf.apply_repeat(5) == 3); | ||
CHECK(cf.apply_repeat(6) == 4); | ||
CHECK(cf.apply_repeat(7) == 5); | ||
CHECK(cf.apply_repeat(8) == 3); | ||
CHECK(cf.apply_repeat(9) == 4); | ||
CHECK(cf.apply_repeat(10) == 5); | ||
CHECK(cf.apply_repeat(11) == 3); | ||
} | ||
SECTION("start=3") { | ||
auto cf = CycleFinder(3, f); | ||
CHECK(cf.until_cycle_start() == 0); | ||
CHECK(cf.cycle_len() == 3); | ||
CHECK(cf.apply_repeat(0) == 3); | ||
CHECK(cf.apply_repeat(1) == 4); | ||
CHECK(cf.apply_repeat(2) == 5); | ||
CHECK(cf.apply_repeat(3) == 3); | ||
CHECK(cf.apply_repeat(4) == 4); | ||
CHECK(cf.apply_repeat(5) == 5); | ||
CHECK(cf.apply_repeat(6) == 3); | ||
CHECK(cf.apply_repeat(7) == 4); | ||
CHECK(cf.apply_repeat(8) == 5); | ||
CHECK(cf.apply_repeat(9) == 3); | ||
CHECK(cf.apply_repeat(10) == 4); | ||
CHECK(cf.apply_repeat(11) == 5); | ||
} | ||
SECTION("start=4") { | ||
auto cf = CycleFinder(4, f); | ||
CHECK(cf.until_cycle_start() == 0); | ||
CHECK(cf.cycle_len() == 3); | ||
CHECK(cf.apply_repeat(0) == 4); | ||
CHECK(cf.apply_repeat(1) == 5); | ||
CHECK(cf.apply_repeat(2) == 3); | ||
CHECK(cf.apply_repeat(3) == 4); | ||
CHECK(cf.apply_repeat(4) == 5); | ||
CHECK(cf.apply_repeat(5) == 3); | ||
CHECK(cf.apply_repeat(6) == 4); | ||
CHECK(cf.apply_repeat(7) == 5); | ||
CHECK(cf.apply_repeat(8) == 3); | ||
CHECK(cf.apply_repeat(9) == 4); | ||
CHECK(cf.apply_repeat(10) == 5); | ||
CHECK(cf.apply_repeat(11) == 3); | ||
} | ||
SECTION("start=6") { | ||
auto cf = CycleFinder(6, f); | ||
CHECK(cf.until_cycle_start() == 0); | ||
CHECK(cf.cycle_len() == 1); | ||
CHECK(cf.apply_repeat(0) == 6); | ||
CHECK(cf.apply_repeat(1) == 6); | ||
CHECK(cf.apply_repeat(2) == 6); | ||
CHECK(cf.apply_repeat(3) == 6); | ||
} | ||
} |