t
This commit is contained in:
171
srctmp/graph.rs
171
srctmp/graph.rs
@ -1,171 +0,0 @@
|
||||
use crate::matrix::SparseMatrixGF2;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
// Graphe de Tanner
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TannerGraph {
|
||||
pub n_var: usize,
|
||||
pub n_chk: usize,
|
||||
var_to_chk: Vec<Vec<usize>>,
|
||||
chk_to_var: Vec<Vec<usize>>,
|
||||
}
|
||||
|
||||
impl TannerGraph {
|
||||
pub fn from_matrix(h: &SparseMatrixGF2) -> Self {
|
||||
let n_var = h.cols;
|
||||
let n_chk = h.rows;
|
||||
let chk_to_var: Vec<Vec<usize>> = (0..n_chk).map(|c| h.row_neighbors(c).to_vec()).collect();
|
||||
let mut var_to_chk = vec![vec![]; n_var];
|
||||
for c in 0..n_chk {
|
||||
for &v in &chk_to_var[c] {
|
||||
var_to_chk[v].push(c);
|
||||
}
|
||||
}
|
||||
Self {
|
||||
n_var,
|
||||
n_chk,
|
||||
var_to_chk,
|
||||
chk_to_var,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var_neighbors(&self, v: usize) -> &[usize] {
|
||||
&self.var_to_chk[v]
|
||||
}
|
||||
pub fn chk_neighbors(&self, c: usize) -> &[usize] {
|
||||
&self.chk_to_var[c]
|
||||
}
|
||||
pub fn var_degree(&self, v: usize) -> usize {
|
||||
self.var_to_chk[v].len()
|
||||
}
|
||||
pub fn chk_degree(&self, c: usize) -> usize {
|
||||
self.chk_to_var[c].len()
|
||||
}
|
||||
|
||||
// Calcule le girth par BFS depuis chaque noeud de variable
|
||||
// O(n * (n + m))
|
||||
pub fn girth(&self) -> usize {
|
||||
let mut min_girth = usize::MAX;
|
||||
for start in 0..self.n_var {
|
||||
if let Some(g) = self.bfs_girth_from_var(start) {
|
||||
min_girth = min_girth.min(g);
|
||||
if min_girth == 4 {
|
||||
return 4;
|
||||
} // minimum possible
|
||||
}
|
||||
}
|
||||
min_girth
|
||||
}
|
||||
|
||||
// Détection rapide de cycles-4, deux var-nodes partagent >= check-nodes
|
||||
pub fn has_4_cycle(&self) -> bool {
|
||||
for v1 in 0..self.n_var {
|
||||
for v2 in (v1 + 1)..self.n_var {
|
||||
let common = self.var_to_chk[v1]
|
||||
.iter()
|
||||
.filter(|c| self.var_to_chk[v2].contains(c))
|
||||
.count();
|
||||
if common >= 2 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// Girth local depuis un noeud de variable v (pour PEG).
|
||||
pub fn local_girth_from_var(&self, v: usize) -> usize {
|
||||
self.bfs_girth_from_var(v).unwrap_or(usize::MAX)
|
||||
}
|
||||
|
||||
// BFS depuis le noeud de variable start,
|
||||
// retourne la longueur du court cycle passant par ce noeud (None si aucun cycle)
|
||||
fn bfs_girth_from_var(&self, start: usize) -> Option<usize> {
|
||||
// dist_var[v] = distance depuis start jusqu'au var-node v
|
||||
// dist_chk[c] = distance depuis start jusqu'au check-node c
|
||||
let mut dist_var = vec![usize::MAX; self.n_var];
|
||||
let mut dist_chk = vec![usize::MAX; self.n_chk];
|
||||
dist_var[start] = 0;
|
||||
|
||||
// File : (is_var: bool, index, distance)
|
||||
let mut queue: VecDeque<(bool, usize, usize)> = VecDeque::new();
|
||||
queue.push_back((true, start, 0));
|
||||
let mut shortest = None;
|
||||
|
||||
while let Some((is_var, node, dist)) = queue.pop_front() {
|
||||
if is_var {
|
||||
for &c in self.var_neighbors(node) {
|
||||
if dist_chk[c] == usize::MAX {
|
||||
dist_chk[c] = dist + 1;
|
||||
queue.push_back((false, c, dist + 1));
|
||||
} else {
|
||||
// Cycle trouvé
|
||||
let cycle_len = dist + 1 + dist_chk[c];
|
||||
shortest = Some(shortest.map_or(cycle_len, |s: usize| s.min(cycle_len)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for &v in self.chk_neighbors(node) {
|
||||
if v == start && dist + 1 >= 2 {
|
||||
let cycle_len = dist + 1;
|
||||
shortest = Some(shortest.map_or(cycle_len, |s: usize| s.min(cycle_len)));
|
||||
continue;
|
||||
}
|
||||
if dist_var[v] == usize::MAX {
|
||||
dist_var[v] = dist + 1;
|
||||
queue.push_back((true, v, dist + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
shortest
|
||||
}
|
||||
|
||||
pub fn var_degree_distribution(&self) -> Vec<f64> {
|
||||
let max_deg = self.var_to_chk.iter().map(|v| v.len()).max().unwrap_or(0);
|
||||
let mut counts = vec![0usize; max_deg + 1];
|
||||
for v in 0..self.n_var {
|
||||
counts[self.var_degree(v)] += 1;
|
||||
}
|
||||
counts
|
||||
.iter()
|
||||
.map(|&c| c as f64 / self.n_var as f64)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn is_regular(&self) -> bool {
|
||||
let d0 = self.var_degree(0);
|
||||
let c0 = self.chk_degree(0);
|
||||
self.var_to_chk.iter().all(|v| v.len() == d0)
|
||||
&& self.chk_to_var.iter().all(|c| c.len() == c0)
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use crate::matrix::SparseMatrixGF2;
|
||||
//
|
||||
// fn simple_h() -> SparseMatrixGF2 {
|
||||
// SparseMatrixGF2::from_dense(&vec![
|
||||
// vec![1u8, 1, 0, 1, 0],
|
||||
// vec![0, 1, 1, 0, 1],
|
||||
// vec![1, 0, 1, 0, 1],
|
||||
// ])
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_construction_from_matrix() {
|
||||
// let h = simple_h();
|
||||
// let g = TannerGraph::from_matrix(&h);
|
||||
// assert_eq!(g.n_var, 5);
|
||||
// assert_eq!(g.n_chk, 3);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_var_degree() {
|
||||
// let g = TannerGraph::from_matrix(&simple_h());
|
||||
// assert_eq!(g.var_degree(0), 2);
|
||||
// }
|
||||
// }
|
||||
Reference in New Issue
Block a user