conjure_core/solver/adaptors/
sat_common.rs1use std::cell::Ref;
5use std::collections::HashMap;
6use std::rc::Rc;
7
8use thiserror::Error;
9
10use crate::{
11 ast as conjure_ast, solver::SolverError, solver::SolverError::*, Model as ConjureModel,
12};
13use crate::metadata::Metadata;
16
17#[derive(Debug, Clone)]
25pub struct CNFModel {
26 pub clauses: Vec<Vec<i32>>,
27 variables: HashMap<conjure_ast::Name, i32>,
28 next_ind: i32,
29}
30impl CNFModel {
31 pub fn new() -> CNFModel {
32 CNFModel {
33 clauses: Vec::new(),
34 variables: HashMap::new(),
35 next_ind: 1,
36 }
37 }
38
39 pub fn from_conjure(conjure_model: ConjureModel) -> Result<CNFModel, SolverError> {
40 let mut ans: CNFModel = CNFModel::new();
41
42 let submodel = conjure_model.as_submodel();
43 let symtab = submodel.symbols();
44 for (name, decl) in symtab.clone().into_iter() {
45 let Some(var) = decl.as_var() else {
47 continue;
48 };
49
50 if var.domain != conjure_ast::Domain::BoolDomain {
52 return Err(ModelFeatureNotSupported(format!(
53 "variable {:?} is not BoolDomain",
54 name
55 )));
56 }
57
58 ans.add_variable(&name);
59 }
60
61 for expr in submodel.constraints() {
62 match ans.add_expression(expr) {
63 Ok(_) => {}
64 Err(error) => {
65 let message = format!("{:?}", error);
66 return Err(ModelFeatureNotSupported(message));
67 }
68 }
69 }
70
71 Ok(ans)
72 }
73
74 #[allow(dead_code)] pub fn get_variables(&self) -> Vec<&conjure_ast::Name> {
77 let mut ans: Vec<&conjure_ast::Name> = Vec::new();
78
79 for key in self.variables.keys() {
80 ans.push(key);
81 }
82
83 ans
84 }
85
86 pub fn get_index(&self, var: &conjure_ast::Name) -> Option<i32> {
88 self.variables.get(var).copied()
89 }
90
91 pub fn get_name(&self, ind: i32) -> Option<&conjure_ast::Name> {
93 for key in self.variables.keys() {
94 let idx = self.get_index(key)?;
95 if idx == ind {
96 return Some(key);
97 }
98 }
99
100 None
101 }
102
103 pub fn add_variable(&mut self, var: &conjure_ast::Name) {
105 self.variables.insert(var.clone(), self.next_ind);
106 self.next_ind += 1;
107 }
108
109 pub fn has_variable<T: HasVariable>(&self, value: T) -> bool {
113 value.has_variable(self)
114 }
115
116 pub fn add_clause(&mut self, vec: &Vec<i32>) -> Result<(), CNFError> {
120 for idx in vec {
121 if !self.has_variable(idx.abs()) {
122 return Err(CNFError::ClauseIndexNotFound(*idx));
123 }
124 }
125 self.clauses.push(vec.clone());
126 Ok(())
127 }
128
129 pub fn add_expression(&mut self, expr: &conjure_ast::Expression) -> Result<(), CNFError> {
133 for row in self.handle_expression(expr)? {
134 self.add_clause(&row)?;
135 }
136 Ok(())
137 }
138
139 #[allow(dead_code)] pub fn as_expression(&self) -> Result<conjure_ast::Expression, CNFError> {
144 let mut expr_clauses: Vec<conjure_ast::Expression> = Vec::new();
145
146 for clause in &self.clauses {
147 expr_clauses.push(self.clause_to_expression(clause)?);
148 }
149
150 Ok(conjure_ast::Expression::And(Metadata::new(), expr_clauses))
151 }
152
153 fn clause_to_expression(&self, clause: &Vec<i32>) -> Result<conjure_ast::Expression, CNFError> {
157 let mut ans: Vec<conjure_ast::Expression> = Vec::new();
158
159 for idx in clause {
160 match self.get_name(idx.abs()) {
161 None => return Err(CNFError::ClauseIndexNotFound(*idx)),
162 Some(name) => {
163 if *idx > 0 {
164 ans.push(conjure_ast::Expression::Atomic(
165 Metadata::new(),
166 conjure_ast::Atom::Reference(name.clone()),
167 ));
168 } else {
169 let expression: conjure_ast::Expression = conjure_ast::Expression::Atomic(
170 Metadata::new(),
171 conjure_ast::Atom::Reference(name.clone()),
172 );
173 ans.push(conjure_ast::Expression::Not(
174 Metadata::new(),
175 Box::from(expression),
176 ))
177 }
178 }
179 }
180 }
181
182 Ok(conjure_ast::Expression::Or(Metadata::new(), ans))
183 }
184
185 fn get_reference_index(&self, name: &conjure_ast::Name) -> Result<i32, CNFError> {
191 match self.get_index(name) {
192 None => Err(CNFError::VariableNameNotFound(name.clone())),
193 Some(ind) => Ok(ind),
194 }
195 }
196
197 fn handle_reference(&self, name: &conjure_ast::Name) -> Result<Vec<i32>, CNFError> {
203 Ok(vec![self.get_reference_index(name)?])
204 }
205
206 fn handle_not(&self, expr: &conjure_ast::Expression) -> Result<Vec<i32>, CNFError> {
210 match expr {
211 conjure_ast::Expression::Atomic(_metadata, conjure_ast::Atom::Reference(name)) => {
213 Ok(vec![-self.get_reference_index(name)?])
214 }
215 _ => Err(CNFError::UnexpectedExpressionInsideNot(expr.clone())),
216 }
217 }
218
219 fn handle_or(&self, expressions: &Vec<conjure_ast::Expression>) -> Result<Vec<i32>, CNFError> {
223 let mut ans: Vec<i32> = Vec::new();
224
225 for expr in expressions {
226 let ret = self.handle_flat_expression(expr)?;
227 for ind in ret {
228 ans.push(ind);
229 }
230 }
231
232 Ok(ans)
233 }
234
235 fn handle_flat_expression(
239 &self,
240 expression: &conjure_ast::Expression,
241 ) -> Result<Vec<i32>, CNFError> {
242 match expression {
243 conjure_ast::Expression::Atomic(_metadata, conjure_ast::Atom::Reference(name)) => {
244 self.handle_reference(name)
245 }
246 conjure_ast::Expression::Not(_metadata, var_box) => self.handle_not(var_box),
247 conjure_ast::Expression::Or(_metadata, expressions) => self.handle_or(expressions),
248 _ => Err(CNFError::UnexpectedExpression(expression.clone())),
249 }
250 }
251
252 fn handle_and(
256 &self,
257 expressions: &Vec<conjure_ast::Expression>,
258 ) -> Result<Vec<Vec<i32>>, CNFError> {
259 let mut ans: Vec<Vec<i32>> = Vec::new();
260
261 for expression in expressions {
262 match expression {
263 conjure_ast::Expression::And(_metadata, _expressions) => {
264 return Err(CNFError::NestedAnd(expression.clone()));
265 }
266 _ => {
267 ans.push(self.handle_flat_expression(expression)?);
268 }
269 }
270 }
271
272 Ok(ans)
273 }
274
275 fn handle_expression(
279 &self,
280 expression: &conjure_ast::Expression,
281 ) -> Result<Vec<Vec<i32>>, CNFError> {
282 match expression {
283 conjure_ast::Expression::And(_metadata, expressions) => self.handle_and(expressions),
284 _ => Ok(vec![self.handle_flat_expression(expression)?]),
285 }
286 }
287}
288
289impl Default for CNFModel {
290 fn default() -> Self {
291 Self::new()
292 }
293}
294
295#[derive(Error, Debug)]
296pub enum CNFError {
297 #[error("Variable with name `{0}` not found")]
298 VariableNameNotFound(conjure_ast::Name),
299
300 #[error("Clause with index `{0}` not found")]
301 ClauseIndexNotFound(i32),
302
303 #[error("Unexpected Expression `{0}` inside Not(). Only Not(Reference) allowed!")]
304 UnexpectedExpressionInsideNot(conjure_ast::Expression),
305
306 #[error(
307 "Unexpected Expression `{0}` found. Only Reference, Not(Reference) and Or(...) allowed!"
308 )]
309 UnexpectedExpression(conjure_ast::Expression),
310
311 #[error("Unexpected nested And: {0}")]
312 NestedAnd(conjure_ast::Expression),
313}
314
315pub trait HasVariable {
317 fn has_variable(self, cnf: &CNFModel) -> bool;
318}
319
320impl HasVariable for i32 {
321 fn has_variable(self, cnf: &CNFModel) -> bool {
322 cnf.get_name(self).is_some()
323 }
324}
325
326impl HasVariable for &conjure_ast::Name {
327 fn has_variable(self, cnf: &CNFModel) -> bool {
328 cnf.get_index(self).is_some()
329 }
330}