GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sep/theory_sep.cpp Lines: 922 1088 84.7 %
Date: 2021-08-01 Branches: 2282 5464 41.8 %

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