use crate::{
Sample,
CombinedHypothesis,
Classifier,
};
use super::checker;
pub trait ObjectiveFunction<H> {
fn eval(&self, sample: &Sample, hypothesis: &CombinedHypothesis<H>) -> f64;
}
pub struct SoftMarginObjective(f64);
impl SoftMarginObjective {
pub fn new(nu: f64) -> Self {
Self(nu)
}
}
impl<H> ObjectiveFunction<H> for SoftMarginObjective
where H: Classifier,
{
fn eval(
&self,
sample: &Sample,
hypothesis: &CombinedHypothesis<H>,
) -> f64
{
checker::check_sample(sample);
let n_sample = sample.shape().0;
checker::check_nu(self.0, n_sample);
let target = sample.target();
let mut margins = hypothesis.confidence_all(sample)
.into_iter()
.zip(target.into_iter())
.map(|(hx, y)| y * hx)
.collect::<Vec<f64>>();
margins.sort_by(|a, b| a.partial_cmp(&b).unwrap());
let unit_weight = 1.0 / self.0;
let mut weight_left = 1.0;
let mut objective_value = 0.0;
for yh in margins {
if weight_left > unit_weight {
objective_value += unit_weight * yh;
weight_left -= unit_weight;
} else {
objective_value += weight_left * yh;
break;
}
}
objective_value
}
}
pub struct HardMarginObjective(SoftMarginObjective);
impl HardMarginObjective {
pub fn new() -> Self {
let soft_margin = SoftMarginObjective::new(1.0);
Self(soft_margin)
}
}
impl<H> ObjectiveFunction<H> for HardMarginObjective
where H: Classifier,
{
fn eval(
&self,
sample: &Sample,
hypothesis: &CombinedHypothesis<H>
) -> f64
{
self.0.eval(sample, hypothesis)
}
}