GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/sep/theory_sep.cpp Lines: 923 1089 84.8 %
Date: 2021-09-29 Branches: 2279 5460 41.7 %

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