Skip to main content

solverforge_solver/heuristic/selector/
entity.rs

1// Entity selectors for iterating over planning entities
2
3use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_scoring::Director;
7
8// A reference to an entity within a solution.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub struct EntityReference {
11    // Index of the entity descriptor.
12    pub descriptor_index: usize,
13    // Index of the entity within its collection.
14    pub entity_index: usize,
15}
16
17impl EntityReference {
18    pub fn new(descriptor_index: usize, entity_index: usize) -> Self {
19        Self {
20            descriptor_index,
21            entity_index,
22        }
23    }
24}
25
26/// Trait for selecting entities from a planning solution.
27///
28/// Entity selectors provide an iteration order over the entities that
29/// the solver will consider for moves.
30///
31/// # Type Parameters
32/// * `S` - The planning solution type
33pub trait EntitySelector<S: PlanningSolution>: Send + Debug {
34    /* Returns an iterator over entity references.
35
36    The iterator yields `EntityReference` values that identify entities
37    within the solution.
38    */
39    fn iter<'a, D: Director<S>>(
40        &'a self,
41        score_director: &'a D,
42    ) -> impl Iterator<Item = EntityReference> + 'a;
43
44    fn size<D: Director<S>>(&self, score_director: &D) -> usize;
45
46    // Returns true if this selector may return the same entity multiple times.
47    fn is_never_ending(&self) -> bool {
48        false
49    }
50}
51
52// An entity selector that iterates over all entities from the solution.
53#[derive(Clone, Debug)]
54pub struct FromSolutionEntitySelector {
55    // The descriptor index to select from.
56    descriptor_index: usize,
57}
58
59impl FromSolutionEntitySelector {
60    pub fn new(descriptor_index: usize) -> Self {
61        Self { descriptor_index }
62    }
63}
64
65impl<S: PlanningSolution> EntitySelector<S> for FromSolutionEntitySelector {
66    fn iter<'a, D: Director<S>>(
67        &'a self,
68        score_director: &'a D,
69    ) -> impl Iterator<Item = EntityReference> + 'a {
70        let count = score_director
71            .entity_count(self.descriptor_index)
72            .unwrap_or(0);
73        let desc_idx = self.descriptor_index;
74        (0..count).map(move |i| EntityReference::new(desc_idx, i))
75    }
76
77    fn size<D: Director<S>>(&self, score_director: &D) -> usize {
78        score_director
79            .entity_count(self.descriptor_index)
80            .unwrap_or(0)
81    }
82}
83
84// An entity selector that iterates over all entities from all descriptors.
85#[derive(Debug, Clone, Default)]
86pub struct AllEntitiesSelector;
87
88impl AllEntitiesSelector {
89    pub fn new() -> Self {
90        Self
91    }
92}
93
94impl<S: PlanningSolution> EntitySelector<S> for AllEntitiesSelector {
95    fn iter<'a, D: Director<S>>(
96        &'a self,
97        score_director: &'a D,
98    ) -> impl Iterator<Item = EntityReference> + 'a {
99        let desc = score_director.solution_descriptor();
100        let descriptor_count = desc.entity_descriptors.len();
101
102        let mut refs = Vec::new();
103        for desc_idx in 0..descriptor_count {
104            let count = score_director.entity_count(desc_idx).unwrap_or(0);
105            for entity_idx in 0..count {
106                refs.push(EntityReference::new(desc_idx, entity_idx));
107            }
108        }
109
110        refs.into_iter()
111    }
112
113    fn size<D: Director<S>>(&self, score_director: &D) -> usize {
114        score_director.total_entity_count().unwrap_or(0)
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121    use crate::test_utils::create_simple_nqueens_director;
122
123    #[test]
124    fn test_from_solution_entity_selector() {
125        let director = create_simple_nqueens_director(4);
126
127        // Verify column values match indices (column is set to index in create_uninitialized_nqueens)
128        let solution = director.working_solution();
129        for (i, queen) in solution.queens.iter().enumerate() {
130            assert_eq!(queen.column, i as i64);
131        }
132
133        let selector = FromSolutionEntitySelector::new(0);
134
135        let refs: Vec<_> = selector.iter(&director).collect();
136        assert_eq!(refs.len(), 4);
137        assert_eq!(refs[0], EntityReference::new(0, 0));
138        assert_eq!(refs[1], EntityReference::new(0, 1));
139        assert_eq!(refs[2], EntityReference::new(0, 2));
140        assert_eq!(refs[3], EntityReference::new(0, 3));
141
142        assert_eq!(selector.size(&director), 4);
143    }
144
145    #[test]
146    fn test_all_entities_selector() {
147        let director = create_simple_nqueens_director(3);
148
149        let selector = AllEntitiesSelector::new();
150
151        let refs: Vec<_> = selector.iter(&director).collect();
152        assert_eq!(refs.len(), 3);
153
154        assert_eq!(selector.size(&director), 3);
155    }
156}