#![feature(nll)]
#[macro_use(s,stack)]
extern crate ndarray;
extern crate rand;
use ndarray::prelude::*;
use ndarray::Zip;
use ndarray::Array;
use rand::{Rng,thread_rng};
use std::time::Instant;
type Matrix = Array2<f32>;
type Vector = Array1<f32>;
#[derive(Debug, PartialEq, Default)]
struct Pivot {
row: usize,
col: usize
}
#[allow(non_snake_case)]
fn initial_tableau(c:&Vector, A:&Matrix, b:&Vector) -> Matrix {
let mut tableau = Array::from_elem((A.rows()+1, A.cols()+1), 0.);
tableau.slice_mut(s![..-1,..-1]).assign(A);
tableau.slice_mut(s![..-1, -1]).assign(b);
tableau.slice_mut(s![-1, ..-1]).assign(c);
tableau
}
fn can_improve(tableau:&Matrix) -> bool {
tableau.slice(s![-1, ..-1]).iter().any(|&x| x < 0.0)
}
fn find_pivot(tableau:&Matrix) -> Result<Pivot, &'static str>{
let last_row = tableau.slice(s![-1, ..-1]);
let mut vmax = 0.0;
let mut col = std::usize::MAX;
for (i, &value) in last_row.iter().enumerate() {
if value < vmax {
col = i;
vmax = value;
}
}
let lc = tableau.cols() - 1;
let mut qmax = std::f32::INFINITY;
let mut row = std::usize::MAX;
for (i, r) in tableau.slice(s![..-1, ..]).outer_iter().enumerate() {
if r[col] > 0.0 {
let q = r[lc] / r[col];
if qmax > q {
qmax = q;
row = i;
}
}
}
if row == std::usize::MAX {
Err("Solution is unbounded")
} else {
Ok(Pivot{row:row, col:col})
}
}
fn do_pivot(tableau:&mut Matrix, pivot:&Pivot) {
let mut pivoting_row = tableau.subview_mut(Axis(0), pivot.row);
pivoting_row /= pivoting_row[pivot.col];
let pivoting_row = pivoting_row.to_owned();
for (i, mut r) in tableau.outer_iter_mut().enumerate() {
if i != pivot.row {
let multiplier = r[pivot.col];
Zip::from(&mut r)
.and(&pivoting_row)
.apply(|w, &x| {*w -= multiplier*x});
}
}
}
#[allow(non_snake_case)]
fn simplex(c:&Vector, A:&Matrix, b:&Vector, basis:&mut [usize]) -> Result<f32, &'static str> {
let mut tableau = initial_tableau(c, A, b);
let mut count = 0;
while can_improve(&tableau) {
count += 1;
let pivot = find_pivot(&tableau)?;
do_pivot(&mut tableau, &pivot);
basis[pivot.row] = pivot.col;
}
println!{"Iterations: {}", count};
let lc = tableau.cols() - 1;
let lr = tableau.rows() - 1;
let last_col = tableau.subview_mut(Axis(1), lc);
let cost = -last_col[lr];
Ok(cost)
}
#[allow(non_snake_case)]
fn main() {
let vars = 100;
let constraints = 50;
let mut rng = thread_rng();
let b = Vector::zeros(constraints)+10.0;
let mut a_p = Matrix::zeros((constraints, vars));
for x in a_p.iter_mut() {
*x = if rng.gen::<f32>() < 0.5 {1.0} else {2.0};
}
let A = stack![Axis(1), a_p, Matrix::eye(constraints)];
let mut c_p = Vector::zeros(vars);
for x in c_p.iter_mut() {
*x = rng.gen_range::<f32>(-20., -10.);
}
let c = stack![Axis(0), c_p, Vector::zeros(constraints)];
let mut basis:Vec<usize> = (vars..vars+constraints).collect();
let now = Instant::now();
match simplex(&c, &A, &b, &mut basis) {
Ok(cost) => println!("Cost is {}", cost),
Err(e) => println!("{}", e)
}
println!("Elapsed time: {:?}", now.elapsed());
}