1use validator::{Validate, ValidationError};
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub enum SweepMode {
5 Metropolis,
6 Gibbs,
7}
8
9impl TryFrom<&str> for SweepMode {
10 type Error = String;
11 fn try_from(s: &str) -> Result<Self, Self::Error> {
12 match s {
13 "metropolis" => Ok(Self::Metropolis),
14 "gibbs" => Ok(Self::Gibbs),
15 _ => Err(format!(
16 "unknown sweep_mode '{s}', expected 'metropolis' or 'gibbs'"
17 )),
18 }
19 }
20}
21
22#[derive(Debug, Clone, Copy, PartialEq)]
23pub enum ClusterMode {
24 Wolff,
25 Sw,
26}
27
28impl TryFrom<&str> for ClusterMode {
29 type Error = String;
30 fn try_from(s: &str) -> Result<Self, Self::Error> {
31 match s {
32 "wolff" => Ok(Self::Wolff),
33 "sw" => Ok(Self::Sw),
34 _ => Err(format!(
35 "unknown cluster_mode '{s}', expected 'wolff' or 'sw'"
36 )),
37 }
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq)]
42pub enum OverlapClusterBuildMode {
43 Houdayer,
44 Jorg,
45 Cmr,
46 Cmr3,
47}
48
49impl OverlapClusterBuildMode {
50 pub fn group_size(&self) -> usize {
51 match self {
52 Self::Cmr3 => 3,
53 _ => 2,
54 }
55 }
56}
57
58impl TryFrom<&str> for OverlapClusterBuildMode {
59 type Error = String;
60 fn try_from(s: &str) -> Result<Self, Self::Error> {
61 match s {
62 "houdayer" => Ok(Self::Houdayer),
63 "jorg" => Ok(Self::Jorg),
64 "cmr" => Ok(Self::Cmr),
65 "cmr3" => Ok(Self::Cmr3),
66 _ => Err(format!(
67 "unknown overlap_cluster_build_mode '{s}', expected 'houdayer', 'jorg', 'cmr', or 'cmr3'"
68 )),
69 }
70 }
71}
72
73#[derive(Debug, Clone, Copy, PartialEq)]
74pub enum OverlapUpdateMode {
75 Swap,
76 Free,
77}
78
79impl TryFrom<&str> for OverlapUpdateMode {
80 type Error = String;
81 fn try_from(s: &str) -> Result<Self, Self::Error> {
82 match s {
83 "swap" => Ok(Self::Swap),
84 "free" => Ok(Self::Free),
85 _ => Err(format!(
86 "unknown overlap_update_mode '{s}', expected 'swap' or 'free'"
87 )),
88 }
89 }
90}
91
92#[derive(Debug)]
93pub struct ClusterConfig {
94 pub interval: usize,
95 pub mode: ClusterMode,
96 pub collect_csd: bool,
97}
98
99fn validate_overlap_cluster_config(cfg: &OverlapClusterConfig) -> Result<(), ValidationError> {
100 if cfg.update_mode == OverlapUpdateMode::Free
101 && !matches!(
102 cfg.mode,
103 OverlapClusterBuildMode::Cmr | OverlapClusterBuildMode::Cmr3
104 )
105 {
106 return Err(ValidationError::new(
107 "overlap_update_mode 'free' requires overlap_cluster_build_mode 'cmr' or 'cmr3'",
108 ));
109 }
110 if cfg.mode == OverlapClusterBuildMode::Cmr3 && cfg.update_mode != OverlapUpdateMode::Free {
111 return Err(ValidationError::new(
112 "overlap_cluster_build_mode 'cmr3' requires overlap_update_mode 'free'",
113 ));
114 }
115 Ok(())
116}
117
118#[derive(Debug, Validate)]
119#[validate(schema(function = "validate_overlap_cluster_config"))]
120pub struct OverlapClusterConfig {
121 pub interval: usize,
122 pub mode: OverlapClusterBuildMode,
123 pub cluster_mode: ClusterMode,
124 pub update_mode: OverlapUpdateMode,
125 pub collect_csd: bool,
126 pub collect_top_clusters: bool,
127}
128
129fn validate_sim_config(cfg: &SimConfig) -> Result<(), ValidationError> {
130 if cfg.n_sweeps < 1 {
131 return Err(ValidationError::new("n_sweeps must be >= 1"));
132 }
133 if cfg.warmup_sweeps > cfg.n_sweeps {
134 return Err(ValidationError::new("warmup_sweeps must be <= n_sweeps"));
135 }
136 if let Some(ref c) = cfg.cluster_update {
137 if c.interval < 1 {
138 return Err(ValidationError::new("cluster_update interval must be >= 1"));
139 }
140 }
141 if let Some(ref h) = cfg.overlap_cluster {
142 if h.interval < 1 {
143 return Err(ValidationError::new(
144 "overlap_cluster interval must be >= 1",
145 ));
146 }
147 }
148 Ok(())
149}
150
151#[derive(Debug, Validate)]
152#[validate(schema(function = "validate_sim_config"))]
153pub struct SimConfig {
154 pub n_sweeps: usize,
155 pub warmup_sweeps: usize,
156 pub sweep_mode: SweepMode,
157 pub cluster_update: Option<ClusterConfig>,
158 pub pt_interval: Option<usize>,
159 #[validate]
160 pub overlap_cluster: Option<OverlapClusterConfig>,
161 pub autocorrelation_max_lag: Option<usize>,
162 pub sequential: bool,
163 pub equilibration_diagnostic: bool,
164}