oxiz_solver/model/
completion.rs1use super::builder::{Model, Value, VarId};
17use rustc_hash::FxHashMap;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum CompletionStrategy {
22 Default,
24 Witness,
26 Minimal,
28}
29
30#[derive(Debug, Clone)]
32pub struct CompletionConfig {
33 pub strategy: CompletionStrategy,
35 pub default_int: i64,
37 pub default_bool: bool,
39}
40
41impl Default for CompletionConfig {
42 fn default() -> Self {
43 Self {
44 strategy: CompletionStrategy::Default,
45 default_int: 0,
46 default_bool: false,
47 }
48 }
49}
50
51#[derive(Debug, Clone, Default)]
53pub struct CompletionStats {
54 pub vars_completed: u64,
56 pub defaults_used: u64,
58 pub witnesses_used: u64,
60}
61
62#[derive(Debug)]
64pub struct ModelCompleter {
65 config: CompletionConfig,
67 witnesses: FxHashMap<VarId, Value>,
69 stats: CompletionStats,
71}
72
73impl ModelCompleter {
74 pub fn new(config: CompletionConfig) -> Self {
76 Self {
77 config,
78 witnesses: FxHashMap::default(),
79 stats: CompletionStats::default(),
80 }
81 }
82
83 pub fn default_config() -> Self {
85 Self::new(CompletionConfig::default())
86 }
87
88 pub fn add_witness(&mut self, var: VarId, value: Value) {
90 self.witnesses.insert(var, value);
91 }
92
93 pub fn complete(&mut self, partial_model: &Model) -> Model {
97 let mut completed = partial_model.clone();
98
99 let missing_vars = self.find_missing_vars(&completed);
101
102 for var in missing_vars {
103 let value = self.complete_variable(var);
104 completed.assign_theory(var, value);
105 self.stats.vars_completed += 1;
106 }
107
108 completed
109 }
110
111 fn find_missing_vars(&self, model: &Model) -> Vec<VarId> {
113 let mut missing = Vec::new();
116
117 for &var in self.witnesses.keys() {
119 if model.get_theory(var).is_none() {
120 missing.push(var);
121 }
122 }
123
124 missing
125 }
126
127 fn complete_variable(&mut self, var: VarId) -> Value {
129 match self.config.strategy {
130 CompletionStrategy::Witness => {
131 if let Some(witness) = self.witnesses.get(&var) {
132 self.stats.witnesses_used += 1;
133 witness.clone()
134 } else {
135 self.stats.defaults_used += 1;
136 self.default_value()
137 }
138 }
139 CompletionStrategy::Default => {
140 self.stats.defaults_used += 1;
141 self.default_value()
142 }
143 CompletionStrategy::Minimal => {
144 if let Some(witness) = self.witnesses.get(&var) {
146 self.stats.witnesses_used += 1;
147 witness.clone()
148 } else {
149 self.stats.defaults_used += 1;
150 self.minimal_value()
151 }
152 }
153 }
154 }
155
156 fn default_value(&self) -> Value {
158 Value::Int(self.config.default_int)
159 }
160
161 fn minimal_value(&self) -> Value {
163 Value::Int(0)
164 }
165
166 pub fn stats(&self) -> &CompletionStats {
168 &self.stats
169 }
170
171 pub fn reset(&mut self) {
173 self.witnesses.clear();
174 self.stats = CompletionStats::default();
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181
182 #[test]
183 fn test_completer_creation() {
184 let completer = ModelCompleter::default_config();
185 assert_eq!(completer.stats().vars_completed, 0);
186 }
187
188 #[test]
189 fn test_add_witness() {
190 let mut completer = ModelCompleter::default_config();
191 completer.add_witness(0, Value::Int(42));
192
193 assert!(completer.witnesses.contains_key(&0));
194 }
195
196 #[test]
197 fn test_complete_with_witnesses() {
198 let config = CompletionConfig {
199 strategy: CompletionStrategy::Witness,
200 ..Default::default()
201 };
202 let mut completer = ModelCompleter::new(config);
203 completer.add_witness(0, Value::Int(10));
204 completer.add_witness(1, Value::Bool(true));
205
206 let partial = Model::new();
207 let _completed = completer.complete(&partial);
208
209 assert!(completer.stats().witnesses_used > 0);
211 }
212
213 #[test]
214 fn test_default_completion() {
215 let config = CompletionConfig {
216 strategy: CompletionStrategy::Default,
217 default_int: 100,
218 ..Default::default()
219 };
220
221 let completer = ModelCompleter::new(config);
222 let default_val = completer.default_value();
223
224 assert_eq!(default_val, Value::Int(100));
225 }
226}