use alloc::{vec, vec::Vec};
use core::fmt::Debug;
pub mod errors;
mod inner;
pub use errors::CrouseError;
use crate::{
impls::compactify,
traits::{Number, SparseMatrix2D, SparseValuedMatrix2D, TryFromUsize},
};
pub trait Crouse: SparseValuedMatrix2D + Sized
where
Self::Value: Number + Into<f64>,
Self::RowIndex: TryFromUsize + Ord,
Self::ColumnIndex: TryFromUsize + Ord,
{
#[allow(clippy::type_complexity)]
#[inline]
fn crouse(
&self,
non_edge_cost: f64,
max_cost: f64,
) -> Result<Vec<(Self::RowIndex, Self::ColumnIndex)>, CrouseError>
where
<Self::ColumnIndex as TryFrom<usize>>::Error: Debug,
<Self::RowIndex as TryFrom<usize>>::Error: Debug,
{
if !max_cost.is_finite() {
return Err(CrouseError::MaximalCostNotFinite);
}
if max_cost <= 0.0 {
return Err(CrouseError::MaximalCostNotPositive);
}
if self.is_empty() {
return Ok(Vec::new());
}
let compact = compactify(self);
let nr = compact.row_map.len();
let nc = compact.col_map.len();
if nr == 0 || nc == 0 {
return Ok(Vec::new());
}
let transposed = nr > nc;
let (eff_nr, eff_nc) = if transposed { (nc, nr) } else { (nr, nc) };
let mut dense = vec![non_edge_cost; eff_nr * eff_nc];
if transposed {
for compact_row in 0..nr {
for (compact_col, value) in compact
.matrix
.sparse_row(compact_row)
.zip(compact.matrix.sparse_row_values(compact_row))
{
dense[compact_col * eff_nc + compact_row] = value;
}
}
} else {
for compact_row in 0..nr {
for (compact_col, value) in compact
.matrix
.sparse_row(compact_row)
.zip(compact.matrix.sparse_row_values(compact_row))
{
dense[compact_row * eff_nc + compact_col] = value;
}
}
}
let assignments = inner::crouse_inner(&dense, eff_nr, eff_nc, max_cost)?;
let mut result = Vec::with_capacity(assignments.len());
for (eff_row, eff_col) in assignments {
let (compact_row, compact_col) =
if transposed { (eff_col, eff_row) } else { (eff_row, eff_col) };
let has_edge = compact.matrix.sparse_row(compact_row).any(|c| c == compact_col);
if has_edge {
let orig_row = compact.row_map[compact_row];
let orig_col = compact.col_map[compact_col];
result.push((orig_row, orig_col));
}
}
Ok(result)
}
}
impl<M: SparseValuedMatrix2D> Crouse for M
where
M::Value: Number + Into<f64>,
M::RowIndex: TryFromUsize + Ord,
M::ColumnIndex: TryFromUsize + Ord,
{
}