Skip to content

Commit 00d468c

Browse files
committed
Update Frobenius basis computation
1 parent ccfe0b8 commit 00d468c

File tree

1 file changed

+62
-27
lines changed

1 file changed

+62
-27
lines changed

verify/algebra/matrix/characteristic.test.cpp

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,38 +14,73 @@ const int mod = 998244353;
1414
using base = modular<mod>;
1515
using polyn = poly_t<base>;
1616

17+
template<bool reduce = false>
18+
auto frobenius_basis(auto const& A) {
19+
assert(A.n() == A.m());
20+
size_t n = A.n();
21+
struct krylov {
22+
vector<vec<base>> basis;
23+
poly_t<base> rec;
24+
};
25+
vector<krylov> blocks;
26+
vector<vec<base>> reduced;
27+
while(size(reduced) < n) {
28+
auto generate_block = [&](auto x) {
29+
krylov block;
30+
while(true) {
31+
vec<base> y = x | vec<base>::ei(n + 1, size(reduced));
32+
for(auto &it: reduced) {
33+
y.reduce_by(it);
34+
}
35+
y.normalize();
36+
if(vec<base>(y[slice(0, n, 1)]) == vec<base>(n)) {
37+
block.rec = vector<base>(
38+
begin(y) + n + size(reduced) - size(block.basis),
39+
begin(y) + n + size(reduced) + 1
40+
);
41+
return std::pair{block, vec<base>(y[slice(n, n, 1)])};
42+
} else {
43+
block.basis.push_back(x);
44+
reduced.push_back(y);
45+
x = A.apply(x);
46+
}
47+
}
48+
};
49+
auto [block, full_rec] = generate_block(vec<base>::random(n));
50+
if constexpr (reduce) {
51+
if(vec<base>(full_rec[slice(0, size(reduced), 1)]) != vec<base>(size(reduced))) {
52+
auto x = block.basis[0];
53+
size_t start = 0;
54+
for(auto &[basis, rec]: blocks) {
55+
polyn cur_rec = vector<base>(
56+
begin(full_rec) + start, begin(full_rec) + start + rec.deg()
57+
);
58+
auto shift = cur_rec / block.rec;
59+
for(int j = 0; j <= shift.deg(); j++) {
60+
x.add_scaled(basis[j], shift[j]);
61+
}
62+
start += rec.deg();
63+
}
64+
reduced.erase(begin(reduced) + start, end(reduced));
65+
tie(block, full_rec) = generate_block(x.normalize());
66+
}
67+
}
68+
blocks.push_back(block);
69+
}
70+
return blocks;
71+
}
72+
1773
void solve() {
1874
size_t n;
1975
cin >> n;
2076
matrix<base> A(n);
2177
A.read();
22-
vector<vec<base>> basis;
23-
auto x = vec<base>::random(n);
24-
size_t degree = 0;
25-
polyn ans = base(1);
26-
while(size(basis) <= n) {
27-
auto y = x | vec<base>::ei(n + 1, size(basis));
28-
for(auto &it: basis) {
29-
y.reduce_by(it);
30-
}
31-
y.normalize();
32-
if(vec<base>(y[slice(0, n, 1)]) == vec<base>(n)) {
33-
vector<base> cur(begin(y) + n + size(basis) - degree,
34-
begin(y) + n + size(basis) + 1);
35-
ans *= polyn(cur);
36-
degree = 0;
37-
if(size(basis) < n) {
38-
x = vec<base>::random(n);
39-
} else {
40-
break;
41-
}
42-
} else {
43-
basis.push_back(y);
44-
x = A.apply(x);
45-
degree++;
46-
}
78+
auto blocks = frobenius_basis(A);
79+
polyn res(1);
80+
for(auto &[basis, rec]: blocks) {
81+
res *= rec;
4782
}
48-
ans.print();
83+
res.print();
4984
}
5085

5186
signed main() {
@@ -57,4 +92,4 @@ signed main() {
5792
while(t--) {
5893
solve();
5994
}
60-
}
95+
}

0 commit comments

Comments
 (0)