char_poly.hpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <vector> | ||
| 4 | #include <bitset> | ||
| 5 | #include <cassert> | ||
| 6 | |||
| 7 | // Compute the characteristic polynomial of a square matrix A over some field. | ||
| 8 | // Not numerically stable at all. | ||
| 9 | // Takes argument by value, use std::move if you can. | ||
| 10 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 28 times.
|
28 | template <typename num> std::vector<num> charPoly(std::vector<std::vector<num>> A) { |
| 11 | 28 | int N = int(A.size()); | |
| 12 |
1/1✓ Branch 4 → 5 taken 28 times.
|
28 | std::vector<num> res; res.reserve(N+1); |
| 13 |
1/1✓ Branch 5 → 6 taken 28 times.
|
28 | res.push_back(num(1)); |
| 14 |
2/2✓ Branch 44 → 7 taken 9590 times.
✓ Branch 44 → 45 taken 28 times.
|
9618 | for (int i = 0, deg = 0; i < N; i++) { |
| 15 | 9590 | auto& Ai = A[i]; | |
| 16 | |||
| 17 | 9590 | int c = i+1; | |
| 18 |
4/4✓ Branch 8 → 9 taken 384437 times.
✓ Branch 8 → 11 taken 1696 times.
✓ Branch 9 → 10 taken 376543 times.
✓ Branch 9 → 11 taken 7894 times.
|
386133 | while (c < N && Ai[c] == num(0)) c++; |
| 19 |
2/2✓ Branch 11 → 12 taken 1696 times.
✓ Branch 11 → 23 taken 7894 times.
|
9590 | if (c == N) { |
| 20 |
1/1✓ Branch 12 → 13 taken 1696 times.
|
1696 | res.resize(i+2, num(0)); |
| 21 |
2/2✓ Branch 21 → 14 taken 458172 times.
✓ Branch 21 → 22 taken 1696 times.
|
459868 | for (int x = deg; x >= 0; x--) { |
| 22 | 458172 | num v = res[x]; | |
| 23 |
2/2✓ Branch 19 → 15 taken 1104371 times.
✓ Branch 19 → 20 taken 458172 times.
|
1562543 | for (int y = x+1, z = i; z >= deg; z--, y++) { |
| 24 |
2/2✓ Branch 15 → 16 taken 494484 times.
✓ Branch 15 → 17 taken 609887 times.
|
2208742 | res[y] -= v * Ai[z]; |
| 25 | } | ||
| 26 | } | ||
| 27 | 1696 | deg = i+1; | |
| 28 | 1696 | continue; | |
| 29 | 1696 | } | |
| 30 | |||
| 31 | 7894 | num vc = Ai[c]; | |
| 32 | 7894 | num ivc = inv(vc); | |
| 33 | |||
| 34 | 7894 | Ai[c] = Ai[i+1]; | |
| 35 | 7894 | Ai[i+1] = 0; | |
| 36 | |||
| 37 | 7894 | std::swap(A[i+1], A[c]); | |
| 38 | 7894 | auto& Ai1 = A[i+1]; | |
| 39 |
2/2✓ Branch 26 → 25 taken 3271757 times.
✓ Branch 26 → 39 taken 7894 times.
|
3279651 | for (int k = deg; k < N; k++) { |
| 40 | 3271757 | Ai1[k] *= vc; | |
| 41 | } | ||
| 42 | |||
| 43 |
2/2✓ Branch 39 → 27 taken 1995001 times.
✓ Branch 39 → 41 taken 7894 times.
|
2002895 | for (int k = i+1; k < N; k++) { |
| 44 | 1995001 | auto& Ak = A[k]; | |
| 45 | { | ||
| 46 | 1995001 | auto& x = Ak[i+1]; | |
| 47 | 1995001 | auto& y = Ak[c]; | |
| 48 | 1995001 | num tmp = y; | |
| 49 | 1995001 | y = x; | |
| 50 | 1995001 | x = tmp * ivc; | |
| 51 | } | ||
| 52 | { | ||
| 53 | 1995001 | num v = Ak[i+1]; | |
| 54 |
2/2✓ Branch 32 → 28 taken 894607571 times.
✓ Branch 32 → 33 taken 1995001 times.
|
896602572 | for (int j = deg; j < N; j++) { |
| 55 |
2/2✓ Branch 28 → 29 taken 446296308 times.
✓ Branch 28 → 30 taken 448311263 times.
|
1789215142 | Ak[j] -= v * Ai[j]; |
| 56 | } | ||
| 57 | } | ||
| 58 |
2/2✓ Branch 33 → 34 taken 1987107 times.
✓ Branch 33 → 38 taken 7894 times.
|
1995001 | if (k > i+1) { |
| 59 | 1987107 | num v = Ai[k]; | |
| 60 |
2/2✓ Branch 37 → 35 taken 891335814 times.
✓ Branch 37 → 38 taken 1987107 times.
|
893322921 | for (int j = deg; j < N; j++) { |
| 61 | 891335814 | Ai1[j] += v * Ak[j]; | |
| 62 | } | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 |
2/2✓ Branch 41 → 40 taken 1276756 times.
✓ Branch 41 → 42 taken 7894 times.
|
1284650 | for (int k = deg; k <= i; k++) { |
| 67 | 1276756 | Ai1[k+1] += Ai[k]; | |
| 68 | } | ||
| 69 | } | ||
| 70 | 28 | reverse(res.begin(), res.end()); | |
| 71 | 28 | return res; | |
| 72 | } | ||
| 73 | |||
| 74 | // Compute the characteristic polynomial of a square matrix A over F2. | ||
| 75 | // Takes argument by value, use std::move if you can. | ||
| 76 | // Note that MAXS must be at least N+1 | ||
| 77 | ✗ | template <std::size_t MAXS> std::bitset<MAXS> charPoly(std::vector<std::bitset<MAXS>> A) { | |
| 78 | using bs = std::bitset<MAXS>; | ||
| 79 | ✗ | int N = int(A.size()); | |
| 80 | ✗ | assert(MAXS >= N+1); | |
| 81 | ✗ | bs ans; ans[0] = 1; | |
| 82 | ✗ | int deg = 0; | |
| 83 | ✗ | for (int i = 0; i < N; i++) { | |
| 84 | { | ||
| 85 | ✗ | int j = int(A[i]._Find_next(i)); | |
| 86 | ✗ | if (j >= N) { | |
| 87 | ✗ | bs nans; | |
| 88 | ✗ | for (; deg <= i; ans <<= 1, deg++) { | |
| 89 | ✗ | if (A[i][deg]) nans ^= ans; | |
| 90 | } | ||
| 91 | ✗ | ans ^= nans; | |
| 92 | ✗ | continue; | |
| 93 | } | ||
| 94 | ✗ | if (j != i+1) { | |
| 95 | ✗ | swap(A[j], A[i+1]); | |
| 96 | ✗ | for (auto& a : A) { | |
| 97 | ✗ | bool tmp = a[j]; | |
| 98 | ✗ | a[j] = a[i+1]; | |
| 99 | ✗ | a[i+1] = tmp; | |
| 100 | } | ||
| 101 | } | ||
| 102 | } | ||
| 103 | ✗ | assert(A[i][i+1]); | |
| 104 | ✗ | bs msk = A[i]; msk.flip(i+1); | |
| 105 | ✗ | for (int k = 0; k < N; k++) { | |
| 106 | ✗ | if (msk[k]) A[i+1] ^= A[k]; | |
| 107 | } | ||
| 108 | ✗ | for (auto& a : A) { | |
| 109 | ✗ | if (a[i+1]) a ^= msk; | |
| 110 | } | ||
| 111 | } | ||
| 112 | ✗ | return ans; | |
| 113 | } | ||
| 114 |