conjure_core/solver/adaptors/rustsat/
adaptor.rs
1use std::any::type_name;
2use std::fmt::format;
3use std::hash::Hash;
4use std::iter::Inspect;
5use std::ops::Deref;
6use std::ptr::null;
7use std::vec;
8
9use clap::error;
10use minion_rs::ast::{Model, Tuple};
11use rustsat::encodings::am1::Def;
12use rustsat::solvers::{Solve, SolverResult};
13use rustsat::types::{Assignment, Clause, Lit, TernaryVal, Var as satVar};
14use std::collections::{BTreeMap, HashMap};
15use std::result::Result::Ok;
16use tracing_subscriber::filter::DynFilterFn;
17
18use crate::ast::Domain::BoolDomain;
19
20use rustsat_minisat::core::Minisat;
21
22use crate::ast::{Atom, Expression, Literal, Name};
23use crate::metadata::Metadata;
24use crate::solver::adaptors::rustsat::convs::handle_cnf;
25use crate::solver::SearchComplete::NoSolutions;
26use crate::solver::{
27 self, private, SearchStatus, SolveSuccess, SolverAdaptor, SolverCallback, SolverError,
28 SolverFamily, SolverMutCallback,
29};
30use crate::stats::SolverStats;
31use crate::{ast as conjure_ast, bug, Model as ConjureModel};
32
33use rustsat::instances::{BasicVarManager, Cnf, SatInstance};
34
35use thiserror::Error;
36
37pub struct SAT {
39 __non_constructable: private::Internal,
40 model_inst: Option<SatInstance>,
41 var_map: Option<HashMap<String, Lit>>,
42 solver_inst: Minisat,
43 decision_refs: Option<Vec<String>>,
44}
45
46impl private::Sealed for SAT {}
47
48impl Default for SAT {
49 fn default() -> Self {
50 SAT {
51 __non_constructable: private::Internal,
52 solver_inst: Minisat::default(),
53 var_map: None,
54 model_inst: None,
55 decision_refs: None,
56 }
57 }
58}
59
60fn get_ref_sols(
61 find_refs: Vec<String>,
62 sol: Assignment,
63 var_map: HashMap<String, Lit>,
64) -> HashMap<Name, Literal> {
65 let mut solution: HashMap<Name, Literal> = HashMap::new();
66
67 for reference in find_refs {
68 let lit: Lit = match var_map.get(&reference) {
71 Some(a) => *a,
72 None => panic!(
73 "There should never be a non-just literal occurring here. Something is broken upstream."
74 ),
75 };
76 solution.insert(
77 Name::UserName(reference),
78 match sol[lit.var()] {
79 TernaryVal::True => Literal::Int(1),
80 TernaryVal::False => Literal::Int(0),
81 TernaryVal::DontCare => Literal::Int(2),
82 },
83 );
84 }
85
86 solution
87}
88
89impl SolverAdaptor for SAT {
90 fn solve(
91 &mut self,
92 callback: SolverCallback,
93 _: private::Internal,
94 ) -> Result<SolveSuccess, SolverError> {
95 let mut solver = &mut self.solver_inst;
96
97 let cnf: (Cnf, BasicVarManager) = self.model_inst.clone().unwrap().into_cnf();
98
99 (*(solver)).add_cnf(cnf.0);
100
101 let mut has_sol = false;
102 loop {
103 let res = solver.solve().unwrap();
104
105 match res {
106 SolverResult::Sat => {}
107 SolverResult::Unsat => {
108 return Ok(SolveSuccess {
109 stats: SolverStats {
110 conjure_solver_wall_time_s: -1.0,
111 solver_family: Some(self.get_family()),
112 solver_adaptor: Some("SAT".to_string()),
113 nodes: None,
114 satisfiable: None,
115 sat_vars: None,
116 sat_clauses: None,
117 },
118 status: if has_sol {
119 SearchStatus::Complete(solver::SearchComplete::HasSolutions)
120 } else {
121 SearchStatus::Complete(NoSolutions)
122 },
123 });
124 }
125 SolverResult::Interrupted => {
126 return Err(SolverError::Runtime("!!Interrupted Solution!!".to_string()))
127 }
128 };
129
130 let sol = solver.full_solution().unwrap();
131 has_sol = true;
132 let solution = get_ref_sols(
133 self.decision_refs.clone().unwrap(),
134 sol.clone(),
135 self.var_map.clone().unwrap(),
136 );
137
138 if !callback(solution) {
139 return Ok(SolveSuccess {
141 stats: SolverStats {
142 conjure_solver_wall_time_s: -1.0,
143 solver_family: Some(self.get_family()),
144 solver_adaptor: Some("SAT".to_string()),
145 nodes: None,
146 satisfiable: None,
147 sat_vars: None,
148 sat_clauses: None,
149 },
150 status: SearchStatus::Incomplete(solver::SearchIncomplete::UserTerminated),
151 });
152 }
153
154 let blocking_vec: Vec<_> = sol.clone().iter().map(|lit| !lit).collect();
155 let mut blocking_cl = Clause::new();
156 for lit_i in blocking_vec {
157 blocking_cl.add(lit_i);
158 }
159
160 solver.add_clause(blocking_cl).unwrap();
161 }
162 }
163
164 fn solve_mut(
165 &mut self,
166 callback: SolverMutCallback,
167 _: private::Internal,
168 ) -> Result<SolveSuccess, SolverError> {
169 Err(SolverError::OpNotSupported("solve_mut".to_owned()))
170 }
171
172 fn load_model(&mut self, model: ConjureModel, _: private::Internal) -> Result<(), SolverError> {
173 let sym_tab = model.as_submodel().symbols().deref().clone();
174 let decisions = sym_tab.into_iter();
175
176 let mut finds: Vec<String> = Vec::new();
177
178 for find_ref in decisions {
179 if (*find_ref.1.domain().unwrap() != BoolDomain) {
180 Err(SolverError::ModelInvalid(
181 "Only Boolean Decision Variables supported".to_string(),
182 ))?;
183 }
184
185 let name = find_ref.0;
186 finds.push(name.to_string());
187 }
188
189 self.decision_refs = Some(finds);
190
191 let m_clone = model.clone();
192 let vec_constr = m_clone.as_submodel().constraints();
193
194 let vec_cnf = vec_constr.clone();
195 let mut var_map: HashMap<String, Lit> = HashMap::new();
205
206 let inst: SatInstance = handle_cnf(&vec_cnf, &mut var_map);
207
208 self.var_map = Some(var_map);
209 let cnf: (Cnf, BasicVarManager) = inst.clone().into_cnf();
210 tracing::info!("CNF: {:?}", cnf.0);
211 self.model_inst = Some(inst);
212
213 Ok(())
214 }
215
216 fn get_family(&self) -> SolverFamily {
217 SolverFamily::SAT
218 }
219
220 fn init_solver(&mut self, _: private::Internal) {}
221
222 fn get_name(&self) -> Option<String> {
223 Some("SAT".to_string())
224 }
225
226 fn add_adaptor_info_to_stats(&self, stats: SolverStats) -> SolverStats {
227 SolverStats {
228 solver_adaptor: self.get_name(),
229 solver_family: Some(self.get_family()),
230 ..stats
231 }
232 }
233}