use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum StrategyName {
Lex,
ReverseLex,
Shuffle,
Halton,
Sobol,
Lhs,
Extrema,
Shells,
Diagonal,
Antidiagonal,
}
impl StrategyName {
pub fn is_streaming(self) -> bool {
matches!(self, StrategyName::Lex)
}
pub fn is_index_sampling(self) -> bool {
matches!(
self,
StrategyName::Halton
| StrategyName::Sobol
| StrategyName::Lhs
| StrategyName::Shuffle
| StrategyName::ReverseLex
)
}
pub fn is_lattice_geometric(self) -> bool {
matches!(
self,
StrategyName::Extrema
| StrategyName::Shells
| StrategyName::Diagonal
| StrategyName::Antidiagonal
)
}
pub fn as_str(self) -> &'static str {
match self {
StrategyName::Lex => "lex",
StrategyName::ReverseLex => "reverse_lex",
StrategyName::Shuffle => "shuffle",
StrategyName::Halton => "halton",
StrategyName::Sobol => "sobol",
StrategyName::Lhs => "lhs",
StrategyName::Extrema => "extrema",
StrategyName::Shells => "shells",
StrategyName::Diagonal => "diagonal",
StrategyName::Antidiagonal => "antidiagonal",
}
}
}
impl std::fmt::Display for StrategyName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ZipMode {
Strict,
Truncate,
Cycle,
}
impl ZipMode {
pub fn as_str(self) -> &'static str {
match self {
ZipMode::Strict => "strict",
ZipMode::Truncate => "truncate",
ZipMode::Cycle => "cycle",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lex_is_the_only_streaming_strategy() {
assert!(StrategyName::Lex.is_streaming());
for s in [
StrategyName::ReverseLex,
StrategyName::Shuffle,
StrategyName::Halton,
StrategyName::Sobol,
StrategyName::Lhs,
StrategyName::Extrema,
StrategyName::Shells,
StrategyName::Diagonal,
StrategyName::Antidiagonal,
] {
assert!(!s.is_streaming(), "{s:?} should not be streaming");
}
}
#[test]
fn index_sampling_strategies_classified_correctly() {
for s in [
StrategyName::Halton,
StrategyName::Sobol,
StrategyName::Lhs,
StrategyName::Shuffle,
StrategyName::ReverseLex,
] {
assert!(s.is_index_sampling(), "{s:?} should be index-sampling");
}
}
#[test]
fn lattice_geometric_strategies_classified_correctly() {
for s in [
StrategyName::Extrema,
StrategyName::Shells,
StrategyName::Diagonal,
StrategyName::Antidiagonal,
] {
assert!(s.is_lattice_geometric(), "{s:?} should be lattice-geometric");
}
}
#[test]
fn strategy_classes_are_disjoint() {
for s in [
StrategyName::ReverseLex,
StrategyName::Shuffle,
StrategyName::Halton,
StrategyName::Sobol,
StrategyName::Lhs,
StrategyName::Extrema,
StrategyName::Shells,
StrategyName::Diagonal,
StrategyName::Antidiagonal,
] {
let sampling = s.is_index_sampling();
let geometric = s.is_lattice_geometric();
assert!(sampling ^ geometric, "{s:?} must be in exactly one class");
}
}
#[test]
fn strategy_string_round_trip() {
let s = StrategyName::Halton;
let json = serde_json::to_string(&s).unwrap();
let back: StrategyName = serde_json::from_str(&json).unwrap();
assert_eq!(s, back);
assert_eq!(s.as_str(), "halton");
}
}