GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sep/theory_sep.cpp Lines: 921 1087 84.7 %
Date: 2021-05-22 Branches: 2274 5448 41.7 %

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