solverforge_solver/builder/context/scalar/
group.rs1use std::fmt;
2
3use super::value_source::ValueSource;
4use super::variable::{ScalarGetter, ScalarSetter, ScalarVariableContext};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct ScalarGroupLimits {
8 pub value_candidate_limit: Option<usize>,
9 pub group_candidate_limit: Option<usize>,
10 pub max_moves_per_step: Option<usize>,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
14pub struct ScalarGroupEdit {
15 pub descriptor_index: usize,
16 pub entity_index: usize,
17 pub variable_name: &'static str,
18 pub to_value: Option<usize>,
19}
20
21impl ScalarGroupEdit {
22 pub fn set_scalar(
23 descriptor_index: usize,
24 entity_index: usize,
25 variable_name: &'static str,
26 to_value: Option<usize>,
27 ) -> Self {
28 Self {
29 descriptor_index,
30 entity_index,
31 variable_name,
32 to_value,
33 }
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38pub struct ScalarGroupCandidate {
39 pub reason: &'static str,
40 pub edits: Vec<ScalarGroupEdit>,
41 pub construction_slot_key: Option<usize>,
42 pub construction_entity_order_key: Option<i64>,
43 pub construction_value_order_key: Option<i64>,
44}
45
46impl ScalarGroupCandidate {
47 pub fn new(reason: &'static str, edits: Vec<ScalarGroupEdit>) -> Self {
48 Self {
49 reason,
50 edits,
51 construction_slot_key: None,
52 construction_entity_order_key: None,
53 construction_value_order_key: None,
54 }
55 }
56
57 pub fn with_construction_slot_key(mut self, key: usize) -> Self {
58 self.construction_slot_key = Some(key);
59 self
60 }
61
62 pub fn with_construction_entity_order_key(mut self, key: i64) -> Self {
63 self.construction_entity_order_key = Some(key);
64 self
65 }
66
67 pub fn with_construction_value_order_key(mut self, key: i64) -> Self {
68 self.construction_value_order_key = Some(key);
69 self
70 }
71}
72
73pub type ScalarGroupCandidateProvider<S> = fn(&S, ScalarGroupLimits) -> Vec<ScalarGroupCandidate>;
74
75pub struct ScalarGroupMember<S> {
76 pub descriptor_index: usize,
77 pub variable_index: usize,
78 pub entity_type_name: &'static str,
79 pub variable_name: &'static str,
80 pub getter: ScalarGetter<S>,
81 pub setter: ScalarSetter<S>,
82 pub value_source: ValueSource<S>,
83 pub allows_unassigned: bool,
84}
85
86impl<S> Clone for ScalarGroupMember<S> {
87 fn clone(&self) -> Self {
88 *self
89 }
90}
91
92impl<S> Copy for ScalarGroupMember<S> {}
93
94impl<S> ScalarGroupMember<S> {
95 pub fn from_scalar_context(context: ScalarVariableContext<S>) -> Self {
96 Self {
97 descriptor_index: context.descriptor_index,
98 variable_index: context.variable_index,
99 entity_type_name: context.entity_type_name,
100 variable_name: context.variable_name,
101 getter: context.getter,
102 setter: context.setter,
103 value_source: context.value_source,
104 allows_unassigned: context.allows_unassigned,
105 }
106 }
107
108 pub fn current_value(&self, solution: &S, entity_index: usize) -> Option<usize> {
109 (self.getter)(solution, entity_index, self.variable_index)
110 }
111
112 pub fn value_is_legal(
113 &self,
114 solution: &S,
115 entity_index: usize,
116 candidate: Option<usize>,
117 ) -> bool {
118 let Some(value) = candidate else {
119 return self.allows_unassigned;
120 };
121 match self.value_source {
122 ValueSource::Empty => false,
123 ValueSource::CountableRange { from, to } => from <= value && value < to,
124 ValueSource::SolutionCount {
125 count_fn,
126 provider_index,
127 } => value < count_fn(solution, provider_index),
128 ValueSource::EntitySlice { values_for_entity } => {
129 values_for_entity(solution, entity_index, self.variable_index).contains(&value)
130 }
131 }
132 }
133}
134
135impl<S> fmt::Debug for ScalarGroupMember<S> {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 f.debug_struct("ScalarGroupMember")
138 .field("descriptor_index", &self.descriptor_index)
139 .field("variable_index", &self.variable_index)
140 .field("entity_type_name", &self.entity_type_name)
141 .field("variable_name", &self.variable_name)
142 .field("value_source", &self.value_source)
143 .field("allows_unassigned", &self.allows_unassigned)
144 .finish()
145 }
146}
147
148pub struct ScalarGroupContext<S> {
149 pub group_name: &'static str,
150 pub members: Vec<ScalarGroupMember<S>>,
151 pub candidate_provider: ScalarGroupCandidateProvider<S>,
152}
153
154impl<S> ScalarGroupContext<S> {
155 pub fn new(
156 group_name: &'static str,
157 members: Vec<ScalarGroupMember<S>>,
158 candidate_provider: ScalarGroupCandidateProvider<S>,
159 ) -> Self {
160 Self {
161 group_name,
162 members,
163 candidate_provider,
164 }
165 }
166
167 pub fn member_for_edit(&self, edit: &ScalarGroupEdit) -> Option<ScalarGroupMember<S>> {
168 self.members.iter().copied().find(|member| {
169 member.descriptor_index == edit.descriptor_index
170 && member.variable_name == edit.variable_name
171 })
172 }
173}
174
175impl<S> Clone for ScalarGroupContext<S> {
176 fn clone(&self) -> Self {
177 Self {
178 group_name: self.group_name,
179 members: self.members.clone(),
180 candidate_provider: self.candidate_provider,
181 }
182 }
183}
184
185impl<S> fmt::Debug for ScalarGroupContext<S> {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 f.debug_struct("ScalarGroupContext")
188 .field("group_name", &self.group_name)
189 .field("members", &self.members)
190 .finish_non_exhaustive()
191 }
192}