use std::ops::{Index, IndexMut};
use crate::{
f32s, f64s,
sparse::SparseVector,
svm::{DenseSVM, SparseSVM},
vectors::Triangular,
};
use simd_aligned::{MatrixD, Rows, VectorD};
pub type DenseProblem = Problem<VectorD<f32s>>;
pub type SparseProblem = Problem<SparseVector<f32>>;
#[derive(Copy, Debug, Clone, PartialEq)]
pub enum Solution {
Label(i32),
Value(f32),
None,
}
#[derive(Debug, Clone)]
pub struct Features<V32> {
data: V32,
}
#[derive(Debug, Clone)]
pub struct Problem<V32> {
pub(crate) features: Features<V32>,
pub(crate) kernel_values: MatrixD<f64s, Rows>,
pub(crate) vote: Vec<u32>,
pub(crate) decision_values: Triangular<f64>,
pub(crate) pairwise: MatrixD<f64s, Rows>,
pub(crate) q: MatrixD<f64s, Rows>,
pub(crate) qp: Vec<f64>,
pub(crate) probabilities: VectorD<f64s>,
pub(crate) result: Solution,
}
impl<T> Problem<T> {
pub const fn solution(&self) -> Solution { self.result }
pub fn probabilities(&self) -> &[f64] { self.probabilities.flat() }
pub fn features(&mut self) -> &mut Features<T> { &mut self.features }
}
impl DenseProblem {
pub(crate) fn with_dimension(total_sv: usize, num_classes: usize, num_attributes: usize) -> Problem<VectorD<f32s>> {
Problem {
features: Features {
data: VectorD::with(0.0, num_attributes),
},
kernel_values: MatrixD::with_dimension(num_classes, total_sv),
pairwise: MatrixD::with_dimension(num_classes, num_classes),
q: MatrixD::with_dimension(num_classes, num_classes),
qp: vec![Default::default(); num_classes],
decision_values: Triangular::with_dimension(num_classes, Default::default()),
vote: vec![Default::default(); num_classes],
probabilities: VectorD::with(0.0, num_classes),
result: Solution::None,
}
}
}
impl SparseProblem {
pub fn clear(&mut self) { self.features.data.clear(); }
pub(crate) fn with_dimension(total_sv: usize, num_classes: usize, _num_attributes: usize) -> Problem<SparseVector<f32>> {
Problem {
features: Features { data: SparseVector::new() },
kernel_values: MatrixD::with_dimension(num_classes, total_sv),
pairwise: MatrixD::with_dimension(num_classes, num_classes),
q: MatrixD::with_dimension(num_classes, num_classes),
qp: vec![Default::default(); num_classes],
decision_values: Triangular::with_dimension(num_classes, Default::default()),
vote: vec![Default::default(); num_classes],
probabilities: VectorD::with(0.0, num_classes),
result: Solution::None,
}
}
}
impl<'a> From<&'a DenseSVM> for DenseProblem {
fn from(svm: &DenseSVM) -> Self { Problem::<VectorD<f32s>>::with_dimension(svm.num_total_sv, svm.classes.len(), svm.num_attributes) }
}
impl<'a> From<&'a SparseSVM> for SparseProblem {
fn from(svm: &SparseSVM) -> Self { Problem::<SparseVector<f32>>::with_dimension(svm.num_total_sv, svm.classes.len(), svm.num_attributes) }
}
impl<V32> Features<V32> {
pub const fn as_raw(&self) -> &V32 { &self.data }
}
impl Features<VectorD<f32s>> {
pub fn as_slice_mut(&mut self) -> &mut [f32] { self.data.flat_mut() }
}
impl Index<usize> for Features<VectorD<f32s>> {
type Output = f32;
fn index(&self, index: usize) -> &f32 { &self.data.flat()[index] }
}
impl IndexMut<usize> for Features<VectorD<f32s>> {
fn index_mut(&mut self, index: usize) -> &mut f32 { &mut self.data.flat_mut()[index] }
}
impl Index<usize> for Features<SparseVector<f32>> {
type Output = f32;
fn index(&self, index: usize) -> &f32 { &self.data[index] }
}
impl IndexMut<usize> for Features<SparseVector<f32>> {
fn index_mut(&mut self, index: usize) -> &mut f32 { &mut self.data[index] }
}