use noisy_float::prelude::*;
use rand::prelude::*;
use rand_pcg::Pcg64;
use soco::{
config::{FractionalConfig, IntegralConfig},
cost::{FailableCost, FailableCostFn, RawCostFn, SingleCostFn},
model::{data_center::DataCenterModelOutputFailure, ModelOutputFailure},
vec_wrapper::VecWrapper,
};
fn wrap<'a, T, D>(
f: impl Fn(i32, T) -> f64 + Send + Sync + 'a,
) -> FailableCostFn<'a, T, D>
where
T: Clone,
D: ModelOutputFailure,
{
FailableCostFn::new(
1,
SingleCostFn::certain(move |t, x| FailableCost::raw(n64(f(t, x)))),
)
}
pub fn constant() -> RawCostFn<'static, IntegralConfig> {
wrap(|_, _| 1.)
}
pub fn constant_simple(
) -> FailableCostFn<'static, f64, DataCenterModelOutputFailure> {
wrap(|_, _| 1.)
}
pub fn penalize_zero() -> RawCostFn<'static, IntegralConfig> {
wrap(|t: i32, j: IntegralConfig| {
t as f64
* if (0..j.d() as usize).all(|k| j[k] <= 0) {
1.
} else {
0.
}
})
}
pub fn random() -> RawCostFn<'static, IntegralConfig> {
wrap(|t: i32, j: IntegralConfig| {
let r: f64 = j
.to_vec()
.into_iter()
.enumerate()
.map(|(k, i)| {
Pcg64::seed_from_u64(t as u64 * k as u64).gen_range(0.0..1.)
* i as f64
})
.sum();
Pcg64::seed_from_u64(t as u64 * r as u64).gen_range(0.0..1_000_000.)
})
}
pub fn inv_e() -> RawCostFn<'static, FractionalConfig> {
wrap(|t: i32, j: FractionalConfig| {
t as f64 * j.iter().map(|&x| std::f64::consts::E.powf(-x)).sum::<f64>()
})
}
pub fn inv_e_sblo() -> FailableCostFn<'static, f64, DataCenterModelOutputFailure>
{
wrap(|t: i32, x: f64| t as f64 * std::f64::consts::E.powf(-x))
}
pub fn parabola() -> RawCostFn<'static, FractionalConfig> {
wrap(|t: i32, j: FractionalConfig| {
assert!(j.d() == 1);
1. / t as f64 * (j[0] - 1.).powi(2)
})
}
pub fn int_parabola() -> RawCostFn<'static, IntegralConfig> {
wrap(|t: i32, j: IntegralConfig| {
assert!(j.d() == 1);
1. / t as f64 * (j[0] as f64 - 1.).powi(2)
})
}
pub fn moving_parabola(m: i32) -> RawCostFn<'static, FractionalConfig> {
wrap(move |t: i32, j: FractionalConfig| {
assert!(j.d() == 1);
(j[0] - ((t % m) as f64)).powi(2)
})
}