Skip to content

Commit 28ae587

Browse files
committed
Factor Frobenius basis out from the test
1 parent 00d468c commit 28ae587

File tree

4 files changed

+71
-60
lines changed

4 files changed

+71
-60
lines changed

cp-algo/linalg/all

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
#define CP_ALGO_LINALG_ALL
33
#include "vector.hpp"
44
#include "matrix.hpp"
5+
#include "frobenius.hpp"
56
#endif // CP_ALGO_LINALG_ALL

cp-algo/linalg/frobenius.hpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#ifndef CP_ALGO_LINALG_FROBENIUS_HPP
2+
#define CP_ALGO_LINALG_FROBENIUS_HPP
3+
#include "matrix.hpp"
4+
#include "../algebra/poly.hpp"
5+
#include <vector>
6+
namespace cp_algo::linalg {
7+
template<bool reduce = false>
8+
auto frobenius_basis(auto const& A) {
9+
using matrix = std::decay_t<decltype(A)>;
10+
using base = matrix::base;
11+
using polyn = algebra::poly_t<base>;
12+
assert(A.n() == A.m());
13+
size_t n = A.n();
14+
struct krylov {
15+
std::vector<vec<base>> basis;
16+
polyn rec;
17+
};
18+
std::vector<krylov> blocks;
19+
std::vector<vec<base>> reduced;
20+
while(size(reduced) < n) {
21+
auto generate_block = [&](auto x) {
22+
krylov block;
23+
while(true) {
24+
vec<base> y = x | vec<base>::ei(n + 1, size(reduced));
25+
for(auto &it: reduced) {
26+
y.reduce_by(it);
27+
}
28+
y.normalize();
29+
if(vec<base>(y[std::slice(0, n, 1)]) == vec<base>(n)) {
30+
block.rec = std::vector<base>(
31+
begin(y) + n + size(reduced) - size(block.basis),
32+
begin(y) + n + size(reduced) + 1
33+
);
34+
return std::pair{block, vec<base>(y[std::slice(n, n, 1)])};
35+
} else {
36+
block.basis.push_back(x);
37+
reduced.push_back(y);
38+
x = A.apply(x);
39+
}
40+
}
41+
};
42+
auto [block, full_rec] = generate_block(vec<base>::random(n));
43+
if constexpr (reduce) {
44+
if(vec<base>(full_rec[std::slice(0, size(reduced), 1)]) != vec<base>(size(reduced))) {
45+
auto x = block.basis[0];
46+
size_t start = 0;
47+
for(auto &[basis, rec]: blocks) {
48+
polyn cur_rec = std::vector<base>(
49+
begin(full_rec) + start, begin(full_rec) + start + rec.deg()
50+
);
51+
auto shift = cur_rec / block.rec;
52+
for(int j = 0; j <= shift.deg(); j++) {
53+
x.add_scaled(basis[j], shift[j]);
54+
}
55+
start += rec.deg();
56+
}
57+
reduced.erase(begin(reduced) + start, end(reduced));
58+
tie(block, full_rec) = generate_block(x.normalize());
59+
}
60+
}
61+
blocks.push_back(block);
62+
}
63+
return blocks;
64+
}
65+
};
66+
#endif // CP_ALGO_LINALG_FROBENIUS_HPP

cp-algo/linalg/matrix.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
#include <vector>
1010
#include <array>
1111
namespace cp_algo::linalg {
12-
template<typename base>
13-
struct matrix: valarray_base<matrix<base>, vec<base>> {
12+
template<typename base_t>
13+
struct matrix: valarray_base<matrix<base_t>, vec<base_t>> {
14+
using base = base_t;
1415
using Base = valarray_base<matrix<base>, vec<base>>;
1516
using Base::Base;
1617

verify/algebra/matrix/characteristic.test.cpp

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
#define PROBLEM "https://judge.yosupo.jp/problem/characteristic_polynomial"
33
#pragma GCC optimize("Ofast,unroll-loops")
44
#pragma GCC target("avx2,tune=native")
5-
#include "cp-algo/algebra/poly.hpp"
6-
#include "cp-algo/linalg/matrix.hpp"
5+
#include "cp-algo/linalg/frobenius.hpp"
76
#include <bits/stdc++.h>
87

98
using namespace std;
@@ -14,62 +13,6 @@ const int mod = 998244353;
1413
using base = modular<mod>;
1514
using polyn = poly_t<base>;
1615

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-
7316
void solve() {
7417
size_t n;
7518
cin >> n;

0 commit comments

Comments
 (0)