Skip to main content

verificar/generator/
strategy.rs

1//! Sampling strategies for code generation
2//!
3//! Different strategies for exploring the space of valid programs.
4
5use super::CoverageMap;
6
7/// Sampling strategy for code generation
8///
9/// From spec Section 4.2: Different strategies for exploring the program space.
10#[derive(Debug, Clone)]
11pub enum SamplingStrategy {
12    /// Exhaustive enumeration up to depth N
13    ///
14    /// Systematically enumerate all valid programs up to the specified AST depth.
15    /// Best for small grammars or low depths.
16    Exhaustive {
17        /// Maximum AST depth to enumerate
18        max_depth: usize,
19    },
20
21    /// Random sampling with grammar weights
22    ///
23    /// Generate random programs using production rule weights.
24    Random {
25        /// Random seed for reproducibility
26        seed: u64,
27        /// Number of samples to generate
28        count: usize,
29    },
30
31    /// Coverage-guided generation (NAUTILUS-style)
32    ///
33    /// Prioritize unexplored AST paths based on coverage feedback.
34    /// From Aschermann et al. (2019) NAUTILUS.
35    CoverageGuided {
36        /// Optional initial coverage map to guide generation
37        coverage_map: Option<CoverageMap>,
38        /// Maximum AST depth for generation
39        max_depth: usize,
40        /// Random seed for reproducibility
41        seed: u64,
42    },
43
44    /// Swarm testing (random feature subsets per batch)
45    ///
46    /// Generate programs using random subsets of language features.
47    /// Implements Heijunka (leveling) for balanced coverage.
48    Swarm {
49        /// Number of features to enable per batch
50        features_per_batch: usize,
51    },
52
53    /// Boundary-focused sampling
54    ///
55    /// Emphasize edge values (0, -1, MAX_INT, empty collections, etc.).
56    Boundary {
57        /// Probability of using a boundary value
58        boundary_probability: f64,
59    },
60}
61
62impl Default for SamplingStrategy {
63    fn default() -> Self {
64        Self::CoverageGuided {
65            coverage_map: None,
66            max_depth: 3,
67            seed: 42,
68        }
69    }
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_default_strategy() {
78        let strategy = SamplingStrategy::default();
79        assert!(matches!(strategy, SamplingStrategy::CoverageGuided { .. }));
80    }
81
82    #[test]
83    fn test_exhaustive_strategy() {
84        let strategy = SamplingStrategy::Exhaustive { max_depth: 5 };
85        if let SamplingStrategy::Exhaustive { max_depth } = strategy {
86            assert_eq!(max_depth, 5);
87        } else {
88            panic!("Expected Exhaustive strategy");
89        }
90    }
91
92    #[test]
93    fn test_boundary_strategy() {
94        let strategy = SamplingStrategy::Boundary {
95            boundary_probability: 0.3,
96        };
97        if let SamplingStrategy::Boundary {
98            boundary_probability,
99        } = strategy
100        {
101            assert!((boundary_probability - 0.3).abs() < f64::EPSILON);
102        } else {
103            panic!("Expected Boundary strategy");
104        }
105    }
106
107    #[test]
108    fn test_random_strategy() {
109        let strategy = SamplingStrategy::Random {
110            seed: 42,
111            count: 100,
112        };
113        if let SamplingStrategy::Random { seed, count } = strategy {
114            assert_eq!(seed, 42);
115            assert_eq!(count, 100);
116        } else {
117            panic!("Expected Random strategy");
118        }
119    }
120
121    #[test]
122    fn test_coverage_guided_strategy() {
123        let strategy = SamplingStrategy::CoverageGuided {
124            coverage_map: None,
125            max_depth: 5,
126            seed: 123,
127        };
128        if let SamplingStrategy::CoverageGuided {
129            max_depth, seed, ..
130        } = strategy
131        {
132            assert_eq!(max_depth, 5);
133            assert_eq!(seed, 123);
134        } else {
135            panic!("Expected CoverageGuided strategy");
136        }
137    }
138
139    #[test]
140    fn test_swarm_strategy() {
141        let strategy = SamplingStrategy::Swarm {
142            features_per_batch: 10,
143        };
144        if let SamplingStrategy::Swarm { features_per_batch } = strategy {
145            assert_eq!(features_per_batch, 10);
146        } else {
147            panic!("Expected Swarm strategy");
148        }
149    }
150
151    #[test]
152    fn test_strategy_debug() {
153        let strategy = SamplingStrategy::Exhaustive { max_depth: 3 };
154        let debug = format!("{:?}", strategy);
155        assert!(debug.contains("Exhaustive"));
156    }
157
158    #[test]
159    fn test_strategy_clone() {
160        let strategy = SamplingStrategy::Random {
161            seed: 42,
162            count: 10,
163        };
164        let cloned = strategy.clone();
165        if let SamplingStrategy::Random { seed, count } = cloned {
166            assert_eq!(seed, 42);
167            assert_eq!(count, 10);
168        } else {
169            panic!("Expected Random strategy clone");
170        }
171    }
172}