use num_traits::Zero;
use relp_num::RationalBig;
use relp_num::RB;
use relp::algorithm::OptimizationResult;
use relp::algorithm::two_phase::matrix_provider::matrix_data::MatrixData;
use relp::algorithm::two_phase::matrix_provider::MatrixProvider;
use relp::algorithm::two_phase::phase_two;
use relp::algorithm::two_phase::strategy::pivot_rule::FirstProfitable;
use relp::algorithm::two_phase::tableau::inverse_maintenance::carry::basis_inverse_rows::BasisInverseRows;
use relp::algorithm::two_phase::tableau::inverse_maintenance::carry::Carry;
use relp::algorithm::two_phase::tableau::inverse_maintenance::InverseMaintainer;
use relp::algorithm::two_phase::tableau::kind::non_artificial::NonArtificial;
use relp::algorithm::two_phase::tableau::Tableau;
use relp::data::linear_algebra::matrix::{ColumnMajor, MatrixOrder};
use relp::data::linear_algebra::vector::{DenseVector, Vector};
use relp::data::linear_program::elements::VariableType;
use relp::data::linear_program::general_form::Variable;
fn main() {
let input_matrix = [
[Some(3), Some(3), Some(3)],
[None, Some(3), Some(3)],
[Some(1), Some(2), Some(3)],
];
let m = input_matrix.len();
let n = input_matrix[0].len();
let column_extreme = |f: fn(_) -> Option<i32>| (0..n)
.map(|j| f((0..m).filter_map(move |i| input_matrix[i][j])).unwrap())
.collect::<Vec<_>>();
let column_min = column_extreme(Iterator::min);
let column_max = column_extreme(Iterator::max);
let subtraction_amount = (0..m).map(|_| Variable {
variable_type: VariableType::Continuous,
cost: RB!(0),
lower_bound: Some(RB!(0)),
upper_bound: None,
shift: RB!(0),
flipped: false,
})
.collect::<Vec<_>>();
let column_minimum = (0..n).map(|_| Variable {
variable_type: VariableType::Continuous,
cost: RB!(-1),
lower_bound: Some(RB!(0)),
upper_bound: None,
shift: RB!(0),
flipped: false,
})
.collect::<Vec<_>>();
let column_maximum = (0..n).map(|_| Variable {
variable_type: VariableType::Continuous,
cost: RB!(1),
lower_bound: Some(RB!(0)),
upper_bound: None,
shift: RB!(0),
flipped: false,
})
.collect::<Vec<_>>();
let variables = [subtraction_amount, column_minimum, column_maximum].concat();
let mut row_major_constraints = Vec::new();
let mut b = Vec::new();
let mut basis_columns = Vec::new();
let mut nr_upper_bounded_constraints = 0;
let mut had_a_min = vec![false; n];
for j in 0..n {
for i in 0..m {
if let Some(value) = input_matrix[i][j] {
row_major_constraints.push(vec![
(i, RB!(1)), (m + j, RB!(1)), ]);
b.push(RB!(value));
basis_columns.push(if value == column_min[j] {
if had_a_min[j] {
m + 2 * n + nr_upper_bounded_constraints
} else {
had_a_min[j] = true;
m + j
}
} else {
m + 2 * n + nr_upper_bounded_constraints
});
nr_upper_bounded_constraints += 1;
}
}
}
let mut nr_lower_bounded_constraints = 0;
let mut had_a_max = vec![false; n];
for j in 0..n {
for i in 0..m {
if let Some(value) = input_matrix[i][j] {
row_major_constraints.push(vec![(i, RB!(1)), (m + n + j, RB!(1))]);
b.push(RB!(value));
basis_columns.push(if value == column_max[j] {
if had_a_max[j] {
m + 2 * n + nr_upper_bounded_constraints + nr_lower_bounded_constraints
} else {
had_a_max[j] = true;
m + n + j
}
} else {
m + 2 * n + nr_upper_bounded_constraints + nr_lower_bounded_constraints
});
nr_lower_bounded_constraints += 1;
}
}
}
let mut constraints = vec![vec![]; m + 2 * n];
for (row_index, row) in row_major_constraints.into_iter().enumerate() {
for (column_index, value) in row {
constraints[column_index].push((row_index, value));
}
}
let constraints = ColumnMajor::new(constraints, nr_upper_bounded_constraints + nr_lower_bounded_constraints, m + 2 * n);
let b = DenseVector::new(b, nr_upper_bounded_constraints + nr_lower_bounded_constraints);
let matrix = MatrixData::new(
&constraints,
&b,
Vec::with_capacity(0),
0, 0, nr_upper_bounded_constraints, nr_lower_bounded_constraints,
&variables,
);
type IM = Carry<RationalBig, BasisInverseRows<RationalBig>>;
let inverse_maintainer = IM::from_basis(&basis_columns, &matrix);
let mut tableau = Tableau::<_, NonArtificial<_>>::new_with_inverse_maintainer(
&matrix, inverse_maintainer, basis_columns.into_iter().collect(),
);
let result = phase_two::primal::<_, _, FirstProfitable>(&mut tableau);
match result {
OptimizationResult::FiniteOptimum(vector) => {
let solution = matrix.reconstruct_solution(vector);
let shifts = (0..m)
.map(|i| match solution.get(i) {
None => Zero::zero(),
Some(value) => value.clone(),
})
.collect::<Vec<_>>();
println!("{:?}", shifts);
},
_ => panic!("We started with a feasible solution, and has at least value 0."),
}
}