use crate::rand::{Rng, *};
use crate::sparse::{Node, SparseMatrix};
use crate::util::{compare_some, *};
use std::cmp::Ordering;
use std::fmt;
use std::fmt::{Display, Formatter};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
NoAvailRows,
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Error::NoAvailRows => write!(f, "not enough rows available"),
}
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Config {
pub nrows: usize,
pub ncols: usize,
pub wc: usize,
}
impl Config {
pub fn run(&self, seed: u64) -> Result<SparseMatrix> {
Peg::new(self, seed).run()
}
}
struct Peg {
wc: usize,
h: SparseMatrix,
rng: Rng,
}
impl Peg {
fn new(conf: &Config, seed: u64) -> Peg {
Peg {
wc: conf.wc,
h: SparseMatrix::new(conf.nrows, conf.ncols),
rng: Rng::seed_from_u64(seed),
}
}
fn insert_edge(&mut self, col: usize) -> Result<()> {
let row_dist = self.h.bfs(Node::Col(col)).row_nodes_distance;
let row_num_dist_and_weight: Vec<_> = row_dist
.into_iter()
.enumerate()
.map(|(j, d)| (j, d, self.h.row_weight(j)))
.collect();
let selected_row = row_num_dist_and_weight
.sort_by_random_min(
|(_, x, w), (_, y, v)| match compare_some(x, y).reverse() {
Ordering::Equal => w.cmp(v),
c => c,
},
&mut self.rng,
)
.ok_or(Error::NoAvailRows)?
.0;
self.h.insert(selected_row, col);
Ok(())
}
fn run(mut self) -> Result<SparseMatrix> {
for col in 0..self.h.num_cols() {
for _ in 0..self.wc {
self.insert_edge(col)?;
}
}
Ok(self.h)
}
}