LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/bags - theory_bags.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 327 360 90.8 %
Date: 2026-04-29 10:45:04 Functions: 28 29 96.6 %
Branches: 161 275 58.5 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Bags theory.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/bags/theory_bags.h"
      14                 :            : 
      15                 :            : #include "expr/emptybag.h"
      16                 :            : #include "expr/skolem_manager.h"
      17                 :            : #include "options/bags_options.h"
      18                 :            : #include "proof/proof_checker.h"
      19                 :            : #include "smt/logic_exception.h"
      20                 :            : #include "theory/bags/bags_utils.h"
      21                 :            : #include "theory/quantifiers/fmf/bounded_integers.h"
      22                 :            : #include "theory/rewriter.h"
      23                 :            : #include "theory/theory_model.h"
      24                 :            : #include "theory_bags.h"
      25                 :            : #include "util/rational.h"
      26                 :            : 
      27                 :            : using namespace cvc5::internal::kind;
      28                 :            : 
      29                 :            : namespace cvc5::internal {
      30                 :            : namespace theory {
      31                 :            : namespace bags {
      32                 :            : 
      33                 :      51035 : TheoryBags::TheoryBags(Env& env, OutputChannel& out, Valuation valuation)
      34                 :            :     : Theory(THEORY_BAGS, env, out, valuation),
      35                 :      51035 :       d_state(env, valuation),
      36                 :      51035 :       d_im(env, *this, d_state),
      37                 :      51035 :       d_ig(env.getNodeManager(), &d_state, &d_im),
      38                 :      51035 :       d_notify(*this, d_im),
      39                 :      51035 :       d_statistics(statisticsRegistry()),
      40                 :      51035 :       d_rewriter(nodeManager(), env.getRewriter(), &d_statistics.d_rewrites),
      41                 :      51035 :       d_termReg(env),
      42                 :      51035 :       d_solver(env, d_state, d_im),
      43                 :     102070 :       d_cpacb(*this)
      44                 :            : {
      45                 :            :   // use the official theory state and inference manager objects
      46                 :      51035 :   d_theoryState = &d_state;
      47                 :      51035 :   d_inferManager = &d_im;
      48                 :      51035 : }
      49                 :            : 
      50                 :     101374 : TheoryBags::~TheoryBags() {}
      51                 :            : 
      52                 :      51035 : TheoryRewriter* TheoryBags::getTheoryRewriter()
      53                 :            : {
      54         [ +  + ]:      51035 :   if (!options().bags.bags)
      55                 :            :   {
      56                 :          5 :     return nullptr;
      57                 :            :   }
      58                 :      51030 :   return &d_rewriter;
      59                 :            : }
      60                 :            : 
      61                 :      19914 : ProofRuleChecker* TheoryBags::getProofChecker() { return nullptr; }
      62                 :            : 
      63                 :      51035 : bool TheoryBags::needsEqualityEngine(EeSetupInfo& esi)
      64                 :            : {
      65                 :      51035 :   esi.d_notify = &d_notify;
      66                 :      51035 :   esi.d_name = "theory::bags::ee";
      67                 :      51035 :   return true;
      68                 :            : }
      69                 :            : 
      70                 :      51035 : void TheoryBags::finishInit()
      71                 :            : {
      72 [ -  + ][ -  + ]:      51035 :   Assert(d_equalityEngine != nullptr);
                 [ -  - ]
      73                 :            : 
      74                 :      51035 :   d_valuation.setUnevaluatedKind(Kind::WITNESS);
      75                 :            : 
      76                 :            :   // functions we are doing congruence over
      77                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_UNION_MAX);
      78                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_UNION_DISJOINT);
      79                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_INTER_MIN);
      80                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_DIFFERENCE_SUBTRACT);
      81                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_DIFFERENCE_REMOVE);
      82                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_COUNT);
      83                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_SETOF);
      84                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_MAKE);
      85                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_CARD);
      86                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::BAG_PARTITION);
      87                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::TABLE_PRODUCT);
      88                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::TABLE_PROJECT);
      89                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::TABLE_AGGREGATE);
      90                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::TABLE_JOIN);
      91                 :      51035 :   d_equalityEngine->addFunctionKind(Kind::TABLE_GROUP);
      92                 :      51035 : }
      93                 :            : 
      94                 :      10563 : TrustNode TheoryBags::ppRewrite(TNode atom, std::vector<SkolemLemma>& lems)
      95                 :            : {
      96         [ +  - ]:      10563 :   Trace("bags-ppr") << "TheoryBags::ppRewrite " << atom << std::endl;
      97                 :            : 
      98                 :      10563 :   NodeManager* nm = nodeManager();
      99                 :            : 
     100 [ +  + ][ +  - ]:      10563 :   switch (atom.getKind())
                 [ +  + ]
     101                 :            :   {
     102                 :         11 :     case Kind::BAG_CHOOSE: return expandChooseOperator(atom, lems);
     103                 :         33 :     case Kind::BAG_CARD:
     104                 :            :     {
     105                 :         33 :       std::vector<Node> asserts;
     106                 :         33 :       Node ret = BagReduction::reduceCardOperator(atom, asserts);
     107                 :         33 :       Node andNode = nm->mkNode(Kind::AND, asserts);
     108                 :         33 :       d_im.lemma(andNode, InferenceId::BAGS_CARD);
     109         [ +  - ]:         66 :       Trace("bags::ppr") << "reduce(" << atom << ") = " << ret
     110                 :          0 :                          << " such that:" << std::endl
     111                 :         33 :                          << andNode << std::endl;
     112                 :         33 :       return TrustNode::mkTrustRewrite(atom, ret, nullptr);
     113                 :         33 :     }
     114                 :          8 :     case Kind::BAG_FOLD:
     115                 :            :     {
     116                 :          8 :       std::vector<Node> asserts;
     117                 :          8 :       Node ret = BagReduction::reduceFoldOperator(atom, asserts);
     118                 :          8 :       Node andNode = nm->mkNode(Kind::AND, asserts);
     119                 :          8 :       d_im.lemma(andNode, InferenceId::BAGS_FOLD);
     120         [ +  - ]:         16 :       Trace("bags::ppr") << "reduce(" << atom << ") = " << ret
     121                 :          0 :                          << " such that:" << std::endl
     122                 :          8 :                          << andNode << std::endl;
     123                 :          8 :       return TrustNode::mkTrustRewrite(atom, ret, nullptr);
     124                 :          8 :     }
     125                 :          0 :     case Kind::TABLE_AGGREGATE:
     126                 :            :     {
     127                 :          0 :       Node ret = BagReduction::reduceAggregateOperator(atom);
     128         [ -  - ]:          0 :       Trace("bags::ppr") << "reduce(" << atom << ") = " << ret << std::endl;
     129                 :          0 :       return TrustNode::mkTrustRewrite(atom, ret, nullptr);
     130                 :          0 :     }
     131                 :         13 :     case Kind::TABLE_PROJECT:
     132                 :            :     {
     133                 :         13 :       Node ret = BagReduction::reduceProjectOperator(atom);
     134         [ +  - ]:         13 :       Trace("bags::ppr") << "reduce(" << atom << ") = " << ret << std::endl;
     135                 :         13 :       return TrustNode::mkTrustRewrite(atom, ret, nullptr);
     136                 :         13 :     }
     137                 :      10498 :     default: return TrustNode::null();
     138                 :            :   }
     139                 :            : }
     140                 :            : 
     141                 :         11 : TrustNode TheoryBags::expandChooseOperator(const Node& node,
     142                 :            :                                            std::vector<SkolemLemma>& lems)
     143                 :            : {
     144 [ -  + ][ -  + ]:         11 :   Assert(node.getKind() == Kind::BAG_CHOOSE);
                 [ -  - ]
     145                 :            : 
     146                 :            :   // (bag.choose A) is eliminated to k, with lemma
     147                 :            :   // (and (= k (uf A)) (or (= A (as bag.empty (Bag E))) (>= (bag.count k A) 1)))
     148                 :            :   // where uf: (Bag E) -> E is a skolem function, and E is the type of elements
     149                 :            :   // of A
     150                 :            : 
     151                 :         11 :   NodeManager* nm = nodeManager();
     152                 :         11 :   SkolemManager* sm = nm->getSkolemManager();
     153                 :         11 :   Node x = sm->mkPurifySkolem(node);
     154                 :         11 :   Node A = node[0];
     155                 :         11 :   TypeNode bagType = A.getType();
     156                 :            :   // use canonical constant to ensure it can be typed
     157                 :         11 :   Node mkElem = NodeManager::mkGroundValue(bagType);
     158                 :            :   // a Null node is used here to get a unique skolem function per bag type
     159                 :         11 :   Node uf = sm->mkSkolemFunction(SkolemId::BAGS_CHOOSE, mkElem);
     160                 :         22 :   Node ufA = nodeManager()->mkNode(Kind::APPLY_UF, uf, A);
     161                 :            : 
     162                 :         11 :   Node equal = x.eqNode(ufA);
     163                 :         11 :   Node emptyBag = nm->mkConst(EmptyBag(bagType));
     164                 :         11 :   Node isEmpty = A.eqNode(emptyBag);
     165                 :         22 :   Node count = nm->mkNode(Kind::BAG_COUNT, x, A);
     166                 :         11 :   Node one = nm->mkConstInt(Rational(1));
     167                 :         22 :   Node geqOne = nm->mkNode(Kind::GEQ, count, one);
     168                 :            :   Node lem =
     169                 :         22 :       nm->mkNode(Kind::AND, equal, nm->mkNode(Kind::OR, isEmpty, geqOne));
     170                 :         11 :   TrustNode tlem = TrustNode::mkTrustLemma(lem, nullptr);
     171                 :         11 :   lems.push_back(SkolemLemma(tlem, x));
     172         [ +  - ]:         22 :   Trace("TheoryBags::ppRewrite")
     173                 :         11 :       << "ppRewrite(" << node << ") = " << x << std::endl;
     174                 :         22 :   return TrustNode::mkTrustRewrite(node, x, nullptr);
     175                 :         11 : }
     176                 :            : 
     177                 :      49204 : void TheoryBags::initialize()
     178                 :            : {
     179                 :      49204 :   d_state.reset();
     180                 :      49204 :   d_opMap.clear();
     181                 :      49204 :   d_state.collectDisequalBagTerms();
     182                 :      49204 :   collectBagsAndCountTerms();
     183                 :      49204 : }
     184                 :            : 
     185                 :      49204 : void TheoryBags::collectBagsAndCountTerms()
     186                 :            : {
     187                 :      49204 :   eq::EqualityEngine* ee = d_state.getEqualityEngine();
     188                 :      49204 :   eq::EqClassesIterator repIt = eq::EqClassesIterator(ee);
     189         [ +  + ]:     180628 :   while (!repIt.isFinished())
     190                 :            :   {
     191                 :     131424 :     Node eqc = (*repIt);
     192         [ +  - ]:     131424 :     Trace("bags-eqc") << "Eqc [ " << eqc << " ] = { ";
     193                 :            : 
     194         [ +  + ]:     131424 :     if (eqc.getType().isBag())
     195                 :            :     {
     196                 :       9285 :       d_state.registerBag(eqc);
     197                 :            :     }
     198                 :            : 
     199                 :     131424 :     eq::EqClassIterator it = eq::EqClassIterator(eqc, ee);
     200         [ +  + ]:     399734 :     while (!it.isFinished())
     201                 :            :     {
     202                 :     268310 :       Node n = (*it);
     203                 :     268310 :       d_opMap[n.getKind()].push_back(n);
     204 [ +  - ][ -  + ]:     268310 :       Trace("bags-eqc") << (*it) << " ";
                 [ -  - ]
     205                 :     268310 :       Kind k = n.getKind();
     206         [ +  + ]:     268310 :       if (k == Kind::BAG_MAKE)
     207                 :            :       {
     208                 :            :         // for terms (bag x c) we need to store x by registering the count term
     209                 :            :         // (bag.count x (bag x c))
     210                 :       1905 :         NodeManager* nm = nodeManager();
     211                 :       3810 :         Node count = nm->mkNode(Kind::BAG_COUNT, n[0], n);
     212                 :       1905 :         d_ig.registerCountTerm(count);
     213                 :       1905 :       }
     214         [ +  + ]:     268310 :       if (k == Kind::BAG_COUNT)
     215                 :            :       {
     216                 :            :         // this takes care of all count terms in each equivalent class
     217                 :      62030 :         d_ig.registerCountTerm(n);
     218                 :            :       }
     219         [ -  + ]:     268310 :       if (k == Kind::BAG_CARD)
     220                 :            :       {
     221                 :          0 :         d_ig.registerCardinalityTerm(n);
     222                 :            :       }
     223         [ +  + ]:     268310 :       if (k == Kind::TABLE_GROUP)
     224                 :            :       {
     225                 :        508 :         d_state.registerGroupTerm(n);
     226                 :            :       }
     227                 :     268310 :       ++it;
     228                 :     268310 :     }
     229         [ +  - ]:     131424 :     Trace("bags-eqc") << " } " << std::endl;
     230                 :     131424 :     ++repIt;
     231                 :     131424 :   }
     232                 :      49204 : }
     233                 :            : 
     234                 :      94489 : void TheoryBags::postCheck(Effort effort)
     235                 :            : {
     236                 :      94489 :   d_im.doPendingFacts();
     237 [ -  + ][ -  + ]:      94489 :   Assert(d_strat.isStrategyInit());
                 [ -  - ]
     238         [ +  + ]:     188714 :   if (!d_state.isInConflict() && !d_valuation.needCheck()
     239 [ +  + ][ +  + ]:     188714 :       && d_strat.hasStrategyEffort(effort))
                 [ +  + ]
     240                 :            :   {
     241         [ +  - ]:      49204 :     Trace("bags::TheoryBags::postCheck") << "effort: " << effort << std::endl;
     242                 :            : 
     243                 :            :     // TODO issue #78: add ++(d_statistics.d_checkRuns);
     244                 :      49204 :     bool sentLemma = false;
     245                 :      49204 :     bool hadPending = false;
     246         [ +  - ]:      49204 :     Trace("bags-check") << "Full effort check..." << std::endl;
     247                 :            :     do
     248                 :            :     {
     249                 :      49204 :       d_im.reset();
     250                 :            :       // TODO issue #78: add ++(d_statistics.d_strategyRuns);
     251         [ +  - ]:      49204 :       Trace("bags-check") << "  * Run strategy..." << std::endl;
     252                 :      49204 :       initialize();
     253                 :      49204 :       runStrategy(effort);
     254                 :            : 
     255                 :            :       // remember if we had pending facts or lemmas
     256                 :      49204 :       hadPending = d_im.hasPending();
     257                 :            :       // Send the facts *and* the lemmas. We send lemmas regardless of whether
     258                 :            :       // we send facts since some lemmas cannot be dropped. Other lemmas are
     259                 :            :       // otherwise avoided by aborting the strategy when a fact is ready.
     260                 :      49204 :       d_im.doPending();
     261                 :            :       // Did we successfully send a lemma? Notice that if hasPending = true
     262                 :            :       // and sentLemma = false, then the above call may have:
     263                 :            :       // (1) had no pending lemmas, but successfully processed pending facts,
     264                 :            :       // (2) unsuccessfully processed pending lemmas.
     265                 :            :       // In either case, we repeat the strategy if we are not in conflict.
     266                 :      49204 :       sentLemma = d_im.hasSentLemma();
     267         [ -  + ]:      49204 :       if (TraceIsOn("bags-check"))
     268                 :            :       {
     269         [ -  - ]:          0 :         Trace("bags-check") << "  ...finish run strategy: ";
     270                 :          0 :         Trace("bags-check") << (hadPending ? "hadPending " : "");
     271                 :          0 :         Trace("bags-check") << (sentLemma ? "sentLemma " : "");
     272                 :          0 :         Trace("bags-check") << (d_state.isInConflict() ? "conflict " : "");
     273 [ -  - ][ -  - ]:          0 :         if (!hadPending && !sentLemma && !d_state.isInConflict())
         [ -  - ][ -  - ]
     274                 :            :         {
     275         [ -  - ]:          0 :           Trace("bags-check") << "(none)";
     276                 :            :         }
     277         [ -  - ]:          0 :         Trace("bags-check") << std::endl;
     278                 :            :       }
     279                 :            :       // repeat if we did not add a lemma or conflict, and we had pending
     280                 :            :       // facts or lemmas.
     281 [ +  - ][ +  + ]:      49204 :     } while (!d_state.isInConflict() && !sentLemma && hadPending);
         [ -  + ][ -  + ]
     282                 :            :   }
     283         [ +  - ]:      94489 :   Trace("bags-check") << "Theory of bags, done check : " << effort << std::endl;
     284 [ -  + ][ -  + ]:      94489 :   Assert(!d_im.hasPendingFact());
                 [ -  - ]
     285 [ -  + ][ -  + ]:      94489 :   Assert(!d_im.hasPendingLemma());
                 [ -  - ]
     286                 :      94489 : }
     287                 :            : 
     288                 :      49204 : void TheoryBags::runStrategy(Theory::Effort e)
     289                 :            : {
     290                 :      49204 :   std::vector<std::pair<InferStep, size_t>>::iterator it = d_strat.stepBegin(e);
     291                 :            :   std::vector<std::pair<InferStep, size_t>>::iterator stepEnd =
     292                 :      49204 :       d_strat.stepEnd(e);
     293                 :            : 
     294         [ +  - ]:      49204 :   Trace("bags-process") << "----check, next round---" << std::endl;
     295         [ +  + ]:     388122 :   while (it != stepEnd)
     296                 :            :   {
     297                 :     340302 :     InferStep curr = it->first;
     298         [ +  + ]:     340302 :     if (curr == BREAK)
     299                 :            :     {
     300 [ +  - ][ +  + ]:     146212 :       if (d_state.isInConflict() || d_im.hasPending())
                 [ +  + ]
     301                 :            :       {
     302                 :       1326 :         break;
     303                 :            :       }
     304                 :            :     }
     305                 :            :     else
     306                 :            :     {
     307 [ +  + ][ -  + ]:     194090 :       if (runInferStep(curr, it->second) || d_state.isInConflict())
                 [ +  + ]
     308                 :            :       {
     309                 :         58 :         break;
     310                 :            :       }
     311                 :            :     }
     312                 :     338918 :     ++it;
     313                 :            :   }
     314         [ +  - ]:      49204 :   Trace("bags-process") << "----finished round---" << std::endl;
     315                 :      49204 : }
     316                 :            : 
     317                 :            : /** run the given inference step */
     318                 :     194090 : bool TheoryBags::runInferStep(InferStep s, int effort)
     319                 :            : {
     320         [ +  - ]:     194090 :   Trace("bags-process") << "Run " << s;
     321         [ -  + ]:     194090 :   if (effort > 0)
     322                 :            :   {
     323         [ -  - ]:          0 :     Trace("bags-process") << ", effort = " << effort;
     324                 :            :   }
     325         [ +  - ]:     194090 :   Trace("bags-process") << "..." << std::endl;
     326 [ +  + ][ +  + ]:     194090 :   switch (s)
                    [ - ]
     327                 :            :   {
     328                 :      49204 :     case CHECK_INIT: break;
     329                 :      48562 :     case CHECK_BAG_MAKE:
     330                 :            :     {
     331         [ +  + ]:      48562 :       if (d_solver.checkBagMake())
     332                 :            :       {
     333                 :         58 :         return true;
     334                 :            :       }
     335                 :      48504 :       break;
     336                 :            :     }
     337                 :      48504 :     case CHECK_BASIC_OPERATIONS: d_solver.checkBasicOperations(); break;
     338                 :      47820 :     case CHECK_QUANTIFIED_OPERATIONS:
     339                 :      47820 :       d_solver.checkQuantifiedOperations();
     340                 :      47820 :       break;
     341                 :          0 :     default: Unreachable(); break;
     342                 :            :   }
     343         [ +  - ]:     388064 :   Trace("bags-process") << "Done " << s
     344                 :          0 :                         << ", addedFact = " << d_im.hasPendingFact()
     345                 :          0 :                         << ", addedLemma = " << d_im.hasPendingLemma()
     346                 :     194032 :                         << ", conflict = " << d_state.isInConflict()
     347                 :     194032 :                         << std::endl;
     348                 :     194032 :   return false;
     349                 :            : }
     350                 :            : 
     351                 :      95330 : void TheoryBags::notifyFact(CVC5_UNUSED TNode atom,
     352                 :            :                             CVC5_UNUSED bool polarity,
     353                 :            :                             CVC5_UNUSED TNode fact,
     354                 :            :                             CVC5_UNUSED bool isInternal)
     355                 :            : {
     356                 :      95330 : }
     357                 :            : 
     358                 :      14694 : bool TheoryBags::collectModelValues(TheoryModel* m,
     359                 :            :                                     const std::set<Node>& termSet)
     360                 :            : {
     361         [ +  - ]:      14694 :   Trace("bags-model") << "TheoryBags : Collect model values" << std::endl;
     362                 :            : 
     363         [ +  - ]:      14694 :   Trace("bags-model") << "Term set: " << termSet << std::endl;
     364                 :            : 
     365                 :            :   // a map from bag representatives to their constructed values
     366                 :      14694 :   std::map<Node, Node> processedBags;
     367                 :            : 
     368         [ +  - ]:      14694 :   Trace("bags-model") << "d_state equality engine:" << std::endl;
     369 [ +  - ][ -  + ]:      29388 :   Trace("bags-model") << d_state.getEqualityEngine()->debugPrintEqc()
                 [ -  - ]
     370                 :      14694 :                       << std::endl;
     371                 :            : 
     372         [ +  - ]:      14694 :   Trace("bags-model") << "model equality engine:" << std::endl;
     373 [ +  - ][ -  + ]:      14694 :   Trace("bags-model") << m->getEqualityEngine()->debugPrintEqc() << std::endl;
                 [ -  - ]
     374                 :            : 
     375                 :            :   // get the relevant bag equivalence classes
     376         [ +  + ]:      19622 :   for (const Node& n : termSet)
     377                 :            :   {
     378                 :       4928 :     TypeNode tn = n.getType();
     379         [ +  + ]:       4928 :     if (!tn.isBag())
     380                 :            :     {
     381                 :            :       // we are only concerned here about bag terms
     382                 :       3801 :       continue;
     383                 :            :     }
     384                 :            : 
     385         [ +  + ]:       1127 :     if (!Theory::isLeafOf(n, TheoryId::THEORY_BAGS))
     386                 :            :     {
     387                 :        339 :       continue;
     388                 :            :     }
     389                 :            : 
     390                 :       1576 :     Node r = d_state.getRepresentative(n);
     391         [ +  + ]:        788 :     if (processedBags.find(r) != processedBags.end())
     392                 :            :     {
     393                 :            :       // skip bags whose representatives are already processed
     394                 :        336 :       continue;
     395                 :            :     }
     396                 :            : 
     397                 :            :     const std::vector<std::pair<Node, Node>>& solverElements =
     398                 :        452 :         d_state.getElementCountPairs(r);
     399                 :        452 :     std::vector<std::pair<Node, Node>> elements;
     400         [ +  + ]:       1105 :     for (std::pair<Node, Node> pair : solverElements)
     401                 :            :     {
     402         [ +  + ]:        653 :       if (termSet.find(pair.first) == termSet.end())
     403                 :            :       {
     404                 :         28 :         continue;
     405                 :            :       }
     406                 :        625 :       elements.push_back(pair);
     407         [ +  + ]:        653 :     }
     408                 :            : 
     409                 :        452 :     std::map<Node, Node> elementReps;
     410         [ +  + ]:       1077 :     for (std::pair<Node, Node> pair : elements)
     411                 :            :     {
     412                 :       1250 :       Node key = d_state.getRepresentative(pair.first);
     413                 :        625 :       Node countSkolem = pair.second;
     414                 :        625 :       Node value = m->getRepresentative(countSkolem);
     415                 :        625 :       elementReps[key] = value;
     416                 :        625 :     }
     417                 :        452 :     Node constructedBag = BagsUtils::constructBagFromElements(tn, elementReps);
     418                 :        452 :     constructedBag = rewrite(constructedBag);
     419                 :        452 :     m->assertEquality(constructedBag, n, true);
     420                 :        452 :     m->assertSkeleton(constructedBag);
     421                 :        452 :     processedBags[r] = constructedBag;
     422 [ +  + ][ +  + ]:       5264 :   }
     423                 :            : 
     424         [ +  - ]:      14694 :   Trace("bags-model") << "processedBags:  " << processedBags << std::endl;
     425                 :      14694 :   return true;
     426                 :      14694 : }
     427                 :            : 
     428                 :       3486 : TrustNode TheoryBags::explain(TNode node) { return d_im.explainLit(node); }
     429                 :            : 
     430                 :          0 : Node TheoryBags::getCandidateModelValue(CVC5_UNUSED TNode node)
     431                 :            : {
     432                 :          0 :   return Node::null();
     433                 :            : }
     434                 :            : 
     435                 :      21628 : void TheoryBags::preRegisterTerm(TNode n)
     436                 :            : {
     437         [ -  + ]:      21628 :   if (!options().bags.bags)
     438                 :            :   {
     439                 :          0 :     std::stringstream ss;
     440                 :          0 :     ss << "Bags not available in this configuration, try --bags.";
     441                 :          0 :     throw LogicException(ss.str());
     442                 :          0 :   }
     443         [ +  - ]:      21628 :   Trace("bags") << "TheoryBags::preRegisterTerm(" << n << ")" << std::endl;
     444 [ +  + ][ -  + ]:      21628 :   switch (n.getKind())
     445                 :            :   {
     446                 :       7756 :     case Kind::EQUAL:
     447                 :            :     {
     448                 :            :       // add trigger predicate for equality and membership
     449                 :       7756 :       d_state.addEqualityEngineTriggerPredicate(n);
     450                 :            :     }
     451                 :       7756 :     break;
     452                 :         44 :     case Kind::BAG_MAP:
     453                 :            :     {
     454                 :         44 :       d_state.checkInjectivity(n[0]);
     455                 :         44 :       d_equalityEngine->addTerm(n);
     456                 :         44 :       break;
     457                 :            :     }
     458                 :          0 :     case Kind::BAG_PARTITION:
     459                 :            :     {
     460                 :          0 :       std::stringstream ss;
     461                 :          0 :       ss << "Term of kind " << n.getKind() << " is not supported yet";
     462                 :          0 :       throw LogicException(ss.str());
     463                 :          0 :     }
     464                 :      13828 :     default: d_equalityEngine->addTerm(n); break;
     465                 :            :   }
     466                 :      21628 : }
     467                 :            : 
     468                 :      50461 : void TheoryBags::presolve()
     469                 :            : {
     470         [ +  - ]:      50461 :   Trace("bags-presolve") << "Started presolve" << std::endl;
     471                 :      50461 :   d_strat.initializeStrategy();
     472         [ +  - ]:      50461 :   Trace("bags-presolve") << "Finished presolve" << std::endl;
     473                 :      50461 : }
     474                 :            : 
     475                 :            : /**************************** eq::NotifyClass *****************************/
     476                 :            : 
     477                 :      15688 : void TheoryBags::eqNotifyNewClass(CVC5_UNUSED TNode n) {}
     478                 :            : 
     479                 :      98820 : void TheoryBags::eqNotifyMerge(CVC5_UNUSED TNode n1, CVC5_UNUSED TNode n2) {}
     480                 :            : 
     481                 :      11924 : void TheoryBags::eqNotifyDisequal(CVC5_UNUSED TNode n1,
     482                 :            :                                   CVC5_UNUSED TNode n2,
     483                 :            :                                   CVC5_UNUSED TNode reason)
     484                 :            : {
     485                 :      11924 : }
     486                 :            : 
     487                 :      15688 : void TheoryBags::NotifyClass::eqNotifyNewClass(TNode n)
     488                 :            : {
     489         [ +  - ]:      31376 :   Trace("bags-eq") << "[bags-eq] eqNotifyNewClass:"
     490                 :      15688 :                    << " n = " << n << std::endl;
     491                 :      15688 :   d_theory.eqNotifyNewClass(n);
     492                 :      15688 : }
     493                 :            : 
     494                 :      98820 : void TheoryBags::NotifyClass::eqNotifyMerge(TNode n1, TNode n2)
     495                 :            : {
     496         [ +  - ]:     197640 :   Trace("bags-eq") << "[bags-eq] eqNotifyMerge:"
     497                 :      98820 :                    << " n1 = " << n1 << " n2 = " << n2 << std::endl;
     498                 :      98820 :   d_theory.eqNotifyMerge(n1, n2);
     499                 :      98820 : }
     500                 :            : 
     501                 :      11924 : void TheoryBags::NotifyClass::eqNotifyDisequal(TNode n1, TNode n2, TNode reason)
     502                 :            : {
     503         [ +  - ]:      23848 :   Trace("bags-eq") << "[bags-eq] eqNotifyDisequal:"
     504                 :          0 :                    << " n1 = " << n1 << " n2 = " << n2 << " reason = " << reason
     505                 :      11924 :                    << std::endl;
     506                 :      11924 :   d_theory.eqNotifyDisequal(n1, n2, reason);
     507                 :      11924 : }
     508                 :            : 
     509                 :      18350 : bool TheoryBags::isCareArg(Node n, unsigned a)
     510                 :            : {
     511         [ +  + ]:      18350 :   if (d_equalityEngine->isTriggerTerm(n[a], THEORY_BAGS))
     512                 :            :   {
     513                 :      12164 :     return true;
     514                 :            :   }
     515         [ -  - ]:          0 :   else if ((n.getKind() == Kind::BAG_COUNT || n.getKind() == Kind::BAG_MAKE)
     516                 :       6186 :            && a == 0 && n[0].getType().isBag())
     517                 :            :   {
     518                 :            :     // when the elements themselves are bags
     519                 :          8 :     return true;
     520                 :            :   }
     521                 :       6178 :   return false;
     522                 :            : }
     523                 :            : 
     524                 :      28127 : void TheoryBags::computeCareGraph()
     525                 :            : {
     526         [ +  - ]:      28127 :   Trace("bags-cg") << "Compute graph for bags" << std::endl;
     527         [ +  + ]:      58867 :   for (const std::pair<const Kind, std::vector<Node>>& it : d_opMap)
     528                 :            :   {
     529                 :      30740 :     Kind k = it.first;
     530 [ +  + ][ +  + ]:      30740 :     if (k == Kind::BAG_MAKE || k == Kind::BAG_COUNT)
     531                 :            :     {
     532         [ +  - ]:        656 :       Trace("bags-cg") << "kind: " << k << ", size = " << it.second.size()
     533                 :        328 :                        << std::endl;
     534                 :        328 :       std::map<TypeNode, TNodeTrie> index;
     535                 :        328 :       unsigned arity = 0;
     536                 :            :       // populate indices
     537         [ +  + ]:       8251 :       for (TNode n : it.second)
     538                 :            :       {
     539         [ +  - ]:       7923 :         Trace("bags-cg") << "computing n:  " << n << std::endl;
     540 [ -  + ][ -  + ]:       7923 :         Assert(d_equalityEngine->hasTerm(n));
                 [ -  - ]
     541                 :       7923 :         TypeNode tn;
     542         [ +  + ]:       7923 :         if (k == Kind::BAG_MAKE)
     543                 :            :         {
     544                 :        196 :           tn = n.getType().getBagElementType();
     545                 :            :         }
     546                 :            :         else
     547                 :            :         {
     548 [ -  + ][ -  + ]:       7727 :           Assert(k == Kind::BAG_COUNT);
                 [ -  - ]
     549                 :       7727 :           tn = n[1].getType().getBagElementType();
     550                 :            :         }
     551                 :       7923 :         std::vector<TNode> childrenReps;
     552                 :       7923 :         bool hasCareArg = false;
     553         [ +  + ]:      23769 :         for (unsigned j = 0; j < n.getNumChildren(); j++)
     554                 :            :         {
     555                 :      15846 :           childrenReps.push_back(d_equalityEngine->getRepresentative(n[j]));
     556         [ +  + ]:      15846 :           if (isCareArg(n, j))
     557                 :            :           {
     558                 :      11146 :             hasCareArg = true;
     559                 :            :           }
     560                 :            :         }
     561         [ +  - ]:       7923 :         if (hasCareArg)
     562                 :            :         {
     563         [ +  - ]:      15846 :           Trace("bags-cg") << "addTerm(" << n << ", " << childrenReps << ")"
     564                 :       7923 :                            << std::endl;
     565                 :       7923 :           index[tn].addTerm(n, childrenReps);
     566                 :       7923 :           arity = childrenReps.size();
     567                 :            :         }
     568                 :            :         else
     569                 :            :         {
     570         [ -  - ]:          0 :           Trace("bags-cg") << "......skip." << std::endl;
     571                 :            :         }
     572                 :       7923 :       }
     573         [ +  - ]:        328 :       if (arity > 0)
     574                 :            :       {
     575                 :            :         // for each index
     576         [ +  + ]:        805 :         for (std::pair<const TypeNode, TNodeTrie>& tt : index)
     577                 :            :         {
     578         [ +  - ]:        954 :           Trace("bags-cg") << "Process index " << tt.first << "..."
     579                 :        477 :                            << std::endl;
     580                 :        477 :           nodeTriePathPairProcess(&tt.second, arity, d_cpacb);
     581                 :            :         }
     582                 :            :       }
     583         [ +  - ]:        328 :       Trace("bags-cg") << "...done" << std::endl;
     584                 :        328 :     }
     585                 :            :   }
     586                 :      28127 : }
     587                 :            : 
     588                 :       1722 : void TheoryBags::processCarePairArgs(TNode a, TNode b)
     589                 :            : {
     590                 :            :   // we care about the equality or disequality between x, y
     591                 :            :   // when (bag.count x A) = (bag.count y A)
     592                 :       1722 :   if (a.getKind() != Kind::BAG_COUNT && d_state.areEqual(a, b))
     593                 :            :   {
     594                 :          2 :     return;
     595                 :            :   }
     596                 :            :   // otherwise, we add pairs for each of their arguments
     597                 :       1720 :   addCarePairArgs(a, b);
     598                 :       1720 :   size_t childrenSize = a.getNumChildren();
     599         [ +  + ]:       5160 :   for (size_t i = 0; i < childrenSize; ++i)
     600                 :            :   {
     601                 :       3440 :     TNode x = a[i];
     602                 :       3440 :     TNode y = b[i];
     603         [ +  + ]:       3440 :     if (!d_equalityEngine->areEqual(x, y))
     604                 :            :     {
     605                 :       1826 :       if (isCareArg(a, i) && isCareArg(b, i))
     606                 :            :       {
     607                 :            :         // splitting on bags (necessary for handling bag of bags properly)
     608         [ +  + ]:        348 :         if (x.getType().isBag())
     609                 :            :         {
     610 [ -  + ][ -  + ]:        234 :           Assert(y.getType().isBag());
                 [ -  - ]
     611         [ +  - ]:        468 :           Trace("bags-cg-lemma")
     612                 :        234 :               << "Should split on : " << x << "==" << y << std::endl;
     613                 :        234 :           Node equal = x.eqNode(y);
     614                 :        234 :           Node lemma = equal.orNode(equal.notNode());
     615                 :        234 :           d_im.lemma(lemma, InferenceId::BAGS_CG_SPLIT);
     616                 :        234 :         }
     617                 :            :       }
     618                 :            :     }
     619                 :       3440 :   }
     620                 :            : }
     621                 :            : 
     622                 :            : }  // namespace bags
     623                 :            : }  // namespace theory
     624                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14