Skip to main content

nekolib/algo/
tortoise_hare.rs

1//! 周期検出。
2
3/// 周期検出を行う。
4///
5/// 与えられた $x\_0$ と $f$ を用いて $x\_i = f(x\_{i-1})$ ($i > 0$) として
6/// 定義される列 $\\{x\_i\\}\_{i=0}\^\\infty$ の周期検出を行う。
7/// $x\_{\\mu} = x\_{\\mu+\\lambda}$ なる最小の $(\\mu, \\lambda)$ を返す。
8///
9/// # Requirements
10/// $f$ は参照透過である。
11///
12/// # Notes
13/// 共通の $f$ に対して、異なる複数の $x\_0$ から周期検出を行いたい場合は、
14/// この関数を複数回呼ぶよりも高速なアルゴリズムがあると思われる。
15/// ある $x\_0$ での出力が $(\\mu, \\lambda)$ であれば、
16/// $x\_i$ ($1\\le i\< \\mu$) での出力は $(\\mu-i, \\lambda)$、
17/// $x\_i$ ($\\mu\\le i<\\mu+\\lambda$) での出力は $(0, \\lambda)$ とわかる。
18/// さらに、これら $\\mu+\\lambda$ 個以外の $x\'$ についても、
19/// $f\^i(x\')$ がこれらのいずれかと等しくなる $i$ が存在すれば、
20/// $\\Theta(\\mu)$ 回の $f$ の呼び出しで $x\', f(x\'), \\dots, f\^{i-1}(x\')$ の出力もわかるはず。
21///
22/// # Complexity
23/// $\\Theta(\\mu+\\lambda)$ 回の $f$ の呼び出しを行う。
24///
25/// # Examples
26/// ```
27/// use nekolib::algo::cycle_mu_lambda;
28///
29/// // 3, 9, 11, 9, 11, ...
30/// assert_eq!(cycle_mu_lambda(3, |x| x * x % 14), (1, 2));
31/// // 2, 6, 4, 5, 1, 3, 2, ...
32/// assert_eq!(cycle_mu_lambda(2, |x| x * 3 % 7), (0, 6));
33/// ```
34///
35/// ```
36/// use nekolib::algo::cycle_mu_lambda;
37///
38/// assert_eq!(cycle_mu_lambda(0, |x| x), (0, 1));
39/// ```
40pub fn cycle_mu_lambda<T, F>(x0: T, f: F) -> (usize, usize)
41where
42    T: Eq + Clone,
43    F: Fn(T) -> T,
44{
45    let mut tor = f(x0.clone());
46    let mut har = f(tor.clone());
47
48    while tor != har {
49        tor = f(tor);
50        har = f(f(har));
51    }
52
53    let mut tor = x0;
54    let mut mu = 0;
55    while tor != har {
56        tor = f(tor);
57        har = f(har);
58        mu += 1;
59    }
60
61    let mut lambda = 1;
62    har = f(tor.clone());
63    while tor != har {
64        har = f(har);
65        lambda += 1;
66    }
67
68    (mu, lambda)
69}
70
71/// $n$ 項目を求める。
72///
73/// 与えられた $x\_0$ と $f$ を用いて $x\_i = f(x\_{i-1})$ ($i > 0$) として
74/// 定義される列 $\\{x\_i\\}\_{i=0}\^\\infty$ の $n$ 項目を求める。
75///
76/// # Requirements
77/// $f$ は参照透過である。
78///
79/// # Complexuty
80/// $x\_{\\mu} = x\_{\\mu+\\lambda}$ なる最小の $(\\mu, \\lambda)$
81/// に対し、$O(\\min\\{n, \\mu+\\lambda\\})$ time.
82///
83/// # Examples
84/// ```
85/// use nekolib::algo::cycle_nth;
86///
87/// let x0 = 0;
88/// let f = |x| (x + 1) % 100; // (mu, lambda) = (0, 100)
89/// assert_eq!(cycle_nth(x0, f, 0), 0);
90/// assert_eq!(cycle_nth(x0, f, 99), 99);
91/// assert_eq!(cycle_nth(x0, f, 100), 0);
92/// assert_eq!(cycle_nth(x0, f, 1000), 0);
93/// assert_eq!(cycle_nth(x0, f, 10_usize.pow(9)), 0);
94///
95/// let x0 = -10;
96/// let f = |x| (x + 1) % 100; // (mu, lambda) = (10, 100)
97/// assert_eq!(cycle_nth(x0, f, 0), -10);
98/// assert_eq!(cycle_nth(x0, f, 99), 89);
99/// assert_eq!(cycle_nth(x0, f, 100), 90);
100/// assert_eq!(cycle_nth(x0, f, 1000), 90);
101/// assert_eq!(cycle_nth(x0, f, 10_usize.pow(9)), 90);
102/// ```
103pub fn cycle_nth<T, F>(x0: T, f: F, n: usize) -> T
104where
105    T: Eq + Clone,
106    F: Fn(T) -> T,
107{
108    if n == 0 {
109        return x0;
110    }
111    if n == 1 {
112        return f(x0);
113    }
114
115    let mut tor = f(x0.clone());
116    let mut har = f(tor.clone());
117    let mut i = 2;
118    while i + 2 <= n && tor != har {
119        tor = f(tor);
120        har = f(f(har));
121        i += 2;
122    }
123    if i == n {
124        return har;
125    }
126    if i + 1 == n {
127        return f(har);
128    }
129
130    let mut tor = x0.clone();
131    let mut mu = 0;
132    while tor != har {
133        tor = f(tor);
134        har = f(har);
135        mu += 1;
136    }
137
138    let mut lambda = 1;
139    har = f(tor.clone());
140    while tor != har {
141        har = f(har);
142        lambda += 1;
143    }
144
145    let n = if n <= mu { n } else { mu + (n - mu) % lambda };
146    let mut x = x0;
147    for _ in 0..n {
148        x = f(x);
149    }
150    x
151}