GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sep/theory_sep.cpp Lines: 910 1081 84.2 %
Date: 2021-11-07 Branches: 2233 5388 41.4 %

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