#[cfg(test)]
mod make_pow_of_2 {
use crate::factories::constant;
use crate::init;
use soco::algorithms::offline::uni_dimensional::optimal_graph_search::make_pow_of_2;
use soco::config::Config;
use soco::problem::{Problem, SimplifiedSmoothedConvexOptimization};
use soco::verifiers::VerifiableProblem;
#[test]
fn _1() {
init();
let p = SimplifiedSmoothedConvexOptimization {
d: 1,
t_end: 1_000,
bounds: vec![103],
switching_cost: vec![1.],
hitting_cost: constant(),
};
p.verify().unwrap();
let transformed_p = make_pow_of_2(p.clone()).unwrap();
transformed_p.verify().unwrap();
assert_eq!(transformed_p.t_end, p.t_end);
assert_eq!(transformed_p.bounds[0], 128);
assert_abs_diff_eq!(
transformed_p.switching_cost[0],
p.switching_cost[0]
);
for t in 1..=transformed_p.t_end {
for j in 0..=transformed_p.bounds[0] {
assert_abs_diff_eq!(
transformed_p.hit_cost(t, Config::single(j)).cost.raw(),
if j <= p.bounds[0] {
1.
} else {
j as f64 * (1. + std::f64::EPSILON)
}
);
}
}
}
}
#[cfg(test)]
mod optimal_graph_search {
use std::sync::Arc;
use crate::{
factories::{penalize_zero, random},
init,
utils::hash_map,
};
use soco::schedule::Schedule;
use soco::verifiers::VerifiableProblem;
use soco::{algorithms::offline::CachedPath, config::Config};
use soco::{
algorithms::offline::{
multi_dimensional::optimal_graph_search::optimal_graph_search as md_optimal_graph_search,
uni_dimensional::optimal_graph_search::{
make_pow_of_2, optimal_graph_search, Options,
},
OfflineAlgorithm, OfflineOptions,
},
problem::Problem,
};
use soco::{
model::{
data_center::{
loads::LoadProfile,
model::{
DataCenterModel, DataCenterOfflineInput, JobType, Location,
ServerType, Source, DEFAULT_KEY,
},
models::{
energy_consumption::{
EnergyConsumptionModel,
SimplifiedLinearEnergyConsumptionModel,
},
energy_cost::{EnergyCostModel, LinearEnergyCostModel},
revenue_loss::{
MinimalDetectableDelayRevenueLossModel,
RevenueLossModel,
},
switching_cost::{SwitchingCost, SwitchingCostModel},
},
DataCenterModelOutputFailure, DataCenterModelOutputSuccess,
},
Model,
},
problem::{
IntegralSimplifiedSmoothedConvexOptimization,
SimplifiedSmoothedConvexOptimization,
},
};
#[test]
fn _1() {
init();
let p = SimplifiedSmoothedConvexOptimization {
d: 1,
t_end: 2,
bounds: vec![2],
switching_cost: vec![1.],
hitting_cost: penalize_zero(),
};
p.verify().unwrap();
let path = optimal_graph_search
.solve_with_default_options(p.clone(), OfflineOptions::default())
.unwrap();
path.xs.verify(p.t_end, &p.bounds).unwrap();
let inv_path = optimal_graph_search
.solve_with_default_options(p.clone(), OfflineOptions::inverted())
.unwrap();
inv_path.xs.verify(p.t_end, &p.bounds).unwrap();
assert_eq!(path.xs, inv_path.xs);
assert_abs_diff_eq!(path.cost, inv_path.cost);
assert_eq!(
path.xs,
Schedule::new(vec![Config::single(1), Config::single(1)])
);
assert_abs_diff_eq!(path.cost, 1.);
assert_relative_eq!(
path.cost,
p.objective_function(&path.xs).unwrap().cost.raw(),
max_relative = 1e-4
);
}
#[test]
fn _2() {
init();
let p = SimplifiedSmoothedConvexOptimization {
d: 1,
t_end: 100,
bounds: vec![8],
switching_cost: vec![1.],
hitting_cost: random(),
};
p.verify().unwrap();
let path = optimal_graph_search
.solve_with_default_options(p.clone(), OfflineOptions::default())
.unwrap();
path.xs.verify(p.t_end, &p.bounds).unwrap();
let inv_path = optimal_graph_search
.solve_with_default_options(p.clone(), OfflineOptions::inverted())
.unwrap();
inv_path.xs.verify(p.t_end, &p.bounds).unwrap();
assert_eq!(path.xs, inv_path.xs);
assert_abs_diff_eq!(path.cost, inv_path.cost);
assert_relative_eq!(
path.cost,
p.objective_function(&path.xs).unwrap().cost.raw(),
max_relative = 1e-4
);
}
#[test]
fn _3() {
init();
let p = SimplifiedSmoothedConvexOptimization {
d: 1,
t_end: 1_000,
bounds: vec![9],
switching_cost: vec![1.],
hitting_cost: random(),
};
p.verify().unwrap();
let CachedPath { path: md_path, .. } = md_optimal_graph_search
.solve_with_default_options(p.clone(), OfflineOptions::default())
.unwrap();
md_path.xs.verify(p.t_end, &p.bounds).unwrap();
let transformed_p = make_pow_of_2(p).unwrap();
let path = optimal_graph_search
.solve_with_default_options(
transformed_p.clone(),
OfflineOptions::default(),
)
.unwrap();
path.xs
.verify(transformed_p.t_end, &transformed_p.bounds)
.unwrap();
let inv_path = optimal_graph_search
.solve_with_default_options(
transformed_p.clone(),
OfflineOptions::inverted(),
)
.unwrap();
inv_path
.xs
.verify(transformed_p.t_end, &transformed_p.bounds)
.unwrap();
assert!(path.cost.is_finite());
assert_abs_diff_eq!(path.cost, md_path.cost);
assert_eq!(path.xs, inv_path.xs);
assert_abs_diff_eq!(path.cost, inv_path.cost);
assert_relative_eq!(
path.cost,
transformed_p
.objective_function(&path.xs)
.unwrap()
.cost
.raw(),
max_relative = 1e-4
);
}
#[test]
fn _4() {
init();
let p = SimplifiedSmoothedConvexOptimization {
d: 1,
t_end: 2,
bounds: vec![2],
switching_cost: vec![1.],
hitting_cost: penalize_zero(),
};
p.verify().unwrap();
let path = optimal_graph_search
.solve(p.clone(), Options::new(2), OfflineOptions::default())
.unwrap();
path.xs.verify(p.t_end, &p.bounds).unwrap();
assert_eq!(
path.xs,
Schedule::new(vec![Config::single(1), Config::single(1)])
);
assert_abs_diff_eq!(path.cost, 0.);
assert_relative_eq!(
path.cost,
p.objective_function_with_default(&path.xs, &Config::single(2))
.unwrap()
.cost
.raw(),
max_relative = 1e-4
);
}
#[test]
fn _5() {
init();
let loads = vec![LoadProfile::raw(vec![1.])];
let delta = 10. * 60.;
let m = 32;
let model = DataCenterModel::new(
delta,
vec![Location {
key: DEFAULT_KEY.to_string(),
m: hash_map(&[(DEFAULT_KEY.to_string(), m)]),
}],
vec![ServerType::default()],
vec![Source::default()],
vec![JobType::default()],
EnergyConsumptionModel::SimplifiedLinear(hash_map(&[(
DEFAULT_KEY.to_string(),
SimplifiedLinearEnergyConsumptionModel { phi_max: 1. },
)])),
EnergyCostModel::Linear(hash_map(&[(
DEFAULT_KEY.to_string(),
LinearEnergyCostModel {
cost: Arc::new(|_| 1.),
},
)])),
RevenueLossModel::MinimalDetectableDelay(hash_map(&[(
DEFAULT_KEY.to_string(),
MinimalDetectableDelayRevenueLossModel::default(),
)])),
SwitchingCostModel::new(hash_map(&[(
DEFAULT_KEY.to_string(),
SwitchingCost {
energy_cost: 1.,
phi_min: 0.5,
phi_max: 1.,
epsilon: 1.,
delta: 1.,
tau: 5.,
rho: 5.,
},
)])),
);
let input = DataCenterOfflineInput { loads };
let p: IntegralSimplifiedSmoothedConvexOptimization<
DataCenterModelOutputSuccess,
DataCenterModelOutputFailure,
> = model.to(input);
p.verify().unwrap();
let CachedPath { path: md_path, .. } = md_optimal_graph_search
.solve_with_default_options(p.clone(), OfflineOptions::default())
.unwrap();
md_path.xs.verify(p.t_end, &p.bounds).unwrap();
let path = optimal_graph_search
.solve(p.clone(), Options::default(), OfflineOptions::default())
.unwrap();
path.xs.verify(p.t_end, &p.bounds).unwrap();
assert!(path.cost.is_finite());
assert_abs_diff_eq!(path.cost, md_path.cost);
assert_relative_eq!(
path.cost,
p.objective_function(&path.xs).unwrap().cost.raw(),
max_relative = 1e-4
);
}
}