Skip to main content

nekolib/seq/
suffix_array.rs

1//! 接尾辞配列。
2
3use std::cmp::Ordering::{Equal, Greater, Less};
4use std::collections::{BTreeMap, BTreeSet};
5use std::fmt::Debug;
6use std::ops::Index;
7
8/// 接尾辞配列。
9///
10/// 文字列 $S$ の各接尾辞を辞書順でソートしたもの。
11/// より正確には、$i$ ($0\\le i\\le |S|$) を $S\[i\\dots\]$ をキーとしてソートした配列 $A$ である。
12///
13/// # Idea
14/// ## 用語の定義など
15///
16/// 文字列 $S$ について、 $S\[|S|\]$ には辞書順最小の文字が入っていると見なす。
17/// また、$S\[|S|+1\]$ には辞書順最大の文字が入っていると見なしている気がする。
18///
19/// 以下、$S\[i\\dots\]$ を接尾辞 $i$ と呼ぶ。
20/// また、例として文字列 `GTCCCGATGTCATGTCAGGA$` を考える。
21///
22/// ```text
23///  G  T  C  C  C  G  A  T  G  T  C  A  T  G  T  C  A  G  G  A  $
24///  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
25/// ```
26///
27/// この文字列の接尾辞配列は次のようになる。
28///
29/// ```text
30///  20 19 16 11  6 15 10  2  3  4 18  5 17 13  8  0 14  9  1 12  7
31/// ```
32///
33/// ### S-type と L-type
34///
35/// まず、接尾辞に対して _S-type_ と _L-type_ を定義する。
36/// 接尾辞 $i$ が接尾辞 $i+1$ より辞書順で小さい (smaller)
37/// とき、接尾辞 $i$ を S-type であると言う。そうでない (larger) とき、L-type
38/// であると言う。長さが異なるので、等しくなることはないことに注意せよ。
39/// なお、接尾辞 $|S|$ は S-type とする。
40/// また、簡単のため、単に「$i$ が S-type である」などと言う。
41///
42/// $i$ ($0\\le i \\lt |S|$) について次が成り立つので、$|S|$ が S-type
43/// であることと合わせて、末尾から順に線形時間で求められる。
44///
45/// - $S\[i\] \\lt S\[i+1\]$ なら、$i$ は S-type。
46/// - $S\[i\] \\gt S\[i+1\]$ なら、$i$ は L-type。
47/// - $S\[i\] = S\[i+1\]$ なら、$i$ と $i+1$ は同じ type。
48///
49/// ### LMS suffix と LMS block
50///
51/// $i-1$ が L-type であるような S-type の $i$ を、特に
52/// LMS (leftmost S-type) suffix と言う。$0$ は LMS ではないことに注意せよ。
53/// また、LMS suffix を、次の LMS suffix(存在すれば)の開始位置で区切ったものを
54/// LMS block と呼ぶ。LMS block は次のようになる。
55///
56/// ```text
57///  G  T  C  C  C  G  A  T  G  T  C  A  T  G  T  C  A  G  G  A  $
58///  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
59///  S  L *S  S  S  L *S  L *S  L  L *S  L *S  L  L *S  L  L  L *S
60///       [------------]
61///                   [------]
62///                         [---------]
63///                                  [------]
64///                                        [---------]
65///                                                 [------------]
66///                                                             []
67/// ```
68///
69/// ### バケット
70///
71/// 接尾辞配列を再掲する。ただし、各 $i$ に対して、その type と $S\[i\]$ を併記する。
72/// ただし、`*S` は LMS を表す。
73///
74/// ```text
75///  20 19 16 11  6 15 10  2  3  4 18  5 17 13  8  0 14  9  1 12  7
76///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
77///  *S  L *S *S *S  L  L *S  S  S  L  L  L *S *S  S  L  L  L  L  L
78/// ```
79///
80/// 同じ文字で始まる接尾辞が連続していることに気づく。この一連の部分をバケットと呼ぶ。
81/// たとえば、`19`, `16`, `11`, `6` の部分を指して `A` のバケットと呼ぶことにする。
82///
83/// さらに、各文字のバケットにおいて、L-type が前半に、S-type が後半に来ていることにも気づく。
84/// これは、$S\[i\] = S\[j\] = c$ であるような接尾辞 $i$ (L-type) と $j$ (S-type)
85/// を考えたとき、接尾辞 $i$ は $c$ が 1 つ以上続いた後に $c$ より小さい文字が現れ、
86/// 接尾辞 $j$ は $c$ が 1 つ以上続いた後に $c$ より大きい文字が現れることから従う。
87///
88/// ### Induced sorting
89///
90/// この操作により、LMS block のソート順を得ることができる。この操作では、部分文字列
91/// $S\[i\\dots j\]$ (inclusive) に辞書順最大の文字を連結したものを考え[^1]、この
92/// $i$ をバケットに入れていく。$j$ については適宜説明する。ここでは、簡単のため
93/// $S\[i\\dots j\]$ に辞書順最大の文字を連結したものを指して、単に部分文字列 $S\[i\\dots j\]$
94/// と呼ぶことにする。
95///
96/// [^1]: よくある説明では suffix $S\[i\\dots\]$ だと思いますが、
97/// それだと納得のいく説明ができなかったのでこういう説明になりました。
98/// 「LMS suffix がソート順に並んでいるときに IS をすると SA
99/// が得られます」というのが示されたあと、適当な順で LMS suffix を入力して
100/// IS を実行されると、もやもやします。
101///
102/// まず、LMS suffix たちの添字 $i$ は得られているとし、それらを対応するバケットの
103/// 末尾に適当な順に入れる。このとき $j = i$ とする。
104///
105/// ```text
106///  20  -  6 11 16  -  -  -  -  2  -  -  -  -  8 13  -  -  -  -  -
107///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
108///  *S  - *S *S *S  -  -  -  - *S  -  -  -  - *S *S  -  -  -  -  -
109/// ```
110///
111/// ```text
112/// 20 $X
113///  - -
114///  6 AX
115/// 11 AX
116/// 16 AX
117///  - -
118///  - -
119///  - -
120///  - -
121///  2 CX
122///  - -
123///  - -
124///  - -
125///  - -
126///  8 GX
127/// 13 GX
128///  - -
129///  - -
130///  - -
131///  - -
132///  - -
133/// ```
134///
135/// バケットを前から走査し、部分文字列 $S\[i\\dots j\]$ を見つけたとき、$i-1$ が L-type
136/// であれば、文字 $S\[i-1\]$ に対応するバケットの空きの先頭に $S\[i-1\\dots j\]$ を入れる。
137///
138/// まず、この操作によりバケットに追加された部分文字列がソート済みであることを帰納的に示す。
139/// 初期状態では明らかにソート済みである。$S\[i\\dots j\]$ を見て $S\[i-1\\dots j\]$
140/// を入れるとき、同一バケット内の L-type の各 $S\[i\'-1\\dots j\'\]$ に対して
141/// $S\[i\'-1\\dots j\'\] \\lt S\[i-1\\dots j\]$ を示せば十分である(LMS については明らかなので)。
142/// これは、$S\[i\'-1\] = S\[i-1\]$ のとき $S\[i\'-1\\dots j\'\] \\lt S\[i-1\\dots j\] \\iff
143/// S\[i\'\\dots j\'\] \\lt S\[i\\dots j\]$ であることと、$i\'$ が $i$ より先に処理されているため
144/// $S\[i\'\\dots j\'\] \\lt S\[i\\dots j\]$ であることから従う。
145///
146/// 次に、L-type であるすべての $i$ がバケットに入っていることを示す。
147/// $i+1$ が LMS であれば、定義から $i$ は L-type であり、これはバケットに入れられる。
148/// L-type である各 $i$ について $S\[i\\dots j\] \\gt S\[i+1\\dots j\]$ なので、
149/// $i+1$ がバケットに入っているならば、$i$ もバケットに入れられる。
150///
151/// ```text
152///  20 19  6 11 16 10 15  -  -  2 18  5 17  -  8 13  9 14  1  7 12
153///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
154///  *S  L *S *S *S  L  L  -  - *S  L  L  L  - *S *S  L  L  L  L  L
155/// ```
156///
157/// ```text
158/// 20 $X
159/// 19 A$X
160///  6 AX
161/// 11 AX
162/// 16 AX
163/// 10 CAX
164/// 15 CAX
165///  - -
166///  - -
167///  2 CX
168/// 18 GA$X
169///  5 GAX
170/// 17 GGA$X
171///  - -
172///  8 GX
173/// 13 GX
174///  9 TCAX
175/// 14 TCAX
176///  1 TCX
177///  7 TGX
178/// 12 TGX
179/// ```
180///
181/// 次に、バケットから LMS を取り除き、逆順から同様の操作を S-type について行う。
182/// すなわち、バケットを後ろから走査し、部分文字列 $S\[i\\dots j\]$ を見つけたとき、
183/// $i-1$ が S-type であれば、文字 $S\[i-1\]$ に対応するバケットの空きの末尾に
184/// $S\[i-1\\dots j\]$ を入れる。
185///
186/// L-type のときと同様の議論から、すべての S-type の $i$ がソート順で得られることがわかる。
187/// S-type と L-type の性質から、すべての $i$ についてソート順で得られたことになる。
188///
189/// ```text
190///  20 19 16  6 11 10 15  2  3  4 18  5 17  8 13  0  9 14  1  7 12
191///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
192///  *S  L *S *S *S  L  L *S  S  S  L  L  L *S *S  S  L  L  L  L  L
193/// ```
194///
195/// ```text
196/// 20 $X
197/// 19 A$X
198/// 16 AGGA$X
199///  6 ATGX
200/// 11 ATGX
201/// 10 CAX
202/// 15 CAX
203///  2 CCCGAX
204///  3 CCGAX
205///  4 CGAX
206/// 18 GA$X
207///  5 GAX
208/// 17 GGA$X
209///  8 GTCAX
210/// 13 GTCAX
211///  0 GTCX
212///  9 TCAX
213/// 14 TCAX
214///  1 TCX
215///  7 TGX
216/// 12 TGX
217/// ```
218///
219/// 各 LMS $i$ に対応する部分文字列が LMS block と等しくなることは簡単に示せて、
220/// 以上より LMS block のソート順が得られることがわかった。なお、初めに LMS
221/// をバケットに入れるときにソート順に入れていれば、$j = |S|$
222/// としても同様の議論ができ、接尾辞配列が得られる。
223///
224/// ## アルゴリズムの概要
225///
226/// まず、$S$ を末尾から走査し、type を求める。
227///
228/// ```text
229///  G  T  C  C  C  G  A  T  G  T  C  A  T  G  T  C  A  G  G  A  $
230///  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
231///  S  L *S  S  S  L *S  L *S  L  L *S  L *S  L  L *S  L  L  L *S
232/// ```
233///
234/// 次に、LMS を出現順にバケットの末尾に置いて induced sorting を行う。
235///
236/// ```text
237///  20  -  6 11 16  -  -  -  -  2  -  -  -  -  8 13  -  -  -  -  -
238///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
239///  *S  - *S *S *S  -  -  -  - *S  -  -  -  - *S *S  -  -  -  -  -
240/// ```
241///
242/// ```text
243///  20 19  6 11 16 10 15  -  -  2 18  5 17  -  8 13  9 14  1  7 12
244///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
245///  *S  L *S *S *S  L  L  -  - *S  L  L  L  - *S *S  L  L  L  L  L
246/// ```
247///
248/// ```text
249///  20 19 16  6 11 10 15  2  3  4 18  5 17  8 13  0  9 14  1  7 12
250///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
251///  *S  L *S *S *S  L  L *S  S  S  L  L  L *S *S  S  L  L  L  L  L
252/// ```
253///
254/// これにより、LMS block の正しいソート順が得られる。
255/// `*S` の添字を得られた順に並べると `20 16 6 11 2 8 13` となり、対応する
256/// LMS block を順に並べると次のようになる[^2]。
257///
258/// [^2]: `$` で始まる `<pre>` がシェルスクリプトではない例。
259///
260/// ```text
261/// $ AGGA$ ATG ATG CCCGA GTCA GTCA
262/// ```
263///
264/// これはソート順で得られているので、隣同士の要素を比較するだけで、各要素の順序づけがわかる。
265/// 等しい要素があることに注意せよ。
266///
267/// ```text
268///  G  T  C  C  C  G  A  T  G  T  C  A  T  G  T  C  A  G  G  A  $
269///  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
270///  S  L *S  S  S  L *S  L *S  L  L *S  L *S  L  L *S  L  L  L *S
271///       [----------][----][-------][----][-------][----------][]
272///                  3     2        4     2        4           1 0
273/// ```
274///
275/// この順序づけによってできる列 (_reduced string_) `3 2 4 2 4 1 0` の接尾辞配列は
276/// 再帰的に SA-IS によって求めることができ、`6 5 3 1 0 4 2` となる。
277///
278/// LMS block たちをそのまま連結させると境界部分の文字が重複するのが気になる。
279/// reduced string 中にも暗黙にそれらの重複があるが、それが許されることに触れておく。
280/// 等しいペアについては、重複の 1 文字目で等しければ 2 文字目でも等しいので、
281/// 辞書順比較には影響しない。等しくないペアについて、`$` 以外の LMS block の形は
282/// `SS..SLL..LS` であり、最悪時でも片方に `LS` が現れた時点で大小関係が決まるので、
283/// 重複部分まで走査されることがない。
284///
285/// これを元の文字列に対応させることで、LMS suffix のソート順が `20 16 11 6 2 13 8`
286/// であるとわかり、これを用いて再度 induced sorting を行う。
287///
288/// ```text
289///  20  - 16 11  6  -  -  -  -  2  -  -  -  - 13  8  -  -  -  -  -
290///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
291///  *S  - *S *S *S  -  -  -  - *S  -  -  -  - *S *S  -  -  -  -  -
292/// ```
293///
294/// ```text
295///  20 19 16 11  6 15 10  -  -  2 18  5 17  - 13  8 14  9  1 12  7
296///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
297///  *S  L *S *S *S  L  L  -  - *S  L  L  L  - *S *S  L  L  L  L  L
298/// ```
299///
300/// ```text
301///  20 19 16 11  6 15 10  2  3  4 18  5 17 13  8  0 14  9  1 12  7
302///   $  A  A  A  A  C  C  C  C  C  G  G  G  G  G  G  T  T  T  T  T
303///  *S  L *S *S *S  L  L *S  S  S  L  L  L *S *S  S  L  L  L  L  L
304/// ```
305///
306/// これにより、所望の接尾辞配列が得られる。
307///
308/// 再帰の base case は、列の各要素が distinct な場合で、逆順列が接尾辞配列となる。
309/// 連続して LMS suffix が現れないことと、先頭位置は LMS にならないことから、
310/// reduced string は元の文字列の半分以下の長さになることがわかる。
311/// よって、長さ $n$ での計算量を $T(n)$ とおくと、$T(1) \\in O(1)$ より次のようになる。
312/// $$ T(n) \\le T(n/2) + O(n) \\in O(n). $$
313///
314/// ## パターン検索
315///
316/// パターン文字列 $T$ の $S$ における出現位置を検索する。
317///
318/// 範囲 $\[0\\dots |S|\]$ を接尾辞配列 $A$ 上で二分探索する。
319/// これは、$S\[A\[i\]\\dots\]$ が $i$ に対して単調増加であることから可能。
320/// 境界の両端を求めることで全列挙したり、片側のみを求めてパターンの有無のみを調べたりできる。
321///
322/// # Complexity
323/// 入力中の文字の種類を $\\sigma$、文字列長を $n$ とする。
324/// SA-IS を用いて構築するため、前処理は $O(\\sigma\\log(\\sigma)+n)$ 時間。
325///
326/// ↑ `todo!()` `String` なら $O(\\sigma+n)$、`[T]` なら mapping に時間がかかって $O(n\\log(\\sigma))$
327/// っぽそう。値の範囲が `0..n` に収まるような `[usize]` に対しては $O(n)$ でできるから、追記かも。
328///
329/// 検索は、パターン長を $m$ として $O(m\\log(n))$ 時間。
330///
331/// # References
332/// - Nong, Ge, Sen Zhang, and Wai Hong Chan. "Two efficient algorithms for linear time suffix array construction." _IEEE Transactions on Computers_ 60, no. 10 (2010): 1471--1484.
333/// - Ko, Pang, and Srinivas Aluru. "Space efficient linear time construction of suffix arrays." In _Annual Symposium on Combinatorial Pattern Matching_, pp. 200--210. Springer, Berlin, Heidelberg, 2003.
334///
335/// ## See also
336/// [CS166](http://web.stanford.edu/class/archive/cs/cs166/cs166.1206/lectures/04/Slides04.pdf)。
337/// 差分スライドの関係でページ数がめちゃくちゃ多くて重いので注意。軽いのは
338/// [こっち](http://web.stanford.edu/class/archive/cs/cs166/cs166.1206/lectures/04/Small04.pdf)。
339#[derive(Clone, Debug, Eq, PartialEq)]
340pub struct SuffixArray<T: Ord> {
341    buf: Vec<T>,
342    sa: Vec<usize>,
343}
344
345impl<T: Ord> From<Vec<T>> for SuffixArray<T> {
346    fn from(buf: Vec<T>) -> Self {
347        let buf_usize = hash(&buf);
348        let sa = sa_is(&buf_usize);
349        Self { buf, sa }
350    }
351}
352
353impl From<String> for SuffixArray<char> {
354    fn from(buf: String) -> Self {
355        let buf: Vec<_> = buf.as_str().chars().collect();
356        let buf_usize = hash_chars(&buf);
357        let sa = sa_is(&buf_usize);
358        Self { buf, sa }
359    }
360}
361
362impl SuffixArray<u8> {
363    pub fn from_bytes(buf: Vec<u8>) -> Self {
364        let buf_usize = hash_bytes(&buf);
365        let sa = sa_is(&buf_usize);
366        Self { buf, sa }
367    }
368}
369
370impl SuffixArray<usize> {
371    pub fn from_hashed(buf: Vec<usize>) -> Self {
372        assert!(Self::is_hashed(&buf));
373        let buf_usize: Vec<_> =
374            buf.iter().map(|&x| x + 1).chain(Some(0)).collect();
375
376        let sa = sa_is(&buf_usize);
377        Self { buf, sa }
378    }
379
380    fn is_hashed(buf: &[usize]) -> bool {
381        let mut count = vec![0; buf.len()];
382        for &x in buf {
383            count[x] += 1;
384        }
385        (0..buf.len())
386            .find(|&i| count[i] == 0)
387            .map(|i| (i..count.len()).all(|i| count[i] == 0))
388            .unwrap_or(true)
389    }
390}
391
392/// 座標圧縮をする。
393///
394/// `buf` の末尾に辞書順最小の文字 `$` を付加した列を、座標圧縮して返す。
395fn hash<T: Ord>(buf: &[T]) -> Vec<usize> {
396    let enc: BTreeSet<_> = buf.iter().collect();
397    let enc: BTreeMap<_, _> =
398        enc.into_iter().enumerate().map(|(i, x)| (x, i)).collect();
399    buf.iter()
400        .map(|x| enc[x] + 1)
401        .chain(std::iter::once(0)) // for '$'
402        .collect()
403}
404
405/// 座標圧縮をする。
406///
407/// `buf` の末尾に辞書順最小の文字 `$` を付加した列を、座標圧縮して返す。`char`
408/// の列を受け取り、バケットソートの要領で行う。
409fn hash_chars(buf: &[char]) -> Vec<usize> {
410    let max = match buf.iter().max() {
411        Some(&c) => c as usize,
412        None => return vec![0], // "$"
413    };
414    let enc = {
415        let mut enc = vec![0; max + 1];
416        for &c in buf {
417            enc[c as usize] = 1;
418        }
419        for i in 1..=max {
420            enc[i] += enc[i - 1];
421        }
422        enc
423    };
424    buf.iter().map(|&x| enc[x as usize])
425        .chain(std::iter::once(0)) // for '$'
426        .collect()
427}
428
429/// 座標圧縮をする。
430///
431/// `buf` の末尾に辞書順最小の文字 `$` を付加した列を、座標圧縮して返す。`u8`
432/// の列を受け取り、バケットソートの要領で行う。
433fn hash_bytes(buf: &[u8]) -> Vec<usize> {
434    let enc = {
435        let mut enc = vec![0; 256];
436        for &b in buf {
437            enc[b as usize] = 1;
438        }
439        for i in 1..=255 {
440            enc[i] += enc[i - 1];
441        }
442        enc
443    };
444    buf.iter().map(|&x| enc[x as usize] )
445        .chain(std::iter::once(0)) // for '$'
446        .collect()
447}
448
449#[derive(Clone, Copy, Debug, Eq, PartialEq)]
450enum LsType {
451    LType,
452    SType(bool), // true iff leftmost S-type
453}
454use LsType::{LType, SType};
455
456/// 出現回数を求める。
457///
458/// `res[x]` が `buf` における `x` の出現回数となる配列 `res` を返す。
459///
460/// # Requirements
461/// `buf` の要素は `0..buf.len()` に含まれる。
462fn count_freq(buf: &[usize]) -> Vec<usize> {
463    let mut res = vec![0; buf.len()];
464    buf.iter().for_each(|&x| res[x] += 1);
465    res
466}
467
468/// 逆順列を返す。
469///
470/// `res[x]` が `buf` における `x` の出現位置となる配列 `res` を返す。
471///
472/// # Requirements
473/// `buf` の要素は `0..buf.len()` に含まれ、かつ distinct である。
474fn inv_perm(buf: &[usize]) -> Vec<usize> {
475    let mut res = vec![0; buf.len()];
476    buf.iter().enumerate().for_each(|(i, &x)| res[x] = i);
477    res
478}
479
480/// LS type を求める。
481///
482/// `res[i]` が `buf[i]` の LS type である配列 `res` を返す。
483fn ls_classify(buf: &[usize]) -> Vec<LsType> {
484    let mut res = vec![SType(false); buf.len()];
485    for i in (0..buf.len() - 1).rev() {
486        res[i] = match buf[i].cmp(&buf[i + 1]) {
487            Less => SType(false),
488            Equal => res[i + 1],
489            Greater => LType,
490        };
491    }
492    for i in 1..buf.len() {
493        if let (LType, SType(_)) = (res[i - 1], res[i]) {
494            res[i] = SType(true);
495        }
496    }
497    res
498}
499
500/// 各バケットの開始位置を求める。
501///
502/// # Input
503/// `count[i]` が `i` 番目のバケットのサイズである配列 `count`。
504fn bucket_head(count: &[usize]) -> Vec<usize> {
505    let n = count.len();
506    let mut head: Vec<_> =
507        std::iter::once(&0).chain(&count[..n - 1]).cloned().collect();
508    for i in 1..n {
509        head[i] += head[i - 1];
510    }
511    head
512}
513
514/// 各バケットの終端位置を求める。
515///
516/// # Input
517/// `count[i]` が `i` 番目のバケットのサイズである配列 `count`。
518fn bucket_tail(count: &[usize]) -> Vec<usize> {
519    let mut tail = count.to_vec();
520    for i in 1..count.len() {
521        tail[i] += tail[i - 1];
522    }
523    tail
524}
525
526/// すでに判明している SA と LS type から、SA の残りの要素を求める。
527fn induce(
528    buf: &[usize],
529    sa: &mut [Option<usize>],
530    count: &[usize],
531    ls: &[LsType],
532) {
533    let mut head = bucket_head(count);
534    for i in 0..sa.len() {
535        if let Some(j) = sa[i] {
536            if j > 0 && ls[j - 1] == LType {
537                sa[head[buf[j - 1]]] = Some(j - 1);
538                head[buf[j - 1]] += 1;
539            }
540        }
541    }
542    let mut tail = bucket_tail(count);
543    for i in (1..count.len()).rev() {
544        if let Some(j) = sa[i] {
545            if j > 0 && ls[j - 1] != LType {
546                tail[buf[j - 1]] -= 1;
547                sa[tail[buf[j - 1]]] = Some(j - 1);
548            }
549        }
550    }
551}
552
553/// 各 LMS block を文字とする文字列を作る。
554///
555/// 新たな文字も辞書順に番号づけられる。
556///
557/// # Examples
558/// `[CCCG][AT][GTC][AT][GTC][AGGA][$]` → `3242410`
559fn reduce(buf: &[usize], lms: &[usize], ls: &[LsType]) -> Vec<usize> {
560    if lms.len() <= 1 {
561        return vec![0; lms.len()];
562    }
563
564    let e = |(i0, i1)| {
565        if (ls[i0], ls[i1]) == (SType(true), SType(true)) {
566            Some(true)
567        } else if ls[i0] != ls[i1] || buf[i0] != buf[i1] {
568            Some(false)
569        } else {
570            None
571        }
572    };
573
574    let mut map = vec![0; buf.len()]; // map[lms[0]] = 0
575    map[lms[1]] = 1;
576    let mut x = 1;
577    for i in 2..lms.len() {
578        let equiv = buf[lms[i]] == buf[lms[i - 1]]
579            && (lms[i] + 1..).zip(lms[i - 1] + 1..).find_map(e).unwrap();
580        if !equiv {
581            x += 1;
582        }
583        map[lms[i]] = x;
584    }
585
586    (0..buf.len())
587        .filter_map(|i| match ls[i] {
588            SType(true) => Some(map[i]),
589            _ => None,
590        })
591        .collect()
592}
593
594/// SA-IS により接尾辞配列を求める。
595fn sa_is(buf: &[usize]) -> Vec<usize> {
596    let len = buf.len();
597    let count = count_freq(buf);
598    if count.iter().all(|&x| x == 1) {
599        return inv_perm(buf);
600    }
601
602    let ls = ls_classify(buf);
603    let mut sa = vec![None; len];
604    let mut tail = bucket_tail(&count);
605    for i in (1..len).rev().filter(|&i| ls[i] == SType(true)) {
606        tail[buf[i]] -= 1;
607        sa[tail[buf[i]]] = Some(i);
608    }
609
610    induce(buf, &mut sa, &count, &ls);
611
612    let lms: Vec<_> = sa
613        .into_iter()
614        .map(std::option::Option::unwrap)
615        .filter(|&i| ls[i] == SType(true))
616        .collect(); // in lexicographic order
617    let rs_sa = sa_is(&reduce(buf, &lms, &ls));
618
619    // in appearing order
620    let lms: Vec<_> = (0..len).filter(|&i| ls[i] == SType(true)).collect();
621
622    let mut tail = bucket_tail(&count);
623    let mut sa = vec![None; len];
624    for i in rs_sa.into_iter().rev() {
625        let j = lms[i];
626        tail[buf[j]] -= 1;
627        sa[tail[buf[j]]] = Some(j);
628    }
629    induce(buf, &mut sa, &count, &ls);
630
631    sa.into_iter().map(std::option::Option::unwrap).collect()
632}
633
634impl<T: Ord> SuffixArray<T> {
635    /// パターン検索を行う。
636    ///
637    /// # Complexity
638    ///
639    /// $O(|T|\\log(|S|))$ 時間。
640    ///
641    /// # Examples
642    ///
643    /// ```
644    /// use nekolib::seq::SuffixArray;
645    ///
646    /// let s: Vec<_> = "abracadabra".chars().collect();
647    /// let sa: SuffixArray<_> = s.into();
648    ///
649    /// assert_eq!(sa.search(&['a']).collect::<Vec<_>>(), vec![10, 7, 0, 3, 5]);
650    /// assert_eq!(
651    ///     sa.search(&"abra".chars().collect::<Vec<_>>()).nth(1),
652    ///     Some(0)
653    /// );
654    /// assert_eq!(sa.search(&['a', 'e']).next(), None);
655    /// ```
656    pub fn search(&self, pat: &[T]) -> impl Iterator<Item = usize> + '_ {
657        let lo = {
658            let mut lt = 1_usize.wrapping_neg();
659            let mut ge = self.sa.len();
660            while ge.wrapping_sub(lt) > 1 {
661                let mid = lt.wrapping_add(ge.wrapping_sub(lt) / 2);
662                let pos = self.sa[mid];
663                match self.buf[pos..].cmp(pat) {
664                    Less => lt = mid,
665                    _ => ge = mid,
666                }
667            }
668            ge
669        };
670        if lo >= self.sa.len() {
671            return self.sa[lo..lo].iter().cloned();
672        }
673        let hi = {
674            let mut le = lo.wrapping_sub(1);
675            let mut gt = self.sa.len();
676            while gt.wrapping_sub(le) > 1 {
677                let mid = le.wrapping_add(gt.wrapping_sub(le) / 2);
678                let pos = self.sa[mid];
679                let len = pat.len().min(self.buf[pos..].len());
680                match self.buf[pos..pos + len].cmp(pat) {
681                    Greater => gt = mid,
682                    _ => le = mid,
683                }
684            }
685            gt
686        };
687        self.sa[lo..hi].iter().cloned()
688    }
689
690    /// 高さ配列を返す。
691    ///
692    /// # Examples
693    /// ```
694    /// use nekolib::seq::SuffixArray;
695    ///
696    /// let s: Vec<_> = "abracadabra".chars().collect();
697    /// let sa: SuffixArray<_> = s.into();
698    /// assert_eq!(sa.lcpa(), [0, 0, 1, 4, 1, 1, 0, 3, 0, 0, 0, 2]);
699    /// ```
700    pub fn lcpa(&self) -> Vec<usize> {
701        let n = self.buf.len();
702        let mut rank = vec![0; n + 1];
703        for i in 0..=n {
704            rank[self.sa[i]] = i;
705        }
706        let mut h = 0;
707        let mut res = vec![0; n + 1];
708        for i in 0..n {
709            let j = self.sa[rank[i] - 1];
710            if h > 0 {
711                h -= 1;
712            }
713            while j + h < n && i + h < n {
714                if self.buf[j + h] != self.buf[i + h] {
715                    break;
716                }
717                h += 1;
718            }
719            res[rank[i]] = h;
720        }
721        res
722    }
723
724    /// 自身を消費し、内部表現を返す。
725    ///
726    /// # Examples
727    ///
728    /// ```
729    /// use nekolib::seq::SuffixArray;
730    ///
731    /// let s: Vec<_> = "abracadabra".chars().collect();
732    /// let sa: SuffixArray<_> = s.into();
733    /// let sa = sa.into_inner();
734    /// assert_eq!(sa, vec![11, 10, 7, 0, 3, 5, 8, 1, 4, 6, 9, 2]);
735    /// ```
736    pub fn into_inner(self) -> Vec<usize> { self.sa }
737}
738
739impl SuffixArray<char> {
740    /// パターン文字列検索を行う。
741    ///
742    /// # Examples
743    /// ```
744    /// use nekolib::seq::SuffixArray;
745    ///
746    /// let sa: SuffixArray<_> = "abracadabra".to_string().into();
747    /// let occ: Vec<_> = sa.search_str("ab").collect();
748    /// assert_eq!(occ, vec![7, 0]);
749    /// let occ: Vec<_> = sa.search_str("a").collect();
750    /// assert_eq!(occ, vec![10, 7, 0, 3, 5]);
751    /// assert_eq!(sa.search_str("e").next(), None);
752    /// ```
753    pub fn search_str(&self, pat: &str) -> impl Iterator<Item = usize> + '_ {
754        let pat: Vec<_> = pat.chars().collect();
755        self.search(&pat)
756    }
757}
758
759impl<T: Ord> Index<usize> for SuffixArray<T> {
760    type Output = usize;
761    fn index(&self, i: usize) -> &usize { &self.sa[i] }
762}
763
764impl<T: Ord> From<SuffixArray<T>> for Vec<usize> {
765    fn from(sa: SuffixArray<T>) -> Self { sa.sa }
766}
767
768#[test]
769fn test_simple() {
770    let buf = "abracadabra".to_string();
771    let sa: SuffixArray<_> = buf.into();
772    let sa: Vec<_> = sa.into();
773    assert_eq!(sa, [11, 10, 7, 0, 3, 5, 8, 1, 4, 6, 9, 2])
774}
775
776#[test]
777fn test_empty_text() {
778    let sa: SuffixArray<_> = "".to_string().into();
779    let occ: Vec<_> = sa.search_str("").collect();
780    assert_eq!(occ, [0]);
781    assert_eq!(sa.search_str("x").next(), None);
782}
783
784#[test]
785fn test_empty_pat() {
786    let sa: SuffixArray<_> = "empty".to_string().into();
787    let occ: Vec<_> = sa.search_str("").collect();
788    assert_eq!(occ, [5, 0, 1, 2, 3, 4]);
789}
790
791#[test]
792fn test_naive() {
793    let n = 1000;
794    let f = |x: &i32| Some((x * 29 + 71) % 143);
795    let buf: Vec<_> = std::iter::successors(Some(2_i32), f).take(n).collect();
796    let naive_sa = {
797        let mut sa: Vec<_> = (0..=n).collect();
798        sa.sort_unstable_by_key(|&i| &buf[i..]);
799        sa
800    };
801    let sa: SuffixArray<_> = buf.into();
802    let sa: Vec<_> = sa.into();
803    assert_eq!(sa, naive_sa);
804}