Branch data Line data Source code
1 : : /******************************************************************************
2 : : * This file is part of the cvc5 project.
3 : : *
4 : : * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
5 : : * in the top-level source directory and their institutional affiliations.
6 : : * All rights reserved. See the file COPYING in the top-level source
7 : : * directory for licensing information.
8 : : * ****************************************************************************
9 : : *
10 : : * Implementation of the theory of separation logic.
11 : : */
12 : :
13 : : #include "theory/sep/theory_sep.h"
14 : :
15 : : #include <map>
16 : :
17 : : #include "base/map_util.h"
18 : : #include "expr/emptyset.h"
19 : : #include "expr/kind.h"
20 : : #include "expr/node_algorithm.h"
21 : : #include "expr/skolem_manager.h"
22 : : #include "options/quantifiers_options.h"
23 : : #include "options/sep_options.h"
24 : : #include "options/smt_options.h"
25 : : #include "proof/trust_id.h"
26 : : #include "smt/logic_exception.h"
27 : : #include "theory/builtin/proof_checker.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::internal::kind;
40 : :
41 : : namespace cvc5::internal {
42 : : namespace theory {
43 : : namespace sep {
44 : :
45 : 50916 : TheorySep::TheorySep(Env& env, OutputChannel& out, Valuation valuation)
46 : : : Theory(THEORY_SEP, env, out, valuation),
47 : 50916 : d_bounds_init(false),
48 : 50916 : d_rewriter(nodeManager()),
49 : 50916 : d_state(env, valuation),
50 : 50916 : d_im(env, *this, d_state, "theory::sep::"),
51 : 50916 : d_notify(*this),
52 : 50916 : d_reduce(userContext()),
53 : 50916 : d_spatial_assertions(context()),
54 : 50916 : d_bound_kind(bound_invalid),
55 : 203664 : d_card_max(0)
56 : : {
57 : 50916 : d_true = nodeManager()->mkConst<bool>(true);
58 : 50916 : d_false = nodeManager()->mkConst<bool>(false);
59 : 50916 : d_tiid = mkTrustId(nodeManager(), TrustId::THEORY_INFERENCE_SEP);
60 : :
61 : : // indicate we are using the default theory state object
62 : 50916 : d_theoryState = &d_state;
63 : 50916 : d_inferManager = &d_im;
64 : :
65 : : // initialize the heap types
66 : 50916 : initializeHeapTypes();
67 : 50916 : }
68 : :
69 : 101142 : TheorySep::~TheorySep()
70 : : {
71 : 50571 : for (std::map<Node, HeapAssertInfo*>::iterator it = d_eqc_info.begin();
72 [ + + ]: 52067 : it != d_eqc_info.end();
73 : 1496 : ++it)
74 : : {
75 [ + - ]: 1496 : delete it->second;
76 : : }
77 : 101142 : }
78 : :
79 : 50916 : void TheorySep::initializeHeapTypes()
80 : : {
81 [ + + ]: 50916 : if (d_env.hasSepHeap())
82 : : {
83 : : // for now, we only allow heap constraints of one type
84 : 891 : d_type_ref = d_env.getSepLocType();
85 : 891 : d_type_data = d_env.getSepDataType();
86 [ + - ]: 1782 : Trace("sep-type") << "Sep: assume location type " << d_type_ref
87 : 0 : << " is associated with data type " << d_type_data
88 : 891 : << std::endl;
89 : 891 : d_nil_ref = nodeManager()->mkNullaryOperator(d_type_ref, Kind::SEP_NIL);
90 : 891 : d_bound_kind = bound_default;
91 : : }
92 : 50916 : }
93 : :
94 : 50916 : TheoryRewriter* TheorySep::getTheoryRewriter()
95 : : {
96 [ + + ]: 50916 : if (!options().sep.sep)
97 : : {
98 : 5 : return nullptr;
99 : : }
100 : 50911 : return &d_rewriter;
101 : : }
102 : :
103 : 19674 : ProofRuleChecker* TheorySep::getProofChecker() { return nullptr; }
104 : :
105 : 50916 : bool TheorySep::needsEqualityEngine(EeSetupInfo& esi)
106 : : {
107 : 50916 : esi.d_notify = &d_notify;
108 : 50916 : esi.d_name = "theory::sep::ee";
109 : 50916 : esi.d_notifyMerge = true;
110 : 50916 : return true;
111 : : }
112 : :
113 : 50916 : void TheorySep::finishInit()
114 : : {
115 [ - + ][ - + ]: 50916 : Assert(d_equalityEngine != nullptr);
[ - - ]
116 : : // The kinds we are treating as function application in congruence
117 : 50916 : d_equalityEngine->addFunctionKind(Kind::SEP_PTO);
118 : : // we could but don't do congruence on SEP_STAR here.
119 : :
120 : : // separation logic predicates are not relevant for model building
121 : 50916 : d_valuation.setIrrelevantKind(Kind::SEP_STAR);
122 : 50916 : d_valuation.setIrrelevantKind(Kind::SEP_WAND);
123 : 50916 : d_valuation.setIrrelevantKind(Kind::SEP_LABEL);
124 : 50916 : d_valuation.setIrrelevantKind(Kind::SEP_PTO);
125 : 50916 : }
126 : :
127 : 8383 : void TheorySep::preRegisterTerm(TNode n)
128 : : {
129 : 8383 : Kind k = n.getKind();
130 [ + + ][ + + ]: 8383 : if (k == Kind::SEP_PTO || k == Kind::SEP_EMP || k == Kind::SEP_STAR
[ + + ]
131 [ + + ]: 7203 : || k == Kind::SEP_WAND)
132 : : {
133 [ - + ]: 1215 : if (!options().sep.sep)
134 : : {
135 : 0 : std::stringstream ss;
136 : : ss << "Separation logic not available in this configuration, try "
137 : 0 : "--sep.";
138 : 0 : throw SafeLogicException(ss.str());
139 : 0 : }
140 : 1215 : ensureHeapTypesFor(n);
141 : : }
142 : 8382 : }
143 : :
144 : 17429 : bool TheorySep::propagateLit(TNode literal)
145 : : {
146 : 17429 : return d_im.propagateLit(literal);
147 : : }
148 : :
149 : 6 : TrustNode TheorySep::explain(TNode literal)
150 : : {
151 [ + - ]: 6 : Trace("sep") << "TheorySep::explain(" << literal << ")" << std::endl;
152 : 6 : return d_im.explainLit(literal);
153 : : }
154 : :
155 : : /////////////////////////////////////////////////////////////////////////////
156 : : // MODEL GENERATION
157 : : /////////////////////////////////////////////////////////////////////////////
158 : :
159 : 4422 : void TheorySep::postProcessModel(TheoryModel* m)
160 : : {
161 [ + - ]: 4422 : Trace("sep-model") << "Printing model for TheorySep..." << std::endl;
162 [ + + ]: 4422 : if (d_type_ref.isNull())
163 : : {
164 : 4053 : return;
165 : : }
166 : :
167 : : // loc -> { data_1, ..., data_n } where (not (pto loc data_1))...(not (pto loc
168 : : // data_n))).
169 : 369 : std::map<Node, std::vector<Node> > heapLocsNegativePtos;
170 : : // set up model
171 [ + - ]: 369 : Trace("sep-model") << "...preparing sep model..." << std::endl;
172 : : // collect data points that are not pointed to
173 : 369 : for (context::CDList<Assertion>::const_iterator it = facts_begin();
174 [ + + ]: 3071 : it != facts_end();
175 : 2702 : ++it)
176 : : {
177 : 2702 : Node lit = (*it).d_assertion;
178 [ + + ]: 2702 : Node atom = lit.getKind() == Kind::NOT ? lit[0] : lit;
179 [ + + ]: 2702 : atom = atom.getKind() == Kind::SEP_LABEL ? atom[0] : atom;
180 [ + + ][ + + ]: 2702 : if (lit.getKind() == Kind::NOT && atom.getKind() == Kind::SEP_PTO)
[ + + ]
181 : : {
182 : 64 : Node v1 = m->getValue(atom[0]);
183 : 64 : Node v2 = m->getValue(atom[1]);
184 [ + - ]: 32 : Trace("sep-model") << v1 << " does not point-to " << v2 << std::endl;
185 : 32 : heapLocsNegativePtos[v1].push_back(v2);
186 : 32 : }
187 : 2702 : }
188 : :
189 : 369 : NodeManager* nm = nodeManager();
190 : 369 : std::vector<Node> sep_children;
191 : 369 : Node m_neq;
192 : 369 : Node m_heap;
193 : : // should only be constructing for one heap type
194 [ - + ][ - + ]: 369 : Assert(m_heap.isNull());
[ - - ]
195 [ + - ]: 738 : Trace("sep-model") << "Model for heap, type = " << d_type_ref
196 : 369 : << " with data type " << d_type_data << " : " << std::endl;
197 : 369 : Node blbl = getBaseLabel();
198 : 369 : computeLabelModel(blbl);
199 : 369 : HeapInfo& hm = d_label_model[blbl];
200 [ + + ]: 369 : if (hm.d_heap_locs_model.empty())
201 : : {
202 [ + - ]: 2 : Trace("sep-model") << " [empty]" << std::endl;
203 : : }
204 : : else
205 : : {
206 [ + + ]: 738 : for (const Node& hv : hm.d_heap_locs_model)
207 : : {
208 [ - + ][ - + ]: 371 : Assert(hv.getKind() == Kind::SET_SINGLETON);
[ - - ]
209 : 371 : std::vector<Node> pto_children;
210 : 371 : Node l = hv[0];
211 [ - + ][ - + ]: 371 : Assert(l.isConst());
[ - - ]
212 : 371 : pto_children.push_back(l);
213 [ + - ]: 371 : Trace("sep-model") << " " << l << " -> ";
214 [ + + ]: 371 : if (d_pto_model[l].isNull())
215 : : {
216 [ + - ]: 2 : Trace("sep-model") << "_";
217 : 2 : TypeEnumerator te_range(d_type_data);
218 [ - + ]: 2 : if (d_env.isFiniteType(d_type_data))
219 : : {
220 : 0 : pto_children.push_back(*te_range);
221 : : }
222 : : else
223 : : {
224 : : // must enumerate until we find one that is not explicitly pointed to
225 : 2 : bool success = false;
226 : 2 : Node cv;
227 : : do
228 : : {
229 : 8 : cv = *te_range;
230 : 8 : if (std::find(heapLocsNegativePtos[l].begin(),
231 : 8 : heapLocsNegativePtos[l].end(),
232 : : cv)
233 [ + + ]: 16 : == heapLocsNegativePtos[l].end())
234 : : {
235 : 2 : success = true;
236 : : }
237 : : else
238 : : {
239 : 6 : ++te_range;
240 : : }
241 [ + + ]: 8 : } while (!success);
242 : 2 : pto_children.push_back(cv);
243 : 2 : }
244 : 2 : }
245 : : else
246 : : {
247 [ + - ]: 369 : Trace("sep-model") << d_pto_model[l];
248 : 369 : Node vpto = m->getValue(d_pto_model[l]);
249 [ - + ][ - + ]: 369 : Assert(vpto.isConst());
[ - - ]
250 : 369 : pto_children.push_back(vpto);
251 : 369 : }
252 [ + - ]: 371 : Trace("sep-model") << std::endl;
253 : 371 : sep_children.push_back(
254 : 742 : nodeManager()->mkNode(Kind::SEP_PTO, pto_children));
255 : 371 : }
256 : : }
257 [ - + ][ - + ]: 369 : Assert(!d_nil_ref.isNull());
[ - - ]
258 : 369 : Node vnil = d_valuation.getModel()->getRepresentative(d_nil_ref);
259 : 369 : m_neq = nm->mkNode(Kind::EQUAL, d_nil_ref, vnil);
260 [ + - ]: 369 : Trace("sep-model") << "sep.nil = " << vnil << std::endl;
261 [ + - ]: 369 : Trace("sep-model") << std::endl;
262 [ + + ]: 369 : if (sep_children.empty())
263 : : {
264 : 2 : TypeNode boolType = nm->booleanType();
265 : 2 : m_heap = nm->mkNullaryOperator(boolType, Kind::SEP_EMP);
266 : 2 : }
267 [ + + ]: 367 : else if (sep_children.size() == 1)
268 : : {
269 : 364 : m_heap = sep_children[0];
270 : : }
271 : : else
272 : : {
273 : 3 : m_heap = nm->mkNode(Kind::SEP_STAR, sep_children);
274 : : }
275 : 369 : m->setHeapModel(m_heap, m_neq);
276 : :
277 [ + - ]: 369 : Trace("sep-model") << "Finished printing model for TheorySep." << std::endl;
278 : 369 : }
279 : :
280 : : /////////////////////////////////////////////////////////////////////////////
281 : : // NOTIFICATIONS
282 : : /////////////////////////////////////////////////////////////////////////////
283 : :
284 [ + - ]: 50355 : void TheorySep::presolve() { Trace("sep-pp") << "Presolving" << std::endl; }
285 : :
286 : : /////////////////////////////////////////////////////////////////////////////
287 : : // MAIN SOLVER
288 : : /////////////////////////////////////////////////////////////////////////////
289 : :
290 : 29528 : bool TheorySep::preNotifyFact(TNode atom,
291 : : bool polarity,
292 : : TNode fact,
293 : : CVC5_UNUSED bool isPrereg,
294 : : CVC5_UNUSED bool isInternal)
295 : : {
296 [ + + ]: 29528 : TNode satom = atom.getKind() == Kind::SEP_LABEL ? atom[0] : atom;
297 [ + + ]: 29528 : TNode slbl = atom.getKind() == Kind::SEP_LABEL ? atom[1] : TNode::null();
298 : 29528 : bool isSpatial = isSpatialKind(satom.getKind());
299 [ + + ]: 29528 : if (isSpatial)
300 : : {
301 : 9764 : reduceFact(atom, polarity, fact);
302 [ + + ]: 9764 : if (!slbl.isNull())
303 : : {
304 : 7621 : d_spatial_assertions.push_back(fact);
305 : : }
306 : : }
307 [ + + ][ + + ]: 29528 : if (!slbl.isNull() && satom.getKind() == Kind::SEP_PTO)
[ + + ]
308 : : {
309 : 6068 : return false;
310 : : }
311 : : // assert to equality if non-spatial or a labelled pto
312 [ + + ]: 23460 : if (!isSpatial)
313 : : {
314 : 19764 : return false;
315 : : }
316 : : // otherwise, maybe propagate
317 : 3696 : doPending();
318 : 3696 : return true;
319 : 29528 : }
320 : :
321 : 25832 : void TheorySep::notifyFact(TNode atom,
322 : : bool polarity,
323 : : CVC5_UNUSED TNode fact,
324 : : CVC5_UNUSED bool isInternal)
325 : : {
326 [ + + ]: 25832 : TNode satom = atom.getKind() == Kind::SEP_LABEL ? atom[0] : atom;
327 [ + + ][ + - ]: 25832 : if (atom.getKind() == Kind::SEP_LABEL && atom[0].getKind() == Kind::SEP_PTO)
[ + + ][ + + ]
[ - - ]
328 : : {
329 : : // associate the equivalence class of the lhs with this pto
330 : 12136 : Node r = getRepresentative(atom[1]);
331 : 6068 : HeapAssertInfo* e = getOrMakeEqcInfo(r, true);
332 [ + + ]: 6068 : if (checkPto(e, atom, polarity))
333 : : {
334 [ + + ]: 5924 : NodeList& elist = polarity ? e->d_posPto : e->d_negPto;
335 : 5924 : elist.push_back(atom);
336 : : }
337 : 6068 : }
338 : : // maybe propagate
339 : 25832 : doPending();
340 : 25832 : }
341 : :
342 : 9764 : void TheorySep::reduceFact(TNode atom, bool polarity, TNode fact)
343 : : {
344 [ + + ]: 9764 : if (d_reduce.find(fact) != d_reduce.end())
345 : : {
346 : : // already reduced
347 : 7853 : return;
348 : : }
349 : 3318 : d_reduce.insert(fact);
350 [ + + ]: 3318 : TNode satom = atom.getKind() == Kind::SEP_LABEL ? atom[0] : atom;
351 [ + + ]: 3318 : TNode slbl = atom.getKind() == Kind::SEP_LABEL ? atom[1] : TNode::null();
352 : 3318 : NodeManager* nm = nodeManager();
353 [ + + ]: 3318 : if (slbl.isNull())
354 : : {
355 [ + - ]: 2426 : Trace("sep-lemma-debug")
356 : 1213 : << "Reducing unlabelled assertion " << atom << std::endl;
357 : : // introduce top-level label, add iff
358 [ + - ]: 2426 : Trace("sep-lemma-debug")
359 : 1213 : << "...reference type is : " << d_type_ref << std::endl;
360 : 1213 : Node b_lbl = getBaseLabel();
361 : 2426 : Node satom_new = nm->mkNode(Kind::SEP_LABEL, satom, b_lbl);
362 : 1213 : Node lem;
363 [ + - ]: 1213 : Trace("sep-lemma-debug") << "...polarity is " << polarity << std::endl;
364 [ + + ]: 1213 : if (polarity)
365 : : {
366 : 1098 : lem = nm->mkNode(Kind::OR, satom.negate(), satom_new);
367 : : }
368 : : else
369 : : {
370 : 115 : lem = nm->mkNode(Kind::OR, satom, satom_new.negate());
371 : : }
372 [ + - ]: 2426 : Trace("sep-lemma-debug")
373 : 1213 : << "Sep::Lemma : base reduction : " << lem << std::endl;
374 : 1213 : d_im.lemma(lem, InferenceId::SEP_LABEL_INTRO);
375 : 1213 : return;
376 : 1213 : }
377 [ + - ]: 2105 : Trace("sep-lemma-debug") << "Reducing assertion " << fact << std::endl;
378 : 2105 : Node conc;
379 [ + + ]: 2105 : if (Node* in_map = FindOrNull(d_red_conc[slbl], satom))
380 : : {
381 : 226 : conc = *in_map;
382 : : }
383 : : else
384 : : {
385 : : // make conclusion based on type of assertion
386 [ + + ][ + + ]: 1879 : if (satom.getKind() == Kind::SEP_STAR || satom.getKind() == Kind::SEP_WAND)
[ + + ]
387 : : {
388 [ + + ]: 276 : if (!d_reference_bound_max.isNull())
389 : : {
390 : 546 : Node blem = nm->mkNode(Kind::SET_SUBSET, slbl, d_reference_bound_max);
391 : 273 : d_im.lemma(blem, InferenceId::SEP_LABEL_DEF);
392 : 273 : }
393 : 276 : std::vector<Node> children;
394 : 276 : std::vector<Node> labels;
395 : 276 : getLabelChildren(satom, slbl, children, labels);
396 : 552 : Node empSet = nm->mkConst(EmptySet(slbl.getType()));
397 [ - + ][ - + ]: 276 : Assert(children.size() > 1);
[ - - ]
398 [ + + ]: 276 : if (satom.getKind() == Kind::SEP_STAR)
399 : : {
400 : : // make disjoint heap
401 : 245 : makeDisjointHeap(slbl, labels);
402 : : }
403 : : else
404 : : {
405 [ - + ][ - + ]: 31 : Assert(satom.getKind() == Kind::SEP_WAND);
[ - - ]
406 : : // nil does not occur in labels[0]
407 [ - + ][ - + ]: 31 : Assert(!d_nil_ref.isNull());
[ - - ]
408 : : Node nrlem =
409 : 62 : nm->mkNode(Kind::SET_MEMBER, d_nil_ref, labels[0]).negate();
410 [ + - ]: 62 : Trace("sep-lemma")
411 : 0 : << "Sep::Lemma: sep.nil not in wand antecedant heap : " << nrlem
412 : 31 : << std::endl;
413 : 31 : d_im.lemma(nrlem, InferenceId::SEP_NIL_NOT_IN_HEAP);
414 : : // make disjoint heap
415 [ + + ][ - - ]: 93 : makeDisjointHeap(labels[1], {slbl, labels[0]});
416 : 31 : }
417 : 276 : conc = nm->mkNode(Kind::AND, children);
418 : 276 : }
419 [ + + ]: 1603 : else if (satom.getKind() == Kind::SEP_PTO)
420 : : {
421 : 1579 : Node ss = nm->mkNode(Kind::SET_SINGLETON, satom[0]);
422 [ + + ]: 1579 : if (slbl != ss)
423 : : {
424 : 1476 : conc = slbl.eqNode(ss);
425 : : }
426 : : // if we are not a part of the root label, we require applying downwards
427 : : // closure, e.g. (SEP_LABEL (pto x y) A) =>
428 : : // (or (SEP_LABEL (pto x y) B) (SEP_LABEL (pto x y) C)) where
429 : : // A is the disjoint union of B and C.
430 [ + + ]: 1579 : if (!sharesRootLabel(slbl, d_base_label))
431 : : {
432 : : std::map<Node, std::vector<Node> >::iterator itc =
433 : 169 : d_childrenMap.find(slbl);
434 [ + + ]: 169 : if (itc != d_childrenMap.end())
435 : : {
436 : 16 : std::vector<Node> disjs;
437 [ + + ]: 48 : for (const Node& c : itc->second)
438 : : {
439 : 32 : disjs.push_back(nm->mkNode(Kind::SEP_LABEL, satom, c));
440 : : }
441 : 16 : Node conc2 = nm->mkNode(Kind::OR, disjs);
442 : 16 : conc = conc.isNull() ? conc2 : nm->mkNode(Kind::AND, conc, conc2);
443 : 16 : }
444 : : }
445 : : // note semantics of sep.nil is enforced globally
446 : 1579 : }
447 [ + - ]: 24 : else if (satom.getKind() == Kind::SEP_EMP)
448 : : {
449 : 24 : Node lem;
450 : 48 : Node emp_s = nm->mkConst(EmptySet(slbl.getType()));
451 [ + + ]: 24 : if (polarity)
452 : : {
453 [ + + ][ - - ]: 69 : lem = nm->mkNode(Kind::OR, {fact.negate(), slbl.eqNode(emp_s)});
454 : : }
455 : : else
456 : : {
457 [ - + ][ - + ]: 1 : Assert(!d_type_ref.isNull());
[ - - ]
458 : 2 : Node kl = NodeManager::mkDummySkolem("loc", d_type_ref);
459 : 2 : Node kd = NodeManager::mkDummySkolem("data", d_type_data);
460 : : Node econc = nm->mkNode(
461 : : Kind::SEP_LABEL,
462 : 3 : nm->mkNode(
463 : 2 : Kind::SEP_STAR, nm->mkNode(Kind::SEP_PTO, kl, kd), d_true),
464 : 3 : slbl);
465 : : // Node econc = nm->mkNode( AND, slbl.eqNode( emp_s ).negate(),
466 : 1 : lem = nm->mkNode(Kind::OR, fact.negate(), econc);
467 : 1 : }
468 [ + - ]: 24 : Trace("sep-lemma") << "Sep::Lemma : emp : " << lem << std::endl;
469 : 24 : d_im.lemma(lem, InferenceId::SEP_EMP);
470 : 24 : }
471 : : else
472 : : {
473 : : // labeled emp should be rewritten
474 : 0 : Unreachable();
475 : : }
476 : 1879 : d_red_conc[slbl][satom] = conc;
477 : : }
478 [ + + ]: 2105 : if (conc.isNull())
479 : : {
480 [ + - ]: 388 : Trace("sep-lemma-debug")
481 : 194 : << "Trivial conclusion, do not add lemma." << std::endl;
482 : 194 : return;
483 : : }
484 [ + + ]: 1911 : bool use_polarity = satom.getKind() == Kind::SEP_WAND ? !polarity : polarity;
485 [ + + ]: 1911 : if (!use_polarity)
486 : : {
487 : : // introduce guard, assert positive version
488 [ + - ]: 606 : Trace("sep-lemma-debug")
489 : 0 : << "Negated spatial constraint asserted to sep theory: " << fact
490 : 303 : << std::endl;
491 : 606 : Node g = NodeManager::mkDummySkolem("G", nm->booleanType());
492 : 606 : d_neg_guard_strategy[g].reset(new DecisionStrategySingleton(
493 : 303 : d_env, "sep_neg_guard", g, getValuation()));
494 : 303 : DecisionStrategySingleton* ds = d_neg_guard_strategy[g].get();
495 : 303 : d_im.getDecisionManager()->registerStrategy(
496 : : DecisionManager::STRAT_SEP_NEG_GUARD, ds);
497 : 303 : Node lit = ds->getLiteral(0);
498 : 303 : d_neg_guard[slbl][satom] = lit;
499 [ + - ]: 606 : Trace("sep-lemma-debug")
500 : 303 : << "Neg guard : " << slbl << " " << satom << " " << lit << std::endl;
501 [ - + ][ - + ]: 303 : AlwaysAssert(!lit.isNull());
[ - - ]
502 : 303 : d_neg_guards.push_back(lit);
503 : 303 : d_guard_to_assertion[lit] = satom;
504 : : // Node lem = nm->mkNode( EQUAL, lit, conc );
505 : 606 : Node lem = nm->mkNode(Kind::OR, lit.negate(), conc);
506 [ + - ]: 303 : Trace("sep-lemma") << "Sep::Lemma : (neg) reduction : " << lem << std::endl;
507 : 303 : d_im.lemma(lem, InferenceId::SEP_NEG_REDUCTION);
508 : 303 : }
509 : : else
510 : : {
511 : : // reduce based on implication
512 : 3216 : Node lem = nm->mkNode(Kind::OR, fact.negate(), conc);
513 [ + - ]: 1608 : Trace("sep-lemma") << "Sep::Lemma : reduction : " << lem << std::endl;
514 : 1608 : d_im.lemma(lem, InferenceId::SEP_POS_REDUCTION);
515 : 1608 : }
516 [ + + ][ + + ]: 4919 : }
[ + + ]
517 : :
518 : 29528 : bool TheorySep::isSpatialKind(Kind k) const
519 : : {
520 [ + + ][ + + ]: 27449 : return k == Kind::SEP_STAR || k == Kind::SEP_WAND || k == Kind::SEP_PTO
521 [ + + ][ + + ]: 56977 : || k == Kind::SEP_EMP;
522 : : }
523 : :
524 : 85468 : void TheorySep::postCheck(Effort level)
525 : : {
526 [ + - ]: 909 : if (level != EFFORT_LAST_CALL || d_state.isInConflict()
527 [ + + ][ + + ]: 86377 : || d_valuation.needCheck())
[ + + ]
528 : : {
529 : 84659 : return;
530 : : }
531 : 899 : NodeManager* nm = nodeManager();
532 [ + - ]: 899 : Trace("sep-process") << "Checking heap at full effort..." << std::endl;
533 : 899 : d_label_model.clear();
534 : 899 : d_tmodel.clear();
535 : 899 : d_pto_model.clear();
536 [ + - ]: 899 : Trace("sep-process") << "---Locations---" << std::endl;
537 : 899 : std::map<Node, int> min_id;
538 [ + + ]: 1956 : for (const Node& t : d_type_references)
539 : : {
540 [ + - ]: 1057 : Trace("sep-process") << " " << t << " = ";
541 [ + + ]: 1057 : if (d_valuation.getModel()->hasTerm(t))
542 : : {
543 : 991 : Node v = d_valuation.getModel()->getRepresentative(t);
544 [ + - ]: 991 : Trace("sep-process") << v << std::endl;
545 : : // take minimal id
546 : 991 : std::map<Node, unsigned>::iterator itrc = d_type_ref_card_id.find(t);
547 [ + + ]: 991 : int tid = itrc == d_type_ref_card_id.end() ? -1 : (int)itrc->second;
548 : : bool set_term_model;
549 [ + + ]: 991 : if (d_tmodel.find(v) == d_tmodel.end())
550 : : {
551 : 977 : set_term_model = true;
552 : : }
553 : : else
554 : : {
555 : 14 : set_term_model = min_id[v] > tid;
556 : : }
557 [ + + ]: 991 : if (set_term_model)
558 : : {
559 : 977 : d_tmodel[v] = t;
560 : 977 : min_id[v] = tid;
561 : : }
562 : 991 : }
563 : : else
564 : : {
565 [ + - ]: 66 : Trace("sep-process") << "?" << std::endl;
566 : : }
567 : : }
568 [ + - ]: 899 : Trace("sep-process") << "---" << std::endl;
569 : : // build positive/negative assertion lists for labels
570 : 899 : std::map<Node, bool> assert_active;
571 : : // get the inactive assertions
572 : 899 : std::map<Node, std::vector<Node> > lbl_to_assertions;
573 [ + + ]: 2759 : for (const Node& fact : d_spatial_assertions)
574 : : {
575 : 1860 : bool polarity = fact.getKind() != Kind::NOT;
576 [ + + ]: 1860 : TNode atom = polarity ? fact : fact[0];
577 [ - + ][ - + ]: 1860 : Assert(atom.getKind() == Kind::SEP_LABEL);
[ - - ]
578 : 1860 : TNode satom = atom[0];
579 : 1860 : TNode slbl = atom[1];
580 : 1860 : lbl_to_assertions[slbl].push_back(fact);
581 : : // check whether assertion is active : either polarity=true, or guard is not
582 : : // asserted false
583 : 1860 : assert_active[fact] = true;
584 : : bool use_polarity =
585 [ + + ]: 1860 : satom.getKind() == Kind::SEP_WAND ? !polarity : polarity;
586 [ + + ]: 1860 : if (use_polarity)
587 : : {
588 [ + + ]: 1242 : if (satom.getKind() == Kind::SEP_PTO)
589 : : {
590 : 1122 : Node vv = d_valuation.getModel()->getRepresentative(satom[0]);
591 [ + + ]: 1122 : if (d_pto_model.find(vv) == d_pto_model.end())
592 : : {
593 [ + - ][ - - ]: 1812 : Trace("sep-process") << "Pto : " << satom[0] << " (" << vv << ") -> "
594 [ - + ][ - + ]: 906 : << satom[1] << std::endl;
[ - - ]
595 : 906 : d_pto_model[vv] = satom[1];
596 : :
597 : : // replace this on pto-model since this term is more relevant
598 [ - + ][ - + ]: 906 : Assert(vv.getType() == d_type_ref);
[ - - ]
599 : 1812 : if (std::find(
600 : : d_type_references.begin(), d_type_references.end(), satom[0])
601 [ + + ]: 2718 : != d_type_references.end())
602 : : {
603 : 902 : d_tmodel[vv] = satom[0];
604 : : }
605 : : }
606 : 1122 : }
607 : : }
608 : : else
609 : : {
610 [ + + ]: 618 : if (d_neg_guard[slbl].find(satom) != d_neg_guard[slbl].end())
611 : : {
612 : : // check if the guard is asserted positively
613 : 1230 : Node guard = d_neg_guard[slbl][satom];
614 : : bool value;
615 [ + - ]: 615 : if (getValuation().hasSatValue(guard, value))
616 : : {
617 : 615 : assert_active[fact] = value;
618 : : }
619 : 615 : }
620 : : }
621 : 1860 : }
622 : : //(recursively) set inactive sub-assertions
623 [ + + ]: 2759 : for (const Node& fact : d_spatial_assertions)
624 : : {
625 [ + + ]: 1860 : if (!assert_active[fact])
626 : : {
627 : 278 : setInactiveAssertionRec(fact, lbl_to_assertions, assert_active);
628 : : }
629 : : }
630 : : // set up model information based on active assertions
631 [ + + ]: 2759 : for (const Node& fact : d_spatial_assertions)
632 : : {
633 : 1860 : bool polarity = fact.getKind() != Kind::NOT;
634 [ + + ]: 1860 : TNode atom = polarity ? fact : fact[0];
635 : 1860 : TNode satom = atom[0];
636 : 1860 : TNode slbl = atom[1];
637 [ + + ]: 1860 : if (assert_active[fact])
638 : : {
639 : 1581 : computeLabelModel(slbl);
640 : : }
641 : 1860 : }
642 : : // debug print
643 [ - + ]: 899 : if (TraceIsOn("sep-process"))
644 : : {
645 [ - - ]: 0 : Trace("sep-process") << "--- Current spatial assertions : " << std::endl;
646 [ - - ]: 0 : for (const Node& fact : d_spatial_assertions)
647 : : {
648 [ - - ]: 0 : Trace("sep-process") << " " << fact;
649 [ - - ]: 0 : if (!assert_active[fact])
650 : : {
651 [ - - ]: 0 : Trace("sep-process") << " [inactive]";
652 : : }
653 [ - - ]: 0 : Trace("sep-process") << std::endl;
654 : : }
655 [ - - ]: 0 : Trace("sep-process") << "---" << std::endl;
656 : : }
657 [ - + ]: 899 : if (TraceIsOn("sep-eqc"))
658 : : {
659 : 0 : Trace("sep-eqc") << d_equalityEngine->debugPrintEqc();
660 : : }
661 : :
662 : 899 : bool addedLemma = false;
663 : 899 : bool needAddLemma = false;
664 : : // check negated star / positive wand
665 : :
666 : : // get active labels
667 : 899 : std::map<Node, bool> active_lbl;
668 [ - + ]: 899 : if (options().sep.sepMinimalRefine)
669 : : {
670 [ - - ]: 0 : for (const Node& fact : d_spatial_assertions)
671 : : {
672 : 0 : bool polarity = fact.getKind() != Kind::NOT;
673 [ - - ]: 0 : TNode atom = polarity ? fact : fact[0];
674 : 0 : TNode satom = atom[0];
675 : : bool use_polarity =
676 [ - - ]: 0 : satom.getKind() == Kind::SEP_WAND ? !polarity : polarity;
677 [ - - ]: 0 : if (!use_polarity)
678 : : {
679 : 0 : Assert(assert_active.find(fact) != assert_active.end());
680 [ - - ]: 0 : if (assert_active[fact])
681 : : {
682 : 0 : Assert(atom.getKind() == Kind::SEP_LABEL);
683 : 0 : TNode slbl = atom[1];
684 : 0 : std::map<Node, std::map<int, Node> >& lms = d_label_map[satom];
685 [ - - ]: 0 : if (lms.find(slbl) != lms.end())
686 : : {
687 [ - - ]: 0 : Trace("sep-process-debug") << "Active lbl : " << slbl << std::endl;
688 : 0 : active_lbl[slbl] = true;
689 : : }
690 : 0 : }
691 : : }
692 : 0 : }
693 : : }
694 : :
695 : : // process spatial assertions
696 [ + + ]: 2759 : for (const Node& fact : d_spatial_assertions)
697 : : {
698 : 1860 : bool polarity = fact.getKind() != Kind::NOT;
699 [ + + ]: 1860 : TNode atom = polarity ? fact : fact[0];
700 : 1860 : TNode satom = atom[0];
701 : :
702 : : bool use_polarity =
703 [ + + ]: 1860 : satom.getKind() == Kind::SEP_WAND ? !polarity : polarity;
704 [ + - ]: 3720 : Trace("sep-process-debug") << " check atom : " << satom << " use polarity "
705 : 1860 : << use_polarity << std::endl;
706 [ + + ]: 1860 : if (use_polarity)
707 : : {
708 : 1242 : continue;
709 : : }
710 [ - + ][ - + ]: 618 : Assert(assert_active.find(fact) != assert_active.end());
[ - - ]
711 [ + + ]: 618 : if (!assert_active[fact])
712 : : {
713 [ + - ]: 496 : Trace("sep-process-debug")
714 : 248 : << "--> inactive negated assertion " << satom << std::endl;
715 : 248 : continue;
716 : : }
717 [ - + ][ - + ]: 370 : Assert(atom.getKind() == Kind::SEP_LABEL);
[ - - ]
718 : 370 : TNode slbl = atom[1];
719 [ + - ]: 740 : Trace("sep-process") << "--> Active negated atom : " << satom
720 : 370 : << ", lbl = " << slbl << std::endl;
721 : : // add refinement lemma
722 [ + + ]: 370 : if (!ContainsKey(d_label_map[satom], slbl))
723 : : {
724 [ + - ]: 269 : Trace("sep-process-debug") << " no children." << std::endl;
725 [ + + ][ + - ]: 269 : Assert(satom.getKind() == Kind::SEP_PTO
[ - + ][ - + ]
[ - - ]
726 : : || satom.getKind() == Kind::SEP_EMP);
727 : 269 : continue;
728 : : }
729 : 101 : needAddLemma = true;
730 [ - + ][ - + ]: 101 : Assert(!d_type_ref.isNull());
[ - - ]
731 : 101 : TypeNode tn = nm->mkSetType(d_type_ref);
732 : : // tn = nm->mkSetType(nm->mkRefType(tn));
733 : 202 : Node o_b_lbl_mval = d_label_model[slbl].getValue(nodeManager(), tn);
734 [ + - ]: 202 : Trace("sep-process") << " Model for " << slbl << " : " << o_b_lbl_mval
735 : 101 : << std::endl;
736 : :
737 : : // get model values
738 : 101 : std::map<int, Node> mvals;
739 : 101 : for (const std::pair<const int, Node>& sub_element :
740 [ + + ]: 446 : d_label_map[satom][slbl])
741 : : {
742 : 244 : int sub_index = sub_element.first;
743 : 244 : Node sub_lbl = sub_element.second;
744 : 244 : computeLabelModel(sub_lbl);
745 : 244 : Node lbl_mval = d_label_model[sub_lbl].getValue(nodeManager(), tn);
746 [ + - ]: 488 : Trace("sep-process-debug") << " child " << sub_index << " : " << sub_lbl
747 : 244 : << ", mval = " << lbl_mval << std::endl;
748 : 244 : mvals[sub_index] = lbl_mval;
749 : 244 : }
750 : :
751 : : // Now, assert model-instantiated implication based on the negation
752 [ - + ][ - + ]: 101 : Assert(d_label_model.find(slbl) != d_label_model.end());
[ - - ]
753 : 101 : std::vector<Node> conc;
754 : 101 : bool inst_success = true;
755 : : // new refinement
756 : : // instantiate the label
757 : 101 : std::map<Node, Node> visited;
758 : : Node inst = instantiateLabel(
759 : 202 : satom, slbl, slbl, o_b_lbl_mval, visited, d_pto_model, tn, active_lbl);
760 [ + - ]: 101 : Trace("sep-inst-debug") << " applied inst : " << inst << std::endl;
761 [ - + ]: 101 : if (inst.isNull())
762 : : {
763 : 0 : inst_success = false;
764 : : }
765 : : else
766 : : {
767 : 101 : inst = rewrite(inst);
768 [ + + ][ - + ]: 101 : if (inst == (polarity ? d_true : d_false))
769 : : {
770 : 0 : inst_success = false;
771 : : }
772 [ + + ]: 101 : conc.push_back(polarity ? inst : inst.negate());
773 : : }
774 [ - + ]: 101 : if (!inst_success)
775 : : {
776 : 0 : continue;
777 : : }
778 : 101 : std::vector<Node> lemc;
779 : 101 : Node pol_atom = atom;
780 [ + + ]: 101 : if (polarity)
781 : : {
782 : 14 : pol_atom = atom.negate();
783 : : }
784 : 101 : lemc.push_back(pol_atom);
785 : 101 : lemc.insert(lemc.end(), conc.begin(), conc.end());
786 : 101 : Node lem = nm->mkNode(Kind::OR, lemc);
787 : 101 : std::vector<Node>& rlems = d_refinement_lem[satom][slbl];
788 [ + + ]: 101 : if (std::find(rlems.begin(), rlems.end(), lem) == rlems.end())
789 : : {
790 : 99 : rlems.push_back(lem);
791 [ + - ]: 198 : Trace("sep-process") << "-----> refinement lemma (#" << rlems.size()
792 : 99 : << ") : " << lem << std::endl;
793 [ + - ]: 198 : Trace("sep-lemma") << "Sep::Lemma : negated star/wand refinement : "
794 : 99 : << lem << std::endl;
795 : 99 : d_im.lemma(lem, InferenceId::SEP_REFINEMENT);
796 : 99 : addedLemma = true;
797 : : }
798 : : else
799 : : {
800 : : // this typically should not happen, should never happen for complete
801 : : // base theories
802 [ + - ]: 4 : Trace("sep-process") << "*** repeated refinement lemma : " << lem
803 : 2 : << std::endl;
804 [ + - ]: 4 : Trace("sep-warn") << "TheorySep : WARNING : repeated refinement lemma : "
805 : 2 : << lem << "!!!" << std::endl;
806 : : }
807 [ + - ][ + - ]: 3888 : }
[ + - ][ + - ]
[ + - ][ + - ]
[ + + ][ + + ]
[ + + ]
808 [ + - ]: 1798 : Trace("sep-process") << "...finished check of negated assertions, addedLemma="
809 : 0 : << addedLemma << ", needAddLemma=" << needAddLemma
810 : 899 : << std::endl;
811 : :
812 [ + + ]: 899 : if (addedLemma)
813 : : {
814 : 90 : return;
815 : : }
816 : : // must witness finite data points-to
817 : : // if the data type is finite
818 [ - + ]: 809 : if (d_env.isFiniteType(d_type_data))
819 : : {
820 : 0 : computeLabelModel(d_base_label);
821 [ - - ]: 0 : Trace("sep-process-debug") << "Check heap data for " << d_type_data
822 : 0 : << " -> " << d_type_data << std::endl;
823 : 0 : std::vector<Node>& hlmodel = d_label_model[d_base_label].d_heap_locs_model;
824 [ - - ]: 0 : for (size_t j = 0, hsize = hlmodel.size(); j < hsize; j++)
825 : : {
826 : 0 : Assert(hlmodel[j].getKind() == Kind::SET_SINGLETON);
827 : 0 : Node l = hlmodel[j][0];
828 [ - - ]: 0 : Trace("sep-process-debug") << " location : " << l << std::endl;
829 [ - - ]: 0 : if (!d_pto_model[l].isNull())
830 : : {
831 [ - - ]: 0 : Trace("sep-process-debug")
832 : 0 : << " points-to data witness : " << d_pto_model[l] << std::endl;
833 : 0 : continue;
834 : : }
835 : 0 : needAddLemma = true;
836 : 0 : Node ll;
837 : 0 : std::map<Node, Node>::iterator itm = d_tmodel.find(l);
838 [ - - ]: 0 : if (itm != d_tmodel.end())
839 : : {
840 : 0 : ll = itm->second;
841 : : }
842 : : // otherwise, could try to assign arbitrary skolem?
843 [ - - ]: 0 : if (!ll.isNull())
844 : : {
845 [ - - ]: 0 : Trace("sep-process") << "Must witness label : " << ll
846 : 0 : << ", data type is " << d_type_data << std::endl;
847 : 0 : Node dsk = NodeManager::mkDummySkolem("dsk", d_type_data);
848 : : // if location is in the heap, then something must point to it
849 : 0 : Node lem = nm->mkNode(
850 : : Kind::IMPLIES,
851 : 0 : {nm->mkNode(Kind::SET_MEMBER, ll, d_base_label),
852 : 0 : nm->mkNode(
853 : 0 : Kind::SEP_STAR, nm->mkNode(Kind::SEP_PTO, ll, dsk), d_true)});
854 [ - - ]: 0 : Trace("sep-lemma") << "Sep::Lemma : witness finite data-pto : " << lem
855 : 0 : << std::endl;
856 : 0 : d_im.lemma(lem, InferenceId::SEP_WITNESS_FINITE_DATA);
857 : 0 : addedLemma = true;
858 : 0 : }
859 : : else
860 : : {
861 : : // This should only happen if we are in an unbounded fragment
862 [ - - ]: 0 : Trace("sep-warn")
863 : 0 : << "TheorySep : WARNING : no term corresponding to location " << l
864 : 0 : << " in heap!!!" << std::endl;
865 : : }
866 [ - - ]: 0 : }
867 : : }
868 : :
869 [ - + ]: 809 : if (addedLemma)
870 : : {
871 : 0 : return;
872 : : }
873 : :
874 [ - + ]: 809 : if (needAddLemma)
875 : : {
876 : 0 : d_im.setModelUnsound(IncompleteId::SEP);
877 : : }
878 [ + - ]: 1618 : Trace("sep-check") << "Sep::check(): " << level
879 : 809 : << " done, conflict=" << d_state.isInConflict()
880 : 809 : << std::endl;
881 [ + + ][ + + ]: 1169 : }
[ + + ][ + + ]
882 : :
883 : 25192 : bool TheorySep::needsCheckLastEffort()
884 : : {
885 : : // We always need a last call effort check when the logic enables separation
886 : : // logic to ensure the heap model is built.
887 : 25192 : return d_env.hasSepHeap();
888 : : }
889 : :
890 : 0 : void TheorySep::conflict(TNode a, TNode b)
891 : : {
892 [ - - ]: 0 : Trace("sep-conflict") << "Sep::conflict : " << a << " " << b << std::endl;
893 : 0 : d_im.conflictEqConstantMerge(a, b);
894 : 0 : }
895 : :
896 : 1498 : TheorySep::HeapAssertInfo::HeapAssertInfo(context::Context* c)
897 : 1498 : : d_posPto(c), d_negPto(c)
898 : : {
899 : 1498 : }
900 : :
901 : 38336 : TheorySep::HeapAssertInfo* TheorySep::getOrMakeEqcInfo(Node n, bool doMake)
902 : : {
903 : 38336 : std::map<Node, HeapAssertInfo*>::iterator e_i = d_eqc_info.find(n);
904 [ + + ]: 38336 : if (e_i == d_eqc_info.end())
905 : : {
906 [ + + ]: 25210 : if (doMake)
907 : : {
908 : 1498 : HeapAssertInfo* ei = new HeapAssertInfo(context());
909 : 1498 : d_eqc_info[n] = ei;
910 : 1498 : return ei;
911 : : }
912 : : else
913 : : {
914 : 23712 : return nullptr;
915 : : }
916 : : }
917 : : else
918 : : {
919 : 13126 : return (*e_i).second;
920 : : }
921 : : }
922 : :
923 : : // Must process assertions at preprocess so that quantified assertions are
924 : : // processed properly.
925 : 65500 : void TheorySep::ppNotifyAssertions(const std::vector<Node>& assertions)
926 : : {
927 [ + + ]: 65500 : if (!d_env.hasSepHeap())
928 : : {
929 : 64609 : return;
930 : : }
931 : 891 : std::map<int, std::map<Node, size_t> > visited;
932 : 891 : std::map<int, std::map<Node, std::vector<Node> > > references;
933 : 891 : std::map<int, std::map<Node, bool> > references_strict;
934 [ + + ]: 4532 : for (unsigned i = 0; i < assertions.size(); i++)
935 : : {
936 [ + - ]: 3641 : Trace("sep-pp") << "Process assertion : " << assertions[i] << std::endl;
937 : 3641 : processAssertion(assertions[i],
938 : : visited,
939 : : references,
940 : : references_strict,
941 : : true,
942 : : true,
943 : : false);
944 : : }
945 : 891 : }
946 : :
947 : : // return cardinality
948 : 6860 : size_t TheorySep::processAssertion(
949 : : Node n,
950 : : std::map<int, std::map<Node, size_t> >& visited,
951 : : std::map<int, std::map<Node, std::vector<Node> > >& references,
952 : : std::map<int, std::map<Node, bool> >& references_strict,
953 : : bool pol,
954 : : bool hasPol,
955 : : bool underSpatial)
956 : : {
957 [ + + ][ + + ]: 6860 : int index = hasPol ? (pol ? 1 : -1) : 0;
958 : 6860 : size_t card = 0;
959 : 6860 : std::map<Node, size_t>::iterator it = visited[index].find(n);
960 [ + + ]: 6860 : if (it == visited[index].end())
961 : : {
962 [ + - ]: 11366 : Trace("sep-pp-debug") << "process assertion : " << n
963 : 5683 : << ", index = " << index << std::endl;
964 [ + + ]: 5683 : if (n.getKind() == Kind::SEP_EMP)
965 : : {
966 : 63 : ensureHeapTypesFor(n);
967 [ + + ][ + + ]: 63 : if (hasPol && pol)
968 : : {
969 : 23 : references[index][n].clear();
970 : 23 : references_strict[index][n] = true;
971 : : }
972 : : else
973 : : {
974 : 40 : card = 1;
975 : : }
976 : : }
977 [ + + ]: 5620 : else if (n.getKind() == Kind::SEP_PTO)
978 : : {
979 : 1340 : ensureHeapTypesFor(n);
980 [ + + ]: 1340 : if (expr::hasBoundVar(n[0]))
981 : : {
982 [ - + ][ - + ]: 7 : Assert(n[0].getType() == d_type_ref);
[ - - ]
983 [ + - ][ + + ]: 7 : if (d_bound_kind != bound_strict && d_bound_kind != bound_invalid)
984 : : {
985 : 4 : d_bound_kind = bound_invalid;
986 [ + - ]: 8 : Trace("sep-bound")
987 : 0 : << "reference cannot be bound (due to quantified pto)."
988 : 4 : << std::endl;
989 : : }
990 : : }
991 : : else
992 : : {
993 : 1333 : references[index][n].push_back(n[0]);
994 : : }
995 [ + + ][ + + ]: 1340 : if (hasPol && pol)
996 : : {
997 : 1165 : references_strict[index][n] = true;
998 : : }
999 : : else
1000 : : {
1001 : 175 : card = 1;
1002 : : }
1003 : : }
1004 : : else
1005 : : {
1006 : : bool isSpatial =
1007 [ + + ][ + + ]: 4280 : n.getKind() == Kind::SEP_WAND || n.getKind() == Kind::SEP_STAR;
1008 [ + + ][ + + ]: 4280 : bool newUnderSpatial = underSpatial || isSpatial;
1009 : 4280 : bool refStrict = isSpatial;
1010 [ + + ]: 7499 : for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++)
1011 : : {
1012 : : bool newHasPol, newPol;
1013 : 3219 : QuantPhaseReq::getEntailPolarity(n, i, hasPol, pol, newHasPol, newPol);
1014 [ + + ][ + + ]: 3219 : int newIndex = newHasPol ? (newPol ? 1 : -1) : 0;
1015 : 3219 : size_t ccard = processAssertion(n[i],
1016 : : visited,
1017 : : references,
1018 : : references_strict,
1019 : : newPol,
1020 : : newHasPol,
1021 : : newUnderSpatial);
1022 : : // update cardinality
1023 [ + + ]: 3219 : if (n.getKind() == Kind::SEP_STAR)
1024 : : {
1025 : 525 : card += ccard;
1026 : : }
1027 [ + + ]: 2694 : else if (n.getKind() == Kind::SEP_WAND)
1028 : : {
1029 [ + + ]: 58 : if (i == 1)
1030 : : {
1031 : 29 : card = ccard;
1032 : : }
1033 : : }
1034 [ + + ]: 2636 : else if (ccard > card)
1035 : : {
1036 : 270 : card = ccard;
1037 : : }
1038 : : // track references if we are or below a spatial operator
1039 [ + + ]: 3219 : if (newUnderSpatial)
1040 : : {
1041 : 728 : bool add = true;
1042 : 1456 : if (references_strict[newIndex].find(n[i])
1043 [ + + ]: 2184 : != references_strict[newIndex].end())
1044 : : {
1045 [ - + ]: 265 : if (!isSpatial)
1046 : : {
1047 : 0 : if (references_strict[index].find(n)
1048 [ - - ]: 0 : == references_strict[index].end())
1049 : : {
1050 : 0 : references_strict[index][n] = true;
1051 : : }
1052 : : else
1053 : : {
1054 : 0 : add = false;
1055 : : // TODO: can derive static equality between sets
1056 : : }
1057 : : }
1058 : : }
1059 : : else
1060 : : {
1061 [ + + ]: 463 : if (isSpatial)
1062 : : {
1063 : 318 : refStrict = false;
1064 : : }
1065 : : }
1066 [ + - ]: 728 : if (add)
1067 : : {
1068 [ + + ]: 1389 : for (unsigned j = 0; j < references[newIndex][n[i]].size(); j++)
1069 : : {
1070 : 661 : if (std::find(references[index][n].begin(),
1071 : 661 : references[index][n].end(),
1072 : 1322 : references[newIndex][n[i]][j])
1073 [ + + ]: 1983 : == references[index][n].end())
1074 : : {
1075 : 593 : references[index][n].push_back(references[newIndex][n[i]][j]);
1076 : : }
1077 : : }
1078 : : }
1079 : : }
1080 : : }
1081 [ + + ][ + + ]: 4280 : if (isSpatial && refStrict)
1082 : : {
1083 [ + - ]: 89 : if (n.getKind() == Kind::SEP_WAND)
1084 : : {
1085 : : // TODO
1086 : : }
1087 : : else
1088 : : {
1089 [ + - ][ + - ]: 89 : Assert(n.getKind() == Kind::SEP_STAR && hasPol && pol);
[ + - ][ + - ]
[ - + ][ - + ]
[ - - ]
1090 : 89 : references_strict[index][n] = true;
1091 : : }
1092 : : }
1093 : : }
1094 : 5683 : visited[index][n] = card;
1095 : : }
1096 : : else
1097 : : {
1098 : 1177 : card = it->second;
1099 : : }
1100 : :
1101 [ + + ][ + + ]: 6860 : if (!underSpatial && (!references[index][n].empty() || card > 0))
[ + + ][ + + ]
1102 : : {
1103 [ - + ][ - + ]: 1318 : Assert(!d_type_ref.isNull());
[ - - ]
1104 : : // add references to overall type
1105 : 1318 : unsigned bt = d_bound_kind;
1106 : 1318 : bool add = true;
1107 [ + + ]: 1318 : if (references_strict[index].find(n) != references_strict[index].end())
1108 : : {
1109 [ + - ]: 1992 : Trace("sep-bound") << "Strict bound found based on " << n
1110 : 996 : << ", index = " << index << std::endl;
1111 [ + + ]: 996 : if (bt != bound_strict)
1112 : : {
1113 : 845 : d_bound_kind = bound_strict;
1114 : 845 : d_card_max = card;
1115 : : }
1116 : : else
1117 : : {
1118 : : // TODO: derive static equality
1119 : 151 : add = false;
1120 : : }
1121 : : }
1122 : : else
1123 : : {
1124 : 322 : add = bt != bound_strict;
1125 : : }
1126 [ + + ]: 2673 : for (const Node& r : references[index][n])
1127 : : {
1128 : 1355 : if (std::find(d_type_references.begin(), d_type_references.end(), r)
1129 [ + + ]: 2710 : == d_type_references.end())
1130 : : {
1131 : 1089 : d_type_references.push_back(r);
1132 : : }
1133 : : }
1134 [ + + ]: 1318 : if (add)
1135 : : {
1136 : : // add max cardinality
1137 [ + + ]: 1113 : if (card > d_card_max)
1138 : : {
1139 : 98 : d_card_max = card;
1140 : : }
1141 : : }
1142 : : }
1143 : 6860 : return card;
1144 : : }
1145 : :
1146 : 2618 : void TheorySep::ensureHeapTypesFor(Node atom) const
1147 : : {
1148 [ - + ][ - + ]: 2618 : Assert(!atom.isNull());
[ - - ]
1149 [ + + ][ + - ]: 2618 : if (!d_type_ref.isNull() && !d_type_data.isNull())
[ + + ]
1150 : : {
1151 [ + + ]: 2617 : if (atom.getKind() == Kind::SEP_PTO)
1152 : : {
1153 : 2284 : TypeNode tn1 = atom[0].getType();
1154 : 2284 : TypeNode tn2 = atom[1].getType();
1155 : : // already declared, ensure compatible
1156 [ + - ]: 4568 : if ((!tn1.isNull() && tn1 != d_type_ref)
1157 [ + - ][ + - ]: 4568 : || (!tn2.isNull() && tn2 != d_type_data))
[ - + ][ - + ]
1158 : : {
1159 : 0 : std::stringstream ss;
1160 : 0 : ss << "ERROR: the separation logic heap type has already been set to "
1161 : 0 : << d_type_ref << " -> " << d_type_data
1162 : : << " but we have a constraint that uses different heap types, "
1163 : 0 : "offending atom is "
1164 : 0 : << atom << " with associated heap type " << tn1 << " -> " << tn2
1165 : 0 : << std::endl;
1166 : 0 : }
1167 : 2284 : }
1168 : : }
1169 : : else
1170 : : {
1171 : : // if not declared yet, and we have a separation logic constraint, throw
1172 : : // an error.
1173 : 1 : std::stringstream ss;
1174 : : // error, heap not declared
1175 : : ss << "ERROR: the type of the separation logic heap has not been declared "
1176 : : "(e.g. via a declare-heap command), and we have a separation logic "
1177 : 1 : "constraint "
1178 : 1 : << atom << std::endl;
1179 : 1 : throw LogicException(ss.str());
1180 : 1 : }
1181 : 2617 : }
1182 : :
1183 : 886 : void TheorySep::initializeBounds()
1184 : : {
1185 [ - + ]: 886 : if (d_bounds_init)
1186 : : {
1187 : 0 : return;
1188 : : }
1189 [ + - ]: 886 : Trace("sep-bound") << "Initialize sep bounds..." << std::endl;
1190 : 886 : d_bounds_init = true;
1191 [ - + ]: 886 : if (d_type_ref.isNull())
1192 : : {
1193 : 0 : return;
1194 : : }
1195 [ + - ]: 1772 : Trace("sep-bound") << "Initialize bounds for " << d_type_ref << "..."
1196 : 886 : << std::endl;
1197 : 886 : size_t n_emp = 0;
1198 [ + + ]: 886 : if (d_bound_kind != bound_invalid)
1199 : : {
1200 : 882 : n_emp = d_card_max;
1201 : : }
1202 [ + - ]: 4 : else if (d_type_references.empty())
1203 : : {
1204 : : // must include at least one constant TODO: remove?
1205 : 4 : n_emp = 1;
1206 : : }
1207 [ + - ]: 1772 : Trace("sep-bound") << "Cardinality element size : " << d_card_max
1208 : 886 : << std::endl;
1209 [ + - ]: 1772 : Trace("sep-bound") << "Type reference size : " << d_type_references.size()
1210 : 886 : << std::endl;
1211 [ + - ]: 1772 : Trace("sep-bound") << "Constructing " << n_emp << " cardinality constants."
1212 : 886 : << std::endl;
1213 [ + + ]: 930 : for (size_t r = 0; r < n_emp; r++)
1214 : : {
1215 : 88 : Node e = NodeManager::mkDummySkolem("e", d_type_ref);
1216 : 44 : d_type_references_card.push_back(e);
1217 : 44 : d_type_ref_card_id[e] = r;
1218 : 44 : }
1219 : : }
1220 : :
1221 : 1582 : Node TheorySep::getBaseLabel()
1222 : : {
1223 [ + + ]: 1582 : if (!d_base_label.isNull())
1224 : : {
1225 : 696 : return d_base_label;
1226 : : }
1227 : 886 : NodeManager* nm = nodeManager();
1228 : 886 : initializeBounds();
1229 [ + - ]: 886 : Trace("sep") << "Make base label for " << d_type_ref << std::endl;
1230 : 886 : std::stringstream ss;
1231 : 886 : ss << "__Lb";
1232 : 886 : TypeNode ltn = nm->mkSetType(d_type_ref);
1233 : 886 : Node n_lbl = NodeManager::mkDummySkolem(ss.str(), ltn);
1234 : 886 : d_base_label = n_lbl;
1235 : : // make reference bound
1236 [ + - ]: 886 : Trace("sep") << "Make reference bound label for " << d_type_ref << std::endl;
1237 : 886 : std::stringstream ss2;
1238 : 886 : ss2 << "__Lu";
1239 : 886 : d_reference_bound = NodeManager::mkDummySkolem(ss2.str(), ltn);
1240 : :
1241 : : // check whether monotonic (elements can be added to tn without effecting
1242 : : // satisfiability)
1243 : 886 : bool tn_is_monotonic = true;
1244 [ + + ]: 886 : if (d_type_ref.isUninterpretedSort())
1245 : : {
1246 : : // TODO: use monotonicity inference
1247 : 42 : tn_is_monotonic = !logicInfo().isQuantified();
1248 : : }
1249 : : else
1250 : : {
1251 : 844 : tn_is_monotonic = !d_env.isFiniteType(d_type_ref);
1252 : : }
1253 : : // add a reference type for maximum occurrences of empty in a constraint
1254 [ + + ]: 886 : if (tn_is_monotonic)
1255 : : {
1256 [ + + ]: 884 : for (const Node& e : d_type_references_card)
1257 : : {
1258 : : // ensure that it is distinct from all other references so far
1259 [ + + ]: 100 : for (const Node& r : d_type_references)
1260 : : {
1261 : 120 : Node eq = nm->mkNode(Kind::EQUAL, e, r);
1262 : 60 : d_im.lemma(eq.negate(), InferenceId::SEP_DISTINCT_REF);
1263 : 60 : }
1264 : 40 : d_type_references.push_back(e);
1265 : : }
1266 : : }
1267 : : else
1268 : : {
1269 : 42 : d_type_references.insert(d_type_references.end(),
1270 : : d_type_references_card.begin(),
1271 : : d_type_references_card.end());
1272 : : }
1273 : :
1274 [ + + ]: 886 : if (d_bound_kind != bound_invalid)
1275 : : {
1276 : : // construct bound
1277 : 882 : d_reference_bound_max = mkUnion(d_type_ref, d_type_references);
1278 [ + - ]: 1764 : Trace("sep-bound") << "overall bound for " << d_base_label << " : "
1279 : 882 : << d_reference_bound_max << std::endl;
1280 : :
1281 : : Node slem =
1282 : 1764 : nm->mkNode(Kind::SET_SUBSET, d_base_label, d_reference_bound_max);
1283 [ + - ]: 1764 : Trace("sep-lemma") << "Sep::Lemma: reference bound for " << d_type_ref
1284 : 882 : << " : " << slem << std::endl;
1285 : 882 : d_im.lemma(slem, InferenceId::SEP_REF_BOUND);
1286 : :
1287 : : // symmetry breaking
1288 : 882 : size_t trcSize = d_type_references_card.size();
1289 [ + + ]: 882 : if (trcSize > 1)
1290 : : {
1291 : 9 : std::map<size_t, Node> lit_mem_map;
1292 [ + + ]: 27 : for (size_t i = 0; i < trcSize; i++)
1293 : : {
1294 : 36 : lit_mem_map[i] = nm->mkNode(
1295 : 36 : Kind::SET_MEMBER, d_type_references_card[i], d_reference_bound_max);
1296 : : }
1297 [ + + ]: 18 : for (size_t i = 0; i < (trcSize - 1); i++)
1298 : : {
1299 : 9 : std::vector<Node> children;
1300 [ + + ]: 18 : for (size_t j = (i + 1); j < trcSize; j++)
1301 : : {
1302 : 9 : children.push_back(lit_mem_map[j].negate());
1303 : : }
1304 [ + - ]: 9 : if (!children.empty())
1305 : : {
1306 : 9 : Node sym_lem = nm->mkAnd(children);
1307 : 9 : sym_lem = nm->mkNode(Kind::IMPLIES, lit_mem_map[i].negate(), sym_lem);
1308 [ + - ]: 18 : Trace("sep-lemma")
1309 : 0 : << "Sep::Lemma: symmetry breaking lemma : " << sym_lem
1310 : 9 : << std::endl;
1311 : 9 : d_im.lemma(sym_lem, InferenceId::SEP_SYM_BREAK);
1312 : 9 : }
1313 : 9 : }
1314 : 9 : }
1315 : 882 : }
1316 : :
1317 : : // assert that nil ref is not in base label
1318 [ - + ][ - + ]: 886 : Assert(!d_nil_ref.isNull());
[ - - ]
1319 : 1772 : Node nrlem = nm->mkNode(Kind::SET_MEMBER, d_nil_ref, n_lbl).negate();
1320 [ + - ]: 1772 : Trace("sep-lemma") << "Sep::Lemma: sep.nil not in base label " << d_type_ref
1321 : 886 : << " : " << nrlem << std::endl;
1322 : 886 : d_im.lemma(nrlem, InferenceId::SEP_NIL_NOT_IN_HEAP);
1323 : :
1324 : 886 : return n_lbl;
1325 : 886 : }
1326 : :
1327 : 882 : Node TheorySep::mkUnion(TypeNode tn, std::vector<Node>& locs)
1328 : : {
1329 : 882 : Node u;
1330 [ + + ]: 882 : if (locs.empty())
1331 : : {
1332 : 2 : TypeNode ltn = nodeManager()->mkSetType(tn);
1333 : 4 : return nodeManager()->mkConst(EmptySet(ltn));
1334 : 2 : }
1335 : : else
1336 : : {
1337 [ + + ]: 2004 : for (unsigned i = 0; i < locs.size(); i++)
1338 : : {
1339 : 1124 : Node s = locs[i];
1340 [ - + ][ - + ]: 1124 : Assert(!s.isNull());
[ - - ]
1341 : 1124 : s = nodeManager()->mkNode(Kind::SET_SINGLETON, s);
1342 [ + + ]: 1124 : if (u.isNull())
1343 : : {
1344 : 880 : u = s;
1345 : : }
1346 : : else
1347 : : {
1348 : 244 : u = nodeManager()->mkNode(Kind::SET_UNION, s, u);
1349 : : }
1350 : 1124 : }
1351 : 880 : return u;
1352 : : }
1353 : 882 : }
1354 : :
1355 : 725 : Node TheorySep::getLabel(Node atom, int child, Node lbl)
1356 : : {
1357 : 725 : std::map<int, Node>::iterator it = d_label_map[atom][lbl].find(child);
1358 [ + + ]: 725 : if (it == d_label_map[atom][lbl].end())
1359 : : {
1360 [ - + ][ - + ]: 643 : Assert(!d_type_ref.isNull());
[ - - ]
1361 : 643 : std::stringstream ss;
1362 : 643 : ss << "__Lc" << child;
1363 : 643 : TypeNode ltn = nodeManager()->mkSetType(d_type_ref);
1364 : 643 : Node n_lbl = NodeManager::mkDummySkolem(ss.str(), ltn);
1365 : 643 : d_label_map[atom][lbl][child] = n_lbl;
1366 : 643 : return n_lbl;
1367 : 643 : }
1368 : : else
1369 : : {
1370 : 82 : return (*it).second;
1371 : : }
1372 : : }
1373 : :
1374 : 276 : void TheorySep::makeDisjointHeap(Node parent, const std::vector<Node>& children)
1375 : : {
1376 [ + - ]: 552 : Trace("sep-debug") << "disjoint heap: " << parent << " for " << children
1377 : 276 : << std::endl;
1378 [ - + ][ - + ]: 276 : Assert(children.size() >= 2);
[ - - ]
1379 [ + + ]: 276 : if (!sharesRootLabel(parent, d_base_label))
1380 : : {
1381 [ - + ][ - + ]: 56 : Assert(d_childrenMap.find(parent) == d_childrenMap.end());
[ - - ]
1382 : 56 : d_childrenMap[parent] = children;
1383 : : }
1384 : : // remember parent relationships
1385 [ + + ]: 919 : for (const Node& c : children)
1386 : : {
1387 [ - + ][ - + ]: 1929 : AssertEqual(c.getType(), parent.getType());
[ - - ]
1388 : 643 : d_parentMap[c].push_back(parent);
1389 : : }
1390 : : // make the disjointness constraints
1391 : 276 : NodeManager* nm = nodeManager();
1392 : 276 : std::vector<Node> lems;
1393 : 552 : Node ulem = nm->mkNode(Kind::SET_UNION, children[0], children[1]);
1394 : 276 : size_t lsize = children.size();
1395 [ + + ]: 367 : for (size_t i = 2; i < lsize; i++)
1396 : : {
1397 : 91 : ulem = nm->mkNode(Kind::SET_UNION, ulem, children[i]);
1398 : : }
1399 : 276 : ulem = parent.eqNode(ulem);
1400 : 276 : lems.push_back(ulem);
1401 : 552 : Node empSet = nm->mkConst(EmptySet(parent.getType()));
1402 [ + + ]: 919 : for (size_t i = 0; i < lsize; i++)
1403 : : {
1404 [ + + ]: 1167 : for (size_t j = (i + 1); j < lsize; j++)
1405 : : {
1406 : 1048 : Node s = nm->mkNode(Kind::SET_INTER, children[i], children[j]);
1407 : 524 : Node ilem = s.eqNode(empSet);
1408 : 524 : lems.push_back(ilem);
1409 : 524 : }
1410 : : }
1411 : : // send out definitional lemmas for introduced sets
1412 [ + + ]: 1076 : for (const Node& clem : lems)
1413 : : {
1414 : 800 : d_im.lemma(clem, InferenceId::SEP_LABEL_DEF);
1415 : : }
1416 : 276 : }
1417 : :
1418 : 12316 : std::vector<Node> TheorySep::getRootLabels(Node p) const
1419 : : {
1420 : 12316 : std::vector<Node> roots;
1421 : 12316 : std::unordered_set<Node> visited;
1422 : 12316 : std::unordered_set<Node>::iterator it;
1423 : 12316 : std::vector<Node> visit;
1424 : 12316 : std::map<Node, std::vector<Node> >::const_iterator itp;
1425 : 12316 : Node cur;
1426 : 12316 : visit.push_back(p);
1427 : : do
1428 : : {
1429 : 27016 : cur = visit.back();
1430 : 27016 : visit.pop_back();
1431 : 27016 : it = visited.find(cur);
1432 [ + - ]: 27016 : if (it == visited.end())
1433 : : {
1434 : 27016 : visited.insert(cur);
1435 : 27016 : itp = d_parentMap.find(cur);
1436 [ + + ]: 27016 : if (itp == d_parentMap.end())
1437 : : {
1438 : 12339 : roots.push_back(cur);
1439 : : }
1440 : : else
1441 : : {
1442 : 14677 : visit.insert(visit.end(), itp->second.begin(), itp->second.end());
1443 : : }
1444 : : }
1445 [ + + ]: 27016 : } while (!visit.empty());
1446 : 24632 : return roots;
1447 : 12316 : }
1448 : :
1449 : 8685 : bool TheorySep::sharesRootLabel(Node p, Node q) const
1450 : : {
1451 [ + + ]: 8685 : if (p == q)
1452 : : {
1453 : 2527 : return true;
1454 : : }
1455 : 6158 : std::vector<Node> rp = getRootLabels(p);
1456 : 6158 : std::vector<Node> rq = getRootLabels(q);
1457 [ + + ]: 7874 : for (const Node& r : rp)
1458 : : {
1459 [ + + ]: 6172 : if (std::find(rq.begin(), rq.end(), r) != rq.end())
1460 : : {
1461 : 4456 : return true;
1462 : : }
1463 : : }
1464 : 1702 : return false;
1465 : 6158 : }
1466 : :
1467 : 797 : Node TheorySep::applyLabel(Node n, Node lbl, std::map<Node, Node>& visited)
1468 : : {
1469 [ - + ][ - + ]: 797 : Assert(n.getKind() != Kind::SEP_LABEL);
[ - - ]
1470 : 797 : NodeManager* nm = nodeManager();
1471 : 797 : Kind k = n.getKind();
1472 : 797 : std::map<Node, Node>::iterator it = visited.find(n);
1473 [ - + ]: 797 : if (it != visited.end())
1474 : : {
1475 : 0 : return it->second;
1476 : : }
1477 : 797 : Node ret;
1478 [ + + ][ + + ]: 797 : if (k == Kind::SEP_STAR || k == Kind::SEP_WAND || k == Kind::SEP_PTO)
[ + + ]
1479 : : {
1480 : 575 : ret = nm->mkNode(Kind::SEP_LABEL, n, lbl);
1481 : : }
1482 [ + + ]: 222 : else if (k == Kind::SEP_EMP)
1483 : : {
1484 : : // (SEP_LABEL sep.emp L) is the same as (= L set.empty)
1485 : 42 : ret = lbl.eqNode(nm->mkConst(EmptySet(lbl.getType())));
1486 : : }
1487 [ + + ][ + + ]: 180 : else if (n.getType().isBoolean() && n.getNumChildren() > 0)
[ + - ][ + + ]
[ - - ]
1488 : : {
1489 : 136 : ret = n;
1490 : 136 : std::vector<Node> children;
1491 [ - + ]: 136 : if (n.getMetaKind() == metakind::PARAMETERIZED)
1492 : : {
1493 : 0 : children.push_back(n.getOperator());
1494 : : }
1495 : 136 : bool childChanged = false;
1496 [ + + ]: 290 : for (const Node& nc : n)
1497 : : {
1498 : 308 : Node aln = applyLabel(nc, lbl, visited);
1499 : 154 : children.push_back(aln);
1500 [ + + ][ + + ]: 154 : childChanged = childChanged || aln != nc;
1501 : 154 : }
1502 [ + + ]: 136 : if (childChanged)
1503 : : {
1504 : 134 : ret = nm->mkNode(n.getKind(), children);
1505 : : }
1506 : 136 : }
1507 : : else
1508 : : {
1509 : 44 : ret = n;
1510 : : }
1511 : 797 : visited[n] = ret;
1512 : 797 : return ret;
1513 : 797 : }
1514 : :
1515 : 452 : Node TheorySep::instantiateLabel(Node n,
1516 : : Node o_lbl,
1517 : : Node lbl,
1518 : : Node lbl_v,
1519 : : std::map<Node, Node>& visited,
1520 : : std::map<Node, Node>& pto_model,
1521 : : TypeNode rtn,
1522 : : std::map<Node, bool>& active_lbl,
1523 : : unsigned ind)
1524 : : {
1525 : 452 : NodeManager* nm = nodeManager();
1526 [ + - ]: 904 : Trace("sep-inst-debug") << "Instantiate label " << n << " " << lbl << " "
1527 : 452 : << lbl_v << std::endl;
1528 [ - - ]: 452 : if (options().sep.sepMinimalRefine && lbl != o_lbl
1529 [ - + ][ - - ]: 452 : && active_lbl.find(lbl) != active_lbl.end())
[ - + ]
1530 : : {
1531 [ - - ]: 0 : Trace("sep-inst") << "...do not instantiate " << o_lbl
1532 : 0 : << " since it has an active sublabel " << lbl
1533 : 0 : << std::endl;
1534 : 0 : return Node::null();
1535 : : }
1536 : : else
1537 : : {
1538 [ - + ]: 452 : if (TraceIsOn("sep-inst"))
1539 : : {
1540 [ - - ]: 0 : if (n.getKind() == Kind::SEP_STAR || n.getKind() == Kind::SEP_WAND
1541 [ - - ][ - - ]: 0 : || n.getKind() == Kind::SEP_PTO || n.getKind() == Kind::SEP_EMP)
[ - - ][ - - ]
1542 : : {
1543 [ - - ]: 0 : for (unsigned j = 0; j < ind; j++)
1544 : : {
1545 [ - - ]: 0 : Trace("sep-inst") << " ";
1546 : : }
1547 [ - - ]: 0 : Trace("sep-inst") << n << "[" << lbl << "] :: " << lbl_v << std::endl;
1548 : : }
1549 : : }
1550 [ - + ][ - + ]: 452 : Assert(n.getKind() != Kind::SEP_LABEL);
[ - - ]
1551 [ + + ][ + + ]: 452 : if (n.getKind() == Kind::SEP_STAR || n.getKind() == Kind::SEP_WAND)
[ + + ]
1552 : : {
1553 [ + + ]: 127 : if (lbl == o_lbl)
1554 : : {
1555 : 101 : std::vector<Node> children;
1556 : 101 : children.resize(n.getNumChildren());
1557 [ - + ][ - + ]: 101 : Assert(d_label_map[n].find(lbl) != d_label_map[n].end());
[ - - ]
1558 : 101 : std::map<int, Node> mvals;
1559 : 101 : for (std::map<int, Node>::iterator itl = d_label_map[n][lbl].begin();
1560 [ + + ]: 345 : itl != d_label_map[n][lbl].end();
1561 : 244 : ++itl)
1562 : : {
1563 : 244 : Node sub_lbl = itl->second;
1564 : 244 : int sub_index = itl->first;
1565 [ + - ][ + - ]: 244 : Assert(sub_index >= 0 && sub_index < (int)children.size());
[ - + ][ - + ]
[ - - ]
1566 [ + - ]: 488 : Trace("sep-inst-debug")
1567 : 244 : << "Sublabel " << sub_index << " is " << sub_lbl << std::endl;
1568 : 244 : Node lbl_mval;
1569 [ + + ][ + + ]: 244 : if (n.getKind() == Kind::SEP_WAND && sub_index == 1)
[ + + ]
1570 : : {
1571 [ - + ][ - + ]: 14 : Assert(d_label_map[n][lbl].find(0) != d_label_map[n][lbl].end());
[ - - ]
1572 : 14 : Node sub_lbl_0 = d_label_map[n][lbl][0];
1573 : 14 : computeLabelModel(sub_lbl_0);
1574 [ - + ][ - + ]: 14 : Assert(d_label_model.find(sub_lbl_0) != d_label_model.end());
[ - - ]
1575 : 14 : lbl_mval = nodeManager()->mkNode(
1576 : : Kind::SET_UNION,
1577 : : lbl,
1578 : 14 : d_label_model[sub_lbl_0].getValue(nodeManager(), rtn));
1579 : 14 : }
1580 : : else
1581 : : {
1582 : 230 : computeLabelModel(sub_lbl);
1583 [ - + ][ - + ]: 230 : Assert(d_label_model.find(sub_lbl) != d_label_model.end());
[ - - ]
1584 : 230 : lbl_mval = d_label_model[sub_lbl].getValue(nodeManager(), rtn);
1585 : : }
1586 [ + - ]: 488 : Trace("sep-inst-debug")
1587 : 244 : << "Sublabel value is " << lbl_mval << std::endl;
1588 : 244 : mvals[sub_index] = lbl_mval;
1589 : 488 : children[sub_index] = instantiateLabel(n[sub_index],
1590 : : o_lbl,
1591 : : sub_lbl,
1592 : : lbl_mval,
1593 : : visited,
1594 : : pto_model,
1595 : : rtn,
1596 : : active_lbl,
1597 : 244 : ind + 1);
1598 [ - + ]: 244 : if (children[sub_index].isNull())
1599 : : {
1600 : 0 : return Node::null();
1601 : : }
1602 [ + - ][ + - ]: 244 : }
1603 : 101 : Node empSet = nodeManager()->mkConst(EmptySet(rtn));
1604 [ + + ]: 101 : if (n.getKind() == Kind::SEP_STAR)
1605 : : {
1606 : : // disjoint contraints
1607 : 87 : std::vector<Node> conj;
1608 : 87 : std::vector<Node> bchildren;
1609 : 87 : bchildren.insert(bchildren.end(), children.begin(), children.end());
1610 : 87 : Node vsu;
1611 : 87 : std::vector<Node> vs;
1612 : 87 : for (std::map<int, Node>::iterator itl = d_label_map[n][lbl].begin();
1613 [ + + ]: 303 : itl != d_label_map[n][lbl].end();
1614 : 216 : ++itl)
1615 : : {
1616 : 216 : Node sub_lbl = itl->second;
1617 : 216 : Node lbl_mval = d_label_model[sub_lbl].getValue(nodeManager(), rtn);
1618 [ + + ]: 401 : for (unsigned j = 0; j < vs.size(); j++)
1619 : : {
1620 : 370 : bchildren.push_back(nodeManager()
1621 : 185 : ->mkNode(Kind::SET_INTER, lbl_mval, vs[j])
1622 : 370 : .eqNode(empSet));
1623 : : }
1624 : 216 : vs.push_back(lbl_mval);
1625 [ + + ]: 216 : if (vsu.isNull())
1626 : : {
1627 : 87 : vsu = lbl_mval;
1628 : : }
1629 : : else
1630 : : {
1631 : 129 : vsu = nodeManager()->mkNode(Kind::SET_UNION, vsu, lbl_mval);
1632 : : }
1633 : 216 : }
1634 : 87 : bchildren.push_back(vsu.eqNode(lbl));
1635 : :
1636 [ - + ][ - + ]: 87 : Assert(bchildren.size() > 1);
[ - - ]
1637 : 87 : conj.push_back(nodeManager()->mkNode(Kind::AND, bchildren));
1638 : 87 : return nodeManager()->mkOr(conj);
1639 : 87 : }
1640 : : else
1641 : : {
1642 : 14 : std::vector<Node> wchildren;
1643 : : // disjoint constraints
1644 : 14 : Node sub_lbl_0 = d_label_map[n][lbl][0];
1645 : : Node lbl_mval_0 =
1646 : 14 : d_label_model[sub_lbl_0].getValue(nodeManager(), rtn);
1647 : 28 : wchildren.push_back(nodeManager()
1648 : : ->mkNode(Kind::SET_INTER, lbl_mval_0, lbl)
1649 : 28 : .eqNode(empSet)
1650 : 28 : .negate());
1651 : :
1652 : : // return the lemma
1653 : 14 : wchildren.push_back(children[0].negate());
1654 : 14 : wchildren.push_back(children[1]);
1655 : 14 : return nodeManager()->mkNode(Kind::OR, wchildren);
1656 : 14 : }
1657 : 101 : }
1658 : : else
1659 : : {
1660 : : // nested star/wand, label it and return
1661 : 26 : return nodeManager()->mkNode(Kind::SEP_LABEL, n, lbl_v);
1662 : : }
1663 : : }
1664 [ + + ]: 325 : else if (n.getKind() == Kind::SEP_PTO)
1665 : : {
1666 : : // check if this pto reference is in the base label, if not, then it does
1667 : : // not need to be added as an assumption
1668 [ - + ][ - + ]: 185 : Assert(d_label_model.find(o_lbl) != d_label_model.end());
[ - - ]
1669 : 370 : Node vr = d_valuation.getModel()->getRepresentative(n[0]);
1670 : 185 : Node svr = nm->mkNode(Kind::SET_SINGLETON, vr);
1671 : : bool inBaseHeap =
1672 : 185 : std::find(d_label_model[o_lbl].d_heap_locs_model.begin(),
1673 : 185 : d_label_model[o_lbl].d_heap_locs_model.end(),
1674 : : svr)
1675 : 370 : != d_label_model[o_lbl].d_heap_locs_model.end();
1676 [ + - ]: 370 : Trace("sep-inst-debug")
1677 : 0 : << "Is in base (non-instantiating) heap : " << inBaseHeap
1678 : 185 : << " for value ref " << vr << " in " << o_lbl << std::endl;
1679 : 185 : std::vector<Node> children;
1680 [ + + ]: 185 : if (inBaseHeap)
1681 : : {
1682 : 324 : Node s = nm->mkNode(Kind::SET_SINGLETON, n[0]);
1683 : 324 : children.push_back(nodeManager()->mkNode(
1684 : : Kind::SEP_LABEL,
1685 : 162 : nodeManager()->mkNode(Kind::SEP_PTO, n[0], n[1]),
1686 : : s));
1687 : 162 : }
1688 : : else
1689 : : {
1690 : : // look up value of data
1691 : 23 : std::map<Node, Node>::iterator it = pto_model.find(vr);
1692 [ + - ]: 23 : if (it != pto_model.end())
1693 : : {
1694 [ + + ]: 23 : if (n[1] != it->second)
1695 : : {
1696 : 9 : children.push_back(nm->mkNode(Kind::EQUAL, n[1], it->second));
1697 : : }
1698 : : }
1699 : : else
1700 : : {
1701 [ - - ]: 0 : Trace("sep-inst-debug")
1702 : 0 : << "Data for " << vr
1703 : 0 : << " was not specified, do not add condition." << std::endl;
1704 : : }
1705 : : }
1706 : 370 : Node singleton = nm->mkNode(Kind::SET_SINGLETON, n[0]);
1707 : 185 : children.push_back(singleton.eqNode(lbl_v));
1708 : 185 : Node ret = nm->mkAnd(children);
1709 [ + - ]: 185 : Trace("sep-inst-debug") << "Return " << ret << std::endl;
1710 : 185 : return ret;
1711 : 185 : }
1712 [ + + ]: 140 : else if (n.getKind() == Kind::SEP_EMP)
1713 : : {
1714 : 36 : return lbl_v.eqNode(nodeManager()->mkConst(EmptySet(lbl_v.getType())));
1715 : : }
1716 : : else
1717 : : {
1718 : 122 : std::map<Node, Node>::iterator it = visited.find(n);
1719 [ + - ]: 122 : if (it == visited.end())
1720 : : {
1721 : 122 : std::vector<Node> children;
1722 [ - + ]: 122 : if (n.getMetaKind() == metakind::PARAMETERIZED)
1723 : : {
1724 : 0 : children.push_back(n.getOperator());
1725 : : }
1726 : 122 : bool childChanged = false;
1727 [ + + ]: 229 : for (unsigned i = 0; i < n.getNumChildren(); i++)
1728 : : {
1729 : : Node aln = instantiateLabel(n[i],
1730 : : o_lbl,
1731 : : lbl,
1732 : : lbl_v,
1733 : : visited,
1734 : : pto_model,
1735 : : rtn,
1736 : : active_lbl,
1737 : 214 : ind);
1738 [ - + ]: 107 : if (aln.isNull())
1739 : : {
1740 : 0 : return Node::null();
1741 : : }
1742 : : else
1743 : : {
1744 : 107 : children.push_back(aln);
1745 [ + - ][ + - ]: 107 : childChanged = childChanged || aln != n[i];
[ + - ][ - - ]
1746 : : }
1747 [ + - ]: 107 : }
1748 : 122 : Node ret = n;
1749 [ + + ]: 122 : if (childChanged)
1750 : : {
1751 : 107 : ret = nodeManager()->mkNode(n.getKind(), children);
1752 : : }
1753 : : // careful about caching
1754 : : // visited[n] = ret;
1755 : 122 : return ret;
1756 : 122 : }
1757 : : else
1758 : : {
1759 : 0 : return it->second;
1760 : : }
1761 : : }
1762 : : }
1763 : : }
1764 : :
1765 : 347 : void TheorySep::setInactiveAssertionRec(
1766 : : Node fact,
1767 : : std::map<Node, std::vector<Node> >& lbl_to_assertions,
1768 : : std::map<Node, bool>& assert_active)
1769 : : {
1770 [ + - ]: 694 : Trace("sep-process-debug")
1771 : 347 : << "setInactiveAssertionRec::inactive : " << fact << std::endl;
1772 : 347 : assert_active[fact] = false;
1773 : 347 : bool polarity = fact.getKind() != Kind::NOT;
1774 [ + + ]: 347 : TNode atom = polarity ? fact : fact[0];
1775 : 347 : TNode satom = atom[0];
1776 : 347 : TNode slbl = atom[1];
1777 [ + + ][ + + ]: 347 : if (satom.getKind() == Kind::SEP_WAND || satom.getKind() == Kind::SEP_STAR)
[ + + ]
1778 : : {
1779 [ + + ]: 123 : for (size_t j = 0, nchild = satom.getNumChildren(); j < nchild; j++)
1780 : : {
1781 : 164 : Node lblc = getLabel(satom, j, slbl);
1782 [ + + ]: 151 : for (unsigned k = 0; k < lbl_to_assertions[lblc].size(); k++)
1783 : : {
1784 : 69 : setInactiveAssertionRec(
1785 : 69 : lbl_to_assertions[lblc][k], lbl_to_assertions, assert_active);
1786 : : }
1787 : 82 : }
1788 : : }
1789 : 347 : }
1790 : :
1791 : 276 : void TheorySep::getLabelChildren(Node satom,
1792 : : Node lbl,
1793 : : std::vector<Node>& children,
1794 : : std::vector<Node>& labels)
1795 : : {
1796 [ + + ]: 919 : for (size_t i = 0, nchild = satom.getNumChildren(); i < nchild; i++)
1797 : : {
1798 : 1286 : Node lblc = getLabel(satom, i, lbl);
1799 [ - + ][ - + ]: 643 : Assert(!lblc.isNull());
[ - - ]
1800 : 643 : std::map<Node, Node> visited;
1801 : 1286 : Node lc = applyLabel(satom[i], lblc, visited);
1802 [ - + ][ - + ]: 643 : Assert(!lc.isNull());
[ - - ]
1803 [ + + ][ + + ]: 643 : if (i == 1 && satom.getKind() == Kind::SEP_WAND)
[ + + ]
1804 : : {
1805 : 31 : lc = lc.negate();
1806 : : }
1807 : 643 : children.push_back(lc);
1808 : 643 : labels.push_back(lblc);
1809 : 643 : }
1810 [ - + ][ - + ]: 276 : Assert(children.size() > 1);
[ - - ]
1811 : 276 : }
1812 : :
1813 : 2438 : void TheorySep::computeLabelModel(Node lbl)
1814 : : {
1815 [ + + ]: 2438 : if (d_label_model[lbl].d_computed)
1816 : : {
1817 : 1040 : return;
1818 : : }
1819 : 1398 : d_label_model[lbl].d_computed = true;
1820 : 1398 : NodeManager* nm = nodeManager();
1821 : : // we must get the value of lbl from the model: this is being run at last
1822 : : // call, after the model is constructed Assert(...); TODO
1823 : 1398 : Node v_val = d_valuation.getModel()->getRepresentative(lbl);
1824 [ + - ]: 2796 : Trace("sep-process") << "Model value (from valuation) for " << lbl << " : "
1825 : 1398 : << v_val << std::endl;
1826 : : // we ignore non-constant values, which are unconstrained and can be assumed
1827 : : // to be empty.
1828 [ + + ][ + + ]: 1398 : if (v_val.isConst() && v_val.getKind() != Kind::SET_EMPTY)
[ + + ]
1829 : : {
1830 [ + + ]: 1457 : while (v_val.getKind() == Kind::SET_UNION)
1831 : : {
1832 [ - + ][ - + ]: 135 : Assert(v_val[0].getKind() == Kind::SET_SINGLETON);
[ - - ]
1833 : 135 : d_label_model[lbl].d_heap_locs_model.push_back(v_val[0]);
1834 : 135 : v_val = v_val[1];
1835 : : }
1836 [ + - ]: 1322 : if (v_val.getKind() == Kind::SET_SINGLETON)
1837 : : {
1838 : 1322 : d_label_model[lbl].d_heap_locs_model.push_back(v_val);
1839 : : }
1840 : : else
1841 : : {
1842 : 0 : throw Exception("Could not establish value of heap in model.");
1843 : : DebugUnhandled();
1844 : : }
1845 : : }
1846 [ + + ]: 2855 : for (const Node& s : d_label_model[lbl].d_heap_locs_model)
1847 : : {
1848 [ - + ][ - + ]: 1457 : Assert(s.getKind() == Kind::SET_SINGLETON);
[ - - ]
1849 : 1457 : Node u = s[0];
1850 : 1457 : Node tt;
1851 : 1457 : std::map<Node, Node>::iterator itm = d_tmodel.find(u);
1852 [ + + ]: 1457 : if (itm == d_tmodel.end())
1853 : : {
1854 : 72 : TypeNode tn = u.getType();
1855 [ + - ]: 144 : Trace("sep-process")
1856 : 0 : << "WARNING: could not find symbolic term in model for " << u
1857 : 72 : << ", cref type " << tn << std::endl;
1858 [ - + ][ - + ]: 72 : Assert(!d_type_references.empty());
[ - - ]
1859 : 72 : tt = d_type_references[0];
1860 : 72 : }
1861 : : else
1862 : : {
1863 : 1385 : tt = itm->second;
1864 : : }
1865 : 1457 : Node stt = nm->mkNode(Kind::SET_SINGLETON, tt);
1866 [ + - ]: 2914 : Trace("sep-process-debug") << "...model : add " << tt << " for " << u
1867 : 1457 : << " in lbl " << lbl << std::endl;
1868 : 1457 : d_label_model[lbl].d_heap_locs.push_back(stt);
1869 : 1457 : }
1870 : 1398 : }
1871 : :
1872 : 6068 : Node TheorySep::getRepresentative(Node t)
1873 : : {
1874 [ + - ]: 6068 : if (d_equalityEngine->hasTerm(t))
1875 : : {
1876 : 12136 : return d_equalityEngine->getRepresentative(t);
1877 : : }
1878 : : else
1879 : : {
1880 : 0 : return t;
1881 : : }
1882 : : }
1883 : :
1884 : 7439 : bool TheorySep::hasTerm(Node a) { return d_equalityEngine->hasTerm(a); }
1885 : :
1886 : 5460 : bool TheorySep::areEqual(Node a, Node b)
1887 : : {
1888 [ + + ]: 5460 : if (a == b)
1889 : : {
1890 : 2526 : return true;
1891 : : }
1892 : 2934 : else if (hasTerm(a) && hasTerm(b))
1893 : : {
1894 : 2277 : return d_equalityEngine->areEqual(a, b);
1895 : : }
1896 : : else
1897 : : {
1898 : 657 : return false;
1899 : : }
1900 : : }
1901 : :
1902 : 2978 : bool TheorySep::areDisequal(Node a, Node b)
1903 : : {
1904 [ + + ]: 2978 : if (a == b)
1905 : : {
1906 : 751 : return false;
1907 : : }
1908 : 2227 : else if (hasTerm(a) && hasTerm(b))
1909 : : {
1910 [ - + ]: 1 : if (d_equalityEngine->areDisequal(a, b, false))
1911 : : {
1912 : 0 : return true;
1913 : : }
1914 : : }
1915 : 2227 : return false;
1916 : : }
1917 : :
1918 : 28553 : void TheorySep::eqNotifyMerge(TNode t1, TNode t2)
1919 : : {
1920 : 28553 : HeapAssertInfo* e2 = getOrMakeEqcInfo(t2, false);
1921 [ + + ][ + + ]: 28553 : if (!e2 || (e2->d_posPto.empty() && e2->d_negPto.empty()))
[ + + ][ + + ]
1922 : : {
1923 : 24838 : return;
1924 : : }
1925 : : // allocate the heap assert info for e1
1926 : 3715 : HeapAssertInfo* e1 = getOrMakeEqcInfo(t1, true);
1927 [ + + ]: 22290 : std::vector<Node> toAdd[2];
1928 [ + + ]: 11145 : for (size_t i = 0; i < 2; i++)
1929 : : {
1930 : 7430 : bool pol = i == 0;
1931 [ + + ]: 7430 : NodeList& e2list = pol ? e2->d_posPto : e2->d_negPto;
1932 [ + + ]: 11473 : for (const Node& p : e2list)
1933 : : {
1934 [ + - ]: 4043 : if (checkPto(e1, p, pol))
1935 : : {
1936 : : // add unless checkPto determined it was redundant
1937 : 4043 : toAdd[i].push_back(p);
1938 : : }
1939 : : }
1940 : : }
1941 : : // now that checks are complete, add them all now
1942 [ + + ]: 11145 : for (size_t i = 0; i < 2; i++)
1943 : : {
1944 [ + + ]: 7430 : NodeList& e1list = i == 0 ? e1->d_posPto : e1->d_negPto;
1945 [ + + ]: 11473 : for (const Node& p : toAdd[i])
1946 : : {
1947 : 4043 : e1list.push_back(p);
1948 : : }
1949 : : }
1950 [ + + ][ - - ]: 11145 : }
1951 : :
1952 : 10111 : bool TheorySep::checkPto(HeapAssertInfo* e, Node p, bool polarity)
1953 : : {
1954 [ - + ][ - + ]: 10111 : Assert(e != nullptr);
[ - - ]
1955 : 10111 : Assert(p.getKind() == Kind::SEP_LABEL && p[0].getKind() == Kind::SEP_PTO);
1956 : 10111 : NodeManager* nm = nodeManager();
1957 : 10111 : Node plbl = p[1];
1958 : 10111 : Node pval = p[0][1];
1959 : 10111 : bool ret = true;
1960 : : // check for inferences involving p with all pto constraints already
1961 : : // contained in e.
1962 [ + + ]: 30333 : for (size_t i = 0; i < 2; i++)
1963 : : {
1964 : 20222 : bool pol = i == 0;
1965 [ + + ]: 20222 : NodeList& elist = pol ? e->d_posPto : e->d_negPto;
1966 [ + + ]: 28301 : for (const Node& q : elist)
1967 : : {
1968 : 8079 : Assert(q.getKind() == Kind::SEP_LABEL && q[0].getKind() == Kind::SEP_PTO);
1969 : 8079 : Node qlbl = q[1];
1970 : 8079 : Node qval = q[0][1];
1971 : : // We use instantiated labels where labels are set to singletons. We
1972 : : // assume these always share a root label.
1973 : 25714 : if (qlbl.getKind() != Kind::SET_SINGLETON
1974 [ + + ]: 7340 : && plbl.getKind() != Kind::SET_SINGLETON
1975 : 15419 : && !sharesRootLabel(plbl, qlbl))
1976 : : {
1977 [ + - ]: 2954 : Trace("sep-pto") << "Constraints " << p << " and " << q
1978 : 1477 : << " do not share a root label" << std::endl;
1979 : : // if do not share a parent, skip
1980 : 1477 : continue;
1981 : : }
1982 [ + + ][ + + ]: 6602 : if (polarity && pol)
1983 : : {
1984 : : // two positive pto
1985 [ + + ]: 3327 : if (!areEqual(pval, qval))
1986 : : {
1987 : 801 : std::vector<Node> exp;
1988 [ + + ]: 801 : if (plbl != qlbl)
1989 : : {
1990 : : // the labels are equal since we are tracking the sets of pto
1991 : : // constraints modulo equality on their labels
1992 [ - + ][ - + ]: 657 : Assert(areEqual(plbl, qlbl));
[ - - ]
1993 : 657 : exp.push_back(plbl.eqNode(qlbl));
1994 : : }
1995 : 801 : exp.push_back(p);
1996 : 801 : exp.push_back(q);
1997 : : // enforces injectiveness of pto
1998 : : // (label (pto x y) A) ^ (label (pto z w) B) ^ A = B => y = w
1999 : 801 : Node concn = pval.eqNode(qval);
2000 [ + - ]: 1602 : Trace("sep-pto") << "prop pos/pos: " << concn << " by " << exp
2001 : 801 : << std::endl;
2002 : 801 : sendLemma(exp, concn, InferenceId::SEP_PTO_PROP);
2003 : : // Don't need to add this if the labels are identical. This is an
2004 : : // optimization to minimize the size of the pto list
2005 [ + + ]: 801 : if (plbl == qlbl)
2006 : : {
2007 : 144 : ret = false;
2008 : : }
2009 : 801 : }
2010 : 3327 : }
2011 [ + + ]: 3275 : else if (polarity != pol)
2012 : : {
2013 : : // a positive and negative pto
2014 : 1489 : bool isSat = false;
2015 : 1489 : std::vector<Node> conc;
2016 : : // based on the lemma below, either the domain or range has to be
2017 : : // disequal. We iterate on each child of the pto
2018 [ + + ]: 4467 : for (size_t j = 0; j < 2; j++)
2019 : : {
2020 [ - + ]: 2978 : if (areDisequal(p[0][j], q[0][j]))
2021 : : {
2022 : 0 : isSat = true;
2023 : 0 : break;
2024 : : }
2025 [ + + ]: 2978 : if (p[0][j] != q[0][j])
2026 : : {
2027 : 2227 : conc.push_back(p[0][j].eqNode(q[0][j]).notNode());
2028 : : }
2029 : : }
2030 [ + - ]: 1489 : if (!isSat)
2031 : : {
2032 : 1489 : std::vector<Node> exp;
2033 [ + + ]: 1489 : if (plbl != qlbl)
2034 : : {
2035 : : // the labels are equal since we are tracking the sets of pto
2036 : : // constraints modulo equality on their labels
2037 [ - + ][ - + ]: 1476 : Assert(areEqual(plbl, qlbl));
[ - - ]
2038 : 1476 : exp.push_back(plbl.eqNode(qlbl));
2039 : : }
2040 [ + + ]: 1489 : Node pos = polarity ? p : q;
2041 [ + + ]: 1489 : Node neg = polarity ? q : p;
2042 : 1489 : exp.push_back(pos);
2043 : 1489 : exp.push_back(neg.notNode());
2044 : 1489 : Node concn = nm->mkOr(conc);
2045 [ + - ]: 2978 : Trace("sep-pto") << "prop neg/pos: " << concn << " by " << exp
2046 : 1489 : << std::endl;
2047 : : // (label (pto x y) A) ^ ~(label (pto z w) B) ^ A = B =>
2048 : : // (x != z or y != w)
2049 : 1489 : sendLemma(exp, concn, InferenceId::SEP_PTO_NEG_PROP);
2050 : 1489 : }
2051 : 1489 : }
2052 : : else
2053 : : {
2054 : : // otherwise if both are disequal, do nothing
2055 : : }
2056 [ + + ][ + + ]: 9556 : }
2057 : : }
2058 : 10111 : return ret;
2059 : 10111 : }
2060 : :
2061 : 2290 : void TheorySep::sendLemma(std::vector<Node>& ant,
2062 : : Node conc,
2063 : : InferenceId id,
2064 : : bool infer)
2065 : : {
2066 [ + - ]: 2290 : Trace("sep-lemma-debug") << "Do rewrite on inference : " << conc << std::endl;
2067 : 2290 : conc = rewrite(conc);
2068 [ + - ]: 2290 : Trace("sep-lemma-debug") << "Got : " << conc << std::endl;
2069 [ + + ]: 2290 : if (conc != d_true)
2070 : : {
2071 [ - + ][ - - ]: 2162 : if (infer && conc != d_false)
[ - + ]
2072 : : {
2073 : 0 : Node ant_n = nodeManager()->mkAnd(ant);
2074 [ - - ]: 0 : Trace("sep-lemma") << "Sep::Infer: " << conc << " from " << ant_n
2075 : 0 : << " by " << id << std::endl;
2076 : 0 : d_im.addPendingFact(conc, id, ant_n);
2077 : 0 : }
2078 : : else
2079 : : {
2080 [ + + ]: 2162 : if (conc == d_false)
2081 : : {
2082 [ + - ]: 568 : Trace("sep-lemma") << "Sep::Conflict: " << ant << " by " << id
2083 : 284 : << std::endl;
2084 [ + + ][ - - ]: 852 : d_im.conflictExp(id, ProofRule::TRUST, ant, {d_tiid, conc});
2085 : : }
2086 : : else
2087 : : {
2088 [ + - ]: 3756 : Trace("sep-lemma") << "Sep::Lemma: " << conc << " from " << ant
2089 : 1878 : << " by " << id << std::endl;
2090 : : TrustNode trn =
2091 : 7512 : d_im.mkLemmaExp(conc, ProofRule::TRUST, ant, {}, {d_tiid, conc});
2092 : 3756 : d_im.addPendingLemma(
2093 : 3756 : trn.getNode(), id, LemmaProperty::NONE, trn.getGenerator());
2094 : 1878 : }
2095 : : }
2096 : : }
2097 : 2290 : }
2098 : :
2099 : 29528 : void TheorySep::doPending()
2100 : : {
2101 : 29528 : d_im.doPendingFacts();
2102 : 29528 : d_im.doPendingLemmas();
2103 : 29528 : }
2104 : :
2105 : 819 : Node TheorySep::HeapInfo::getValue(NodeManager* nm, TypeNode tn)
2106 : : {
2107 [ - + ][ - + ]: 819 : Assert(d_heap_locs.size() == d_heap_locs_model.size());
[ - - ]
2108 [ + + ]: 819 : if (d_heap_locs.empty())
2109 : : {
2110 : 344 : return nm->mkConst(EmptySet(tn));
2111 : : }
2112 : 647 : Node curr = d_heap_locs[0];
2113 [ + + ]: 798 : for (unsigned j = 1; j < d_heap_locs.size(); j++)
2114 : : {
2115 : 151 : curr = nm->mkNode(Kind::SET_UNION, d_heap_locs[j], curr);
2116 : : }
2117 : 647 : return curr;
2118 : 647 : }
2119 : :
2120 : : } // namespace sep
2121 : : } // namespace theory
2122 : : } // namespace cvc5::internal
|