Sparse linear assignment

Solvers for weighted perfect matching problem (linear assignment) for bipartite graphs. Both solvers use variants of auction algorithm and implemented in Rust.

Usage

```rust use sparselinearassignment::{AuctionSolver, KhoslaSolver};

fn main() -> Result<(), Box> { // We have 2 people and 4 objects // weights between person i and objects j let weights = vec![ // person 0 can connect with all objects vec![10, 6, 14, 1], // person 1 can connect with first 3 objects vec![17, 18, 16] ]; let expectedcost = 1. + 16.; let expectedpersontoobject = vec![3, 2]; // u32::MAX value is used to indicate that the corresponding object is not assigned. // If there is no perfect matching unassigned people in person_to_object will be marked by // u32::MAX too let expectedobjecttoperson = vec![u32::MAX, u32::MAX, 1, 0]; // Create KhoslaSolver and AuctionSolution instances with expected capacity of rows, // columns and arcs. We can reuse them in case there is a need to solve multiple assignment // problems. let maxrowscapacity = 10; let maxcolumnscapacity = 10; let maxarcscapacity = 100; let (mut solver, mut solution) = KhoslaSolver::new( maxrowscapacity, maxcolumnscapacity, maxarcs_capacity);

// init solver and CSR storage before populating weights for the next problem instance let numrows = weights.len(); let numcols = weights[0].len(); solver.init(numrows as u32, numcols as u32)?; // populate weights into CSR storage and init the solver // row indices are expected to be nondecreasing (0..weights.len() as u32) .zip(weights.iter()) .foreach(|(i, rowref)| { let jindices = (0..rowref.len() as u32).collect::>(); let values = rowref.iter().map(|v| ((*v) as f64)).collect::>(); solver.extendfromvalues(i, jindices.asslice(), values.asslice()).unwrap(); }); // solve the problem instance. We want to minimize the cost of the assignment. let maximize = false; solver.solve(&mut solution, maximize, None)?; // We found perfect matching and all people are assigned asserteq!(solution.numunassigned, 0); asserteq!(solver.getobjective(&solution), expectedcost); asserteq!(solution.persontoobject, expectedpersontoobject); asserteq!(solution.objecttoperson, expectedobjectto_person); Ok(()) } ``` See tests for more examples.