rustproof_libsmt/backends/
smtlib2.rs1use std::process::{Child};
7use std::collections::{HashMap};
8use std::io::{Read, Write};
9
10use petgraph::graph::{Graph, NodeIndex};
11use petgraph::EdgeDirection;
12
13use backends::backend::{Logic, SMTBackend, SMTNode, SMTResult};
14use super::backend::SMTRes;
15
16pub trait SMTProc {
27 fn init(&mut self);
31 fn pipe<'a>(&'a mut self) -> &'a mut Child;
33
34 fn write<T: AsRef<str>>(&mut self, s: T) -> Result<(), String> {
35 if let Some(ref mut stdin) = self.pipe().stdin.as_mut() {
37 stdin.write(s.as_ref().as_bytes()).expect("Write to stdin failed");
38 stdin.flush().expect("Failed to flush stdin");
39 }
40 Ok(())
41 }
42
43 fn read(&mut self) -> String {
44 let mut bytes_read = [0; 2048];
54 let mut s = String::new();
55 let solver = self.pipe();
56 if let Some(ref mut stdout) = solver.stdout.as_mut() {
57 loop {
58 let n = stdout.read(&mut bytes_read).unwrap();
59 s = format!("{}{}",
60 s,
61 String::from_utf8(bytes_read[0..n].to_vec()).unwrap());
62 if n < 2048 {
63 break;
64 }
65 }
66 }
67 s
68 }
69
70 fn read_checksat_output(&mut self) -> String {
72 let mut buf = String::new();
74 if let Some(ref mut stdout) = self.pipe().stdout.as_mut() {
76 loop {
77 for (_,c) in stdout.bytes().enumerate() {
78 let chr = c.unwrap() as char;
79 buf.push(chr);
80 if buf.ends_with("sat") {
81 return buf;
82 }
83 }
84 }
85 }
86 unreachable!()
87 }
88
89 fn read_getmodel_output(&mut self) -> String {
91 let mut buf = String::new();
93 if let Some(ref mut stdout) = self.pipe().stdout.as_mut() {
95 let mut count = 0;
97 loop {
98 for (_,c) in stdout.bytes().enumerate() {
99 let chr = c.unwrap() as char;
100 if chr=='\n' && count==0 {
102 continue;
103 }
104 buf.push(chr);
105 match chr {
106 '(' => { count+=1; },
107 ')' => { count-=1; },
108 _ => {}
109 }
110 if count==0 {
111 return buf;
112 }
113 }
114 }
115 }
116 unreachable!()
117 }
118
119}
120
121#[derive(Clone, Debug)]
122pub enum EdgeData {
123 EdgeOrder(usize),
124}
125
126#[derive(Clone, Debug)]
127pub struct SMTLib2<T: Logic> {
128 logic: Option<T>,
129 gr: Graph<T::Fns, EdgeData>,
130 var_index: usize,
131 var_map: HashMap<String, (NodeIndex, T::Sorts)>,
132 idx_map: HashMap<NodeIndex, String>,
133}
134
135impl<L: Logic> SMTLib2<L> {
136 pub fn new(logic: Option<L>) -> SMTLib2<L> {
137 let solver = SMTLib2 {
138 logic: logic,
139 gr: Graph::new(),
140 var_index: 0,
141 var_map: HashMap::new(),
142 idx_map: HashMap::new(),
143 };
144 solver
145 }
146
147 pub fn expand_assertion(&self, ni: NodeIndex) -> String {
149 let mut children = self.gr
150 .edges_directed(ni, EdgeDirection::Outgoing)
151 .map(|(other, edge)| {
152 match *edge {
153 EdgeData::EdgeOrder(ref i) => (other, *i),
154 }
155 })
156 .collect::<Vec<_>>();
157 children.sort_by(|x, y| (x.1).cmp(&y.1));
158
159 let mut assertion = self.gr[ni].to_string();
160
161 assertion = if self.gr[ni].is_fn() {
162 format!("({}", assertion)
163 } else {
164 assertion
165 };
166
167 for node in &children {
168 assertion = format!("{} {}", assertion, self.expand_assertion(node.0))
169 }
170
171 if self.gr[ni].is_fn() {
172 format!("{})", assertion)
173 } else {
174 assertion
175 }
176 }
177
178 pub fn new_const<T: Into<L::Fns>>(&mut self, cval: T) -> NodeIndex {
179 self.gr.add_node(cval.into())
180 }
181}
182
183impl<L: Logic> SMTBackend for SMTLib2<L> {
184 type Idx = NodeIndex;
185 type Logic = L;
186
187 fn new_var<T, P>(&mut self, var_name: Option<T>, ty: P) -> Self::Idx
188 where T: AsRef<str>,
189 P: Into<<<Self as SMTBackend>::Logic as Logic>::Sorts>
190 {
191 let var_name = var_name.map(|s| s.as_ref().to_owned()).unwrap_or({
192 self.var_index += 1;
193 format!("X_{}", self.var_index)
194 });
195 let typ = ty.into();
196 let idx = self.gr.add_node(Self::Logic::free_var(var_name.clone(), typ.clone()));
197 self.var_map.insert(var_name.clone(), (idx, typ));
198 self.idx_map.insert(idx, var_name);
199 idx
200 }
201
202 fn set_logic<S: SMTProc>(&mut self, smt_proc: &mut S) {
203 if self.logic.is_none() {
204 return;
205 }
206 let logic = self.logic.unwrap().clone();
207 smt_proc.write(format!("(set-logic {})\n", logic));
208 }
209
210 fn assert<T: Into<L::Fns>>(&mut self, assert: T, ops: &[Self::Idx]) -> Self::Idx {
211 let assertion = self.gr.add_node(assert.into());
213 for (i, op) in ops.iter().enumerate() {
214 self.gr.add_edge(assertion, *op, EdgeData::EdgeOrder(i));
215 }
216 assertion
217 }
218
219 fn check_sat<S: SMTProc>(&mut self, smt_proc: &mut S, debug: bool) -> SMTRes {
220 let mut decls = Vec::new();
222 for (name, val) in &self.var_map {
223 let ni = &val.0;
224 let ty = &val.1;
225 if self.gr[*ni].is_var() {
226 decls.push(format!("(declare-fun {} () {})\n", name, ty));
227 }
228 }
229 let mut assertions = Vec::new();
231 for idx in self.gr.node_indices() {
232 if self.gr.edges_directed(idx, EdgeDirection::Incoming).collect::<Vec<_>>().is_empty() {
233 if self.gr[idx].is_fn() {
234 assertions.push(format!("(assert {})\n", self.expand_assertion(idx)));
235 }
236 }
237 }
238
239 for w in decls.iter().chain(assertions.iter()) {
240 if debug { print!("{}", w) };
241 smt_proc.write(w);
242 }
243
244 smt_proc.write("(check-sat)\n".to_owned());
245 let read = smt_proc.read_checksat_output();
246 if &read == "sat" {
247 SMTRes::Sat(read, None)
248 } else if &read == "unsat" {
249 SMTRes::Unsat(read, None)
250 } else {
251 SMTRes::Error(read, None)
252 }
253 }
254
255 fn solve<S: SMTProc>(&mut self, smt_proc: &mut S, debug: bool) -> (SMTResult<HashMap<Self::Idx, u64>>, SMTRes) {
257 let mut result = HashMap::new();
258 let check_sat = self.check_sat(smt_proc, debug);
259 match check_sat {
261 SMTRes::Sat(ref res, _) => {
262 smt_proc.write("(get-model)\n".to_owned());
263 let read_result = smt_proc.read_getmodel_output();
264 return (Ok(result), SMTRes::Sat(res.clone(), Some(read_result)));
265 },
266 _ => {}
267 }
268
269 (Ok(result), check_sat.clone())
270 }
271}