use itertools::Itertools;
use crate::core::num::{EpsilonEquality, Field, StabilityCmp};
use super::mat::Mat;
pub struct Cone<F: Field> {
generators: Vec<Mat<F>>,
facets: Vec<Face<F>>,
orth_comp_basis: Vec<Mat<F>>,
ambient_dim: usize,
dim: usize,
}
pub struct Face<F: Field> {
normal: Mat<F>,
generators: Vec<Mat<F>>
}
impl<F: Field + StabilityCmp + EpsilonEquality + PartialOrd> Cone<F> {
pub fn new(generators: Vec<Mat<F>>) -> Cone<F> {
let ambient_dim = generators[0].rows();
let generator_mat = Mat::from_row_vectors(&generators);
let rref = generator_mat.row_echelon().to_rref();
let dim = rref.rank();
let orth_comp_basis = rref.compute_kernel();
let mut facets: Vec<Face<F>> = vec![];
'outer: for subset in generators.iter().combinations(dim-1) {
let subset_owned : Vec<Mat<F>> = subset.iter().map(|&m| m.clone()).collect();
let subset_mat = Mat::from_row_vectors(&subset_owned);
let subset_rref = subset_mat.row_echelon().to_rref();
if subset_rref.rank() != dim-1 {
continue;
}
let mut subset_kernel = subset_rref.compute_kernel();
let mut normal = subset_kernel[0].clone();
if let Some(ordering) = generators[0].dot(&normal).partial_cmp(&F::ZERO) {
let is_above = match ordering {
std::cmp::Ordering::Less => false,
_ => true
};
if !is_above {
normal.scale(F::ZERO-F::ONE);
}
for g in generators.iter() {
if let Some(ordering) = g.dot(&normal).partial_cmp(&F::ZERO) {
match ordering {
std::cmp::Ordering::Less => continue 'outer,
_ => {}
};
} else {
continue 'outer;
}
}
let facet = Face {
normal,
generators: subset_owned
};
facets.push(facet);
}
}
Cone {
generators,
facets,
orth_comp_basis,
ambient_dim,
dim
}
}
}