haar_lib/linalg/mod_p/
lineq.rs1use crate::{linalg::mod_p::gaussian_elim::*, num::ff::*};
6
7pub fn lineq<F>(
17 mut a: Vec<Vec<F::Element>>,
18 b: Vec<F::Element>,
19 modulo: &F,
20) -> Option<(Vec<F::Element>, Vec<Vec<F::Element>>)>
21where
22 F: FF,
23 F::Element: FFElem,
24{
25 let n = a.len();
26 assert_eq!(b.len(), n);
27
28 let Some(m) = a.first().map(|a| a.len()) else {
29 panic!("行数は0以上でなければならない。")
30 };
31 assert!(a.iter().all(|r| r.len() == m));
32
33 for (r, bi) in a.iter_mut().zip(b.iter()) {
34 r.push(*bi);
35 }
36
37 let (rank, mut a) = gaussian_elim(a);
38
39 let dim = m - rank;
40
41 let b: Vec<_> = a.iter_mut().map(|r| r.pop().unwrap()).collect();
42
43 if rank > 0 && a[rank - 1].iter().all(|x| x.value() == 0) {
44 return None;
45 }
46
47 let mut index_zero = vec![];
48 let mut index_one = vec![];
49 {
50 let mut k = 0;
51 for ai in a.iter().take(rank) {
52 for (j, aij) in ai.iter().enumerate().take(m).skip(k) {
53 if aij.value() != 0 {
54 index_one.push(j);
55 k = j + 1;
56 break;
57 }
58 index_zero.push(j);
59 }
60 }
61 for j in k..m {
62 index_zero.push(j);
63 }
64 }
65
66 assert_eq!(index_zero.len(), dim);
67 assert_eq!(index_one.len(), rank);
68
69 let mut sol = vec![modulo.zero(); m];
70 for (i, x) in b.into_iter().take(rank).enumerate() {
71 sol[index_one[i]] = x;
72 }
73
74 let mut bases = vec![vec![modulo.zero(); m]; dim];
75 for i in 0..rank {
76 for (j, &k) in index_zero.iter().enumerate() {
77 bases[j][index_one[i]] = -a[i][k];
78 }
79 }
80
81 for i in 0..dim {
82 bases[i][index_zero[i]] = modulo.one();
83 }
84
85 Some((sol, bases))
86}