use oximo_core::{Domain, Variable};
use oximo_expr::VarId;
use rustc_hash::FxHashMap;
use super::analyze::Analysis;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Bucket {
NlBothC,
NlOnlyC,
NlOnlyO,
NlBothI,
NlOnlyCI,
NlOnlyOI,
LinC,
LinB,
LinI,
}
impl Bucket {
fn order(self) -> u8 {
match self {
Bucket::NlBothC => 0,
Bucket::NlBothI => 1,
Bucket::NlOnlyC => 2,
Bucket::NlOnlyCI => 3,
Bucket::NlOnlyO => 4,
Bucket::NlOnlyOI => 5,
Bucket::LinC => 6,
Bucket::LinB => 7,
Bucket::LinI => 8,
}
}
}
fn bucket_for(v: &Variable, analysis: &Analysis) -> Bucket {
let in_c = analysis.nl_vars_c.contains(&v.id);
let in_o = analysis.nl_vars_o.contains(&v.id);
let is_int = v.domain.is_integer();
let is_bin = matches!(v.domain, Domain::Binary);
match (in_c, in_o, is_int) {
(true, true, false) => Bucket::NlBothC,
(true, false, false) => Bucket::NlOnlyC,
(false, true, false) => Bucket::NlOnlyO,
(true, true, true) => Bucket::NlBothI,
(true, false, true) => Bucket::NlOnlyCI,
(false, true, true) => Bucket::NlOnlyOI,
(false, false, false) => Bucket::LinC,
(false, false, true) => {
if is_bin {
Bucket::LinB
} else {
Bucket::LinI
}
}
}
}
#[derive(Debug)]
pub(crate) struct Permutation {
pub(crate) var_order: Vec<VarId>,
pub(crate) var_index: FxHashMap<VarId, u32>,
pub(crate) con_order: Vec<usize>,
}
impl Permutation {
pub(crate) fn build(vars: &[Variable], analysis: &Analysis) -> Self {
let mut indexed: Vec<(usize, Bucket)> =
vars.iter().enumerate().map(|(i, v)| (i, bucket_for(v, analysis))).collect();
indexed.sort_by_key(|(i, b)| (b.order(), *i));
let var_order: Vec<VarId> = indexed.iter().map(|(i, _)| vars[*i].id).collect();
let mut var_index: FxHashMap<VarId, u32> = FxHashMap::default();
for (nl_idx, vid) in var_order.iter().enumerate() {
var_index.insert(*vid, u32::try_from(nl_idx).expect("var count overflow"));
}
let mut nl_idx: Vec<usize> = Vec::new();
let mut lin_idx: Vec<usize> = Vec::new();
for (i, form) in analysis.cons.iter().enumerate() {
if form.is_nonlinear() {
nl_idx.push(i);
} else {
lin_idx.push(i);
}
}
let con_order: Vec<usize> = nl_idx.into_iter().chain(lin_idx).collect();
Self { var_order, var_index, con_order }
}
}