1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Haniel Barbosa, Tim King |
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 |
|
* Implementation of the theory of separation logic. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/sep/theory_sep.h" |
17 |
|
|
18 |
|
#include <map> |
19 |
|
|
20 |
|
#include "base/map_util.h" |
21 |
|
#include "expr/emptyset.h" |
22 |
|
#include "expr/kind.h" |
23 |
|
#include "expr/skolem_manager.h" |
24 |
|
#include "options/quantifiers_options.h" |
25 |
|
#include "options/sep_options.h" |
26 |
|
#include "options/smt_options.h" |
27 |
|
#include "smt/logic_exception.h" |
28 |
|
#include "theory/decision_manager.h" |
29 |
|
#include "theory/quantifiers/term_database.h" |
30 |
|
#include "theory/quantifiers/term_util.h" |
31 |
|
#include "theory/quantifiers_engine.h" |
32 |
|
#include "theory/rewriter.h" |
33 |
|
#include "theory/sep/theory_sep_rewriter.h" |
34 |
|
#include "theory/theory_model.h" |
35 |
|
#include "theory/valuation.h" |
36 |
|
#include "util/cardinality.h" |
37 |
|
|
38 |
|
using namespace std; |
39 |
|
using namespace cvc5::kind; |
40 |
|
|
41 |
|
namespace cvc5 { |
42 |
|
namespace theory { |
43 |
|
namespace sep { |
44 |
|
|
45 |
9917 |
TheorySep::TheorySep(Env& env, OutputChannel& out, Valuation valuation) |
46 |
|
: Theory(THEORY_SEP, env, out, valuation), |
47 |
9917 |
d_lemmas_produced_c(userContext()), |
48 |
|
d_bounds_init(false), |
49 |
|
d_state(env, valuation), |
50 |
|
d_im(env, *this, d_state, d_pnm, "theory::sep::"), |
51 |
|
d_notify(*this), |
52 |
9917 |
d_reduce(userContext()), |
53 |
29751 |
d_spatial_assertions(context()) |
54 |
|
{ |
55 |
9917 |
d_true = NodeManager::currentNM()->mkConst<bool>(true); |
56 |
9917 |
d_false = NodeManager::currentNM()->mkConst<bool>(false); |
57 |
|
|
58 |
|
// indicate we are using the default theory state object |
59 |
9917 |
d_theoryState = &d_state; |
60 |
9917 |
d_inferManager = &d_im; |
61 |
9917 |
} |
62 |
|
|
63 |
29742 |
TheorySep::~TheorySep() { |
64 |
10207 |
for( std::map< Node, HeapAssertInfo * >::iterator it = d_eqc_info.begin(); it != d_eqc_info.end(); ++it ){ |
65 |
293 |
delete it->second; |
66 |
|
} |
67 |
19828 |
} |
68 |
|
|
69 |
121 |
void TheorySep::declareSepHeap(TypeNode locT, TypeNode dataT) |
70 |
|
{ |
71 |
121 |
if (!d_type_ref.isNull()) |
72 |
|
{ |
73 |
4 |
TypeNode te1 = d_loc_to_data_type.begin()->first; |
74 |
4 |
std::stringstream ss; |
75 |
2 |
ss << "ERROR: cannot declare heap types for separation logic more than " |
76 |
|
"once. We are declaring heap of type "; |
77 |
2 |
ss << locT << " -> " << dataT << ", but we already have "; |
78 |
2 |
ss << d_type_ref << " -> " << d_type_data; |
79 |
2 |
throw LogicException(ss.str()); |
80 |
|
} |
81 |
238 |
Node nullAtom; |
82 |
119 |
registerRefDataTypes(locT, dataT, nullAtom); |
83 |
119 |
} |
84 |
|
|
85 |
9917 |
TheoryRewriter* TheorySep::getTheoryRewriter() { return &d_rewriter; } |
86 |
|
|
87 |
3783 |
ProofRuleChecker* TheorySep::getProofChecker() { return nullptr; } |
88 |
|
|
89 |
9917 |
bool TheorySep::needsEqualityEngine(EeSetupInfo& esi) |
90 |
|
{ |
91 |
9917 |
esi.d_notify = &d_notify; |
92 |
9917 |
esi.d_name = "theory::sep::ee"; |
93 |
9917 |
esi.d_notifyMerge = true; |
94 |
9917 |
return true; |
95 |
|
} |
96 |
|
|
97 |
9917 |
void TheorySep::finishInit() |
98 |
|
{ |
99 |
9917 |
Assert(d_equalityEngine != nullptr); |
100 |
|
// The kinds we are treating as function application in congruence |
101 |
9917 |
d_equalityEngine->addFunctionKind(kind::SEP_PTO); |
102 |
|
// we could but don't do congruence on SEP_STAR here. |
103 |
9917 |
} |
104 |
|
|
105 |
1876 |
void TheorySep::preRegisterTerm(TNode n) |
106 |
|
{ |
107 |
1876 |
Kind k = n.getKind(); |
108 |
1876 |
if (k == SEP_PTO || k == SEP_EMP || k == SEP_STAR || k == SEP_WAND) |
109 |
|
{ |
110 |
282 |
registerRefDataTypesAtom(n); |
111 |
|
} |
112 |
1875 |
} |
113 |
|
|
114 |
|
Node TheorySep::mkAnd( std::vector< TNode >& assumptions ) { |
115 |
|
if( assumptions.empty() ){ |
116 |
|
return d_true; |
117 |
|
}else if( assumptions.size()==1 ){ |
118 |
|
return assumptions[0]; |
119 |
|
}else{ |
120 |
|
return NodeManager::currentNM()->mkNode( kind::AND, assumptions ); |
121 |
|
} |
122 |
|
} |
123 |
|
|
124 |
|
|
125 |
|
///////////////////////////////////////////////////////////////////////////// |
126 |
|
// T-PROPAGATION / REGISTRATION |
127 |
|
///////////////////////////////////////////////////////////////////////////// |
128 |
|
|
129 |
3923 |
bool TheorySep::propagateLit(TNode literal) |
130 |
|
{ |
131 |
3923 |
return d_im.propagateLit(literal); |
132 |
|
} |
133 |
|
|
134 |
|
TrustNode TheorySep::explain(TNode literal) |
135 |
|
{ |
136 |
|
Debug("sep") << "TheorySep::explain(" << literal << ")" << std::endl; |
137 |
|
return d_im.explainLit(literal); |
138 |
|
} |
139 |
|
|
140 |
|
|
141 |
|
///////////////////////////////////////////////////////////////////////////// |
142 |
|
// SHARING |
143 |
|
///////////////////////////////////////////////////////////////////////////// |
144 |
|
|
145 |
6262 |
void TheorySep::computeCareGraph() { |
146 |
6262 |
Debug("sharing") << "Theory::computeCareGraph<" << getId() << ">()" << endl; |
147 |
7087 |
for (unsigned i = 0; i < d_sharedTerms.size(); ++ i) { |
148 |
1650 |
TNode a = d_sharedTerms[i]; |
149 |
1650 |
TypeNode aType = a.getType(); |
150 |
2429 |
for (unsigned j = i + 1; j < d_sharedTerms.size(); ++ j) { |
151 |
2545 |
TNode b = d_sharedTerms[j]; |
152 |
1604 |
if (b.getType() != aType) { |
153 |
|
// We don't care about the terms of different types |
154 |
663 |
continue; |
155 |
|
} |
156 |
941 |
switch (d_valuation.getEqualityStatus(a, b)) { |
157 |
624 |
case EQUALITY_TRUE_AND_PROPAGATED: |
158 |
|
case EQUALITY_FALSE_AND_PROPAGATED: |
159 |
|
// If we know about it, we should have propagated it, so we can skip |
160 |
624 |
break; |
161 |
317 |
default: |
162 |
|
// Let's split on it |
163 |
317 |
addCarePair(a, b); |
164 |
317 |
break; |
165 |
|
} |
166 |
|
} |
167 |
|
} |
168 |
6262 |
} |
169 |
|
|
170 |
|
|
171 |
|
///////////////////////////////////////////////////////////////////////////// |
172 |
|
// MODEL GENERATION |
173 |
|
///////////////////////////////////////////////////////////////////////////// |
174 |
|
|
175 |
629 |
void TheorySep::postProcessModel( TheoryModel* m ){ |
176 |
629 |
Trace("sep-model") << "Printing model for TheorySep..." << std::endl; |
177 |
|
|
178 |
1258 |
std::vector< Node > sep_children; |
179 |
1258 |
Node m_neq; |
180 |
1258 |
Node m_heap; |
181 |
636 |
for( std::map< TypeNode, Node >::iterator it = d_base_label.begin(); it != d_base_label.end(); ++it ){ |
182 |
|
//should only be constructing for one heap type |
183 |
7 |
Assert(m_heap.isNull()); |
184 |
7 |
Assert(d_loc_to_data_type.find(it->first) != d_loc_to_data_type.end()); |
185 |
7 |
Trace("sep-model") << "Model for heap, type = " << it->first << " with data type " << d_loc_to_data_type[it->first] << " : " << std::endl; |
186 |
14 |
TypeNode data_type = d_loc_to_data_type[it->first]; |
187 |
7 |
computeLabelModel( it->second ); |
188 |
7 |
if( d_label_model[it->second].d_heap_locs_model.empty() ){ |
189 |
1 |
Trace("sep-model") << " [empty]" << std::endl; |
190 |
|
}else{ |
191 |
15 |
for( unsigned j=0; j<d_label_model[it->second].d_heap_locs_model.size(); j++ ){ |
192 |
9 |
Assert(d_label_model[it->second].d_heap_locs_model[j].getKind() |
193 |
|
== kind::SINGLETON); |
194 |
18 |
std::vector< Node > pto_children; |
195 |
18 |
Node l = d_label_model[it->second].d_heap_locs_model[j][0]; |
196 |
9 |
Assert(l.isConst()); |
197 |
9 |
pto_children.push_back( l ); |
198 |
9 |
Trace("sep-model") << " " << l << " -> "; |
199 |
9 |
if( d_pto_model[l].isNull() ){ |
200 |
|
Trace("sep-model") << "_"; |
201 |
|
TypeEnumerator te_range( data_type ); |
202 |
|
if (d_state.isFiniteType(data_type)) |
203 |
|
{ |
204 |
|
pto_children.push_back( *te_range ); |
205 |
|
}else{ |
206 |
|
//must enumerate until we find one that is not explicitly pointed to |
207 |
|
bool success = false; |
208 |
|
Node cv; |
209 |
|
do{ |
210 |
|
cv = *te_range; |
211 |
|
if( std::find( d_heap_locs_nptos[l].begin(), d_heap_locs_nptos[l].end(), cv )==d_heap_locs_nptos[l].end() ){ |
212 |
|
success = true; |
213 |
|
}else{ |
214 |
|
++te_range; |
215 |
|
} |
216 |
|
}while( !success ); |
217 |
|
pto_children.push_back( cv ); |
218 |
|
} |
219 |
|
}else{ |
220 |
9 |
Trace("sep-model") << d_pto_model[l]; |
221 |
18 |
Node vpto = d_valuation.getModel()->getRepresentative( d_pto_model[l] ); |
222 |
9 |
Assert(vpto.isConst()); |
223 |
9 |
pto_children.push_back( vpto ); |
224 |
|
} |
225 |
9 |
Trace("sep-model") << std::endl; |
226 |
9 |
sep_children.push_back( NodeManager::currentNM()->mkNode( kind::SEP_PTO, pto_children ) ); |
227 |
|
} |
228 |
|
} |
229 |
14 |
Node nil = getNilRef( it->first ); |
230 |
14 |
Node vnil = d_valuation.getModel()->getRepresentative( nil ); |
231 |
7 |
m_neq = NodeManager::currentNM()->mkNode( kind::EQUAL, nil, vnil ); |
232 |
7 |
Trace("sep-model") << "sep.nil = " << vnil << std::endl; |
233 |
7 |
Trace("sep-model") << std::endl; |
234 |
7 |
if( sep_children.empty() ){ |
235 |
2 |
TypeEnumerator te_domain( it->first ); |
236 |
2 |
TypeEnumerator te_range( d_loc_to_data_type[it->first] ); |
237 |
1 |
m_heap = NodeManager::currentNM()->mkNode( kind::SEP_EMP, *te_domain, *te_range ); |
238 |
6 |
}else if( sep_children.size()==1 ){ |
239 |
4 |
m_heap = sep_children[0]; |
240 |
|
}else{ |
241 |
2 |
m_heap = NodeManager::currentNM()->mkNode( kind::SEP_STAR, sep_children ); |
242 |
|
} |
243 |
7 |
m->setHeapModel( m_heap, m_neq ); |
244 |
|
} |
245 |
629 |
Trace("sep-model") << "Finished printing model for TheorySep." << std::endl; |
246 |
629 |
} |
247 |
|
|
248 |
|
///////////////////////////////////////////////////////////////////////////// |
249 |
|
// NOTIFICATIONS |
250 |
|
///////////////////////////////////////////////////////////////////////////// |
251 |
|
|
252 |
|
|
253 |
15241 |
void TheorySep::presolve() { |
254 |
15241 |
Trace("sep-pp") << "Presolving" << std::endl; |
255 |
15241 |
} |
256 |
|
|
257 |
|
|
258 |
|
///////////////////////////////////////////////////////////////////////////// |
259 |
|
// MAIN SOLVER |
260 |
|
///////////////////////////////////////////////////////////////////////////// |
261 |
|
|
262 |
7044 |
bool TheorySep::preNotifyFact( |
263 |
|
TNode atom, bool polarity, TNode fact, bool isPrereg, bool isInternal) |
264 |
|
{ |
265 |
14088 |
TNode satom = atom.getKind() == SEP_LABEL ? atom[0] : atom; |
266 |
14088 |
TNode slbl = atom.getKind() == SEP_LABEL ? atom[1] : TNode::null(); |
267 |
7044 |
bool isSpatial = isSpatialKind(satom.getKind()); |
268 |
7044 |
if (isSpatial) |
269 |
|
{ |
270 |
3008 |
reduceFact(atom, polarity, fact); |
271 |
3008 |
if (!slbl.isNull()) |
272 |
|
{ |
273 |
2127 |
d_spatial_assertions.push_back(fact); |
274 |
|
} |
275 |
|
} |
276 |
|
// assert to equality if non-spatial or a labelled pto |
277 |
7044 |
if (!isSpatial || (!slbl.isNull() && satom.getKind() == SEP_PTO)) |
278 |
|
{ |
279 |
5103 |
return false; |
280 |
|
} |
281 |
|
// otherwise, maybe propagate |
282 |
1941 |
doPending(); |
283 |
1941 |
return true; |
284 |
|
} |
285 |
|
|
286 |
5103 |
void TheorySep::notifyFact(TNode atom, |
287 |
|
bool polarity, |
288 |
|
TNode fact, |
289 |
|
bool isInternal) |
290 |
|
{ |
291 |
10206 |
TNode satom = atom.getKind() == SEP_LABEL ? atom[0] : atom; |
292 |
5103 |
if (atom.getKind() == SEP_LABEL && atom[0].getKind() == SEP_PTO) |
293 |
|
{ |
294 |
|
// associate the equivalence class of the lhs with this pto |
295 |
2134 |
Node r = getRepresentative(atom[1]); |
296 |
1067 |
HeapAssertInfo* ei = getOrMakeEqcInfo(r, true); |
297 |
1067 |
addPto(ei, r, atom, polarity); |
298 |
|
} |
299 |
|
// maybe propagate |
300 |
5103 |
doPending(); |
301 |
5103 |
} |
302 |
|
|
303 |
3008 |
void TheorySep::reduceFact(TNode atom, bool polarity, TNode fact) |
304 |
|
{ |
305 |
3008 |
if (d_reduce.find(fact) != d_reduce.end()) |
306 |
|
{ |
307 |
|
// already reduced |
308 |
5011 |
return; |
309 |
|
} |
310 |
810 |
d_reduce.insert(fact); |
311 |
1005 |
TNode satom = atom.getKind() == SEP_LABEL ? atom[0] : atom; |
312 |
1005 |
TNode slbl = atom.getKind() == SEP_LABEL ? atom[1] : TNode::null(); |
313 |
810 |
NodeManager* nm = NodeManager::currentNM(); |
314 |
810 |
SkolemManager* sm = nm->getSkolemManager(); |
315 |
810 |
if (slbl.isNull()) |
316 |
|
{ |
317 |
570 |
Trace("sep-lemma-debug") |
318 |
285 |
<< "Reducing unlabelled assertion " << atom << std::endl; |
319 |
|
// introduce top-level label, add iff |
320 |
570 |
TypeNode refType = getReferenceType(satom); |
321 |
570 |
Trace("sep-lemma-debug") |
322 |
285 |
<< "...reference type is : " << refType << std::endl; |
323 |
570 |
Node b_lbl = getBaseLabel(refType); |
324 |
570 |
Node satom_new = nm->mkNode(SEP_LABEL, satom, b_lbl); |
325 |
570 |
Node lem; |
326 |
285 |
Trace("sep-lemma-debug") << "...polarity is " << polarity << std::endl; |
327 |
285 |
if (polarity) |
328 |
|
{ |
329 |
226 |
lem = nm->mkNode(OR, satom.negate(), satom_new); |
330 |
|
} |
331 |
|
else |
332 |
|
{ |
333 |
59 |
lem = nm->mkNode(OR, satom, satom_new.negate()); |
334 |
|
} |
335 |
570 |
Trace("sep-lemma-debug") |
336 |
285 |
<< "Sep::Lemma : base reduction : " << lem << std::endl; |
337 |
285 |
d_im.lemma(lem, InferenceId::SEP_LABEL_INTRO); |
338 |
285 |
return; |
339 |
|
} |
340 |
525 |
Trace("sep-lemma-debug") << "Reducing assertion " << fact << std::endl; |
341 |
720 |
Node conc; |
342 |
525 |
if (Node* in_map = FindOrNull(d_red_conc[slbl], satom)) |
343 |
|
{ |
344 |
54 |
conc = *in_map; |
345 |
|
} |
346 |
|
else |
347 |
|
{ |
348 |
|
// make conclusion based on type of assertion |
349 |
471 |
if (satom.getKind() == SEP_STAR || satom.getKind() == SEP_WAND) |
350 |
|
{ |
351 |
326 |
std::vector<Node> children; |
352 |
326 |
std::vector<Node> c_lems; |
353 |
326 |
TypeNode tn = getReferenceType(satom); |
354 |
163 |
if (d_reference_bound_max.find(tn) != d_reference_bound_max.end()) |
355 |
|
{ |
356 |
161 |
c_lems.push_back(nm->mkNode(SUBSET, slbl, d_reference_bound_max[tn])); |
357 |
|
} |
358 |
326 |
std::vector<Node> labels; |
359 |
163 |
getLabelChildren(satom, slbl, children, labels); |
360 |
326 |
Node empSet = nm->mkConst(EmptySet(slbl.getType())); |
361 |
163 |
Assert(children.size() > 1); |
362 |
163 |
if (satom.getKind() == SEP_STAR) |
363 |
|
{ |
364 |
|
// reduction for heap : union, pairwise disjoint |
365 |
292 |
Node ulem = nm->mkNode(UNION, labels[0], labels[1]); |
366 |
146 |
size_t lsize = labels.size(); |
367 |
201 |
for (size_t i = 2; i < lsize; i++) |
368 |
|
{ |
369 |
55 |
ulem = nm->mkNode(UNION, ulem, labels[i]); |
370 |
|
} |
371 |
146 |
ulem = slbl.eqNode(ulem); |
372 |
292 |
Trace("sep-lemma-debug") |
373 |
146 |
<< "Sep::Lemma : star reduction, union : " << ulem << std::endl; |
374 |
146 |
c_lems.push_back(ulem); |
375 |
493 |
for (size_t i = 0; i < lsize; i++) |
376 |
|
{ |
377 |
642 |
for (size_t j = (i + 1); j < lsize; j++) |
378 |
|
{ |
379 |
590 |
Node s = nm->mkNode(INTERSECTION, labels[i], labels[j]); |
380 |
590 |
Node ilem = s.eqNode(empSet); |
381 |
590 |
Trace("sep-lemma-debug") |
382 |
295 |
<< "Sep::Lemma : star reduction, disjoint : " << ilem |
383 |
295 |
<< std::endl; |
384 |
295 |
c_lems.push_back(ilem); |
385 |
|
} |
386 |
|
} |
387 |
|
} |
388 |
|
else |
389 |
|
{ |
390 |
34 |
Node ulem = nm->mkNode(UNION, slbl, labels[0]); |
391 |
17 |
ulem = ulem.eqNode(labels[1]); |
392 |
34 |
Trace("sep-lemma-debug") |
393 |
17 |
<< "Sep::Lemma : wand reduction, union : " << ulem << std::endl; |
394 |
17 |
c_lems.push_back(ulem); |
395 |
34 |
Node s = nm->mkNode(INTERSECTION, slbl, labels[0]); |
396 |
34 |
Node ilem = s.eqNode(empSet); |
397 |
34 |
Trace("sep-lemma-debug") |
398 |
17 |
<< "Sep::Lemma : wand reduction, disjoint : " << ilem << std::endl; |
399 |
17 |
c_lems.push_back(ilem); |
400 |
|
// nil does not occur in labels[0] |
401 |
34 |
Node nr = getNilRef(tn); |
402 |
34 |
Node nrlem = nm->mkNode(MEMBER, nr, labels[0]).negate(); |
403 |
34 |
Trace("sep-lemma") |
404 |
17 |
<< "Sep::Lemma: sep.nil not in wand antecedant heap : " << nrlem |
405 |
17 |
<< std::endl; |
406 |
17 |
d_im.lemma(nrlem, InferenceId::SEP_NIL_NOT_IN_HEAP); |
407 |
|
} |
408 |
|
// send out definitional lemmas for introduced sets |
409 |
799 |
for (const Node& clem : c_lems) |
410 |
|
{ |
411 |
636 |
Trace("sep-lemma") << "Sep::Lemma : definition : " << clem << std::endl; |
412 |
636 |
d_im.lemma(clem, InferenceId::SEP_LABEL_DEF); |
413 |
|
} |
414 |
163 |
conc = nm->mkNode(AND, children); |
415 |
|
} |
416 |
308 |
else if (satom.getKind() == SEP_PTO) |
417 |
|
{ |
418 |
|
// TODO(project##230): Find a safe type for the singleton operator |
419 |
616 |
Node ss = nm->mkSingleton(satom[0].getType(), satom[0]); |
420 |
308 |
if (slbl != ss) |
421 |
|
{ |
422 |
|
conc = slbl.eqNode(ss); |
423 |
|
} |
424 |
|
// note semantics of sep.nil is enforced globally |
425 |
|
} |
426 |
|
else if (satom.getKind() == SEP_EMP) |
427 |
|
{ |
428 |
|
Node lem; |
429 |
|
Node emp_s = nm->mkConst(EmptySet(slbl.getType())); |
430 |
|
if (polarity) |
431 |
|
{ |
432 |
|
lem = nm->mkNode(OR, fact.negate(), slbl.eqNode(emp_s)); |
433 |
|
} |
434 |
|
else |
435 |
|
{ |
436 |
|
Node kl = sm->mkDummySkolem("loc", getReferenceType(satom)); |
437 |
|
Node kd = sm->mkDummySkolem("data", getDataType(satom)); |
438 |
|
Node econc = nm->mkNode( |
439 |
|
SEP_LABEL, |
440 |
|
nm->mkNode(SEP_STAR, nm->mkNode(SEP_PTO, kl, kd), d_true), |
441 |
|
slbl); |
442 |
|
// Node econc = nm->mkNode( AND, slbl.eqNode( emp_s ).negate(), |
443 |
|
lem = nm->mkNode(OR, fact.negate(), econc); |
444 |
|
} |
445 |
|
Trace("sep-lemma") << "Sep::Lemma : emp : " << lem << std::endl; |
446 |
|
d_im.lemma(lem, InferenceId::SEP_EMP); |
447 |
|
} |
448 |
|
else |
449 |
|
{ |
450 |
|
// labeled emp should be rewritten |
451 |
|
Unreachable(); |
452 |
|
} |
453 |
471 |
d_red_conc[slbl][satom] = conc; |
454 |
|
} |
455 |
525 |
if (conc.isNull()) |
456 |
|
{ |
457 |
660 |
Trace("sep-lemma-debug") |
458 |
330 |
<< "Trivial conclusion, do not add lemma." << std::endl; |
459 |
330 |
return; |
460 |
|
} |
461 |
195 |
bool use_polarity = satom.getKind() == SEP_WAND ? !polarity : polarity; |
462 |
195 |
if (!use_polarity) |
463 |
|
{ |
464 |
|
// introduce guard, assert positive version |
465 |
160 |
Trace("sep-lemma-debug") |
466 |
80 |
<< "Negated spatial constraint asserted to sep theory: " << fact |
467 |
80 |
<< std::endl; |
468 |
160 |
Node g = sm->mkDummySkolem("G", nm->booleanType()); |
469 |
240 |
d_neg_guard_strategy[g].reset(new DecisionStrategySingleton( |
470 |
160 |
"sep_neg_guard", g, context(), getValuation())); |
471 |
80 |
DecisionStrategySingleton* ds = d_neg_guard_strategy[g].get(); |
472 |
80 |
d_im.getDecisionManager()->registerStrategy( |
473 |
|
DecisionManager::STRAT_SEP_NEG_GUARD, ds); |
474 |
160 |
Node lit = ds->getLiteral(0); |
475 |
80 |
d_neg_guard[slbl][satom] = lit; |
476 |
160 |
Trace("sep-lemma-debug") |
477 |
80 |
<< "Neg guard : " << slbl << " " << satom << " " << lit << std::endl; |
478 |
80 |
AlwaysAssert(!lit.isNull()); |
479 |
80 |
d_neg_guards.push_back(lit); |
480 |
80 |
d_guard_to_assertion[lit] = satom; |
481 |
|
// Node lem = nm->mkNode( EQUAL, lit, conc ); |
482 |
160 |
Node lem = nm->mkNode(OR, lit.negate(), conc); |
483 |
80 |
Trace("sep-lemma") << "Sep::Lemma : (neg) reduction : " << lem << std::endl; |
484 |
80 |
d_im.lemma(lem, InferenceId::SEP_NEG_REDUCTION); |
485 |
|
} |
486 |
|
else |
487 |
|
{ |
488 |
|
// reduce based on implication |
489 |
230 |
Node lem = nm->mkNode(OR, fact.negate(), conc); |
490 |
115 |
Trace("sep-lemma") << "Sep::Lemma : reduction : " << lem << std::endl; |
491 |
115 |
d_im.lemma(lem, InferenceId::SEP_POS_REDUCTION); |
492 |
|
} |
493 |
|
} |
494 |
|
|
495 |
7044 |
bool TheorySep::isSpatialKind(Kind k) const |
496 |
|
{ |
497 |
7044 |
return k == SEP_STAR || k == SEP_WAND || k == SEP_PTO || k == SEP_EMP; |
498 |
|
} |
499 |
|
|
500 |
27398 |
void TheorySep::postCheck(Effort level) |
501 |
|
{ |
502 |
54894 |
if (level != EFFORT_LAST_CALL || d_state.isInConflict() |
503 |
27496 |
|| d_valuation.needCheck()) |
504 |
|
{ |
505 |
54661 |
return; |
506 |
|
} |
507 |
98 |
NodeManager* nm = NodeManager::currentNM(); |
508 |
98 |
SkolemManager* sm = nm->getSkolemManager(); |
509 |
98 |
Trace("sep-process") << "Checking heap at full effort..." << std::endl; |
510 |
98 |
d_label_model.clear(); |
511 |
98 |
d_tmodel.clear(); |
512 |
98 |
d_pto_model.clear(); |
513 |
98 |
Trace("sep-process") << "---Locations---" << std::endl; |
514 |
135 |
std::map<Node, int> min_id; |
515 |
98 |
for (std::map<TypeNode, std::vector<Node> >::iterator itt = |
516 |
98 |
d_type_references_all.begin(); |
517 |
196 |
itt != d_type_references_all.end(); |
518 |
|
++itt) |
519 |
|
{ |
520 |
321 |
for (const Node& t : itt->second) |
521 |
|
{ |
522 |
223 |
Trace("sep-process") << " " << t << " = "; |
523 |
223 |
if (d_valuation.getModel()->hasTerm(t)) |
524 |
|
{ |
525 |
444 |
Node v = d_valuation.getModel()->getRepresentative(t); |
526 |
222 |
Trace("sep-process") << v << std::endl; |
527 |
|
// take minimal id |
528 |
222 |
std::map<Node, unsigned>::iterator itrc = d_type_ref_card_id.find(t); |
529 |
222 |
int tid = itrc == d_type_ref_card_id.end() ? -1 : (int)itrc->second; |
530 |
|
bool set_term_model; |
531 |
222 |
if (d_tmodel.find(v) == d_tmodel.end()) |
532 |
|
{ |
533 |
205 |
set_term_model = true; |
534 |
|
}else{ |
535 |
17 |
set_term_model = min_id[v] > tid; |
536 |
|
} |
537 |
222 |
if (set_term_model) |
538 |
|
{ |
539 |
205 |
d_tmodel[v] = t; |
540 |
205 |
min_id[v] = tid; |
541 |
|
} |
542 |
|
} |
543 |
|
else |
544 |
|
{ |
545 |
1 |
Trace("sep-process") << "?" << std::endl; |
546 |
|
} |
547 |
|
} |
548 |
|
} |
549 |
98 |
Trace("sep-process") << "---" << std::endl; |
550 |
|
// build positive/negative assertion lists for labels |
551 |
135 |
std::map<Node, bool> assert_active; |
552 |
|
// get the inactive assertions |
553 |
135 |
std::map<Node, std::vector<Node> > lbl_to_assertions; |
554 |
429 |
for (NodeList::const_iterator i = d_spatial_assertions.begin(); |
555 |
429 |
i != d_spatial_assertions.end(); |
556 |
|
++i) |
557 |
|
{ |
558 |
662 |
Node fact = (*i); |
559 |
331 |
bool polarity = fact.getKind() != NOT; |
560 |
662 |
TNode atom = polarity ? fact : fact[0]; |
561 |
331 |
Assert(atom.getKind() == SEP_LABEL); |
562 |
662 |
TNode satom = atom[0]; |
563 |
662 |
TNode slbl = atom[1]; |
564 |
331 |
lbl_to_assertions[slbl].push_back(fact); |
565 |
|
// check whether assertion is active : either polarity=true, or guard is not |
566 |
|
// asserted false |
567 |
331 |
assert_active[fact] = true; |
568 |
331 |
bool use_polarity = satom.getKind() == SEP_WAND ? !polarity : polarity; |
569 |
331 |
if (use_polarity) |
570 |
|
{ |
571 |
223 |
if (satom.getKind() == SEP_PTO) |
572 |
|
{ |
573 |
318 |
Node vv = d_valuation.getModel()->getRepresentative(satom[0]); |
574 |
159 |
if (d_pto_model.find(vv) == d_pto_model.end()) |
575 |
|
{ |
576 |
282 |
Trace("sep-process") << "Pto : " << satom[0] << " (" << vv << ") -> " |
577 |
141 |
<< satom[1] << std::endl; |
578 |
141 |
d_pto_model[vv] = satom[1]; |
579 |
|
|
580 |
|
// replace this on pto-model since this term is more relevant |
581 |
282 |
TypeNode vtn = vv.getType(); |
582 |
564 |
if (std::find(d_type_references_all[vtn].begin(), |
583 |
141 |
d_type_references_all[vtn].end(), |
584 |
564 |
satom[0]) |
585 |
423 |
!= d_type_references_all[vtn].end()) |
586 |
|
{ |
587 |
139 |
d_tmodel[vv] = satom[0]; |
588 |
|
} |
589 |
|
} |
590 |
|
} |
591 |
|
} |
592 |
|
else |
593 |
|
{ |
594 |
108 |
if (d_neg_guard[slbl].find(satom) != d_neg_guard[slbl].end()) |
595 |
|
{ |
596 |
|
// check if the guard is asserted positively |
597 |
186 |
Node guard = d_neg_guard[slbl][satom]; |
598 |
|
bool value; |
599 |
93 |
if (getValuation().hasSatValue(guard, value)) |
600 |
|
{ |
601 |
93 |
assert_active[fact] = value; |
602 |
|
} |
603 |
|
} |
604 |
|
} |
605 |
|
} |
606 |
|
//(recursively) set inactive sub-assertions |
607 |
429 |
for (NodeList::const_iterator i = d_spatial_assertions.begin(); |
608 |
429 |
i != d_spatial_assertions.end(); |
609 |
|
++i) |
610 |
|
{ |
611 |
662 |
Node fact = (*i); |
612 |
331 |
if (!assert_active[fact]) |
613 |
|
{ |
614 |
28 |
setInactiveAssertionRec(fact, lbl_to_assertions, assert_active); |
615 |
|
} |
616 |
|
} |
617 |
|
// set up model information based on active assertions |
618 |
429 |
for (NodeList::const_iterator i = d_spatial_assertions.begin(); |
619 |
429 |
i != d_spatial_assertions.end(); |
620 |
|
++i) |
621 |
|
{ |
622 |
662 |
Node fact = (*i); |
623 |
331 |
bool polarity = fact.getKind() != NOT; |
624 |
662 |
TNode atom = polarity ? fact : fact[0]; |
625 |
662 |
TNode satom = atom[0]; |
626 |
662 |
TNode slbl = atom[1]; |
627 |
331 |
if (assert_active[fact]) |
628 |
|
{ |
629 |
303 |
computeLabelModel(slbl); |
630 |
|
} |
631 |
|
} |
632 |
|
// debug print |
633 |
98 |
if (Trace.isOn("sep-process")) |
634 |
|
{ |
635 |
|
Trace("sep-process") << "--- Current spatial assertions : " << std::endl; |
636 |
|
for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) { |
637 |
|
Node fact = (*i); |
638 |
|
Trace("sep-process") << " " << fact; |
639 |
|
if (!assert_active[fact]) |
640 |
|
{ |
641 |
|
Trace("sep-process") << " [inactive]"; |
642 |
|
} |
643 |
|
Trace("sep-process") << std::endl; |
644 |
|
} |
645 |
|
Trace("sep-process") << "---" << std::endl; |
646 |
|
} |
647 |
98 |
if (Trace.isOn("sep-eqc")) |
648 |
|
{ |
649 |
|
Trace("sep-eqc") << d_equalityEngine->debugPrintEqc(); |
650 |
|
} |
651 |
|
|
652 |
98 |
bool addedLemma = false; |
653 |
98 |
bool needAddLemma = false; |
654 |
|
// check negated star / positive wand |
655 |
98 |
if (options::sepCheckNeg()) |
656 |
|
{ |
657 |
|
// get active labels |
658 |
196 |
std::map<Node, bool> active_lbl; |
659 |
98 |
if (options::sepMinimalRefine()) |
660 |
|
{ |
661 |
|
for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) { |
662 |
|
Node fact = (*i); |
663 |
|
bool polarity = fact.getKind() != NOT; |
664 |
|
TNode atom = polarity ? fact : fact[0]; |
665 |
|
TNode satom = atom[0]; |
666 |
|
bool use_polarity = satom.getKind() == SEP_WAND ? !polarity : polarity; |
667 |
|
if( !use_polarity ){ |
668 |
|
Assert(assert_active.find(fact) != assert_active.end()); |
669 |
|
if( assert_active[fact] ){ |
670 |
|
Assert(atom.getKind() == SEP_LABEL); |
671 |
|
TNode slbl = atom[1]; |
672 |
|
std::map<Node, std::map<int, Node> >& lms = d_label_map[satom]; |
673 |
|
if (lms.find(slbl) != lms.end()) |
674 |
|
{ |
675 |
|
Trace("sep-process-debug") |
676 |
|
<< "Active lbl : " << slbl << std::endl; |
677 |
|
active_lbl[slbl] = true; |
678 |
|
} |
679 |
|
} |
680 |
|
} |
681 |
|
} |
682 |
|
} |
683 |
|
|
684 |
|
// process spatial assertions |
685 |
429 |
for (NodeList::const_iterator i = d_spatial_assertions.begin(); |
686 |
429 |
i != d_spatial_assertions.end(); |
687 |
|
++i) |
688 |
|
{ |
689 |
398 |
Node fact = (*i); |
690 |
331 |
bool polarity = fact.getKind() != NOT; |
691 |
398 |
TNode atom = polarity ? fact : fact[0]; |
692 |
398 |
TNode satom = atom[0]; |
693 |
|
|
694 |
331 |
bool use_polarity = satom.getKind() == SEP_WAND ? !polarity : polarity; |
695 |
662 |
Trace("sep-process-debug") |
696 |
331 |
<< " check atom : " << satom << " use polarity " << use_polarity |
697 |
331 |
<< std::endl; |
698 |
331 |
if (use_polarity) |
699 |
|
{ |
700 |
223 |
continue; |
701 |
|
} |
702 |
108 |
Assert(assert_active.find(fact) != assert_active.end()); |
703 |
134 |
if (!assert_active[fact]) |
704 |
|
{ |
705 |
52 |
Trace("sep-process-debug") |
706 |
26 |
<< "--> inactive negated assertion " << satom << std::endl; |
707 |
26 |
continue; |
708 |
|
} |
709 |
82 |
Assert(atom.getKind() == SEP_LABEL); |
710 |
149 |
TNode slbl = atom[1]; |
711 |
164 |
Trace("sep-process") << "--> Active negated atom : " << satom |
712 |
82 |
<< ", lbl = " << slbl << std::endl; |
713 |
|
// add refinement lemma |
714 |
97 |
if (!ContainsKey(d_label_map[satom], slbl)) |
715 |
|
{ |
716 |
15 |
Trace("sep-process-debug") << " no children." << std::endl; |
717 |
15 |
Assert(satom.getKind() == SEP_PTO || satom.getKind() == SEP_EMP); |
718 |
15 |
continue; |
719 |
|
} |
720 |
67 |
needAddLemma = true; |
721 |
134 |
TypeNode tn = getReferenceType(satom); |
722 |
67 |
tn = nm->mkSetType(tn); |
723 |
|
// tn = nm->mkSetType(nm->mkRefType(tn)); |
724 |
134 |
Node o_b_lbl_mval = d_label_model[slbl].getValue(tn); |
725 |
134 |
Trace("sep-process") << " Model for " << slbl << " : " << o_b_lbl_mval |
726 |
67 |
<< std::endl; |
727 |
|
|
728 |
|
// get model values |
729 |
134 |
std::map<int, Node> mvals; |
730 |
225 |
for (const std::pair<const int, Node>& sub_element : d_label_map[satom][slbl]) |
731 |
|
{ |
732 |
158 |
int sub_index = sub_element.first; |
733 |
316 |
Node sub_lbl = sub_element.second; |
734 |
158 |
computeLabelModel(sub_lbl); |
735 |
316 |
Node lbl_mval = d_label_model[sub_lbl].getValue(tn); |
736 |
316 |
Trace("sep-process-debug") |
737 |
158 |
<< " child " << sub_index << " : " << sub_lbl |
738 |
158 |
<< ", mval = " << lbl_mval << std::endl; |
739 |
158 |
mvals[sub_index] = lbl_mval; |
740 |
|
} |
741 |
|
|
742 |
|
// Now, assert model-instantiated implication based on the negation |
743 |
67 |
Assert(d_label_model.find(slbl) != d_label_model.end()); |
744 |
134 |
std::vector<Node> conc; |
745 |
67 |
bool inst_success = true; |
746 |
|
// new refinement |
747 |
|
// instantiate the label |
748 |
134 |
std::map<Node, Node> visited; |
749 |
|
Node inst = instantiateLabel(satom, |
750 |
|
slbl, |
751 |
|
slbl, |
752 |
|
o_b_lbl_mval, |
753 |
|
visited, |
754 |
|
d_pto_model, |
755 |
|
tn, |
756 |
134 |
active_lbl); |
757 |
67 |
Trace("sep-inst-debug") << " applied inst : " << inst << std::endl; |
758 |
67 |
if (inst.isNull()) |
759 |
|
{ |
760 |
|
inst_success = false; |
761 |
|
} |
762 |
|
else |
763 |
|
{ |
764 |
67 |
inst = Rewriter::rewrite(inst); |
765 |
67 |
if (inst == (polarity ? d_true : d_false)) |
766 |
|
{ |
767 |
|
inst_success = false; |
768 |
|
} |
769 |
67 |
conc.push_back(polarity ? inst : inst.negate()); |
770 |
|
} |
771 |
67 |
if (!inst_success) |
772 |
|
{ |
773 |
|
continue; |
774 |
|
} |
775 |
134 |
std::vector<Node> lemc; |
776 |
134 |
Node pol_atom = atom; |
777 |
67 |
if (polarity) |
778 |
|
{ |
779 |
13 |
pol_atom = atom.negate(); |
780 |
|
} |
781 |
67 |
lemc.push_back(pol_atom); |
782 |
67 |
lemc.insert(lemc.end(), conc.begin(), conc.end()); |
783 |
134 |
Node lem = nm->mkNode(OR, lemc); |
784 |
67 |
std::vector<Node>& rlems = d_refinement_lem[satom][slbl]; |
785 |
67 |
if (std::find(rlems.begin(), rlems.end(), lem) == rlems.end()) |
786 |
|
{ |
787 |
67 |
rlems.push_back(lem); |
788 |
134 |
Trace("sep-process") << "-----> refinement lemma (#" << rlems.size() |
789 |
67 |
<< ") : " << lem << std::endl; |
790 |
134 |
Trace("sep-lemma") << "Sep::Lemma : negated star/wand refinement : " |
791 |
67 |
<< lem << std::endl; |
792 |
67 |
d_im.lemma(lem, InferenceId::SEP_REFINEMENT); |
793 |
67 |
addedLemma = true; |
794 |
|
} |
795 |
|
else |
796 |
|
{ |
797 |
|
// this typically should not happen, should never happen for complete |
798 |
|
// base theories |
799 |
|
Trace("sep-process") |
800 |
|
<< "*** repeated refinement lemma : " << lem << std::endl; |
801 |
|
Trace("sep-warn") |
802 |
|
<< "TheorySep : WARNING : repeated refinement lemma : " << lem |
803 |
|
<< "!!!" << std::endl; |
804 |
|
} |
805 |
|
} |
806 |
196 |
Trace("sep-process") |
807 |
98 |
<< "...finished check of negated assertions, addedLemma=" << addedLemma |
808 |
98 |
<< ", needAddLemma=" << needAddLemma << std::endl; |
809 |
|
} |
810 |
98 |
if (addedLemma) |
811 |
|
{ |
812 |
61 |
return; |
813 |
|
} |
814 |
|
// must witness finite data points-to |
815 |
74 |
for (std::map<TypeNode, Node>::iterator it = d_base_label.begin(); |
816 |
74 |
it != d_base_label.end(); |
817 |
|
++it) |
818 |
|
{ |
819 |
37 |
TypeNode data_type = d_loc_to_data_type[it->first]; |
820 |
|
// if the data type is finite |
821 |
37 |
if (!d_state.isFiniteType(data_type)) |
822 |
|
{ |
823 |
37 |
continue; |
824 |
|
} |
825 |
|
computeLabelModel(it->second); |
826 |
|
Trace("sep-process-debug") << "Check heap data for " << it->first << " -> " |
827 |
|
<< data_type << std::endl; |
828 |
|
std::vector<Node>& hlmodel = d_label_model[it->second].d_heap_locs_model; |
829 |
|
for (size_t j = 0, hsize = hlmodel.size(); j < hsize; j++) |
830 |
|
{ |
831 |
|
Assert(hlmodel[j].getKind() == SINGLETON); |
832 |
|
Node l = hlmodel[j][0]; |
833 |
|
Trace("sep-process-debug") << " location : " << l << std::endl; |
834 |
|
if (!d_pto_model[l].isNull()) |
835 |
|
{ |
836 |
|
Trace("sep-process-debug") |
837 |
|
<< " points-to data witness : " << d_pto_model[l] << std::endl; |
838 |
|
continue; |
839 |
|
} |
840 |
|
needAddLemma = true; |
841 |
|
Node ll; |
842 |
|
std::map<Node, Node>::iterator itm = d_tmodel.find(l); |
843 |
|
if (itm != d_tmodel.end()) |
844 |
|
{ |
845 |
|
ll = itm->second; |
846 |
|
} |
847 |
|
// otherwise, could try to assign arbitrary skolem? |
848 |
|
if (!ll.isNull()) |
849 |
|
{ |
850 |
|
Trace("sep-process") << "Must witness label : " << ll |
851 |
|
<< ", data type is " << data_type << std::endl; |
852 |
|
Node dsk = sm->mkDummySkolem( |
853 |
|
"dsk", data_type, "pto-data for implicit location"); |
854 |
|
// if location is in the heap, then something must point to it |
855 |
|
Node lem = nm->mkNode( |
856 |
|
IMPLIES, |
857 |
|
nm->mkNode(MEMBER, ll, it->second), |
858 |
|
nm->mkNode(SEP_STAR, nm->mkNode(SEP_PTO, ll, dsk), d_true)); |
859 |
|
Trace("sep-lemma") << "Sep::Lemma : witness finite data-pto : " << lem |
860 |
|
<< std::endl; |
861 |
|
d_im.lemma(lem, InferenceId::SEP_WITNESS_FINITE_DATA); |
862 |
|
addedLemma = true; |
863 |
|
} |
864 |
|
else |
865 |
|
{ |
866 |
|
// This should only happen if we are in an unbounded fragment |
867 |
|
Trace("sep-warn") |
868 |
|
<< "TheorySep : WARNING : no term corresponding to location " << l |
869 |
|
<< " in heap!!!" << std::endl; |
870 |
|
} |
871 |
|
} |
872 |
|
} |
873 |
37 |
if (addedLemma) |
874 |
|
{ |
875 |
|
return; |
876 |
|
} |
877 |
|
// set up model |
878 |
37 |
Trace("sep-process-debug") << "...preparing sep model..." << std::endl; |
879 |
37 |
d_heap_locs_nptos.clear(); |
880 |
|
// collect data points that are not pointed to |
881 |
364 |
for (context::CDList<Assertion>::const_iterator it = facts_begin(); |
882 |
364 |
it != facts_end(); |
883 |
|
++it) |
884 |
|
{ |
885 |
654 |
Node lit = (*it).d_assertion; |
886 |
327 |
if (lit.getKind() == NOT && lit[0].getKind() == SEP_PTO) |
887 |
|
{ |
888 |
2 |
Node satom = lit[0]; |
889 |
2 |
Node v1 = d_valuation.getModel()->getRepresentative(satom[0]); |
890 |
2 |
Node v2 = d_valuation.getModel()->getRepresentative(satom[1]); |
891 |
2 |
Trace("sep-process-debug") |
892 |
1 |
<< v1 << " does not point-to " << v2 << std::endl; |
893 |
1 |
d_heap_locs_nptos[v1].push_back(v2); |
894 |
|
} |
895 |
|
} |
896 |
|
|
897 |
37 |
if (needAddLemma) |
898 |
|
{ |
899 |
|
d_im.setIncomplete(IncompleteId::SEP); |
900 |
|
} |
901 |
74 |
Trace("sep-check") << "Sep::check(): " << level |
902 |
74 |
<< " done, conflict=" << d_state.isInConflict() |
903 |
37 |
<< std::endl; |
904 |
|
} |
905 |
|
|
906 |
5711 |
bool TheorySep::needsCheckLastEffort() { |
907 |
5711 |
return hasFacts(); |
908 |
|
} |
909 |
|
|
910 |
|
void TheorySep::conflict(TNode a, TNode b) { |
911 |
|
Trace("sep-conflict") << "Sep::conflict : " << a << " " << b << std::endl; |
912 |
|
d_im.conflictEqConstantMerge(a, b); |
913 |
|
} |
914 |
|
|
915 |
|
|
916 |
293 |
TheorySep::HeapAssertInfo::HeapAssertInfo( context::Context* c ) : d_pto(c), d_has_neg_pto(c,false) { |
917 |
|
|
918 |
293 |
} |
919 |
|
|
920 |
17029 |
TheorySep::HeapAssertInfo * TheorySep::getOrMakeEqcInfo( Node n, bool doMake ) { |
921 |
17029 |
std::map< Node, HeapAssertInfo* >::iterator e_i = d_eqc_info.find( n ); |
922 |
17029 |
if( e_i==d_eqc_info.end() ){ |
923 |
15128 |
if( doMake ){ |
924 |
293 |
HeapAssertInfo* ei = new HeapAssertInfo(context()); |
925 |
293 |
d_eqc_info[n] = ei; |
926 |
293 |
return ei; |
927 |
|
}else{ |
928 |
14835 |
return NULL; |
929 |
|
} |
930 |
|
}else{ |
931 |
1901 |
return (*e_i).second; |
932 |
|
} |
933 |
|
} |
934 |
|
|
935 |
|
//for now, assume all constraints are for the same heap type (ensured by logic exceptions thrown in computeReferenceType2) |
936 |
1279 |
TypeNode TheorySep::getReferenceType( Node n ) { |
937 |
1279 |
Assert(!d_type_ref.isNull()); |
938 |
1279 |
return d_type_ref; |
939 |
|
} |
940 |
|
|
941 |
|
TypeNode TheorySep::getDataType( Node n ) { |
942 |
|
Assert(!d_type_data.isNull()); |
943 |
|
return d_type_data; |
944 |
|
} |
945 |
|
|
946 |
|
// Must process assertions at preprocess so that quantified assertions are |
947 |
|
// processed properly. |
948 |
13775 |
void TheorySep::ppNotifyAssertions(const std::vector<Node>& assertions) { |
949 |
27550 |
std::map<int, std::map<Node, int> > visited; |
950 |
27550 |
std::map<int, std::map<Node, std::vector<Node> > > references; |
951 |
27550 |
std::map<int, std::map<Node, bool> > references_strict; |
952 |
137559 |
for (unsigned i = 0; i < assertions.size(); i++) { |
953 |
123784 |
Trace("sep-pp") << "Process assertion : " << assertions[i] << std::endl; |
954 |
123784 |
processAssertion(assertions[i], visited, references, references_strict, |
955 |
|
true, true, false); |
956 |
|
} |
957 |
|
// if data type is unconstrained, assume a fresh uninterpreted sort |
958 |
13775 |
if (!d_type_ref.isNull()) { |
959 |
117 |
if (d_type_data.isNull()) { |
960 |
|
d_type_data = NodeManager::currentNM()->mkSort("_sep_U"); |
961 |
|
Trace("sep-type") << "Sep: assume data type " << d_type_data << std::endl; |
962 |
|
d_loc_to_data_type[d_type_ref] = d_type_data; |
963 |
|
} |
964 |
|
} |
965 |
13775 |
} |
966 |
|
|
967 |
|
//return cardinality |
968 |
3659264 |
int TheorySep::processAssertion( |
969 |
|
Node n, |
970 |
|
std::map<int, std::map<Node, int> >& visited, |
971 |
|
std::map<int, std::map<Node, std::vector<Node> > >& references, |
972 |
|
std::map<int, std::map<Node, bool> >& references_strict, |
973 |
|
bool pol, |
974 |
|
bool hasPol, |
975 |
|
bool underSpatial) |
976 |
|
{ |
977 |
3659264 |
int index = hasPol ? ( pol ? 1 : -1 ) : 0; |
978 |
3659264 |
int card = 0; |
979 |
3659264 |
std::map< Node, int >::iterator it = visited[index].find( n ); |
980 |
3659264 |
if( it==visited[index].end() ){ |
981 |
1615128 |
Trace("sep-pp-debug") << "process assertion : " << n << ", index = " << index << std::endl; |
982 |
1615128 |
if( n.getKind()==kind::SEP_EMP ){ |
983 |
45 |
registerRefDataTypesAtom(n); |
984 |
45 |
if( hasPol && pol ){ |
985 |
15 |
references[index][n].clear(); |
986 |
15 |
references_strict[index][n] = true; |
987 |
|
}else{ |
988 |
30 |
card = 1; |
989 |
|
} |
990 |
1615083 |
}else if( n.getKind()==kind::SEP_PTO ){ |
991 |
367 |
registerRefDataTypesAtom(n); |
992 |
367 |
if( quantifiers::TermUtil::hasBoundVarAttr( n[0] ) ){ |
993 |
2 |
TypeNode tn1 = n[0].getType(); |
994 |
1 |
if( d_bound_kind[tn1]!=bound_strict && d_bound_kind[tn1]!=bound_invalid ){ |
995 |
1 |
d_bound_kind[tn1] = bound_invalid; |
996 |
2 |
Trace("sep-bound") |
997 |
1 |
<< "reference cannot be bound (due to quantified pto)." |
998 |
1 |
<< std::endl; |
999 |
|
} |
1000 |
|
}else{ |
1001 |
366 |
references[index][n].push_back( n[0] ); |
1002 |
|
} |
1003 |
367 |
if( hasPol && pol ){ |
1004 |
262 |
references_strict[index][n] = true; |
1005 |
|
}else{ |
1006 |
105 |
card = 1; |
1007 |
|
} |
1008 |
|
}else{ |
1009 |
1614716 |
bool isSpatial = n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_STAR; |
1010 |
1614716 |
bool newUnderSpatial = underSpatial || isSpatial; |
1011 |
1614716 |
bool refStrict = isSpatial; |
1012 |
5150196 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1013 |
|
bool newHasPol, newPol; |
1014 |
3535480 |
QuantPhaseReq::getEntailPolarity( n, i, hasPol, pol, newHasPol, newPol ); |
1015 |
3535480 |
int newIndex = newHasPol ? ( newPol ? 1 : -1 ) : 0; |
1016 |
3535480 |
int ccard = processAssertion( n[i], visited, references, references_strict, newPol, newHasPol, newUnderSpatial ); |
1017 |
|
//update cardinality |
1018 |
3535480 |
if( n.getKind()==kind::SEP_STAR ){ |
1019 |
315 |
card += ccard; |
1020 |
3535165 |
}else if( n.getKind()==kind::SEP_WAND ){ |
1021 |
32 |
if( i==1 ){ |
1022 |
16 |
card = ccard; |
1023 |
|
} |
1024 |
3535133 |
}else if( ccard>card ){ |
1025 |
176 |
card = ccard; |
1026 |
|
} |
1027 |
|
//track references if we are or below a spatial operator |
1028 |
3535480 |
if( newUnderSpatial ){ |
1029 |
429 |
bool add = true; |
1030 |
429 |
if( references_strict[newIndex].find( n[i] )!=references_strict[newIndex].end() ){ |
1031 |
163 |
if( !isSpatial ){ |
1032 |
|
if( references_strict[index].find( n )==references_strict[index].end() ){ |
1033 |
|
references_strict[index][n] = true; |
1034 |
|
}else{ |
1035 |
|
add = false; |
1036 |
|
//TODO: can derive static equality between sets |
1037 |
|
} |
1038 |
|
} |
1039 |
|
}else{ |
1040 |
266 |
if( isSpatial ){ |
1041 |
184 |
refStrict = false; |
1042 |
|
} |
1043 |
|
} |
1044 |
429 |
if( add ){ |
1045 |
820 |
for( unsigned j=0; j<references[newIndex][n[i]].size(); j++ ){ |
1046 |
391 |
if( std::find( references[index][n].begin(), references[index][n].end(), references[newIndex][n[i]][j] )==references[index][n].end() ){ |
1047 |
354 |
references[index][n].push_back( references[newIndex][n[i]][j] ); |
1048 |
|
} |
1049 |
|
} |
1050 |
|
} |
1051 |
|
} |
1052 |
|
} |
1053 |
1614716 |
if( isSpatial && refStrict ){ |
1054 |
55 |
if( n.getKind()==kind::SEP_WAND ){ |
1055 |
|
//TODO |
1056 |
|
}else{ |
1057 |
55 |
Assert(n.getKind() == kind::SEP_STAR && hasPol && pol); |
1058 |
55 |
references_strict[index][n] = true; |
1059 |
|
} |
1060 |
|
} |
1061 |
|
} |
1062 |
1615128 |
visited[index][n] = card; |
1063 |
|
}else{ |
1064 |
2044136 |
card = it->second; |
1065 |
|
} |
1066 |
|
|
1067 |
3659264 |
if( !underSpatial && ( !references[index][n].empty() || card>0 ) ){ |
1068 |
766 |
TypeNode tn = getReferenceType( n ); |
1069 |
383 |
Assert(!tn.isNull()); |
1070 |
|
// add references to overall type |
1071 |
383 |
unsigned bt = d_bound_kind[tn]; |
1072 |
383 |
bool add = true; |
1073 |
383 |
if( references_strict[index].find( n )!=references_strict[index].end() ){ |
1074 |
170 |
Trace("sep-bound") << "Strict bound found based on " << n << ", index = " << index << std::endl; |
1075 |
170 |
if( bt!=bound_strict ){ |
1076 |
85 |
d_bound_kind[tn] = bound_strict; |
1077 |
|
//d_type_references[tn].clear(); |
1078 |
85 |
d_card_max[tn] = card; |
1079 |
|
}else{ |
1080 |
|
//TODO: derive static equality |
1081 |
85 |
add = false; |
1082 |
|
} |
1083 |
|
}else{ |
1084 |
213 |
add = bt!=bound_strict; |
1085 |
|
} |
1086 |
791 |
for( unsigned i=0; i<references[index][n].size(); i++ ){ |
1087 |
408 |
if( std::find( d_type_references[tn].begin(), d_type_references[tn].end(), references[index][n][i] )==d_type_references[tn].end() ){ |
1088 |
246 |
d_type_references[tn].push_back( references[index][n][i] ); |
1089 |
|
} |
1090 |
|
} |
1091 |
383 |
if( add ){ |
1092 |
|
//add max cardinality |
1093 |
241 |
if( card>(int)d_card_max[tn] ){ |
1094 |
57 |
d_card_max[tn] = card; |
1095 |
|
} |
1096 |
|
} |
1097 |
|
} |
1098 |
3659264 |
return card; |
1099 |
|
} |
1100 |
|
|
1101 |
693 |
void TheorySep::registerRefDataTypesAtom(Node atom) |
1102 |
|
{ |
1103 |
1386 |
TypeNode tn1; |
1104 |
1386 |
TypeNode tn2; |
1105 |
693 |
Kind k = atom.getKind(); |
1106 |
693 |
if (k == SEP_PTO || k == SEP_EMP) |
1107 |
|
{ |
1108 |
545 |
tn1 = atom[0].getType(); |
1109 |
545 |
tn2 = atom[1].getType(); |
1110 |
|
} |
1111 |
|
else |
1112 |
|
{ |
1113 |
148 |
Assert(k == SEP_STAR || k == SEP_WAND); |
1114 |
|
} |
1115 |
694 |
registerRefDataTypes(tn1, tn2, atom); |
1116 |
692 |
} |
1117 |
|
|
1118 |
812 |
void TheorySep::registerRefDataTypes(TypeNode tn1, TypeNode tn2, Node atom) |
1119 |
|
{ |
1120 |
812 |
if (!d_type_ref.isNull()) |
1121 |
|
{ |
1122 |
692 |
Assert(!atom.isNull()); |
1123 |
|
// already declared, ensure compatible |
1124 |
1929 |
if ((!tn1.isNull() && !tn1.isComparableTo(d_type_ref)) |
1125 |
2076 |
|| (!tn2.isNull() && !tn2.isComparableTo(d_type_data))) |
1126 |
|
{ |
1127 |
|
std::stringstream ss; |
1128 |
|
ss << "ERROR: the separation logic heap type has already been set to " |
1129 |
|
<< d_type_ref << " -> " << d_type_data |
1130 |
|
<< " but we have a constraint that uses different heap types, " |
1131 |
|
"offending atom is " |
1132 |
|
<< atom << " with associated heap type " << tn1 << " -> " << tn2 |
1133 |
|
<< std::endl; |
1134 |
|
} |
1135 |
692 |
return; |
1136 |
|
} |
1137 |
|
// if not declared yet, and we have a separation logic constraint, throw |
1138 |
|
// an error. |
1139 |
120 |
if (!atom.isNull()) |
1140 |
|
{ |
1141 |
2 |
std::stringstream ss; |
1142 |
|
// error, heap not declared |
1143 |
|
ss << "ERROR: the type of the separation logic heap has not been declared " |
1144 |
|
"(e.g. via a declare-heap command), and we have a separation logic " |
1145 |
1 |
"constraint " |
1146 |
1 |
<< atom << std::endl; |
1147 |
1 |
throw LogicException(ss.str()); |
1148 |
|
} |
1149 |
|
// otherwise set it |
1150 |
238 |
Trace("sep-type") << "Sep: assume location type " << tn1 |
1151 |
119 |
<< " is associated with data type " << tn2 << std::endl; |
1152 |
119 |
d_loc_to_data_type[tn1] = tn2; |
1153 |
|
// for now, we only allow heap constraints of one type |
1154 |
119 |
d_type_ref = tn1; |
1155 |
119 |
d_type_data = tn2; |
1156 |
119 |
d_bound_kind[tn1] = bound_default; |
1157 |
|
} |
1158 |
|
|
1159 |
115 |
void TheorySep::initializeBounds() { |
1160 |
115 |
if( !d_bounds_init ){ |
1161 |
115 |
Trace("sep-bound") << "Initialize sep bounds..." << std::endl; |
1162 |
115 |
d_bounds_init = true; |
1163 |
115 |
NodeManager* nm = NodeManager::currentNM(); |
1164 |
115 |
SkolemManager* sm = nm->getSkolemManager(); |
1165 |
230 |
for( std::map< TypeNode, TypeNode >::iterator it = d_loc_to_data_type.begin(); it != d_loc_to_data_type.end(); ++it ){ |
1166 |
230 |
TypeNode tn = it->first; |
1167 |
115 |
Trace("sep-bound") << "Initialize bounds for " << tn << "..." << std::endl; |
1168 |
115 |
unsigned n_emp = 0; |
1169 |
115 |
if( d_bound_kind[tn] != bound_invalid ){ |
1170 |
114 |
n_emp = d_card_max[tn]; |
1171 |
1 |
}else if( d_type_references[tn].empty() ){ |
1172 |
|
//must include at least one constant TODO: remove? |
1173 |
1 |
n_emp = 1; |
1174 |
|
} |
1175 |
115 |
Trace("sep-bound") << "Cardinality element size : " << d_card_max[tn] << std::endl; |
1176 |
115 |
Trace("sep-bound") << "Type reference size : " << d_type_references[tn].size() << std::endl; |
1177 |
115 |
Trace("sep-bound") << "Constructing " << n_emp << " cardinality constants." << std::endl; |
1178 |
145 |
for( unsigned r=0; r<n_emp; r++ ){ |
1179 |
|
Node e = |
1180 |
60 |
sm->mkDummySkolem("e", tn, "cardinality bound element for seplog"); |
1181 |
30 |
d_type_references_card[tn].push_back( e ); |
1182 |
30 |
d_type_ref_card_id[e] = r; |
1183 |
|
} |
1184 |
|
} |
1185 |
|
} |
1186 |
115 |
} |
1187 |
|
|
1188 |
285 |
Node TheorySep::getBaseLabel( TypeNode tn ) { |
1189 |
285 |
std::map< TypeNode, Node >::iterator it = d_base_label.find( tn ); |
1190 |
285 |
if( it==d_base_label.end() ){ |
1191 |
115 |
NodeManager* nm = NodeManager::currentNM(); |
1192 |
115 |
SkolemManager* sm = nm->getSkolemManager(); |
1193 |
115 |
initializeBounds(); |
1194 |
115 |
Trace("sep") << "Make base label for " << tn << std::endl; |
1195 |
230 |
std::stringstream ss; |
1196 |
115 |
ss << "__Lb"; |
1197 |
230 |
TypeNode ltn = nm->mkSetType(tn); |
1198 |
230 |
Node n_lbl = sm->mkDummySkolem(ss.str(), ltn, "base label"); |
1199 |
115 |
d_base_label[tn] = n_lbl; |
1200 |
|
//make reference bound |
1201 |
115 |
Trace("sep") << "Make reference bound label for " << tn << std::endl; |
1202 |
230 |
std::stringstream ss2; |
1203 |
115 |
ss2 << "__Lu"; |
1204 |
115 |
d_reference_bound[tn] = sm->mkDummySkolem(ss2.str(), ltn, ""); |
1205 |
115 |
d_type_references_all[tn].insert( d_type_references_all[tn].end(), d_type_references[tn].begin(), d_type_references[tn].end() ); |
1206 |
|
|
1207 |
|
//check whether monotonic (elements can be added to tn without effecting satisfiability) |
1208 |
115 |
bool tn_is_monotonic = true; |
1209 |
115 |
if( tn.isSort() ){ |
1210 |
|
//TODO: use monotonicity inference |
1211 |
21 |
tn_is_monotonic = !logicInfo().isQuantified(); |
1212 |
|
}else{ |
1213 |
94 |
tn_is_monotonic = tn.getCardinality().isInfinite(); |
1214 |
|
} |
1215 |
|
//add a reference type for maximum occurrences of empty in a constraint |
1216 |
115 |
if( options::sepDisequalC() && tn_is_monotonic ){ |
1217 |
119 |
for( unsigned r=0; r<d_type_references_card[tn].size(); r++ ){ |
1218 |
50 |
Node e = d_type_references_card[tn][r]; |
1219 |
|
//ensure that it is distinct from all other references so far |
1220 |
64 |
for( unsigned j=0; j<d_type_references_all[tn].size(); j++ ){ |
1221 |
78 |
Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, e, d_type_references_all[tn][j] ); |
1222 |
39 |
d_im.lemma(eq.negate(), InferenceId::SEP_DISTINCT_REF); |
1223 |
|
} |
1224 |
25 |
d_type_references_all[tn].push_back( e ); |
1225 |
|
} |
1226 |
|
}else{ |
1227 |
|
//break symmetries TODO |
1228 |
|
|
1229 |
21 |
d_type_references_all[tn].insert( d_type_references_all[tn].end(), d_type_references_card[tn].begin(), d_type_references_card[tn].end() ); |
1230 |
|
} |
1231 |
|
//Assert( !d_type_references_all[tn].empty() ); |
1232 |
|
|
1233 |
115 |
if (d_bound_kind[tn] != bound_invalid) |
1234 |
|
{ |
1235 |
|
//construct bound |
1236 |
114 |
d_reference_bound_max[tn] = mkUnion( tn, d_type_references_all[tn] ); |
1237 |
114 |
Trace("sep-bound") << "overall bound for " << d_base_label[tn] << " : " << d_reference_bound_max[tn] << std::endl; |
1238 |
|
|
1239 |
228 |
Node slem = NodeManager::currentNM()->mkNode( kind::SUBSET, d_base_label[tn], d_reference_bound_max[tn] ); |
1240 |
114 |
Trace("sep-lemma") << "Sep::Lemma: reference bound for " << tn << " : " << slem << std::endl; |
1241 |
114 |
d_im.lemma(slem, InferenceId::SEP_REF_BOUND); |
1242 |
|
|
1243 |
|
//symmetry breaking |
1244 |
114 |
if( d_type_references_card[tn].size()>1 ){ |
1245 |
12 |
std::map< unsigned, Node > lit_mem_map; |
1246 |
18 |
for( unsigned i=0; i<d_type_references_card[tn].size(); i++ ){ |
1247 |
12 |
lit_mem_map[i] = NodeManager::currentNM()->mkNode( kind::MEMBER, d_type_references_card[tn][i], d_reference_bound_max[tn]); |
1248 |
|
} |
1249 |
12 |
for( unsigned i=0; i<(d_type_references_card[tn].size()-1); i++ ){ |
1250 |
12 |
std::vector< Node > children; |
1251 |
12 |
for( unsigned j=(i+1); j<d_type_references_card[tn].size(); j++ ){ |
1252 |
6 |
children.push_back( lit_mem_map[j].negate() ); |
1253 |
|
} |
1254 |
6 |
if( !children.empty() ){ |
1255 |
12 |
Node sym_lem = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::AND, children ); |
1256 |
6 |
sym_lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, lit_mem_map[i].negate(), sym_lem ); |
1257 |
6 |
Trace("sep-lemma") << "Sep::Lemma: symmetry breaking lemma : " << sym_lem << std::endl; |
1258 |
6 |
d_im.lemma(sym_lem, InferenceId::SEP_SYM_BREAK); |
1259 |
|
} |
1260 |
|
} |
1261 |
|
} |
1262 |
|
} |
1263 |
|
|
1264 |
|
//assert that nil ref is not in base label |
1265 |
230 |
Node nr = getNilRef( tn ); |
1266 |
230 |
Node nrlem = NodeManager::currentNM()->mkNode( kind::MEMBER, nr, n_lbl ).negate(); |
1267 |
115 |
Trace("sep-lemma") << "Sep::Lemma: sep.nil not in base label " << tn << " : " << nrlem << std::endl; |
1268 |
115 |
d_im.lemma(nrlem, InferenceId::SEP_NIL_NOT_IN_HEAP); |
1269 |
|
|
1270 |
115 |
return n_lbl; |
1271 |
|
}else{ |
1272 |
170 |
return it->second; |
1273 |
|
} |
1274 |
|
} |
1275 |
|
|
1276 |
139 |
Node TheorySep::getNilRef( TypeNode tn ) { |
1277 |
139 |
std::map< TypeNode, Node >::iterator it = d_nil_ref.find( tn ); |
1278 |
139 |
if( it==d_nil_ref.end() ){ |
1279 |
230 |
Node nil = NodeManager::currentNM()->mkNullaryOperator( tn, kind::SEP_NIL ); |
1280 |
115 |
setNilRef( tn, nil ); |
1281 |
115 |
return nil; |
1282 |
|
}else{ |
1283 |
24 |
return it->second; |
1284 |
|
} |
1285 |
|
} |
1286 |
|
|
1287 |
115 |
void TheorySep::setNilRef( TypeNode tn, Node n ) { |
1288 |
115 |
Assert(n.getType() == tn); |
1289 |
115 |
d_nil_ref[tn] = n; |
1290 |
115 |
} |
1291 |
|
|
1292 |
114 |
Node TheorySep::mkUnion( TypeNode tn, std::vector< Node >& locs ) { |
1293 |
228 |
Node u; |
1294 |
114 |
if( locs.empty() ){ |
1295 |
4 |
TypeNode ltn = NodeManager::currentNM()->mkSetType(tn); |
1296 |
2 |
return NodeManager::currentNM()->mkConst(EmptySet(ltn)); |
1297 |
|
}else{ |
1298 |
385 |
for( unsigned i=0; i<locs.size(); i++ ){ |
1299 |
546 |
Node s = locs[i]; |
1300 |
273 |
Assert(!s.isNull()); |
1301 |
273 |
s = NodeManager::currentNM()->mkSingleton(tn, s); |
1302 |
273 |
if( u.isNull() ){ |
1303 |
112 |
u = s; |
1304 |
|
}else{ |
1305 |
161 |
u = NodeManager::currentNM()->mkNode( kind::UNION, s, u ); |
1306 |
|
} |
1307 |
|
} |
1308 |
112 |
return u; |
1309 |
|
} |
1310 |
|
} |
1311 |
|
|
1312 |
445 |
Node TheorySep::getLabel( Node atom, int child, Node lbl ) { |
1313 |
445 |
std::map< int, Node >::iterator it = d_label_map[atom][lbl].find( child ); |
1314 |
445 |
if( it==d_label_map[atom][lbl].end() ){ |
1315 |
381 |
NodeManager* nm = NodeManager::currentNM(); |
1316 |
381 |
SkolemManager* sm = nm->getSkolemManager(); |
1317 |
762 |
TypeNode refType = getReferenceType( atom ); |
1318 |
762 |
std::stringstream ss; |
1319 |
381 |
ss << "__Lc" << child; |
1320 |
762 |
TypeNode ltn = NodeManager::currentNM()->mkSetType(refType); |
1321 |
|
//TypeNode ltn = NodeManager::currentNM()->mkSetType(NodeManager::currentNM()->mkRefType(refType)); |
1322 |
762 |
Node n_lbl = sm->mkDummySkolem(ss.str(), ltn, "sep label"); |
1323 |
381 |
d_label_map[atom][lbl][child] = n_lbl; |
1324 |
381 |
d_label_map_parent[n_lbl] = lbl; |
1325 |
381 |
return n_lbl; |
1326 |
|
}else{ |
1327 |
64 |
return (*it).second; |
1328 |
|
} |
1329 |
|
} |
1330 |
|
|
1331 |
470 |
Node TheorySep::applyLabel( Node n, Node lbl, std::map< Node, Node >& visited ) { |
1332 |
470 |
Assert(n.getKind() != kind::SEP_LABEL); |
1333 |
470 |
if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_EMP ){ |
1334 |
369 |
return NodeManager::currentNM()->mkNode( kind::SEP_LABEL, n, lbl ); |
1335 |
101 |
}else if( !n.getType().isBoolean() || n.getNumChildren()==0 ){ |
1336 |
24 |
return n; |
1337 |
|
}else{ |
1338 |
77 |
std::map< Node, Node >::iterator it = visited.find( n ); |
1339 |
77 |
if( it==visited.end() ){ |
1340 |
154 |
std::vector< Node > children; |
1341 |
77 |
if (n.getMetaKind() == kind::metakind::PARAMETERIZED) { |
1342 |
|
children.push_back( n.getOperator() ); |
1343 |
|
} |
1344 |
77 |
bool childChanged = false; |
1345 |
166 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1346 |
178 |
Node aln = applyLabel( n[i], lbl, visited ); |
1347 |
89 |
children.push_back( aln ); |
1348 |
89 |
childChanged = childChanged || aln!=n[i]; |
1349 |
|
} |
1350 |
154 |
Node ret = n; |
1351 |
77 |
if( childChanged ){ |
1352 |
75 |
ret = NodeManager::currentNM()->mkNode( n.getKind(), children ); |
1353 |
|
} |
1354 |
77 |
visited[n] = ret; |
1355 |
77 |
return ret; |
1356 |
|
}else{ |
1357 |
|
return it->second; |
1358 |
|
} |
1359 |
|
} |
1360 |
|
} |
1361 |
|
|
1362 |
290 |
Node TheorySep::instantiateLabel(Node n, |
1363 |
|
Node o_lbl, |
1364 |
|
Node lbl, |
1365 |
|
Node lbl_v, |
1366 |
|
std::map<Node, Node>& visited, |
1367 |
|
std::map<Node, Node>& pto_model, |
1368 |
|
TypeNode rtn, |
1369 |
|
std::map<Node, bool>& active_lbl, |
1370 |
|
unsigned ind) |
1371 |
|
{ |
1372 |
290 |
Trace("sep-inst-debug") << "Instantiate label " << n << " " << lbl << " " << lbl_v << std::endl; |
1373 |
290 |
if( options::sepMinimalRefine() && lbl!=o_lbl && active_lbl.find( lbl )!=active_lbl.end() ){ |
1374 |
|
Trace("sep-inst") << "...do not instantiate " << o_lbl << " since it has an active sublabel " << lbl << std::endl; |
1375 |
|
return Node::null(); |
1376 |
|
}else{ |
1377 |
290 |
if( Trace.isOn("sep-inst") ){ |
1378 |
|
if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND || n.getKind()==kind::SEP_PTO || n.getKind()==kind::SEP_EMP ){ |
1379 |
|
for( unsigned j=0; j<ind; j++ ){ Trace("sep-inst") << " "; } |
1380 |
|
Trace("sep-inst") << n << "[" << lbl << "] :: " << lbl_v << std::endl; |
1381 |
|
} |
1382 |
|
} |
1383 |
290 |
Assert(n.getKind() != kind::SEP_LABEL); |
1384 |
290 |
if( n.getKind()==kind::SEP_STAR || n.getKind()==kind::SEP_WAND ){ |
1385 |
82 |
if( lbl==o_lbl ){ |
1386 |
134 |
std::vector< Node > children; |
1387 |
67 |
children.resize( n.getNumChildren() ); |
1388 |
67 |
Assert(d_label_map[n].find(lbl) != d_label_map[n].end()); |
1389 |
134 |
std::map< int, Node > mvals; |
1390 |
225 |
for( std::map< int, Node >::iterator itl = d_label_map[n][lbl].begin(); itl != d_label_map[n][lbl].end(); ++itl ){ |
1391 |
316 |
Node sub_lbl = itl->second; |
1392 |
158 |
int sub_index = itl->first; |
1393 |
158 |
Assert(sub_index >= 0 && sub_index < (int)children.size()); |
1394 |
158 |
Trace("sep-inst-debug") << "Sublabel " << sub_index << " is " << sub_lbl << std::endl; |
1395 |
316 |
Node lbl_mval; |
1396 |
158 |
if( n.getKind()==kind::SEP_WAND && sub_index==1 ){ |
1397 |
13 |
Assert(d_label_map[n][lbl].find(0) != d_label_map[n][lbl].end()); |
1398 |
26 |
Node sub_lbl_0 = d_label_map[n][lbl][0]; |
1399 |
13 |
computeLabelModel( sub_lbl_0 ); |
1400 |
13 |
Assert(d_label_model.find(sub_lbl_0) != d_label_model.end()); |
1401 |
13 |
lbl_mval = NodeManager::currentNM()->mkNode( kind::UNION, lbl, d_label_model[sub_lbl_0].getValue( rtn ) ); |
1402 |
|
}else{ |
1403 |
145 |
computeLabelModel( sub_lbl ); |
1404 |
145 |
Assert(d_label_model.find(sub_lbl) != d_label_model.end()); |
1405 |
145 |
lbl_mval = d_label_model[sub_lbl].getValue( rtn ); |
1406 |
|
} |
1407 |
158 |
Trace("sep-inst-debug") << "Sublabel value is " << lbl_mval << std::endl; |
1408 |
158 |
mvals[sub_index] = lbl_mval; |
1409 |
158 |
children[sub_index] = instantiateLabel( n[sub_index], o_lbl, sub_lbl, lbl_mval, visited, pto_model, rtn, active_lbl, ind+1 ); |
1410 |
158 |
if( children[sub_index].isNull() ){ |
1411 |
|
return Node::null(); |
1412 |
|
} |
1413 |
|
} |
1414 |
134 |
Node empSet = NodeManager::currentNM()->mkConst(EmptySet(rtn)); |
1415 |
67 |
if( n.getKind()==kind::SEP_STAR ){ |
1416 |
|
|
1417 |
|
//disjoint contraints |
1418 |
108 |
std::vector< Node > conj; |
1419 |
108 |
std::vector< Node > bchildren; |
1420 |
54 |
bchildren.insert( bchildren.end(), children.begin(), children.end() ); |
1421 |
108 |
Node vsu; |
1422 |
108 |
std::vector< Node > vs; |
1423 |
186 |
for( std::map< int, Node >::iterator itl = d_label_map[n][lbl].begin(); itl != d_label_map[n][lbl].end(); ++itl ){ |
1424 |
264 |
Node sub_lbl = itl->second; |
1425 |
264 |
Node lbl_mval = d_label_model[sub_lbl].getValue( rtn ); |
1426 |
242 |
for( unsigned j=0; j<vs.size(); j++ ){ |
1427 |
110 |
bchildren.push_back( NodeManager::currentNM()->mkNode( kind::INTERSECTION, lbl_mval, vs[j] ).eqNode( empSet ) ); |
1428 |
|
} |
1429 |
132 |
vs.push_back( lbl_mval ); |
1430 |
132 |
if( vsu.isNull() ){ |
1431 |
54 |
vsu = lbl_mval; |
1432 |
|
}else{ |
1433 |
78 |
vsu = NodeManager::currentNM()->mkNode( kind::UNION, vsu, lbl_mval ); |
1434 |
|
} |
1435 |
|
} |
1436 |
54 |
bchildren.push_back( vsu.eqNode( lbl ) ); |
1437 |
|
|
1438 |
54 |
Assert(bchildren.size() > 1); |
1439 |
54 |
conj.push_back( NodeManager::currentNM()->mkNode( kind::AND, bchildren ) ); |
1440 |
|
|
1441 |
54 |
if( options::sepChildRefine() ){ |
1442 |
|
//child-specific refinements (TODO: use ?) |
1443 |
|
for( unsigned i=0; i<children.size(); i++ ){ |
1444 |
|
std::vector< Node > tchildren; |
1445 |
|
Node mval = mvals[i]; |
1446 |
|
tchildren.push_back( |
1447 |
|
NodeManager::currentNM()->mkNode(kind::SUBSET, mval, lbl)); |
1448 |
|
tchildren.push_back( children[i] ); |
1449 |
|
std::vector< Node > rem_children; |
1450 |
|
for( unsigned j=0; j<children.size(); j++ ){ |
1451 |
|
if( j!=i ){ |
1452 |
|
rem_children.push_back( n[j] ); |
1453 |
|
} |
1454 |
|
} |
1455 |
|
std::map< Node, Node > rvisited; |
1456 |
|
Node rem = rem_children.size()==1 ? rem_children[0] : NodeManager::currentNM()->mkNode( kind::SEP_STAR, rem_children ); |
1457 |
|
rem = applyLabel( rem, NodeManager::currentNM()->mkNode( kind::SETMINUS, lbl, mval ), rvisited ); |
1458 |
|
tchildren.push_back( rem ); |
1459 |
|
conj.push_back( NodeManager::currentNM()->mkNode( kind::AND, tchildren ) ); |
1460 |
|
} |
1461 |
|
} |
1462 |
54 |
return conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( kind::OR, conj ); |
1463 |
|
}else{ |
1464 |
26 |
std::vector< Node > wchildren; |
1465 |
|
//disjoint constraints |
1466 |
26 |
Node sub_lbl_0 = d_label_map[n][lbl][0]; |
1467 |
26 |
Node lbl_mval_0 = d_label_model[sub_lbl_0].getValue( rtn ); |
1468 |
13 |
wchildren.push_back( NodeManager::currentNM()->mkNode( kind::INTERSECTION, lbl_mval_0, lbl ).eqNode( empSet ).negate() ); |
1469 |
|
|
1470 |
|
//return the lemma |
1471 |
13 |
wchildren.push_back( children[0].negate() ); |
1472 |
13 |
wchildren.push_back( children[1] ); |
1473 |
13 |
return NodeManager::currentNM()->mkNode( kind::OR, wchildren ); |
1474 |
|
} |
1475 |
|
}else{ |
1476 |
|
//nested star/wand, label it and return |
1477 |
15 |
return NodeManager::currentNM()->mkNode( kind::SEP_LABEL, n, lbl_v ); |
1478 |
|
} |
1479 |
208 |
}else if( n.getKind()==kind::SEP_PTO ){ |
1480 |
|
//check if this pto reference is in the base label, if not, then it does not need to be added as an assumption |
1481 |
121 |
Assert(d_label_model.find(o_lbl) != d_label_model.end()); |
1482 |
242 |
Node vr = d_valuation.getModel()->getRepresentative( n[0] ); |
1483 |
|
// TODO(project##230): Find a safe type for the singleton operator |
1484 |
242 |
Node svr = NodeManager::currentNM()->mkSingleton(vr.getType(), vr); |
1485 |
121 |
bool inBaseHeap = std::find( d_label_model[o_lbl].d_heap_locs_model.begin(), d_label_model[o_lbl].d_heap_locs_model.end(), svr )!=d_label_model[o_lbl].d_heap_locs_model.end(); |
1486 |
121 |
Trace("sep-inst-debug") << "Is in base (non-instantiating) heap : " << inBaseHeap << " for value ref " << vr << " in " << o_lbl << std::endl; |
1487 |
242 |
std::vector< Node > children; |
1488 |
121 |
if( inBaseHeap ){ |
1489 |
|
// TODO(project##230): Find a safe type for the singleton operator |
1490 |
194 |
Node s = NodeManager::currentNM()->mkSingleton(n[0].getType(), n[0]); |
1491 |
97 |
children.push_back( NodeManager::currentNM()->mkNode( kind::SEP_LABEL, NodeManager::currentNM()->mkNode( kind::SEP_PTO, n[0], n[1] ), s ) ); |
1492 |
|
}else{ |
1493 |
|
//look up value of data |
1494 |
24 |
std::map< Node, Node >::iterator it = pto_model.find( vr ); |
1495 |
24 |
if( it!=pto_model.end() ){ |
1496 |
19 |
if( n[1]!=it->second ){ |
1497 |
6 |
children.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, n[1], it->second ) ); |
1498 |
|
} |
1499 |
|
}else{ |
1500 |
5 |
Trace("sep-inst-debug") << "Data for " << vr << " was not specified, do not add condition." << std::endl; |
1501 |
|
} |
1502 |
|
} |
1503 |
|
// TODO(project##230): Find a safe type for the singleton operator |
1504 |
242 |
Node singleton = NodeManager::currentNM()->mkSingleton(n[0].getType(), n[0]); |
1505 |
121 |
children.push_back(singleton.eqNode(lbl_v)); |
1506 |
242 |
Node ret = children.empty() ? NodeManager::currentNM()->mkConst( true ) : ( children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::AND, children ) ); |
1507 |
121 |
Trace("sep-inst-debug") << "Return " << ret << std::endl; |
1508 |
121 |
return ret; |
1509 |
87 |
}else if( n.getKind()==kind::SEP_EMP ){ |
1510 |
|
//return NodeManager::currentNM()->mkConst( lbl_v.getKind()==kind::EMPTYSET ); |
1511 |
|
return lbl_v.eqNode( |
1512 |
13 |
NodeManager::currentNM()->mkConst(EmptySet(lbl_v.getType()))); |
1513 |
|
}else{ |
1514 |
74 |
std::map< Node, Node >::iterator it = visited.find( n ); |
1515 |
74 |
if( it==visited.end() ){ |
1516 |
148 |
std::vector< Node > children; |
1517 |
74 |
if (n.getMetaKind() == kind::metakind::PARAMETERIZED) { |
1518 |
|
children.push_back( n.getOperator() ); |
1519 |
|
} |
1520 |
74 |
bool childChanged = false; |
1521 |
139 |
for( unsigned i=0; i<n.getNumChildren(); i++ ){ |
1522 |
130 |
Node aln = instantiateLabel( n[i], o_lbl, lbl, lbl_v, visited, pto_model, rtn, active_lbl, ind ); |
1523 |
65 |
if( aln.isNull() ){ |
1524 |
|
return Node::null(); |
1525 |
|
}else{ |
1526 |
65 |
children.push_back( aln ); |
1527 |
65 |
childChanged = childChanged || aln!=n[i]; |
1528 |
|
} |
1529 |
|
} |
1530 |
148 |
Node ret = n; |
1531 |
74 |
if( childChanged ){ |
1532 |
65 |
ret = NodeManager::currentNM()->mkNode( n.getKind(), children ); |
1533 |
|
} |
1534 |
|
//careful about caching |
1535 |
|
//visited[n] = ret; |
1536 |
74 |
return ret; |
1537 |
|
}else{ |
1538 |
|
return it->second; |
1539 |
|
} |
1540 |
|
} |
1541 |
|
} |
1542 |
|
} |
1543 |
|
|
1544 |
32 |
void TheorySep::setInactiveAssertionRec( Node fact, std::map< Node, std::vector< Node > >& lbl_to_assertions, std::map< Node, bool >& assert_active ) { |
1545 |
32 |
Trace("sep-process-debug") << "setInactiveAssertionRec::inactive : " << fact << std::endl; |
1546 |
32 |
assert_active[fact] = false; |
1547 |
32 |
bool polarity = fact.getKind() != kind::NOT; |
1548 |
64 |
TNode atom = polarity ? fact : fact[0]; |
1549 |
64 |
TNode satom = atom[0]; |
1550 |
64 |
TNode slbl = atom[1]; |
1551 |
32 |
if (satom.getKind() == SEP_WAND || satom.getKind() == SEP_STAR) |
1552 |
|
{ |
1553 |
96 |
for (size_t j = 0, nchild = satom.getNumChildren(); j < nchild; j++) |
1554 |
|
{ |
1555 |
128 |
Node lblc = getLabel(satom, j, slbl); |
1556 |
68 |
for( unsigned k=0; k<lbl_to_assertions[lblc].size(); k++ ){ |
1557 |
4 |
setInactiveAssertionRec( lbl_to_assertions[lblc][k], lbl_to_assertions, assert_active ); |
1558 |
|
} |
1559 |
|
} |
1560 |
|
} |
1561 |
32 |
} |
1562 |
|
|
1563 |
163 |
void TheorySep::getLabelChildren(Node satom, |
1564 |
|
Node lbl, |
1565 |
|
std::vector<Node>& children, |
1566 |
|
std::vector<Node>& labels) |
1567 |
|
{ |
1568 |
544 |
for (size_t i = 0, nchild = satom.getNumChildren(); i < nchild; i++) |
1569 |
|
{ |
1570 |
762 |
Node lblc = getLabel(satom, i, lbl); |
1571 |
381 |
Assert(!lblc.isNull()); |
1572 |
762 |
std::map< Node, Node > visited; |
1573 |
762 |
Node lc = applyLabel(satom[i], lblc, visited); |
1574 |
381 |
Assert(!lc.isNull()); |
1575 |
381 |
if (i == 1 && satom.getKind() == SEP_WAND) |
1576 |
|
{ |
1577 |
17 |
lc = lc.negate(); |
1578 |
|
} |
1579 |
381 |
children.push_back( lc ); |
1580 |
381 |
labels.push_back( lblc ); |
1581 |
|
} |
1582 |
163 |
Assert(children.size() > 1); |
1583 |
163 |
} |
1584 |
|
|
1585 |
626 |
void TheorySep::computeLabelModel( Node lbl ) { |
1586 |
626 |
if( !d_label_model[lbl].d_computed ){ |
1587 |
395 |
d_label_model[lbl].d_computed = true; |
1588 |
|
|
1589 |
|
//we must get the value of lbl from the model: this is being run at last call, after the model is constructed |
1590 |
|
//Assert(...); TODO |
1591 |
790 |
Node v_val = d_valuation.getModel()->getRepresentative( lbl ); |
1592 |
395 |
Trace("sep-process") << "Model value (from valuation) for " << lbl << " : " << v_val << std::endl; |
1593 |
395 |
if( v_val.getKind()!=kind::EMPTYSET ){ |
1594 |
541 |
while( v_val.getKind()==kind::UNION ){ |
1595 |
98 |
Assert(v_val[0].getKind() == kind::SINGLETON); |
1596 |
98 |
d_label_model[lbl].d_heap_locs_model.push_back(v_val[0]); |
1597 |
98 |
v_val = v_val[1]; |
1598 |
|
} |
1599 |
345 |
if( v_val.getKind()==kind::SINGLETON ){ |
1600 |
345 |
d_label_model[lbl].d_heap_locs_model.push_back( v_val ); |
1601 |
|
}else{ |
1602 |
|
throw Exception("Could not establish value of heap in model."); |
1603 |
|
Assert(false); |
1604 |
|
} |
1605 |
|
} |
1606 |
838 |
for( unsigned j=0; j<d_label_model[lbl].d_heap_locs_model.size(); j++ ){ |
1607 |
886 |
Node u = d_label_model[lbl].d_heap_locs_model[j]; |
1608 |
443 |
Assert(u.getKind() == kind::SINGLETON); |
1609 |
443 |
u = u[0]; |
1610 |
886 |
Node tt; |
1611 |
443 |
std::map< Node, Node >::iterator itm = d_tmodel.find( u ); |
1612 |
443 |
if( itm==d_tmodel.end() ) { |
1613 |
|
//Trace("sep-process") << "WARNING: could not find symbolic term in model for " << u << std::endl; |
1614 |
|
//Assert( false ); |
1615 |
|
//tt = u; |
1616 |
|
//TypeNode tn = u.getType().getRefConstituentType(); |
1617 |
8 |
TypeNode tn = u.getType(); |
1618 |
4 |
Trace("sep-process") << "WARNING: could not find symbolic term in model for " << u << ", cref type " << tn << std::endl; |
1619 |
4 |
Assert(d_type_references_all.find(tn) != d_type_references_all.end()); |
1620 |
4 |
Assert(!d_type_references_all[tn].empty()); |
1621 |
4 |
tt = d_type_references_all[tn][0]; |
1622 |
|
}else{ |
1623 |
439 |
tt = itm->second; |
1624 |
|
} |
1625 |
|
// TODO(project##230): Find a safe type for the singleton operator |
1626 |
886 |
Node stt = NodeManager::currentNM()->mkSingleton(tt.getType(), tt); |
1627 |
443 |
Trace("sep-process-debug") << "...model : add " << tt << " for " << u << " in lbl " << lbl << std::endl; |
1628 |
443 |
d_label_model[lbl].d_heap_locs.push_back( stt ); |
1629 |
|
} |
1630 |
|
} |
1631 |
626 |
} |
1632 |
|
|
1633 |
1067 |
Node TheorySep::getRepresentative( Node t ) { |
1634 |
1067 |
if (d_equalityEngine->hasTerm(t)) |
1635 |
|
{ |
1636 |
1067 |
return d_equalityEngine->getRepresentative(t); |
1637 |
|
}else{ |
1638 |
|
return t; |
1639 |
|
} |
1640 |
|
} |
1641 |
|
|
1642 |
944 |
bool TheorySep::hasTerm(Node a) { return d_equalityEngine->hasTerm(a); } |
1643 |
|
|
1644 |
645 |
bool TheorySep::areEqual( Node a, Node b ){ |
1645 |
645 |
if( a==b ){ |
1646 |
44 |
return true; |
1647 |
601 |
}else if( hasTerm( a ) && hasTerm( b ) ){ |
1648 |
326 |
return d_equalityEngine->areEqual(a, b); |
1649 |
|
}else{ |
1650 |
275 |
return false; |
1651 |
|
} |
1652 |
|
} |
1653 |
|
|
1654 |
|
bool TheorySep::areDisequal( Node a, Node b ){ |
1655 |
|
if( a==b ){ |
1656 |
|
return false; |
1657 |
|
}else if( hasTerm( a ) && hasTerm( b ) ){ |
1658 |
|
if (d_equalityEngine->areDisequal(a, b, false)) |
1659 |
|
{ |
1660 |
|
return true; |
1661 |
|
} |
1662 |
|
} |
1663 |
|
return false; |
1664 |
|
} |
1665 |
|
|
1666 |
15431 |
void TheorySep::eqNotifyMerge(TNode t1, TNode t2) |
1667 |
|
{ |
1668 |
15431 |
HeapAssertInfo * e2 = getOrMakeEqcInfo( t2, false ); |
1669 |
15431 |
if( e2 && ( !e2->d_pto.get().isNull() || e2->d_has_neg_pto.get() ) ){ |
1670 |
531 |
HeapAssertInfo * e1 = getOrMakeEqcInfo( t1, true ); |
1671 |
531 |
if( !e2->d_pto.get().isNull() ){ |
1672 |
530 |
if( !e1->d_pto.get().isNull() ){ |
1673 |
169 |
Trace("sep-pto-debug") << "While merging " << t1 << " " << t2 << ", merge pto." << std::endl; |
1674 |
169 |
mergePto( e1->d_pto.get(), e2->d_pto.get() ); |
1675 |
|
}else{ |
1676 |
361 |
e1->d_pto.set( e2->d_pto.get() ); |
1677 |
|
} |
1678 |
|
} |
1679 |
531 |
e1->d_has_neg_pto.set( e1->d_has_neg_pto.get() || e2->d_has_neg_pto.get() ); |
1680 |
|
//validate |
1681 |
531 |
validatePto( e1, t1 ); |
1682 |
|
} |
1683 |
15431 |
} |
1684 |
|
|
1685 |
1345 |
void TheorySep::validatePto( HeapAssertInfo * ei, Node ei_n ) { |
1686 |
1345 |
if( !ei->d_pto.get().isNull() && ei->d_has_neg_pto.get() ){ |
1687 |
4 |
for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) { |
1688 |
6 |
Node fact = (*i); |
1689 |
3 |
if (fact.getKind() == kind::NOT) |
1690 |
|
{ |
1691 |
2 |
TNode atom = fact[0]; |
1692 |
1 |
Assert(atom.getKind() == kind::SEP_LABEL); |
1693 |
2 |
TNode satom = atom[0]; |
1694 |
1 |
if (satom.getKind() == SEP_PTO) |
1695 |
|
{ |
1696 |
1 |
if( areEqual( atom[1], ei_n ) ){ |
1697 |
1 |
addPto( ei, ei_n, atom, false ); |
1698 |
|
} |
1699 |
|
} |
1700 |
|
} |
1701 |
|
} |
1702 |
|
//we have now processed all pending negated pto |
1703 |
1 |
ei->d_has_neg_pto.set( false ); |
1704 |
|
} |
1705 |
1345 |
} |
1706 |
|
|
1707 |
1068 |
void TheorySep::addPto( HeapAssertInfo * ei, Node ei_n, Node p, bool polarity ) { |
1708 |
1068 |
Trace("sep-pto") << "Add pto " << p << ", pol = " << polarity << " to eqc " << ei_n << std::endl; |
1709 |
1068 |
if( !ei->d_pto.get().isNull() ){ |
1710 |
243 |
if( polarity ){ |
1711 |
182 |
Trace("sep-pto-debug") << "...eqc " << ei_n << " already has pto " << ei->d_pto.get() << ", merge." << std::endl; |
1712 |
182 |
mergePto( ei->d_pto.get(), p ); |
1713 |
|
}else{ |
1714 |
122 |
Node pb = ei->d_pto.get(); |
1715 |
61 |
Trace("sep-pto") << "Process positive/negated pto " << " " << pb << " " << p << std::endl; |
1716 |
61 |
Assert(pb.getKind() == kind::SEP_LABEL |
1717 |
|
&& pb[0].getKind() == kind::SEP_PTO); |
1718 |
61 |
Assert(p.getKind() == kind::SEP_LABEL && p[0].getKind() == kind::SEP_PTO); |
1719 |
61 |
Assert(areEqual(pb[1], p[1])); |
1720 |
122 |
std::vector< Node > exp; |
1721 |
61 |
if( pb[1]!=p[1] ){ |
1722 |
|
//if( pb[1].getKind()==kind::SINGLETON && p[1].getKind()==kind::SINGLETON ){ |
1723 |
|
// exp.push_back( pb[1][0].eqNode( p[1][0] ) ); |
1724 |
|
//}else{ |
1725 |
24 |
exp.push_back( pb[1].eqNode( p[1] ) ); |
1726 |
|
//} |
1727 |
|
} |
1728 |
61 |
exp.push_back( pb ); |
1729 |
61 |
exp.push_back( p.negate() ); |
1730 |
122 |
std::vector< Node > conc; |
1731 |
61 |
if( pb[0][1]!=p[0][1] ){ |
1732 |
61 |
conc.push_back( pb[0][1].eqNode( p[0][1] ).negate() ); |
1733 |
|
} |
1734 |
|
//if( pb[1]!=p[1] ){ |
1735 |
|
// conc.push_back( pb[1].eqNode( p[1] ).negate() ); |
1736 |
|
//} |
1737 |
122 |
Node n_conc = conc.empty() ? d_false : ( conc.size()==1 ? conc[0] : NodeManager::currentNM()->mkNode( kind::OR, conc ) ); |
1738 |
61 |
Trace("sep-pto") << "Conclusion is " << n_conc << std::endl; |
1739 |
|
// propagation for (pto x y) ^ ~(pto z w) ^ x = z => y != w |
1740 |
61 |
sendLemma( exp, n_conc, InferenceId::SEP_PTO_NEG_PROP); |
1741 |
|
} |
1742 |
|
}else{ |
1743 |
825 |
if( polarity ){ |
1744 |
814 |
ei->d_pto.set( p ); |
1745 |
814 |
validatePto( ei, ei_n ); |
1746 |
|
}else{ |
1747 |
11 |
ei->d_has_neg_pto.set( true ); |
1748 |
|
} |
1749 |
|
} |
1750 |
1068 |
} |
1751 |
|
|
1752 |
351 |
void TheorySep::mergePto( Node p1, Node p2 ) { |
1753 |
351 |
Trace("sep-lemma-debug") << "Merge pto " << p1 << " " << p2 << std::endl; |
1754 |
351 |
Assert(p1.getKind() == kind::SEP_LABEL && p1[0].getKind() == kind::SEP_PTO); |
1755 |
351 |
Assert(p2.getKind() == kind::SEP_LABEL && p2[0].getKind() == kind::SEP_PTO); |
1756 |
351 |
if( !areEqual( p1[0][1], p2[0][1] ) ){ |
1757 |
690 |
std::vector< Node > exp; |
1758 |
345 |
if( p1[1]!=p2[1] ){ |
1759 |
232 |
Assert(areEqual(p1[1], p2[1])); |
1760 |
232 |
exp.push_back( p1[1].eqNode( p2[1] ) ); |
1761 |
|
} |
1762 |
345 |
exp.push_back( p1 ); |
1763 |
345 |
exp.push_back( p2 ); |
1764 |
|
//enforces injectiveness of pto : (pto x y) ^ (pto y w) ^ x = y => y = w |
1765 |
345 |
sendLemma( exp, p1[0][1].eqNode( p2[0][1] ), InferenceId::SEP_PTO_PROP); |
1766 |
|
} |
1767 |
351 |
} |
1768 |
|
|
1769 |
406 |
void TheorySep::sendLemma( std::vector< Node >& ant, Node conc, InferenceId id, bool infer ) { |
1770 |
406 |
Trace("sep-lemma-debug") << "Do rewrite on inference : " << conc << std::endl; |
1771 |
406 |
conc = Rewriter::rewrite( conc ); |
1772 |
406 |
Trace("sep-lemma-debug") << "Got : " << conc << std::endl; |
1773 |
406 |
if( conc!=d_true ){ |
1774 |
394 |
if( infer && conc!=d_false ){ |
1775 |
|
Node ant_n = NodeManager::currentNM()->mkAnd(ant); |
1776 |
|
Trace("sep-lemma") << "Sep::Infer: " << conc << " from " << ant_n << " by " << id << std::endl; |
1777 |
|
d_im.addPendingFact(conc, id, ant_n); |
1778 |
|
}else{ |
1779 |
394 |
if( conc==d_false ){ |
1780 |
16 |
Trace("sep-lemma") << "Sep::Conflict: " << ant << " by " << id |
1781 |
8 |
<< std::endl; |
1782 |
8 |
d_im.conflictExp(id, PfRule::THEORY_INFERENCE, ant, {conc}); |
1783 |
|
}else{ |
1784 |
772 |
Trace("sep-lemma") << "Sep::Lemma: " << conc << " from " << ant |
1785 |
386 |
<< " by " << id << std::endl; |
1786 |
|
TrustNode trn = |
1787 |
772 |
d_im.mkLemmaExp(conc, PfRule::THEORY_INFERENCE, ant, {}, {conc}); |
1788 |
772 |
d_im.addPendingLemma( |
1789 |
772 |
trn.getNode(), id, LemmaProperty::NONE, trn.getGenerator()); |
1790 |
|
} |
1791 |
|
} |
1792 |
|
} |
1793 |
406 |
} |
1794 |
|
|
1795 |
7044 |
void TheorySep::doPending() |
1796 |
|
{ |
1797 |
7044 |
d_im.doPendingFacts(); |
1798 |
7044 |
d_im.doPendingLemmas(); |
1799 |
7044 |
} |
1800 |
|
|
1801 |
|
void TheorySep::debugPrintHeap( HeapInfo& heap, const char * c ) { |
1802 |
|
Trace(c) << "[" << std::endl; |
1803 |
|
Trace(c) << " "; |
1804 |
|
for( unsigned j=0; j<heap.d_heap_locs.size(); j++ ){ |
1805 |
|
Trace(c) << heap.d_heap_locs[j] << " "; |
1806 |
|
} |
1807 |
|
Trace(c) << std::endl; |
1808 |
|
Trace(c) << "]" << std::endl; |
1809 |
|
} |
1810 |
|
|
1811 |
528 |
Node TheorySep::HeapInfo::getValue( TypeNode tn ) { |
1812 |
528 |
Assert(d_heap_locs.size() == d_heap_locs_model.size()); |
1813 |
528 |
if( d_heap_locs.empty() ){ |
1814 |
134 |
return NodeManager::currentNM()->mkConst(EmptySet(tn)); |
1815 |
|
} |
1816 |
788 |
Node curr = d_heap_locs[0]; |
1817 |
516 |
for (unsigned j = 1; j < d_heap_locs.size(); j++) |
1818 |
|
{ |
1819 |
122 |
curr = NodeManager::currentNM()->mkNode(kind::UNION, d_heap_locs[j], curr); |
1820 |
|
} |
1821 |
394 |
return curr; |
1822 |
|
} |
1823 |
|
|
1824 |
|
} // namespace sep |
1825 |
|
} // namespace theory |
1826 |
29514 |
} // namespace cvc5 |