2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
52#include <unordered_map>
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
82
83
84
85
86
87
90
91
95
96
100
101
105
106
110
111
115
116
122template <ComponentType T>
124template <CoefficientType T>
126template <ComponentType T>
129template <ComponentType T>
131template <ComponentType T>
133template <ComponentType T>
135template <ComponentType T>
137template <ReliablyComparableType T>
139template <ComponentType T>
140std::ostream& operator<<(
std::ostream& os,
const Matrix<T>& rhs);
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174template <ComponentType T>
179 template <ReliablyComparableType U>
181 template <ReliablyComparableType U>
183 friend std::ostream& operator<< <>(
std::ostream& os,
const Matrix& rhs);
190
191
200
201
202
203
204 Matrix(size_t m, size_t n,
const T& l);
207
208
209
210
211 constexpr Matrix(size_t m, size_t n, std::initializer_list<T> l);
214
215
216
217
218 Matrix(std::initializer_list<std::initializer_list<T>> l);
227 transposed(other.transposed),
235 transposed(other.transposed),
240 other.transposed =
false;
242 other.cache.invalidate();
246
247
248
249
250
251
252
253
254 template <FiniteFieldType S>
259
260
261
262
263
264
265
266
267
268
275
276
289
290
305
306
309
310
311
312
316
317
318
319
323
324
325
326
333
334
335
336
337
338
345
346
349
350
351
352
353
354
355
356
357
358
359
360
361
362
369
370
373
374
375
376
380
381
382
383
387
388
389
390
391 constexpr bool is_empty()
const noexcept {
return m == 0 || n == 0; }
394
395
396
397
398
399
400
404 const bool b = std::ranges::all_of(data, [&zero](
const T& v) {
return v == zero; });
410
411
412
413
417 return std::ranges::all_of(data, [&zero](
const T& v) {
return v == zero; });
428
429
430
431
432
433
434
439
440
441
442
450
451
452
453
454
455
459
460
461
462
463
464
465
466
467
468
469
470
476
477
478
479
480
481
486
487
488
489
497
498
499
500
501
502
503
504
505
510
511
512
513
514
515
516
517
522
523
524
525
526
527
532
533
534
535
545
546
549
550
551
552
553
554
555
556
557
558 template <
typename U>
563
564
565
566
567
568
569
570
574
575
576
577
578
579
580
584
585
586
587
588
589
590
594
595
596
597
598
599
600
601
602
603
607
608
609
610
611
612
613
614
615
619
620
621
622
623
624
625
629
630
631
632
633
634
635
639
640
641
642
643
644
645
649
650
651
652
653
654
655
659
660
661
662
663
664
665
666
670
671
672
673
674
675
676
677
681
682
683
684
685
686
687
688
692
693
694
695
696
697
698
699
703
704
705
706
707
708
709
710
711
715
716
717
718
719
720
721
722
723
727
728
729
730
731
732
733
734
736 if (i >= m || j >= m)
737 throw std::invalid_argument(
"trying to add row to other row, at least one of them is non-existent");
738 return add_scaled_row(T(1), i, j);
742
743
744
745
746
747
748
749
751 if (i >= n || j >= n)
752 throw std::invalid_argument(
"trying to add column to other column, at least one of them is non-existent");
754 add_scaled_row(T(1), i, j);
760
761
762
763
764
765
766
770
771
772
773
774
775
776
780
781
782
783
784
785
786
790
791
792
793
794
795
796
799#ifdef CECCO_ERASURE_SUPPORT
802
803
804
805
806
807
808
809
810
811
812
813
814
815
820
821
822
823
824
825
826
827
832
833
834
835
836
837
838
839
840
845
846
847
848
849
850
851
859
860
861
862
863
864
865
870
871
872
873
874
875
876
884
885
886
887
888
889
890
891
892
897
898
899
900
901
902
903
911
912
913
914
915
916
917
922
923
924
925
926
927
928
940
941
944
945
946
947
951
952
953
954
958
959
960
961
962
963
964
968
969
970
971
972
973
977
978
979
980
981
982
983
984
985
990
991
992
993
994
995
996
997
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1019
1020
1023
1024
1025
1026
1027
1028
1029
1030 template <FiniteFieldType S>
1035
1036
1037
1038
1042
1043
1044
1045
1046
1047
1048
1049
1050
1058 std::vector<T> data;
1066 bool transposed =
false;
1072 enum CacheIds { Rank = 0, Weight = 1 };
1075 size_t calculate_weight()
const
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088 constexpr void determine_type_tag() {
1089 if constexpr (!ReliablyComparableType<T>)
return;
1091 const auto at = [
this](size_t i, size_t j) ->
const T& {
1092 return transposed ? data[i + j * m] : data[i * n + j];
1096 bool all_zero =
true;
1097 bool diagonal = (m == n);
1098 bool all_identity = (m == n);
1099 bool toeplitz =
true;
1100 for (size_t i = 0; i < m; ++i) {
1101 for (size_t j = 0; j < n; ++j) {
1102 const T& x = at(i, j);
1104 if (x != zero) all_zero =
false;
1105 if (x != one) all_identity =
false;
1106 }
else if (x != zero) {
1109 all_identity =
false;
1111 if (i > 0 && j > 0 && x != at(i - 1, j - 1)) toeplitz =
false;
1113 if (!all_zero && !diagonal && !toeplitz)
return;
1117 else if (all_identity)
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137 template <
bool this_transposed,
bool rhs_transposed>
1138 static void multiply_kernel(
const T* this_data,
const T* rhs_data, T* res_data, size_t M, size_t K, size_t N,
1140 for (size_t ii = 0; ii < M; ii += BS) {
1141 const size_t imax = std::min(ii + BS, M);
1142 for (size_t kk = 0; kk < K; kk += BS) {
1143 const size_t kmax = std::min(kk + BS, K);
1144 for (size_t jj = 0; jj < N; jj += BS) {
1145 const size_t jmax = std::min(jj + BS, N);
1146 for (size_t i = ii; i < imax; ++i) {
1147 for (size_t k = kk; k < kmax; ++k) {
1148 const size_t this_idx = this_transposed ? (i + k * M) : (i * K + k);
1149 const T aik = this_data[this_idx];
1150 const size_t res_row_offset = i * N;
1151 for (size_t j = jj; j < jmax; ++j) {
1152 const size_t rhs_idx = rhs_transposed ? (k + j * K) : (k * N + j);
1153 res_data[res_row_offset + j] += aik * rhs_data[rhs_idx];
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173 template <
bool transposed>
1174 static void eliminate_row_kernel(T* data, size_t m, size_t n, size_t target_row, size_t pivot_row, size_t start_col,
1176 if constexpr (!transposed) {
1178 T* target_data = data + target_row * n;
1179 const T* pivot_data = data + pivot_row * n;
1180 for (size_t j = start_col; j < n; ++j) {
1181 target_data[j] -= f * pivot_data[j];
1185 for (size_t j = start_col; j < n; ++j) {
1186 data[target_row + j * m] -= f * data[pivot_row + j * m];
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201 template <
bool transposed>
1202 static size_t ref_elimination_kernel(T* data, size_t m, size_t n, size_t h, size_t k) {
1204 while (h < m && k < n) {
1208 for (size_t row = h; row < m; ++row) {
1209 const size_t idx = transposed ? (row + k * m) : (row * n + k);
1210 if (data[idx] != zero) {
1220 if constexpr (!transposed)
1221 std::swap_ranges(data + h * n, data + (h + 1) * n, data + p * n);
1223 for (size_t j = 0; j < n; ++j)
std::swap(data[h + j * m], data[p + j * m]);
1225 if constexpr (!std::is_same_v<T, Fp<2>>) {
1226 const size_t pivot_idx = transposed ? (h + k * m) : (h * n + k);
1227 const T inv = T(1) / data[pivot_idx];
1228 if constexpr (!transposed) {
1229 for (size_t j = k; j < n; ++j) data[h * n + j] *= inv;
1231 for (size_t j = k; j < n; ++j) data[h + j * m] *= inv;
1236 for (size_t i = h + 1; i < m; ++i) {
1237 const size_t f_idx = transposed ? (i + k * m) : (i * n + k);
1238 const T f = data[f_idx];
1240 if (f != zero) eliminate_row_kernel<transposed>(data, m, n, i, h, k, f);
1251
1252
1253
1254
1255
1256
1257
1258 template <
bool transposed>
1259 void rref_backward_elimination_kernel(T* data, size_t m, size_t n, size_t r) {
1261 for (size_t i = 0; i < r; ++i) {
1262 const size_t pivot_row = r - 1 - i;
1265 size_t pivot_col = 0;
1266 while (pivot_col < n) {
1267 const size_t pivot_idx = transposed ? (pivot_row + pivot_col * m) : (pivot_row * n + pivot_col);
1268 if (data[pivot_idx] != zero) {
1274 if (pivot_col < n) {
1276 for (size_t row = 0; row < pivot_row; ++row) {
1277 const size_t f_idx = transposed ? (row + pivot_col * m) : (row * n + pivot_col);
1278 const T f = data[f_idx];
1280 if (f != zero) eliminate_row_kernel<transposed>(data, m, n, row, pivot_row, pivot_col, f);
1287
1288
1289 size_t calculate_rank()
const
1295template <ComponentType T>
1300template <ComponentType T>
1303 if (l.size() != m * n) {
1304 throw std::invalid_argument(
1305 "number of elements in initializer list does not correspond to number of rows and columns specified");
1307 determine_type_tag();
1310template <ComponentType T>
1313 for (
auto it = l.begin(); it != l.end(); ++it) {
1314 if (it->size() > n) n = it->size();
1317 data.resize(m * n, T(0));
1320 for (
auto row = l.begin(); row != l.end(); ++row) {
1322 for (
auto val = row->begin(); val != row->end(); ++val) set_component(i, j++, *val);
1325 determine_type_tag();
1328template <ComponentType T>
1330 std::copy(v.data.begin(), v.data.end(), data.begin());
1333 cache.
template set<Rank>(0);
1334 cache.
template set<Weight>(0);
1336 if constexpr (ReliablyComparableType<T>) {
1337 if (n == 1 && data[0] != T(0)) {
1338 if (data[0] == T(1))
1342 cache.
template set<Rank>(1);
1343 cache.
template set<Weight>(1);
1344 }
else if (v.is_zero()) {
1346 cache.
template set<Rank>(0);
1347 cache.
template set<Weight>(0);
1349 cache.
template set<Rank>(1);
1356template <FiniteFieldType S>
1369template <ComponentType T>
1379 if (
tok[0] ==
'#') {
1426#ifdef CECCO_ERASURE_SUPPORT
1438template <ComponentType T>
1440 if (
this == &rhs)
return *
this;
1444 transposed = rhs.transposed;
1450template <ComponentType T>
1452 if (
this == &rhs)
return *
this;
1453 data = std::move(rhs.data);
1456 transposed = rhs.transposed;
1458 cache = std::move(rhs.cache);
1461 rhs.transposed =
false;
1463 rhs.cache.invalidate();
1481template <ComponentType T>
1484 if constexpr (FiniteFieldType<T>) {
1485 if constexpr (T::get_characteristic() == 2)
return res;
1488 std::ranges::for_each(res.data, [](T& x) { x = -x; });
1494 for (size_t mu = 0; mu < m; ++mu) res.data[mu * n + mu] = -res.data[mu * n + mu];
1500template <ComponentType T>
1502 if constexpr (FiniteFieldType<T>) {
1503 if constexpr (T::get_characteristic() == 2)
return std::move(*
this);
1506 std::ranges::for_each(data, [](T& x) { x = -x; });
1513 for (size_t mu = 0; mu < m; ++mu) data[mu * n + mu] = -data[mu * n + mu];
1516 return std::move(*
this);
1519template <ComponentType T>
1521 if (m != rhs.m || n != rhs.n)
1522 throw std::invalid_argument(
1523 "trying to add two matrices of different "
1533 for (size_t mu = 0; mu < m; ++mu) data[mu * n + mu] += rhs.data[mu * n + mu];
1534 if constexpr (ReliablyComparableType<T>) {
1536 bool identity =
true;
1537 for (size_t mu = 0; mu < m && (zero || identity); ++mu) {
1538 const T& x = data[mu * n + mu];
1539 if (x != T(0)) zero =
false;
1540 if (x != T(1)) identity =
false;
1554 if (transposed == rhs.transposed) {
1555 std::transform(data.begin(), data.end(), rhs.data.begin(), data.begin(), std::plus<T>{});
1558 const T* b = rhs.data.data();
1559 for (size_t mu = 0; mu < m; ++mu)
1560 for (size_t nu = 0; nu < n; ++nu)
1561 a[transposed ? (mu + nu * m) : (mu * n + nu)] += b[rhs.transposed ? (mu + nu * m) : (mu * n + nu)];
1565 determine_type_tag();
1569template <ComponentType T>
1571 if (m != rhs.m || n != rhs.n)
1572 throw std::invalid_argument(
1573 "trying to subtract two matrices of different "
1575 if constexpr (FiniteFieldType<T>) {
1576 if constexpr (T::get_characteristic() == 2)
return operator+=(rhs
);
1586 for (size_t mu = 0; mu < m; ++mu) data[mu * n + mu] -= rhs.data[mu * n + mu];
1587 if constexpr (ReliablyComparableType<T>) {
1589 bool identity =
true;
1590 for (size_t mu = 0; mu < m && (zero || identity); ++mu) {
1591 const T& x = data[mu * n + mu];
1592 if (x != T(0)) zero =
false;
1593 if (x != T(1)) identity =
false;
1607 if (transposed == rhs.transposed) {
1608 std::transform(data.begin(), data.end(), rhs.data.begin(), data.begin(), std::minus<T>{});
1611 const T* b = rhs.data.data();
1612 for (size_t mu = 0; mu < m; ++mu)
1613 for (size_t nu = 0; nu < n; ++nu)
1614 a[transposed ? (mu + nu * m) : (mu * n + nu)] -= b[rhs.transposed ? (mu + nu * m) : (mu * n + nu)];
1618 determine_type_tag();
1622template <ComponentType T>
1625 throw std::invalid_argument(
1626 "trying to multiply two matrices "
1627 "with incompatible dimensions");
1629 *
this = Matrix(m, rhs.n);
1638 for (size_t mu = 0; mu < m; ++mu) data[mu * n + mu] *= rhs.data[mu * n + mu];
1639 if constexpr (ReliablyComparableType<T>) {
1641 bool identity =
true;
1642 for (size_t mu = 0; mu < m && (zero || identity); ++mu) {
1643 const T& x = data[mu * n + mu];
1644 if (x != T(0)) zero =
false;
1645 if (x != T(1)) identity =
false;
1657 for (size_t mu = 0; mu < m; ++mu) res.scale_row((*
this)(mu, mu), mu);
1658 *
this =
std::move(res);
1664 for (size_t mu = 0; mu < m; ++mu)
1665 for (size_t nu = 0; nu < n; ++nu) data[mu * n + nu] *= rhs.data[nu * rhs.n + nu];
1667 for (size_t nu = 0; nu < n; ++nu) {
1668 const T& s = rhs.data[nu * rhs.n + nu];
1669 for (size_t mu = 0; mu < m; ++mu) data[mu + nu * m] *= s;
1674 const size_t M = get_m();
1675 const size_t K = get_n();
1676 const size_t N = rhs.get_n();
1677 Matrix<T> res(M, N, T(0));
1679 const T* this_data =
this->data.data();
1680 const T* rhs_data = rhs.data.data();
1681 T* res_data = res.data.data();
1684 constexpr size_t BS = 64;
1686 if (!
this->transposed && !rhs.transposed) {
1687 multiply_kernel<
false,
false>(this_data, rhs_data, res_data, M, K, N, BS);
1688 }
else if (
this->transposed && !rhs.transposed) {
1689 multiply_kernel<
true,
false>(this_data, rhs_data, res_data, M, K, N, BS);
1690 }
else if (!
this->transposed && rhs.transposed) {
1691 multiply_kernel<
false,
true>(this_data, rhs_data, res_data, M, K, N, BS);
1693 multiply_kernel<
true,
true>(this_data, rhs_data, res_data, M, K, N, BS);
1696 *
this =
std::move(res);
1698 determine_type_tag();
1703template <ComponentType T>
1706 *
this = Matrix(m, n);
1710 std::ranges::for_each(data, [&s](T& x) { x *= s; });
1713 for (size_t mu = 0; mu < m; ++mu) data[mu * n + mu] *= s;
1719template <ComponentType T>
1740template <ComponentType T>
1763template <ComponentType T>
1764size_t
Matrix<T>::calculate_weight()
const
1767 if (
m == 0 ||
n == 0)
return 0;
1773#ifdef CECCO_ERASURE_SUPPORT
1780template <ComponentType T>
1787template <ComponentType T>
1789 if (m != n)
throw std::invalid_argument(
"trying to extract diagonal of non-square matrix");
1791 for (size_t i = 0; i < n; ++i) res.data[i] = (*
this)(i, i);
1792 res.cache.invalidate();
1800 if (
m !=
n)
throw std::
invalid_argument(
"trying to calculate characteristic polynomial of non-square matrix");
1801 if (
m == 0)
throw std::
invalid_argument(
"trying to calculate characteristic polynomial of empty matrix");
1811 T a = (*
this)(
i,
i);
1817 }
else if (
m -
i == 2) {
1862 throw std::
logic_error(
"characteristic_polynomial(): unhandled matrix type");
1929 if (
m == 1)
return ((*
this))(0, 0);
1933 return (
m % 2 == 0) ?
c : -
c;
1979 throw std::
out_of_range(
"row space too big (more than 10^10 elements) to compute all elements");
2003template <
typename U>
2025 if (
i ==
j &&
m ==
n)
2054 if (
m == 1 &&
n == 1) {
2104 if (
i +
h >
m ||
j +
w >
n)
2106 "trying to extract a submatrix with incompatible "
2135 }
else if (
i ==
j &&
h ==
w) {
2146 "trying to replace submatrix with "
2147 "matrix of incompatible dimensions");
2167 "trying to horizontally join two "
2168 "matrices of incompatible dimensions");
2196 "trying to vertically join two "
2197 "matrices of incompatible dimensions");
2277 const T&
s = (*
this)(
mu,
mu);
2295 const T&
s = (*
this)(
mu,
nu);
2317 if (
i ==
j)
return *
this;
2332 if (
i ==
j)
return *
this;
2348 if (
s ==
T(1))
return *
this;
2362 if ((*
this)(
i,
i) ==
T(0))
return *
this;
2383 if (
s ==
T(1))
return *
this;
2392 if (
i >=
m ||
j >=
m)
2393 throw std::
invalid_argument(
"trying to add scaled row to other row, at least one of them is non-existent");
2394 if (
s ==
T(0))
return *
this;
2414 if (
pivot ==
T(0))
return *
this;
2426 if (
i >=
n ||
j >=
n)
2428 "trying to add scaled column to other column, at least one of them is non-existent");
2429 if (
s ==
T(0))
return *
this;
2438 if (
v.
empty())
return *
this;
2486 if (
v.
empty())
return *
this;
2514#ifdef CECCO_ERASURE_SUPPORT
2552 if (
v.
empty())
return *
this;
2572 if (
v.
empty())
return *
this;
2667 if (
m == 1 &&
n == 1 &&
l !=
T(0)) {
2674 }
else if (
l ==
T(0)) {
2729 if ((*
this)(
i,
i) ==
T(0)) {
2772 if (
r ==
m &&
m ==
n)
2774 else if (
r ==
n &&
n > 0)
2813 if ((*
this)(
i,
i) ==
T(0)) {
2877 if ((*
this)(
mu,
mu) ==
T(0))
2879 "trying to invert a non-invertible matrix/a diagonal matrix with at least one zero on the "
2896 throw std::
invalid_argument(
"trying to create superfield vector from subfield matrix, wrong number of rows");
2930#ifdef CECCO_ERASURE_SUPPORT
2946 file <<
std::
setw(3) <<
static_cast<
int>(
r) <<
" " <<
std::
setw(3) <<
static_cast<
int>(
g) <<
" "
2947 <<
std::
setw(3) <<
static_cast<
int>(
b) <<
" ";
2968
2969
3000
3001
3032
3033
3050
3051
3064
3065
3082
3083
3100
3101
3137
3138
3139
3140
3141
3142
3143
3148 "trying to calculate Hamming distance between matrices of different "
3158 "trying to calculate Hamming distance between matrices of different "
3167 "trying to calculate Hamming distance between matrices of different "
3176 "trying to calculate Hamming distance between matrices of different "
3466#ifdef CECCO_ERASURE_SUPPORT
3695
3696
3697
3698
3699
3700
3701
3708 }
else if (
lhs.
m == 1) {
3710 }
else if (
lhs.
n == 1) {
3745
3746
3747
3748
3755
3756
3757
3758
3759
3760
3761
3765 os <<
" (empty matrix)";
3784 os <<
" " << (
rhs.
m == 1 ?
"(" :
"⌈");
3790 os << (
rhs.
m == 1 ?
")" :
"⌉");
3816
3817
3820
3821
3822
3823
3824
3825
3832
3833
3834
3835
3836
3846
3847
3848
3849
3850
3851
3852
3861 throw std::
invalid_argument(
"Trying to construct permutation matrix from a list that is not a permutation");
3875
3876
3877
3878
3879
3888
3889
3890
3891
3892
3893
3916 }
else if (
m != 0) {
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3938 "vector for constructing m x n Toeplitz matrix must have "
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3980
3981
3982
3983
3984
3985
3986
3987
3993 "vector for constructing Vandermonde matrix must have "
3994 "at least one element");
3995 if (
m == 0)
throw std::
invalid_argument(
"trying to construct Vandermonde matrix with zero rows");
3997 throw std::
invalid_argument(
"vector for constructing Vandermonde matrix must have pairwise distinct elements");
4015
4016
4017
4018
4019
4029
4030
4031
4032
4033
4040
4041
4042
4043
4044
4045
4046
4047
4048
Dense m × n matrix over a CECCO::ComponentType.
Matrix(std::initializer_list< std::initializer_list< T > > l)
From nested initializer lists, e.g. {{1, 2, 3}, {4, 5, 6}}.
Matrix(size_t m, size_t n, const T &l)
m × n matrix with every component equal to l
constexpr bool is_empty() const noexcept
Check if matrix is empty.
constexpr bool is_zero()
Check if the matrix is zero, caching the result via the type tag.
Matrix< T > & swap_columns(size_t i, size_t j)
Swap columns i and j.
constexpr Matrix operator+() const &
Unary + (lvalue): returns a copy.
Matrix & randomize()
Fill matrix with random values.
Matrix< T > & diagonal_join(const Matrix &other)
Block-diagonal join: this in the upper-left, other in the lower-right.
size_t wH() const
Hamming weight: number of non-zero, non-erased components; cached on first call.
Matrix< T > get_submatrix(size_t i, size_t j, size_t h, size_t w) const
Extract submatrix from region [i, i+h) × [j, j+w).
constexpr Matrix & operator=(const Matrix &rhs)
constexpr Matrix & operator=(Matrix &&rhs) noexcept
friend constexpr Matrix< T > ToeplitzMatrix(const Vector< T > &v, size_t m, size_t n)
m × n Toeplitz matrix from its diagonal entries
bool is_invertible() const
Check if matrix is invertible.
Matrix(const std::string &filename)
Read from a PPM (P3) image file using the 64-entry colormap of export_as_ppm.
Vector< T > to_vector() const
Flatten in row-major order.
Matrix< T > basis_of_kernel() const
Alias for basis_of_nullspace.
Matrix< T > & add_scaled_column(const T &s, size_t i, size_t j)
col[j] ← col[j] + s · col[i]
const T & operator()(size_t i, size_t j) const
Access component (i, j) (read-only).
Matrix & operator-=(const Matrix &rhs)
Component-wise subtraction this(i, j) -= rhs(i, j).
constexpr size_t get_m() const noexcept
Get the number of rows.
constexpr Matrix operator-() const &
Unary − (lvalue): returns a new matrix with each component negated.
constexpr Matrix() noexcept=default
Default constructor: empty matrix.
constexpr bool is_zero() const
Check if the matrix is zero (no caching).
Matrix< T > & reverse_columns()
Reverse the column order.
constexpr Matrix(const Matrix &other)
void export_as_ppm(const std::string &filename) const
Export the matrix as a PPM (P3) image.
Matrix< T > & set_submatrix(size_t i, size_t j, const Matrix &N)
Overwrite the region starting at (i, j) with N.
Matrix & operator*=(const Matrix &rhs)
Matrix multiplication *this = *this · rhs.
Matrix< T > & horizontal_join(const Matrix &other)
Concatenate other to the right (column-wise).
constexpr size_t get_n() const noexcept
Get the number of columns.
friend constexpr bool operator==(const Matrix< U > &lhs, const Matrix< U > &rhs)
constexpr Matrix(size_t m, size_t n, std::initializer_list< T > l)
m × n matrix from a flat initializer list (row-major)
constexpr Matrix operator-() &&
Unary − (rvalue): negates components in place.
Vector< T > get_col(size_t j) const
Extract column j as a (row) vector.
Matrix(const Vector< T > &v)
1 × n row matrix from a Vector<T>
constexpr Matrix(size_t m, size_t n)
m × n zero matrix (tag details::Zero)
Matrix< T > & scale_row(const T &s, size_t i)
row[i] ← s · row[i]
friend constexpr Matrix< T > DiagonalMatrix(const Vector< T > &v)
Diagonal matrix with diagonal v (strongest tag of details::Zero, details::Identity,...
Matrix & operator/=(const T &s)
Divide every component by the scalar s.
friend constexpr Matrix< T > IdentityMatrix(size_t m)
m × m identity matrix I_m
constexpr Matrix< T > & transpose()
Transpose in place.
constexpr Matrix(Matrix &&other) noexcept
Matrix< T > & delete_rows(const std::vector< size_t > &v)
Delete the rows whose indices appear in v.
constexpr Matrix(const Matrix< S > &other)
Cross-field conversion between two finite fields of the same characteristic.
Matrix< T > & add_scaled_row(const T &s, size_t i, size_t j)
row[j] ← row[j] + s · row[i]
Matrix< T > & add_row(size_t i, size_t j)
row[j] ← row[j] + row[i]
constexpr Matrix operator+() &&noexcept
Unary + (rvalue): returns the rvalue itself.
Matrix< T > & rref(size_t *rank_ptr=nullptr)
Reduced row echelon form (RREF).
Matrix< T > & reverse_rows()
Reverse the row order.
Matrix< T > & scale_column(const T &s, size_t i)
col[i] ← s · col[i]
Matrix< T > basis_of_nullspace() const
Basis of the nullspace (right kernel).
constexpr Matrix< T > & fill(const T &l)
Set every component to l.
Matrix & operator+=(const Matrix &rhs)
Component-wise addition this(i, j) += rhs(i, j).
Matrix< T > & Kronecker_product(const Matrix &other)
Kronecker (tensor) product with other.
Matrix< T > & swap_rows(size_t i, size_t j)
Swap rows i and j.
Vector< T > get_row(size_t i) const
Extract row i as a vector.
constexpr Vector< S > as_vector() const
Reinterpret the columns as elements of a superfield.
constexpr Matrix & operator*=(const T &s)
Multiply every component by the scalar s.
Matrix< T > & delete_column(size_t i)
Delete column i (single-index convenience for delete_columns).
std::vector< Vector< T > > rowspace() const
Enumerate every vector in the row space.
Matrix< T > & add_column(size_t i, size_t j)
col[j] ← col[j] + col[i]
Matrix< T > & vertical_join(const Matrix &other)
Concatenate other below (row-wise).
Matrix< T > & invert()
Invert in place.
Matrix< T > & delete_columns(const std::vector< size_t > &v)
Delete the columns whose indices appear in v.
std::vector< T > eigenvalues() const
Eigenvalues lying in the underlying finite field.
std::vector< Vector< T > > span() const
Alias for rowspace.
Matrix< T > & delete_row(size_t i)
Delete row i (single-index convenience for delete_rows).
Matrix< T > & ref(size_t *rank_ptr=nullptr)
Row echelon form (REF), with a binary-field fast path.
Univariate polynomial p(x) = a₀ + a₁x + … + aₙxⁿ over a CECCO::CoefficientType.
Vector v = (v₀, v₁, …, vₙ₋₁) over a CECCO::ComponentType.
Contains implementation details not to be exposed to the user. Functions and classes here may change ...
matrix_type_t
Matrix structural type tag for optimization (internal).
@ Generic
Generic matrix with arbitrary elements.
@ Identity
Identity matrix with ones on diagonal and zeros elsewhere.
@ Toeplitz
Toeplitz matrix T_{i,j} = t_{i-j} with constant diagonals.
@ Zero
Zero matrix with all elements equal to zero.
@ Vandermonde
Vandermonde matrix with arithmetic progressions (of pairwise distinct elements) in columns.
@ Diagonal
Diagonal matrix (square) with non-zero elements only on the main diagonal.
Provides a framework for error correcting codes.
constexpr Matrix< T > ToeplitzMatrix(const Vector< T > &v, size_t m, size_t n)
m × n Toeplitz matrix from its diagonal entries
constexpr Matrix< T > VandermondeMatrix(const Vector< T > &v, size_t m)
Vandermonde matrix V_{i, j} = v[j]^i.
constexpr Matrix< T > DiagonalMatrix(const Vector< T > &v)
Diagonal matrix with diagonal v (strongest tag of details::Zero, details::Identity,...
constexpr Matrix< T > IdentityMatrix(size_t m)
m × m identity matrix I_m
constexpr Matrix< T > ZeroMatrix(size_t m, size_t n)
m × n matrix of zeros (tag details::Zero)