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