use crate::{
configs::{self, SimpleId},
defaults,
helpers::err,
io::SupportingFileExts,
multi_ch_constructor,
};
use serde::Deserialize;
use std::{
fs::OpenOptions,
path::{Path, PathBuf},
};
#[derive(Clone, Debug)]
pub struct Config {
pub results_dir: PathBuf,
pub multi_ch_constructor: multi_ch_constructor::Config,
pub iter_0_cfg: PathBuf,
pub iter_i_cfg: PathBuf,
pub optimization: Optimization,
pub num_iter: usize,
pub monitoring: MonitoringConfig,
pub num_threads: usize,
pub seed: u64,
pub min_new_metric: Option<f64>,
pub is_err_when_metric_is_zero: bool,
}
impl SupportingFileExts for Config {
fn supported_exts<'a>() -> &'a [&'a str] {
&["yaml"]
}
}
impl Config {
pub fn try_from_str(yaml_str: &str) -> err::Result<Config> {
let proto_cfg: ProtoConfig = {
match serde_yaml::from_str(yaml_str) {
Ok(proto_cfg) => proto_cfg,
Err(e) => {
return Err(err::Msg::from(format!(
"Serde couldn't parse yaml-str due to error: {}",
e
)))
}
}
};
Ok(Config::from(proto_cfg))
}
pub fn from_str(yaml_str: &str) -> Config {
match Config::try_from_str(yaml_str) {
Ok(cfg) => cfg,
Err(msg) => panic!("{}", msg),
}
}
pub fn try_from_yaml<P: AsRef<Path> + ?Sized>(path: &P) -> err::Result<Config> {
let path = path.as_ref();
let file = {
Config::find_supported_ext(path)?;
match OpenOptions::new().read(true).open(path) {
Ok(file) => file,
Err(e) => {
return Err(err::Msg::from(format!(
"Couldn't open {} due to error: {}",
path.display(),
e
)))
}
}
};
let proto_cfg: ProtoConfig = match serde_yaml::from_reader(file) {
Ok(proto_cfg) => proto_cfg,
Err(e) => {
return Err(err::Msg::from(format!(
"Serde couldn't read {} due to error: {}",
path.display(),
e
)))
}
};
Ok(Config::from(proto_cfg))
}
pub fn from_yaml<P: AsRef<Path> + ?Sized>(path: &P) -> Config {
match Config::try_from_yaml(path) {
Ok(cfg) => cfg,
Err(msg) => panic!("{}", msg),
}
}
}
impl From<ProtoConfig> for Config {
fn from(proto_cfg: ProtoConfig) -> Config {
Config {
seed: proto_cfg.seed.unwrap_or(defaults::SEED),
results_dir: proto_cfg.results_dir,
iter_0_cfg: proto_cfg.iter_0_cfg,
iter_i_cfg: proto_cfg.iter_i_cfg,
multi_ch_constructor: proto_cfg.multi_ch_constructor,
num_iter: proto_cfg.num_metric_updates + 1,
monitoring: MonitoringConfig::from(proto_cfg.monitoring),
optimization: Optimization::from(proto_cfg.optimization),
num_threads: proto_cfg
.num_threads
.unwrap_or(defaults::balancing::NUM_THREADS),
min_new_metric: proto_cfg.min_new_metric,
is_err_when_metric_is_zero: proto_cfg
.is_err_when_metric_is_zero
.unwrap_or(defaults::balancing::IS_ERR_WHEN_METRIC_IS_ZERO),
}
}
}
#[derive(Clone, Debug)]
pub struct Optimization {
pub metric_id: SimpleId,
pub method: OptimizationMethod,
}
impl From<ProtoOptimization> for Optimization {
fn from(proto_optimization: ProtoOptimization) -> Optimization {
Optimization {
metric_id: proto_optimization.metric_id,
method: OptimizationMethod::from(proto_optimization.method),
}
}
}
#[derive(Clone, Debug)]
pub enum OptimizationMethod {
ExplicitEuler { correction: f64 },
Averaging,
}
impl From<ProtoOptimizationMethod> for OptimizationMethod {
fn from(proto_method: ProtoOptimizationMethod) -> OptimizationMethod {
match proto_method {
ProtoOptimizationMethod::ExplicitEuler { correction } => {
OptimizationMethod::ExplicitEuler { correction }
}
ProtoOptimizationMethod::Averaging => OptimizationMethod::Averaging,
}
}
}
#[derive(Clone, Debug)]
pub struct MonitoringConfig {
pub edges_info: configs::writing::network::edges::Config,
pub is_writing_for_smarts: bool,
}
impl From<ProtoMonitoringConfig> for MonitoringConfig {
fn from(proto_cfg: ProtoMonitoringConfig) -> MonitoringConfig {
MonitoringConfig {
edges_info: proto_cfg.edges_info,
is_writing_for_smarts: proto_cfg
.is_writing_for_smarts
.unwrap_or(defaults::smarts::IS_WRITING),
}
}
}
#[derive(Debug, Deserialize)]
#[serde(try_from = "RawConfig")]
pub struct ProtoConfig {
pub seed: Option<u64>,
pub results_dir: PathBuf,
pub iter_0_cfg: PathBuf,
pub iter_i_cfg: PathBuf,
pub multi_ch_constructor: multi_ch_constructor::Config,
pub num_metric_updates: usize,
pub monitoring: ProtoMonitoringConfig,
pub optimization: ProtoOptimization,
pub num_threads: Option<usize>,
pub min_new_metric: Option<f64>,
pub is_err_when_metric_is_zero: Option<bool>,
}
impl From<RawConfig> for ProtoConfig {
fn from(raw_cfg: RawConfig) -> ProtoConfig {
let raw_cfg = raw_cfg.balancing;
ProtoConfig {
seed: raw_cfg.seed,
results_dir: raw_cfg.results_dir,
multi_ch_constructor: raw_cfg.multi_ch_constructor,
num_metric_updates: raw_cfg.number_of_metric_updates,
iter_0_cfg: raw_cfg.iter_0_cfg,
iter_i_cfg: raw_cfg.iter_i_cfg,
monitoring: ProtoMonitoringConfig::from(raw_cfg.monitoring),
optimization: ProtoOptimization::from(raw_cfg.optimization),
num_threads: raw_cfg.num_threads,
min_new_metric: raw_cfg.min_new_metric,
is_err_when_metric_is_zero: raw_cfg.is_err_when_metric_is_zero,
}
}
}
#[derive(Clone, Debug)]
pub struct ProtoMonitoringConfig {
pub edges_info: configs::writing::network::edges::Config,
pub is_writing_for_smarts: Option<bool>,
}
impl From<RawMonitoringConfig> for ProtoMonitoringConfig {
fn from(raw_cfg: RawMonitoringConfig) -> ProtoMonitoringConfig {
ProtoMonitoringConfig {
edges_info: configs::writing::network::edges::Config::from(raw_cfg.edges_info),
is_writing_for_smarts: raw_cfg.is_writing_for_smarts,
}
}
}
#[derive(Clone, Debug)]
pub struct ProtoOptimization {
metric_id: SimpleId,
method: ProtoOptimizationMethod,
}
impl From<RawOptimization> for ProtoOptimization {
fn from(raw_optimization: RawOptimization) -> ProtoOptimization {
ProtoOptimization {
metric_id: raw_optimization.metric_id,
method: ProtoOptimizationMethod::from(raw_optimization.method),
}
}
}
#[derive(Clone, Debug)]
pub enum ProtoOptimizationMethod {
ExplicitEuler { correction: f64 },
Averaging,
}
impl From<RawOptimizationMethod> for ProtoOptimizationMethod {
fn from(raw_method: RawOptimizationMethod) -> ProtoOptimizationMethod {
match raw_method {
RawOptimizationMethod::ExplicitEuler { correction } => {
ProtoOptimizationMethod::ExplicitEuler { correction }
}
RawOptimizationMethod::Averaging => ProtoOptimizationMethod::Averaging,
}
}
}
#[derive(Debug, Deserialize)]
pub struct RawConfig {
pub balancing: RawContent,
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RawContent {
pub seed: Option<u64>,
#[serde(rename = "results-dir")]
pub results_dir: PathBuf,
#[serde(rename = "iter-0-cfg")]
pub iter_0_cfg: PathBuf,
#[serde(rename = "iter-i-cfg")]
pub iter_i_cfg: PathBuf,
#[serde(flatten)]
pub multi_ch_constructor: multi_ch_constructor::Config,
#[serde(rename = "number_of_metric-updates")]
pub number_of_metric_updates: usize,
pub monitoring: RawMonitoringConfig,
#[serde(rename = "optimizing_with")]
pub optimization: RawOptimization,
#[serde(rename = "number_of_threads")]
pub num_threads: Option<usize>,
pub min_new_metric: Option<f64>,
#[serde(rename = "throw_err_when_new_metric_is_zero")]
pub is_err_when_metric_is_zero: Option<bool>,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RawMonitoringConfig {
#[serde(flatten)]
edges_info: configs::writing::network::edges::ProtoConfig,
#[serde(rename = "export_vehicles_for_SMARTS")]
is_writing_for_smarts: Option<bool>,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct RawOptimization {
#[serde(rename = "metric-id")]
metric_id: SimpleId,
method: RawOptimizationMethod,
}
#[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum RawOptimizationMethod {
#[serde(rename = "explicit_euler")]
ExplicitEuler {
#[serde(rename = "correction")]
correction: f64,
},
#[serde(rename = "averaging")]
Averaging,
}