LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/sep - theory_sep.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 970 1076 90.1 %
Date: 2025-01-20 12:43:42 Functions: 45 46 97.8 %
Branches: 725 1142 63.5 %

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

Generated by: LCOV version 1.14