use crate::{
sparse::SparseVector,
svm::{DenseSVM, SparseSVM},
vectors::Triangular,
};
use simd_aligned::{
arch::{f32x8, f64x4},
MatSimd, Rows, VecSimd,
};
pub type DenseFeatures = FeatureVector<VecSimd<f32x8>>;
pub type SparseFeatures = FeatureVector<SparseVector<f32>>;
#[derive(Copy, Debug, Clone, PartialEq)]
pub enum Label {
Class(i32),
Value(f32),
None,
}
#[derive(Debug, Clone)]
pub struct FeatureVector<T> {
pub(crate) features: T,
pub(crate) kernel_values: MatSimd<f64x4, Rows>,
pub(crate) vote: Vec<u32>,
pub(crate) decision_values: Triangular<f64>,
pub(crate) pairwise: MatSimd<f64x4, Rows>,
pub(crate) q: MatSimd<f64x4, Rows>,
pub(crate) qp: Vec<f64>,
pub(crate) probabilities: VecSimd<f64x4>,
pub(crate) result: Label,
}
impl<T> FeatureVector<T> {
pub const fn label(&self) -> Label {
self.result
}
pub fn probabilities(&self) -> &[f64] {
self.probabilities.flat()
}
}
impl FeatureVector<VecSimd<f32x8>> {
pub fn features(&mut self) -> &mut [f32] {
self.features.flat_mut()
}
}
impl FeatureVector<SparseVector<f32>> {
pub fn features(&mut self) -> &mut SparseVector<f32> {
&mut self.features
}
}
impl DenseFeatures {
pub(crate) fn with_dimension(total_sv: usize, num_classes: usize, num_attributes: usize) -> Self {
Self {
features: VecSimd::with(0.0, num_attributes),
kernel_values: MatSimd::with_dimension(num_classes, total_sv),
pairwise: MatSimd::with_dimension(num_classes, num_classes),
q: MatSimd::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: VecSimd::with(0.0, num_classes),
result: Label::None,
}
}
}
impl SparseFeatures {
pub fn clear(&mut self) {
self.features.clear();
}
pub(crate) fn with_dimension(total_sv: usize, num_classes: usize, _num_attributes: usize) -> Self {
Self {
features: SparseVector::new(),
kernel_values: MatSimd::with_dimension(num_classes, total_sv),
pairwise: MatSimd::with_dimension(num_classes, num_classes),
q: MatSimd::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: VecSimd::with(0.0, num_classes),
result: Label::None,
}
}
}
impl From<&DenseSVM> for DenseFeatures {
fn from(svm: &DenseSVM) -> Self {
Self::with_dimension(svm.num_total_sv, svm.classes.len(), svm.num_attributes)
}
}
impl From<&SparseSVM> for SparseFeatures {
fn from(svm: &SparseSVM) -> Self {
Self::with_dimension(svm.num_total_sv, svm.classes.len(), svm.num_attributes)
}
}