1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::problem::KurobakoProblemRecipe;
use crate::solver::KurobakoSolverRecipe;
use kurobako_core::json;
use kurobako_core::{Error, ErrorKind, Result};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::num::NonZeroUsize;
use std::str::FromStr;
use structopt::StructOpt;
#[derive(Debug, Clone, StructOpt, Serialize, Deserialize)]
#[structopt(rename_all = "kebab-case")]
#[allow(missing_docs)]
pub struct StudyRecipe {
#[structopt(long, parse(try_from_str = json::parse_json))]
pub solver: KurobakoSolverRecipe,
#[structopt(long, parse(try_from_str = json::parse_json))]
pub problem: KurobakoProblemRecipe,
#[structopt(long, default_value = "20")]
pub budget: u64,
#[structopt(long, default_value = "1")]
pub concurrency: NonZeroUsize,
#[structopt(long, default_value = "random")]
pub scheduling: Scheduling,
#[structopt(long)]
pub seed: Option<u64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, StructOpt, Serialize, Deserialize)]
#[structopt(rename_all = "kebab-case")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[allow(missing_docs)]
pub enum Scheduling {
Random,
Fair,
}
impl Default for Scheduling {
fn default() -> Self {
Self::Random
}
}
impl FromStr for Scheduling {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
match s {
"random" => Ok(Self::Random),
"fair" => Ok(Self::Fair),
_ => track_panic!(ErrorKind::InvalidInput, "Unknown scheduling type: {:?}", s),
}
}
}
impl fmt::Display for Scheduling {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Random => write!(f, "random"),
Self::Fair => write!(f, "fair"),
}
}
}
#[derive(Debug, Clone, StructOpt, Serialize, Deserialize)]
#[structopt(rename_all = "kebab-case")]
pub struct StudiesRecipe {
#[structopt(long, parse(try_from_str = json::parse_json))]
pub solvers: Vec<KurobakoSolverRecipe>,
#[structopt(long, parse(try_from_str = json::parse_json))]
pub problems: Vec<KurobakoProblemRecipe>,
#[structopt(long, default_value = "10")]
pub repeats: usize,
#[structopt(long, default_value = "20")]
pub budget: u64,
#[structopt(long, default_value = "1")]
pub concurrency: NonZeroUsize,
#[structopt(long, default_value = "random")]
pub scheduling: Scheduling,
#[structopt(long)]
pub seed: Option<u64>,
}
impl StudiesRecipe {
pub fn studies(&self) -> impl Iterator<Item = StudyRecipe> {
let mut studies = Vec::new();
for i in 0..self.repeats {
for problem in &self.problems {
for solver in &self.solvers {
let seed = self.seed.map(|s| s + i as u64);
let study = StudyRecipe {
solver: solver.clone(),
problem: problem.clone(),
budget: self.budget,
concurrency: self.concurrency,
scheduling: self.scheduling,
seed,
};
studies.push(study);
}
}
}
studies.into_iter()
}
}