solverforge_core/domain/
value_range.rs

1//! Value range providers for planning variables.
2//!
3//! Value range providers define the possible values that can be assigned to
4//! planning variables. They can be static (fixed list) or dynamic (computed
5//! from the solution state).
6
7/// Provides values for a planning variable.
8///
9/// This trait is implemented for types that can produce a list of valid values
10/// for a planning variable. The values can be static or computed dynamically
11/// based on the solution state.
12///
13/// # Type Parameters
14///
15/// * `S` - The solution type
16/// * `V` - The value type (must match the planning variable's type)
17///
18/// # Example
19///
20/// ```
21/// use solverforge_core::domain::ValueRangeProvider;
22///
23/// // Define a solution with a size field
24/// struct NQueensSolution {
25///     n: i32,
26/// }
27///
28/// // Implement a value range provider that computes row values
29/// struct RowRangeProvider;
30///
31/// impl ValueRangeProvider<NQueensSolution, i32> for RowRangeProvider {
32///     fn get_values(&self, solution: &NQueensSolution) -> Vec<i32> {
33///         (0..solution.n).collect()
34///     }
35/// }
36///
37/// let solution = NQueensSolution { n: 8 };
38/// let provider = RowRangeProvider;
39/// assert_eq!(provider.get_values(&solution), vec![0, 1, 2, 3, 4, 5, 6, 7]);
40/// assert_eq!(provider.value_count(&solution), 8);
41/// ```
42pub trait ValueRangeProvider<S, V>: Send + Sync {
43    /// Returns all possible values for the variable.
44    ///
45    /// This method is called during move generation to determine which
46    /// values can be assigned to a planning variable.
47    fn get_values(&self, solution: &S) -> Vec<V>;
48
49    /// Returns the number of possible values.
50    ///
51    /// The default implementation calls `get_values` and returns the length,
52    /// but implementations may override this for efficiency if the count
53    /// can be computed without materializing the values.
54    fn value_count(&self, solution: &S) -> usize {
55        self.get_values(solution).len()
56    }
57
58    /// Returns whether the value range is empty.
59    fn is_empty(&self, solution: &S) -> bool {
60        self.value_count(solution) == 0
61    }
62}
63
64/// A value range provider backed by a field in the solution.
65///
66/// This is the most common case: a `Vec<V>` field that contains the possible values.
67pub struct FieldValueRangeProvider<S, V, F>
68where
69    F: Fn(&S) -> &Vec<V> + Send + Sync,
70{
71    getter: F,
72    _marker: std::marker::PhantomData<(S, V)>,
73}
74
75impl<S, V, F> FieldValueRangeProvider<S, V, F>
76where
77    F: Fn(&S) -> &Vec<V> + Send + Sync,
78{
79    /// Creates a new field-based value range provider.
80    pub fn new(getter: F) -> Self {
81        Self {
82            getter,
83            _marker: std::marker::PhantomData,
84        }
85    }
86}
87
88impl<S, V, F> ValueRangeProvider<S, V> for FieldValueRangeProvider<S, V, F>
89where
90    S: Send + Sync,
91    V: Clone + Send + Sync,
92    F: Fn(&S) -> &Vec<V> + Send + Sync,
93{
94    fn get_values(&self, solution: &S) -> Vec<V> {
95        (self.getter)(solution).clone()
96    }
97
98    fn value_count(&self, solution: &S) -> usize {
99        (self.getter)(solution).len()
100    }
101}
102
103/// A value range provider that computes values dynamically.
104///
105/// Use this when values are computed from solution state rather than
106/// stored in a field.
107pub struct ComputedValueRangeProvider<S, V, F>
108where
109    F: Fn(&S) -> Vec<V> + Send + Sync,
110{
111    compute: F,
112    _marker: std::marker::PhantomData<(S, V)>,
113}
114
115impl<S, V, F> ComputedValueRangeProvider<S, V, F>
116where
117    F: Fn(&S) -> Vec<V> + Send + Sync,
118{
119    /// Creates a new computed value range provider.
120    pub fn new(compute: F) -> Self {
121        Self {
122            compute,
123            _marker: std::marker::PhantomData,
124        }
125    }
126}
127
128impl<S, V, F> ValueRangeProvider<S, V> for ComputedValueRangeProvider<S, V, F>
129where
130    S: Send + Sync,
131    V: Send + Sync,
132    F: Fn(&S) -> Vec<V> + Send + Sync,
133{
134    fn get_values(&self, solution: &S) -> Vec<V> {
135        (self.compute)(solution)
136    }
137}
138
139/// A static value range with a fixed set of values.
140///
141/// Use this when the possible values don't depend on solution state.
142pub struct StaticValueRange<V> {
143    values: Vec<V>,
144}
145
146impl<V> StaticValueRange<V> {
147    /// Creates a new static value range.
148    pub fn new(values: Vec<V>) -> Self {
149        Self { values }
150    }
151}
152
153impl<S, V> ValueRangeProvider<S, V> for StaticValueRange<V>
154where
155    S: Send + Sync,
156    V: Clone + Send + Sync,
157{
158    fn get_values(&self, _solution: &S) -> Vec<V> {
159        self.values.clone()
160    }
161
162    fn value_count(&self, _solution: &S) -> usize {
163        self.values.len()
164    }
165}
166
167/// An integer range value provider.
168///
169/// Efficiently provides a contiguous range of integers without storing them.
170pub struct IntegerRange {
171    start: i64,
172    end: i64,
173}
174
175impl IntegerRange {
176    /// Creates a new integer range [start, end).
177    pub fn new(start: i64, end: i64) -> Self {
178        Self { start, end }
179    }
180
181    /// Creates a range from 0 to n (exclusive).
182    pub fn from_zero(n: i64) -> Self {
183        Self::new(0, n)
184    }
185}
186
187impl<S> ValueRangeProvider<S, i64> for IntegerRange
188where
189    S: Send + Sync,
190{
191    fn get_values(&self, _solution: &S) -> Vec<i64> {
192        (self.start..self.end).collect()
193    }
194
195    fn value_count(&self, _solution: &S) -> usize {
196        (self.end - self.start).max(0) as usize
197    }
198}
199
200impl<S> ValueRangeProvider<S, i32> for IntegerRange
201where
202    S: Send + Sync,
203{
204    fn get_values(&self, _solution: &S) -> Vec<i32> {
205        (self.start as i32..self.end as i32).collect()
206    }
207
208    fn value_count(&self, _solution: &S) -> usize {
209        (self.end - self.start).max(0) as usize
210    }
211}
212
213#[cfg(test)]
214mod tests {
215    use super::*;
216
217    struct TestSolution {
218        n: i32,
219        values: Vec<i32>,
220    }
221
222    #[test]
223    fn test_static_value_range() {
224        let range = StaticValueRange::new(vec![1, 2, 3, 4, 5]);
225        let solution = TestSolution {
226            n: 5,
227            values: vec![],
228        };
229
230        assert_eq!(range.get_values(&solution), vec![1, 2, 3, 4, 5]);
231        assert_eq!(range.value_count(&solution), 5);
232        assert!(!range.is_empty(&solution));
233    }
234
235    #[test]
236    fn test_field_value_range_provider() {
237        let provider = FieldValueRangeProvider::new(|s: &TestSolution| &s.values);
238        let solution = TestSolution {
239            n: 3,
240            values: vec![10, 20, 30],
241        };
242
243        assert_eq!(provider.get_values(&solution), vec![10, 20, 30]);
244        assert_eq!(provider.value_count(&solution), 3);
245    }
246
247    #[test]
248    fn test_computed_value_range_provider() {
249        let provider = ComputedValueRangeProvider::new(|s: &TestSolution| (0..s.n).collect());
250        let solution = TestSolution {
251            n: 4,
252            values: vec![],
253        };
254
255        assert_eq!(provider.get_values(&solution), vec![0, 1, 2, 3]);
256        assert_eq!(provider.value_count(&solution), 4);
257    }
258
259    #[test]
260    fn test_integer_range() {
261        let range = IntegerRange::new(5, 10);
262        let solution = TestSolution {
263            n: 0,
264            values: vec![],
265        };
266
267        let values: Vec<i64> =
268            ValueRangeProvider::<TestSolution, i64>::get_values(&range, &solution);
269        assert_eq!(values, vec![5, 6, 7, 8, 9]);
270        assert_eq!(
271            ValueRangeProvider::<TestSolution, i64>::value_count(&range, &solution),
272            5
273        );
274    }
275
276    #[test]
277    fn test_integer_range_i32() {
278        let range = IntegerRange::from_zero(3);
279        let solution = TestSolution {
280            n: 0,
281            values: vec![],
282        };
283
284        let values: Vec<i32> =
285            ValueRangeProvider::<TestSolution, i32>::get_values(&range, &solution);
286        assert_eq!(values, vec![0, 1, 2]);
287    }
288}