1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Tim King, Haniel Barbosa |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* Theory of separation logic. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__SEP__THEORY_SEP_H |
19 |
|
#define CVC5__THEORY__SEP__THEORY_SEP_H |
20 |
|
|
21 |
|
#include "context/cdhashmap.h" |
22 |
|
#include "context/cdhashset.h" |
23 |
|
#include "context/cdlist.h" |
24 |
|
#include "context/cdqueue.h" |
25 |
|
#include "theory/decision_strategy.h" |
26 |
|
#include "theory/inference_manager_buffered.h" |
27 |
|
#include "theory/sep/theory_sep_rewriter.h" |
28 |
|
#include "theory/theory.h" |
29 |
|
#include "theory/theory_state.h" |
30 |
|
#include "theory/uf/equality_engine.h" |
31 |
|
#include "util/statistics_stats.h" |
32 |
|
|
33 |
|
namespace cvc5 { |
34 |
|
namespace theory { |
35 |
|
|
36 |
|
class TheoryModel; |
37 |
|
|
38 |
|
namespace sep { |
39 |
|
|
40 |
|
class TheorySep : public Theory { |
41 |
|
typedef context::CDList<Node> NodeList; |
42 |
|
typedef context::CDHashSet<Node> NodeSet; |
43 |
|
typedef context::CDHashMap<Node, Node> NodeNodeMap; |
44 |
|
|
45 |
|
///////////////////////////////////////////////////////////////////////////// |
46 |
|
// MISC |
47 |
|
///////////////////////////////////////////////////////////////////////////// |
48 |
|
|
49 |
|
private: |
50 |
|
/** all lemmas sent */ |
51 |
|
NodeSet d_lemmas_produced_c; |
52 |
|
|
53 |
|
/** True node for predicates = true */ |
54 |
|
Node d_true; |
55 |
|
|
56 |
|
/** True node for predicates = false */ |
57 |
|
Node d_false; |
58 |
|
|
59 |
|
//whether bounds have been initialized |
60 |
|
bool d_bounds_init; |
61 |
|
|
62 |
|
TheorySepRewriter d_rewriter; |
63 |
|
/** A (default) theory state object */ |
64 |
|
TheoryState d_state; |
65 |
|
/** A buffered inference manager */ |
66 |
|
InferenceManagerBuffered d_im; |
67 |
|
|
68 |
|
Node mkAnd( std::vector< TNode >& assumptions ); |
69 |
|
|
70 |
|
int processAssertion( |
71 |
|
Node n, |
72 |
|
std::map<int, std::map<Node, int> >& visited, |
73 |
|
std::map<int, std::map<Node, std::vector<Node> > >& references, |
74 |
|
std::map<int, std::map<Node, bool> >& references_strict, |
75 |
|
bool pol, |
76 |
|
bool hasPol, |
77 |
|
bool underSpatial); |
78 |
|
|
79 |
|
public: |
80 |
|
TheorySep(context::Context* c, |
81 |
|
context::UserContext* u, |
82 |
|
OutputChannel& out, |
83 |
|
Valuation valuation, |
84 |
|
const LogicInfo& logicInfo, |
85 |
|
ProofNodeManager* pnm = nullptr); |
86 |
|
~TheorySep(); |
87 |
|
|
88 |
|
/** |
89 |
|
* Declare heap. For smt2 inputs, this is called when the command |
90 |
|
* (declare-heap (locT datat)) is invoked by the user. This sets locT as the |
91 |
|
* location type and dataT is the data type for the heap. This command can be |
92 |
|
* executed once only, and must be invoked before solving separation logic |
93 |
|
* inputs. |
94 |
|
*/ |
95 |
|
void declareSepHeap(TypeNode locT, TypeNode dataT) override; |
96 |
|
|
97 |
|
//--------------------------------- initialization |
98 |
|
/** get the official theory rewriter of this theory */ |
99 |
|
TheoryRewriter* getTheoryRewriter() override; |
100 |
|
/** get the proof checker of this theory */ |
101 |
|
ProofRuleChecker* getProofChecker() override; |
102 |
|
/** |
103 |
|
* Returns true if we need an equality engine. If so, we initialize the |
104 |
|
* information regarding how it should be setup. For details, see the |
105 |
|
* documentation in Theory::needsEqualityEngine. |
106 |
|
*/ |
107 |
|
bool needsEqualityEngine(EeSetupInfo& esi) override; |
108 |
|
/** finish initialization */ |
109 |
|
void finishInit() override; |
110 |
|
//--------------------------------- end initialization |
111 |
|
/** preregister term */ |
112 |
|
void preRegisterTerm(TNode n) override; |
113 |
|
|
114 |
|
std::string identify() const override { return std::string("TheorySep"); } |
115 |
|
|
116 |
|
///////////////////////////////////////////////////////////////////////////// |
117 |
|
// PREPROCESSING |
118 |
|
///////////////////////////////////////////////////////////////////////////// |
119 |
|
|
120 |
|
public: |
121 |
|
void ppNotifyAssertions(const std::vector<Node>& assertions) override; |
122 |
|
///////////////////////////////////////////////////////////////////////////// |
123 |
|
// T-PROPAGATION / REGISTRATION |
124 |
|
///////////////////////////////////////////////////////////////////////////// |
125 |
|
|
126 |
|
private: |
127 |
|
/** Should be called to propagate the literal. */ |
128 |
|
bool propagateLit(TNode literal); |
129 |
|
/** Conflict when merging constants */ |
130 |
|
void conflict(TNode a, TNode b); |
131 |
|
|
132 |
|
public: |
133 |
|
TrustNode explain(TNode n) override; |
134 |
|
|
135 |
|
public: |
136 |
|
void computeCareGraph() override; |
137 |
|
|
138 |
|
///////////////////////////////////////////////////////////////////////////// |
139 |
|
// MODEL GENERATION |
140 |
|
///////////////////////////////////////////////////////////////////////////// |
141 |
|
|
142 |
|
public: |
143 |
|
void postProcessModel(TheoryModel* m) override; |
144 |
|
|
145 |
|
///////////////////////////////////////////////////////////////////////////// |
146 |
|
// NOTIFICATIONS |
147 |
|
///////////////////////////////////////////////////////////////////////////// |
148 |
|
|
149 |
|
public: |
150 |
|
|
151 |
|
void presolve() override; |
152 |
9847 |
void shutdown() override {} |
153 |
|
|
154 |
|
///////////////////////////////////////////////////////////////////////////// |
155 |
|
// MAIN SOLVER |
156 |
|
///////////////////////////////////////////////////////////////////////////// |
157 |
|
|
158 |
|
//--------------------------------- standard check |
159 |
|
/** Do we need a check call at last call effort? */ |
160 |
|
bool needsCheckLastEffort() override; |
161 |
|
/** Post-check, called after the fact queue of the theory is processed. */ |
162 |
|
void postCheck(Effort level) override; |
163 |
|
/** Pre-notify fact, return true if processed. */ |
164 |
|
bool preNotifyFact(TNode atom, |
165 |
|
bool pol, |
166 |
|
TNode fact, |
167 |
|
bool isPrereg, |
168 |
|
bool isInternal) override; |
169 |
|
/** Notify fact */ |
170 |
|
void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override; |
171 |
|
//--------------------------------- end standard check |
172 |
|
|
173 |
|
private: |
174 |
|
/** Ensures that the reduction has been added for the given fact */ |
175 |
|
void reduceFact(TNode atom, bool polarity, TNode fact); |
176 |
|
/** Is spatial kind? */ |
177 |
|
bool isSpatialKind(Kind k) const; |
178 |
|
// NotifyClass: template helper class for d_equalityEngine - handles |
179 |
|
// call-back from congruence closure module |
180 |
9853 |
class NotifyClass : public eq::EqualityEngineNotify |
181 |
|
{ |
182 |
|
TheorySep& d_sep; |
183 |
|
|
184 |
|
public: |
185 |
9853 |
NotifyClass(TheorySep& sep) : d_sep(sep) {} |
186 |
|
|
187 |
|
bool eqNotifyTriggerPredicate(TNode predicate, bool value) override |
188 |
|
{ |
189 |
|
Debug("sep::propagate") |
190 |
|
<< "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " |
191 |
|
<< (value ? "true" : "false") << ")" << std::endl; |
192 |
|
Assert(predicate.getKind() == kind::EQUAL); |
193 |
|
// Just forward to sep |
194 |
|
if (value) |
195 |
|
{ |
196 |
|
return d_sep.propagateLit(predicate); |
197 |
|
} |
198 |
|
return d_sep.propagateLit(predicate.notNode()); |
199 |
|
} |
200 |
3923 |
bool eqNotifyTriggerTermEquality(TheoryId tag, |
201 |
|
TNode t1, |
202 |
|
TNode t2, |
203 |
|
bool value) override |
204 |
|
{ |
205 |
7846 |
Debug("sep::propagate") |
206 |
3923 |
<< "NotifyClass::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 |
207 |
3923 |
<< ", " << (value ? "true" : "false") << ")" << std::endl; |
208 |
3923 |
if (value) |
209 |
|
{ |
210 |
|
// Propagate equality between shared terms |
211 |
1194 |
return d_sep.propagateLit(t1.eqNode(t2)); |
212 |
|
} |
213 |
2729 |
return d_sep.propagateLit(t1.eqNode(t2).notNode()); |
214 |
|
} |
215 |
|
|
216 |
|
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override |
217 |
|
{ |
218 |
|
Debug("sep::propagate") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 |
219 |
|
<< ", " << t2 << ")" << std::endl; |
220 |
|
d_sep.conflict(t1, t2); |
221 |
|
} |
222 |
|
|
223 |
3441 |
void eqNotifyNewClass(TNode t) override {} |
224 |
35665 |
void eqNotifyMerge(TNode t1, TNode t2) override |
225 |
|
{ |
226 |
35665 |
d_sep.eqNotifyMerge(t1, t2); |
227 |
35665 |
} |
228 |
2729 |
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {} |
229 |
|
}; |
230 |
|
|
231 |
|
/** The notify class for d_equalityEngine */ |
232 |
|
NotifyClass d_notify; |
233 |
|
|
234 |
|
/** list of all refinement lemms */ |
235 |
|
std::map< Node, std::map< Node, std::vector< Node > > > d_refinement_lem; |
236 |
|
|
237 |
|
//cache for positive polarity start reduction |
238 |
|
NodeSet d_reduce; |
239 |
|
std::map< Node, std::map< Node, Node > > d_red_conc; |
240 |
|
std::map< Node, std::map< Node, Node > > d_neg_guard; |
241 |
|
std::vector< Node > d_neg_guards; |
242 |
|
/** a (singleton) decision strategy for each negative guard. */ |
243 |
|
std::map<Node, std::unique_ptr<DecisionStrategySingleton> > |
244 |
|
d_neg_guard_strategy; |
245 |
|
std::map< Node, Node > d_guard_to_assertion; |
246 |
|
NodeList d_spatial_assertions; |
247 |
|
|
248 |
|
//data,ref type (globally fixed) |
249 |
|
TypeNode d_type_ref; |
250 |
|
TypeNode d_type_data; |
251 |
|
//currently fix one data type for each location type, throw error if using more than one |
252 |
|
std::map< TypeNode, TypeNode > d_loc_to_data_type; |
253 |
|
//information about types |
254 |
|
std::map< TypeNode, Node > d_base_label; |
255 |
|
std::map< TypeNode, Node > d_nil_ref; |
256 |
|
//reference bound |
257 |
|
std::map< TypeNode, Node > d_reference_bound; |
258 |
|
std::map< TypeNode, Node > d_reference_bound_max; |
259 |
|
std::map< TypeNode, std::vector< Node > > d_type_references; |
260 |
|
//kind of bound for reference types |
261 |
|
enum { |
262 |
|
bound_strict, |
263 |
|
bound_default, |
264 |
|
bound_invalid, |
265 |
|
}; |
266 |
|
std::map< TypeNode, unsigned > d_bound_kind; |
267 |
|
|
268 |
|
std::map< TypeNode, std::vector< Node > > d_type_references_card; |
269 |
|
std::map< Node, unsigned > d_type_ref_card_id; |
270 |
|
std::map< TypeNode, std::vector< Node > > d_type_references_all; |
271 |
|
std::map< TypeNode, unsigned > d_card_max; |
272 |
|
//for empty argument |
273 |
|
std::map< TypeNode, Node > d_emp_arg; |
274 |
|
//map from ( atom, label, child index ) -> label |
275 |
|
std::map< Node, std::map< Node, std::map< int, Node > > > d_label_map; |
276 |
|
std::map< Node, Node > d_label_map_parent; |
277 |
|
|
278 |
|
//term model |
279 |
|
std::map< Node, Node > d_tmodel; |
280 |
|
std::map< Node, Node > d_pto_model; |
281 |
|
|
282 |
|
class HeapAssertInfo { |
283 |
|
public: |
284 |
|
HeapAssertInfo( context::Context* c ); |
285 |
293 |
~HeapAssertInfo(){} |
286 |
|
context::CDO< Node > d_pto; |
287 |
|
context::CDO< bool > d_has_neg_pto; |
288 |
|
}; |
289 |
|
std::map< Node, HeapAssertInfo * > d_eqc_info; |
290 |
|
HeapAssertInfo * getOrMakeEqcInfo( Node n, bool doMake = false ); |
291 |
|
|
292 |
|
//get global reference/data type |
293 |
|
TypeNode getReferenceType( Node n ); |
294 |
|
TypeNode getDataType( Node n ); |
295 |
|
/** |
296 |
|
* Register reference data types for atom. Calls the method below for |
297 |
|
* the appropriate types. |
298 |
|
*/ |
299 |
|
void registerRefDataTypesAtom(Node atom); |
300 |
|
/** |
301 |
|
* This is called either when: |
302 |
|
* (A) a declare-heap command is issued with tn1/tn2, and atom is null, or |
303 |
|
* (B) an atom specifying the heap type tn1/tn2 is registered to this theory. |
304 |
|
* We set the heap type if we are are case (A), and check whether the |
305 |
|
* heap type is consistent in the case of (B). |
306 |
|
*/ |
307 |
|
void registerRefDataTypes(TypeNode tn1, TypeNode tn2, Node atom); |
308 |
|
//get location/data type |
309 |
|
//get the base label for the spatial assertion |
310 |
|
Node getBaseLabel( TypeNode tn ); |
311 |
|
Node getNilRef( TypeNode tn ); |
312 |
|
void setNilRef( TypeNode tn, Node n ); |
313 |
|
Node getLabel( Node atom, int child, Node lbl ); |
314 |
|
Node applyLabel( Node n, Node lbl, std::map< Node, Node >& visited ); |
315 |
|
void getLabelChildren( Node atom, Node lbl, std::vector< Node >& children, std::vector< Node >& labels ); |
316 |
|
|
317 |
395 |
class HeapInfo { |
318 |
|
public: |
319 |
395 |
HeapInfo() : d_computed(false) {} |
320 |
|
//information about the model |
321 |
|
bool d_computed; |
322 |
|
std::vector< Node > d_heap_locs; |
323 |
|
std::vector< Node > d_heap_locs_model; |
324 |
|
//get value |
325 |
|
Node getValue( TypeNode tn ); |
326 |
|
}; |
327 |
|
//heap info ( label -> HeapInfo ) |
328 |
|
std::map< Node, HeapInfo > d_label_model; |
329 |
|
// loc -> { data_1, ..., data_n } where (not (pto loc data_1))...(not (pto loc data_n))). |
330 |
|
std::map< Node, std::vector< Node > > d_heap_locs_nptos; |
331 |
|
|
332 |
|
void debugPrintHeap( HeapInfo& heap, const char * c ); |
333 |
|
void validatePto( HeapAssertInfo * ei, Node ei_n ); |
334 |
|
void addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity ); |
335 |
|
void mergePto( Node p1, Node p2 ); |
336 |
|
void computeLabelModel( Node lbl ); |
337 |
|
Node instantiateLabel(Node n, |
338 |
|
Node o_lbl, |
339 |
|
Node lbl, |
340 |
|
Node lbl_v, |
341 |
|
std::map<Node, Node>& visited, |
342 |
|
std::map<Node, Node>& pto_model, |
343 |
|
TypeNode rtn, |
344 |
|
std::map<Node, bool>& active_lbl, |
345 |
|
unsigned ind = 0); |
346 |
|
void setInactiveAssertionRec( Node fact, std::map< Node, std::vector< Node > >& lbl_to_assertions, std::map< Node, bool >& assert_active ); |
347 |
|
|
348 |
|
Node mkUnion( TypeNode tn, std::vector< Node >& locs ); |
349 |
|
|
350 |
|
private: |
351 |
|
Node getRepresentative( Node t ); |
352 |
|
bool hasTerm( Node a ); |
353 |
|
bool areEqual( Node a, Node b ); |
354 |
|
bool areDisequal( Node a, Node b ); |
355 |
|
void eqNotifyMerge(TNode t1, TNode t2); |
356 |
|
|
357 |
|
void sendLemma( std::vector< Node >& ant, Node conc, InferenceId id, bool infer = false ); |
358 |
|
void doPending(); |
359 |
|
|
360 |
|
public: |
361 |
|
|
362 |
|
void initializeBounds(); |
363 |
|
};/* class TheorySep */ |
364 |
|
|
365 |
|
} // namespace sep |
366 |
|
} // namespace theory |
367 |
|
} // namespace cvc5 |
368 |
|
|
369 |
|
#endif /* CVC5__THEORY__SEP__THEORY_SEP_H */ |