Skip to content

Commit 79e8561

Browse files
authored
Merge pull request #335 from hitonanode/f2-determinant
F2 determinant
2 parents c830874 + cd1a3f0 commit 79e8561

File tree

6 files changed

+115
-13
lines changed

6 files changed

+115
-13
lines changed

linear_algebra_matrix/linalg_bitset.hpp

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// Complexity: O(nm + nm rank(M) / 64)
1010
// Verified: abc276_h (2000 x 8000)
1111
template <int Wmax>
12-
std::vector<std::bitset<Wmax>> gauss_jordan(int W, std::vector<std::bitset<Wmax>> M) {
12+
std::vector<std::bitset<Wmax>> f2_gauss_jordan(int W, std::vector<std::bitset<Wmax>> M) {
1313
assert(W <= Wmax);
1414
int H = M.size(), c = 0;
1515
for (int h = 0; h < H and c < W; ++h, ++c) {
@@ -33,7 +33,7 @@ std::vector<std::bitset<Wmax>> gauss_jordan(int W, std::vector<std::bitset<Wmax>
3333
}
3434

3535
// Rank of Gauss-Jordan eliminated matrix
36-
template <int Wmax> int rank_gauss_jordan(int W, const std::vector<std::bitset<Wmax>> &M) {
36+
template <int Wmax> int f2_rank_gauss_jordan(int W, const std::vector<std::bitset<Wmax>> &M) {
3737
assert(W <= Wmax);
3838
for (int h = (int)M.size() - 1; h >= 0; h--) {
3939
int j = 0;
@@ -43,27 +43,54 @@ template <int Wmax> int rank_gauss_jordan(int W, const std::vector<std::bitset<W
4343
return 0;
4444
}
4545

46+
// determinant of F2 matrix.
47+
// Return 0 if the matrix is singular, otherwise return 1.
48+
// Complexity: O(W^3 / 64)
49+
template <int Wmax> int f2_determinant(const std::vector<std::bitset<Wmax>> &M) {
50+
const int H = M.size();
51+
if (H > Wmax) return 0;
52+
53+
auto tmp = M;
54+
for (int h = 0; h < H; ++h) {
55+
int piv = -1;
56+
for (int j = h; j < H; ++j) {
57+
if (tmp.at(j).test(h)) {
58+
piv = j;
59+
break;
60+
}
61+
}
62+
if (piv == -1) return 0; // singular
63+
64+
if (piv != h) std::swap(tmp.at(piv), tmp.at(h));
65+
for (int hh = h + 1; hh < H; ++hh) {
66+
if (tmp.at(hh).test(h)) tmp.at(hh) ^= tmp.at(h);
67+
}
68+
}
69+
70+
return 1; // nonsingular
71+
}
72+
4673
template <int W1, int W2>
4774
std::vector<std::bitset<W2>>
48-
matmul(const std::vector<std::bitset<W1>> &A, const std::vector<std::bitset<W2>> &B) {
75+
f2_matmul(const std::vector<std::bitset<W1>> &A, const std::vector<std::bitset<W2>> &B) {
4976
int H = A.size(), K = B.size();
5077
std::vector<std::bitset<W2>> C(H);
5178
for (int i = 0; i < H; i++) {
5279
for (int j = 0; j < K; j++) {
53-
if (A[i][j]) C[i] ^= B[j];
80+
if (A.at(i).test(j)) C.at(i) ^= B.at(j);
5481
}
5582
}
5683
return C;
5784
}
5885

5986
template <int Wmax>
60-
std::vector<std::bitset<Wmax>> matpower(std::vector<std::bitset<Wmax>> X, long long n) {
87+
std::vector<std::bitset<Wmax>> f2_matpower(std::vector<std::bitset<Wmax>> X, long long n) {
6188
int D = X.size();
6289
std::vector<std::bitset<Wmax>> ret(D);
6390
for (int i = 0; i < D; i++) ret[i][i] = 1;
6491
while (n) {
65-
if (n & 1) ret = matmul<Wmax, Wmax>(ret, X);
66-
X = matmul<Wmax, Wmax>(X, X), n >>= 1;
92+
if (n & 1) ret = f2_matmul<Wmax, Wmax>(ret, X);
93+
X = f2_matmul<Wmax, Wmax>(X, X), n >>= 1;
6794
}
6895
return ret;
6996
}
@@ -74,7 +101,7 @@ std::vector<std::bitset<Wmax>> matpower(std::vector<std::bitset<Wmax>> X, long l
74101
// Complexity: O(HW + HW rank(A) / 64 + W^2 len(freedoms))
75102
template <int Wmax, class Vec>
76103
std::tuple<bool, std::bitset<Wmax>, std::vector<std::bitset<Wmax>>>
77-
system_of_linear_equations(std::vector<std::bitset<Wmax>> A, Vec b, int W) {
104+
f2_system_of_linear_equations(std::vector<std::bitset<Wmax>> A, Vec b, int W) {
78105
int H = A.size();
79106
assert(W <= Wmax);
80107
assert(A.size() == b.size());
@@ -84,7 +111,7 @@ system_of_linear_equations(std::vector<std::bitset<Wmax>> A, Vec b, int W) {
84111
for (int j = 0; j < W; ++j) M[i][j] = A[i][j];
85112
M[i][W] = b[i];
86113
}
87-
M = gauss_jordan<Wmax + 1>(W + 1, M);
114+
M = f2_gauss_jordan<Wmax + 1>(W + 1, M);
88115
std::vector<int> ss(W, -1);
89116
std::vector<int> ss_nonneg_js;
90117
for (int i = 0; i < H; i++) {

linear_algebra_matrix/linalg_bitset.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@ vector<bitset<Wmax>> A;
1515
vector<bool> b;
1616

1717
// Solve Ax = b (x: F_2^W)
18-
auto [feasible, x0, freedoms] = system_of_linear_equations<Wmax, vector<bool>>(A, b, W);
18+
auto [feasible, x0, freedoms] = f2_system_of_linear_equations<Wmax, vector<bool>>(A, b, W);
19+
20+
// Calc determinant (or check whether A is regular)
21+
int det = f2_determinant<dim>(mat);
1922
```
2023

2124
## 問題例
2225

2326
- [AOJ 2624: Graph Automata Player](https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2624)
2427
- [No.1421 国勢調査 (Hard) - yukicoder](https://yukicoder.me/problems/no/1421)
2528
- [AtCoder Beginner Contest 276 Ex - Construct a Matrix](https://atcoder.jp/contests/abc276/tasks/abc276_h) $2000 \times 8000$ 行列の線型方程式を解く.
29+
- [Library Checker: Determinant of Matrix (Mod 2)](https://judge.yosupo.jp/problem/matrix_det_mod_2)

linear_algebra_matrix/test/linalg_bitset.test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ int main() {
2626
}
2727

2828
cin >> T;
29-
A = matpower<Wmax>(A, T);
29+
A = f2_matpower<Wmax>(A, T);
3030
for (int i = 0; i < N; i++) A[i][N] = v[i];
31-
A = gauss_jordan<Wmax>(N + 1, A);
31+
A = f2_gauss_jordan<Wmax>(N + 1, A);
3232

3333
for (int i = 0; i < N; i++) {
3434
if (A[i].count() == 1 and A[i][N]) {

linear_algebra_matrix/test/linalg_bitset.yuki1421.test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ int main() {
5959
}
6060
A.emplace_back(a);
6161
}
62-
auto [ok, solution, freedoms] = system_of_linear_equations<Wmax, vector<bool>>(A, b, N);
62+
auto [ok, solution, freedoms] = f2_system_of_linear_equations<Wmax, vector<bool>>(A, b, N);
6363
if (!ok) bad();
6464
for (int i = 0; i < N; ++i) ret[i] += int(solution[i]) << d;
6565
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#define PROBLEM "https://judge.yosupo.jp/problem/matrix_det_mod_2"
2+
#include "../linalg_bitset.hpp"
3+
4+
#include <bitset>
5+
#include <iostream>
6+
#include <string>
7+
#include <vector>
8+
9+
using namespace std;
10+
11+
int main() {
12+
cin.tie(nullptr);
13+
ios::sync_with_stdio(false);
14+
15+
constexpr int dim = 1 << 12;
16+
using BS = bitset<dim>;
17+
18+
int N;
19+
cin >> N;
20+
vector<BS> mat(N);
21+
for (auto &v : mat) {
22+
string s;
23+
cin >> s;
24+
v = BS(s);
25+
}
26+
27+
cout << f2_determinant<dim>(mat) << '\n';
28+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#define PROBLEM "https://judge.yosupo.jp/problem/matrix_product_mod_2"
2+
#include "../linalg_bitset.hpp"
3+
4+
#include <algorithm>
5+
#include <bitset>
6+
#include <iostream>
7+
#include <string>
8+
#include <vector>
9+
using namespace std;
10+
11+
int main() {
12+
cin.tie(nullptr);
13+
ios::sync_with_stdio(false);
14+
15+
constexpr int dim = 1 << 12;
16+
17+
using BS = bitset<dim>;
18+
19+
int N, M, K;
20+
cin >> N >> M >> K;
21+
22+
vector<BS> A(N), B(M);
23+
for (auto &v : A) {
24+
string s;
25+
cin >> s;
26+
std::reverse(s.begin(), s.end()); // bitset に文字列 s を与えると s[0] が最高位になるので反転
27+
v = BS(s);
28+
}
29+
30+
for (auto &v : B) {
31+
string s;
32+
cin >> s;
33+
std::reverse(s.begin(), s.end());
34+
v = BS(s);
35+
}
36+
37+
auto C = f2_matmul<dim, dim>(A, B);
38+
for (const auto &v : C) {
39+
auto tmp = v.to_string();
40+
std::reverse(tmp.begin(), tmp.end());
41+
cout << tmp.substr(0, K) << '\n';
42+
}
43+
}

0 commit comments

Comments
 (0)