LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/bags - inference_generator.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 594 662 89.7 %
Date: 2026-06-02 01:25:26 Functions: 59 66 89.4 %
Branches: 97 278 34.9 %

           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                 :            :  * Inference generator utility.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "inference_generator.h"
      14                 :            : 
      15                 :            : #include "expr/attribute.h"
      16                 :            : #include "expr/bound_var_manager.h"
      17                 :            : #include "expr/dtype_cons.h"
      18                 :            : #include "expr/emptybag.h"
      19                 :            : #include "expr/skolem_manager.h"
      20                 :            : #include "theory/bags/bags_utils.h"
      21                 :            : #include "theory/bags/inference_manager.h"
      22                 :            : #include "theory/bags/solver_state.h"
      23                 :            : #include "theory/datatypes/project_op.h"
      24                 :            : #include "theory/datatypes/tuple_utils.h"
      25                 :            : #include "theory/quantifiers/fmf/bounded_integers.h"
      26                 :            : #include "theory/uf/equality_engine.h"
      27                 :            : #include "util/rational.h"
      28                 :            : 
      29                 :            : using namespace cvc5::internal::kind;
      30                 :            : using namespace cvc5::internal::theory::datatypes;
      31                 :            : 
      32                 :            : namespace cvc5::internal {
      33                 :            : namespace theory {
      34                 :            : namespace bags {
      35                 :            : 
      36                 :     102240 : InferenceGenerator::InferenceGenerator(NodeManager* nm,
      37                 :            :                                        SolverState* state,
      38                 :     102240 :                                        InferenceManager* im)
      39                 :     102240 :     : d_nm(nm), d_sm(d_nm->getSkolemManager()), d_state(state), d_im(im)
      40                 :            : {
      41                 :     102240 :   d_true = d_nm->mkConst(true);
      42                 :     102240 :   d_zero = d_nm->mkConstInt(Rational(0));
      43                 :     102240 :   d_one = d_nm->mkConstInt(Rational(1));
      44                 :     102240 : }
      45                 :            : 
      46                 :      64758 : void InferenceGenerator::registerCountTerm(Node n)
      47                 :            : {
      48 [ -  + ][ -  + ]:      64758 :   Assert(n.getKind() == Kind::BAG_COUNT);
                 [ -  - ]
      49                 :     129516 :   Node element = d_state->getRepresentative(n[0]);
      50                 :     129516 :   Node bag = d_state->getRepresentative(n[1]);
      51                 :     129516 :   Node count = d_nm->mkNode(Kind::BAG_COUNT, element, bag);
      52                 :      64758 :   Node skolem = registerAndAssertSkolemLemma(count);
      53                 :      64758 :   d_state->registerCountTerm(bag, element, skolem);
      54                 :      64758 : }
      55                 :            : 
      56                 :          0 : void InferenceGenerator::registerCardinalityTerm(Node n)
      57                 :            : {
      58                 :          0 :   Assert(n.getKind() == Kind::BAG_CARD);
      59                 :          0 :   Node bag = d_state->getRepresentative(n[0]);
      60                 :          0 :   Node cardTerm = d_nm->mkNode(Kind::BAG_CARD, bag);
      61                 :          0 :   Node skolem = registerAndAssertSkolemLemma(cardTerm);
      62                 :          0 :   d_state->registerCardinalityTerm(cardTerm, skolem);
      63                 :          0 :   Node premise = n[0].eqNode(bag);
      64                 :          0 :   Node conclusion = skolem.eqNode(n);
      65                 :          0 :   Node lemma = premise.notNode().orNode(conclusion);
      66                 :          0 :   d_im->addPendingLemma(lemma, InferenceId::BAGS_SKOLEM);
      67                 :          0 : }
      68                 :            : 
      69                 :      15193 : InferInfo InferenceGenerator::nonNegativeCount(Node n, Node e)
      70                 :            : {
      71 [ -  + ][ -  + ]:      15193 :   Assert(n.getType().isBag());
                 [ -  - ]
      72 [ -  + ][ -  + ]:      60772 :   AssertEqual(e.getType(), n.getType().getBagElementType());
                 [ -  - ]
      73                 :            : 
      74                 :      15193 :   InferInfo inferInfo(d_im, InferenceId::BAGS_NON_NEGATIVE_COUNT);
      75                 :      30386 :   Node count = d_nm->mkNode(Kind::BAG_COUNT, e, n);
      76                 :      30386 :   Node gte = d_nm->mkNode(Kind::GEQ, count, d_zero);
      77                 :      15193 :   inferInfo.d_conclusion = gte;
      78                 :      30386 :   return inferInfo;
      79                 :      15193 : }
      80                 :            : 
      81                 :          0 : InferInfo InferenceGenerator::nonNegativeCardinality(Node n)
      82                 :            : {
      83                 :          0 :   InferInfo inferInfo(d_im, InferenceId::BAGS_NON_NEGATIVE_COUNT);
      84                 :          0 :   Node gte = d_nm->mkNode(Kind::GEQ, n, d_zero);
      85                 :          0 :   inferInfo.d_conclusion = gte;
      86                 :          0 :   return inferInfo;
      87                 :          0 : }
      88                 :            : 
      89                 :         87 : InferInfo InferenceGenerator::bagMake(Node n)
      90                 :            : {
      91 [ -  + ][ -  + ]:         87 :   Assert(n.getKind() == Kind::BAG_MAKE);
                 [ -  - ]
      92                 :            :   /*
      93                 :            :    * (or
      94                 :            :    *   (and (<  c 1) (= (bag x c) (as bag.empty (Bag E))))
      95                 :            :    *   (and (>= c 1) (not (= (bag x c) (as bag.empty (Bag E))))
      96                 :            :    */
      97                 :         87 :   Node x = n[0];
      98                 :         87 :   Node c = n[1];
      99                 :         87 :   InferInfo inferInfo(d_im, InferenceId::BAGS_BAG_MAKE_SPLIT);
     100                 :        174 :   Node empty = d_nm->mkConst(EmptyBag(n.getType()));
     101                 :        174 :   Node equal = d_nm->mkNode(Kind::EQUAL, n, empty);
     102                 :        174 :   Node geq = d_nm->mkNode(Kind::GEQ, c, d_one);
     103                 :         87 :   Node isEmpty = geq.notNode().andNode(equal);
     104                 :         87 :   Node isNotEmpty = geq.andNode(equal.notNode());
     105                 :         87 :   Node orNode = isEmpty.orNode(isNotEmpty);
     106                 :         87 :   inferInfo.d_conclusion = orNode;
     107                 :        174 :   return inferInfo;
     108                 :         87 : }
     109                 :            : 
     110                 :       2194 : InferInfo InferenceGenerator::bagMake(Node n, Node e)
     111                 :            : {
     112 [ -  + ][ -  + ]:       2194 :   Assert(n.getKind() == Kind::BAG_MAKE);
                 [ -  - ]
     113 [ -  + ][ -  + ]:       8776 :   AssertEqual(e.getType(), n.getType().getBagElementType());
                 [ -  - ]
     114                 :            : 
     115                 :            :   /*
     116                 :            :    * (ite (and (= e x) (>= c 1))
     117                 :            :    *   (= (bag.count e skolem) c)
     118                 :            :    *   (= (bag.count e skolem) 0))
     119                 :            :    */
     120                 :       2194 :   Node x = n[0];
     121                 :       2194 :   Node c = n[1];
     122                 :       2194 :   InferInfo inferInfo(d_im, InferenceId::BAGS_BAG_MAKE);
     123                 :       4388 :   Node same = d_nm->mkNode(Kind::EQUAL, e, x);
     124                 :       4388 :   Node geq = d_nm->mkNode(Kind::GEQ, c, d_one);
     125                 :       2194 :   Node andNode = same.andNode(geq);
     126                 :       2194 :   Node skolem = registerAndAssertSkolemLemma(n);
     127                 :       4388 :   Node count = getMultiplicityTerm(e, skolem);
     128                 :       4388 :   Node equalC = d_nm->mkNode(Kind::EQUAL, count, c);
     129                 :       4388 :   Node equalZero = d_nm->mkNode(Kind::EQUAL, count, d_zero);
     130                 :       4388 :   Node ite = d_nm->mkNode(Kind::ITE, andNode, equalC, equalZero);
     131                 :       2194 :   inferInfo.d_conclusion = ite;
     132                 :       4388 :   return inferInfo;
     133                 :       2194 : }
     134                 :            : 
     135                 :       2724 : InferInfo InferenceGenerator::bagDisequality(Node equality, Node witness)
     136                 :            : {
     137                 :       2724 :   Assert(equality.getKind() == Kind::EQUAL && equality[0].getType().isBag());
     138                 :       2724 :   Node A = equality[0];
     139                 :       2724 :   Node B = equality[1];
     140                 :            : 
     141                 :       2724 :   InferInfo inferInfo(d_im, InferenceId::BAGS_DISEQUALITY);
     142                 :            : 
     143                 :       5448 :   Node countA = getMultiplicityTerm(witness, A);
     144                 :       5448 :   Node countB = getMultiplicityTerm(witness, B);
     145                 :            : 
     146                 :       2724 :   Node disequal = countA.eqNode(countB).notNode();
     147                 :            : 
     148                 :       2724 :   inferInfo.d_premises.push_back(equality.notNode());
     149                 :       2724 :   inferInfo.d_conclusion = disequal;
     150                 :       5448 :   return inferInfo;
     151                 :       2724 : }
     152                 :            : 
     153                 :     213372 : Node InferenceGenerator::registerAndAssertSkolemLemma(Node& n)
     154                 :            : {
     155                 :     213372 :   Node skolem = d_sm->mkPurifySkolem(n);
     156                 :     213372 :   Node lemma = n.eqNode(skolem);
     157                 :     213372 :   d_im->addPendingLemma(lemma, InferenceId::BAGS_SKOLEM);
     158         [ +  - ]:     426744 :   Trace("bags-skolems") << "bags-skolems:  " << skolem << " = " << n
     159                 :     213372 :                         << std::endl;
     160                 :     426744 :   return skolem;
     161                 :     213372 : }
     162                 :            : 
     163                 :       1125 : InferInfo InferenceGenerator::empty(Node n, Node e)
     164                 :            : {
     165 [ -  + ][ -  + ]:       1125 :   Assert(n.getKind() == Kind::BAG_EMPTY);
                 [ -  - ]
     166 [ -  + ][ -  + ]:       4500 :   AssertEqual(e.getType(), n.getType().getBagElementType());
                 [ -  - ]
     167                 :            : 
     168                 :       1125 :   InferInfo inferInfo(d_im, InferenceId::BAGS_EMPTY);
     169                 :       1125 :   Node skolem = registerAndAssertSkolemLemma(n);
     170                 :       2250 :   Node count = getMultiplicityTerm(e, skolem);
     171                 :            : 
     172                 :       1125 :   Node equal = count.eqNode(d_zero);
     173                 :       1125 :   inferInfo.d_conclusion = equal;
     174                 :       2250 :   return inferInfo;
     175                 :       1125 : }
     176                 :            : 
     177                 :       1790 : InferInfo InferenceGenerator::unionDisjoint(Node n, Node e)
     178                 :            : {
     179                 :       1790 :   Assert(n.getKind() == Kind::BAG_UNION_DISJOINT && n[0].getType().isBag());
     180 [ -  + ][ -  + ]:       7160 :   AssertEqual(e.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     181                 :            : 
     182                 :       1790 :   Node A = n[0];
     183                 :       1790 :   Node B = n[1];
     184                 :       1790 :   InferInfo inferInfo(d_im, InferenceId::BAGS_UNION_DISJOINT);
     185                 :            : 
     186                 :       3580 :   Node countA = getMultiplicityTerm(e, A);
     187                 :       3580 :   Node countB = getMultiplicityTerm(e, B);
     188                 :            : 
     189                 :       1790 :   Node skolem = registerAndAssertSkolemLemma(n);
     190                 :       3580 :   Node count = getMultiplicityTerm(e, skolem);
     191                 :            : 
     192                 :       3580 :   Node sum = d_nm->mkNode(Kind::ADD, countA, countB);
     193                 :       1790 :   Node equal = count.eqNode(sum);
     194                 :            : 
     195                 :       1790 :   inferInfo.d_conclusion = equal;
     196                 :       3580 :   return inferInfo;
     197                 :       1790 : }
     198                 :            : 
     199                 :        123 : InferInfo InferenceGenerator::unionMax(Node n, Node e)
     200                 :            : {
     201                 :        123 :   Assert(n.getKind() == Kind::BAG_UNION_MAX && n[0].getType().isBag());
     202 [ -  + ][ -  + ]:        492 :   AssertEqual(e.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     203                 :            : 
     204                 :        123 :   Node A = n[0];
     205                 :        123 :   Node B = n[1];
     206                 :        123 :   InferInfo inferInfo(d_im, InferenceId::BAGS_UNION_MAX);
     207                 :            : 
     208                 :        246 :   Node countA = getMultiplicityTerm(e, A);
     209                 :        246 :   Node countB = getMultiplicityTerm(e, B);
     210                 :            : 
     211                 :        123 :   Node skolem = registerAndAssertSkolemLemma(n);
     212                 :        246 :   Node count = getMultiplicityTerm(e, skolem);
     213                 :            : 
     214                 :        246 :   Node gt = d_nm->mkNode(Kind::GT, countA, countB);
     215                 :        246 :   Node max = d_nm->mkNode(Kind::ITE, gt, countA, countB);
     216                 :        123 :   Node equal = count.eqNode(max);
     217                 :            : 
     218                 :        123 :   inferInfo.d_conclusion = equal;
     219                 :        246 :   return inferInfo;
     220                 :        123 : }
     221                 :            : 
     222                 :         51 : InferInfo InferenceGenerator::intersection(Node n, Node e)
     223                 :            : {
     224                 :         51 :   Assert(n.getKind() == Kind::BAG_INTER_MIN && n[0].getType().isBag());
     225 [ -  + ][ -  + ]:        204 :   AssertEqual(e.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     226                 :            : 
     227                 :         51 :   Node A = n[0];
     228                 :         51 :   Node B = n[1];
     229                 :         51 :   InferInfo inferInfo(d_im, InferenceId::BAGS_INTERSECTION_MIN);
     230                 :            : 
     231                 :        102 :   Node countA = getMultiplicityTerm(e, A);
     232                 :        102 :   Node countB = getMultiplicityTerm(e, B);
     233                 :         51 :   Node skolem = registerAndAssertSkolemLemma(n);
     234                 :        102 :   Node count = getMultiplicityTerm(e, skolem);
     235                 :            : 
     236                 :        102 :   Node lt = d_nm->mkNode(Kind::LT, countA, countB);
     237                 :        102 :   Node min = d_nm->mkNode(Kind::ITE, lt, countA, countB);
     238                 :         51 :   Node equal = count.eqNode(min);
     239                 :         51 :   inferInfo.d_conclusion = equal;
     240                 :        102 :   return inferInfo;
     241                 :         51 : }
     242                 :            : 
     243                 :        100 : InferInfo InferenceGenerator::differenceSubtract(Node n, Node e)
     244                 :            : {
     245                 :        100 :   Assert(n.getKind() == Kind::BAG_DIFFERENCE_SUBTRACT
     246                 :            :          && n[0].getType().isBag());
     247 [ -  + ][ -  + ]:        400 :   AssertEqual(e.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     248                 :            : 
     249                 :        100 :   Node A = n[0];
     250                 :        100 :   Node B = n[1];
     251                 :        100 :   InferInfo inferInfo(d_im, InferenceId::BAGS_DIFFERENCE_SUBTRACT);
     252                 :            : 
     253                 :        200 :   Node countA = getMultiplicityTerm(e, A);
     254                 :        200 :   Node countB = getMultiplicityTerm(e, B);
     255                 :        100 :   Node skolem = registerAndAssertSkolemLemma(n);
     256                 :        200 :   Node count = getMultiplicityTerm(e, skolem);
     257                 :            : 
     258                 :        200 :   Node subtract = d_nm->mkNode(Kind::SUB, countA, countB);
     259                 :        200 :   Node gte = d_nm->mkNode(Kind::GEQ, countA, countB);
     260                 :        200 :   Node difference = d_nm->mkNode(Kind::ITE, gte, subtract, d_zero);
     261                 :        100 :   Node equal = count.eqNode(difference);
     262                 :        100 :   inferInfo.d_conclusion = equal;
     263                 :        200 :   return inferInfo;
     264                 :        100 : }
     265                 :            : 
     266                 :        138 : InferInfo InferenceGenerator::differenceRemove(Node n, Node e)
     267                 :            : {
     268                 :        138 :   Assert(n.getKind() == Kind::BAG_DIFFERENCE_REMOVE && n[0].getType().isBag());
     269 [ -  + ][ -  + ]:        552 :   AssertEqual(e.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     270                 :            : 
     271                 :        138 :   Node A = n[0];
     272                 :        138 :   Node B = n[1];
     273                 :        138 :   InferInfo inferInfo(d_im, InferenceId::BAGS_DIFFERENCE_REMOVE);
     274                 :            : 
     275                 :        276 :   Node countA = getMultiplicityTerm(e, A);
     276                 :        276 :   Node countB = getMultiplicityTerm(e, B);
     277                 :            : 
     278                 :        138 :   Node skolem = registerAndAssertSkolemLemma(n);
     279                 :        276 :   Node count = getMultiplicityTerm(e, skolem);
     280                 :            : 
     281                 :        276 :   Node notInB = d_nm->mkNode(Kind::LEQ, countB, d_zero);
     282                 :        276 :   Node difference = d_nm->mkNode(Kind::ITE, notInB, countA, d_zero);
     283                 :        138 :   Node equal = count.eqNode(difference);
     284                 :        138 :   inferInfo.d_conclusion = equal;
     285                 :        276 :   return inferInfo;
     286                 :        138 : }
     287                 :            : 
     288                 :         25 : InferInfo InferenceGenerator::setof(Node n, Node e)
     289                 :            : {
     290                 :         25 :   Assert(n.getKind() == Kind::BAG_SETOF && n[0].getType().isBag());
     291 [ -  + ][ -  + ]:        100 :   AssertEqual(e.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     292                 :            : 
     293                 :         25 :   Node A = n[0];
     294                 :         25 :   InferInfo inferInfo(d_im, InferenceId::BAGS_SETOF);
     295                 :            : 
     296                 :         50 :   Node countA = getMultiplicityTerm(e, A);
     297                 :         25 :   Node skolem = registerAndAssertSkolemLemma(n);
     298                 :         50 :   Node count = getMultiplicityTerm(e, skolem);
     299                 :            : 
     300                 :         50 :   Node gte = d_nm->mkNode(Kind::GEQ, countA, d_one);
     301                 :         50 :   Node ite = d_nm->mkNode(Kind::ITE, gte, d_one, d_zero);
     302                 :         25 :   Node equal = count.eqNode(ite);
     303                 :         25 :   inferInfo.d_conclusion = equal;
     304                 :         50 :   return inferInfo;
     305                 :         25 : }
     306                 :            : 
     307                 :          0 : InferInfo InferenceGenerator::cardEmpty(const std::pair<Node, Node>& pair,
     308                 :            :                                         Node n)
     309                 :            : {
     310                 :          0 :   Assert(pair.first.getKind() == Kind::BAG_CARD);
     311                 :          0 :   Assert(n.getKind() == Kind::BAG_EMPTY
     312                 :            :          && CVC5_EQUAL(n.getType(), pair.first[0].getType()));
     313                 :          0 :   InferInfo inferInfo(d_im, InferenceId::BAGS_CARD_EMPTY);
     314                 :          0 :   Node premise = pair.first[0].eqNode(n);
     315                 :          0 :   Node conclusion = pair.second.eqNode(d_zero);
     316                 :          0 :   inferInfo.d_conclusion = premise.eqNode(conclusion);
     317                 :          0 :   return inferInfo;
     318                 :          0 : }
     319                 :            : 
     320                 :          0 : InferInfo InferenceGenerator::cardBagMake(const std::pair<Node, Node>& pair,
     321                 :            :                                           Node n)
     322                 :            : {
     323                 :          0 :   Assert(pair.first.getKind() == Kind::BAG_CARD);
     324                 :          0 :   Assert(n.getKind() == Kind::BAG_MAKE
     325                 :            :          && CVC5_EQUAL(n.getType(), pair.first[0].getType()));
     326                 :            :   //(=>
     327                 :            :   //  (and (= A (bag x c)) (>= 0 c))
     328                 :            :   //  (= (bag.card A) c))
     329                 :          0 :   Node c = n[1];
     330                 :          0 :   InferInfo inferInfo(d_im, InferenceId::BAGS_CARD);
     331                 :          0 :   Node nonNegative = d_nm->mkNode(Kind::GEQ, c, d_zero);
     332                 :          0 :   Node premise = pair.first[0].eqNode(n).andNode(nonNegative);
     333                 :          0 :   Node conclusion = pair.second.eqNode(c);
     334                 :          0 :   inferInfo.d_conclusion = premise.notNode().orNode(conclusion);
     335                 :          0 :   return inferInfo;
     336                 :          0 : }
     337                 :            : 
     338                 :          0 : InferInfo InferenceGenerator::cardUnionDisjoint(
     339                 :            :     Node premise, Node parent, const std::vector<Node>& children)
     340                 :            : {
     341                 :          0 :   Assert(premise.getType().isBoolean());
     342                 :          0 :   Assert(!children.empty());
     343                 :          0 :   InferInfo inferInfo(d_im, InferenceId::BAGS_CARD);
     344                 :            : 
     345                 :          0 :   std::vector<Node>::const_iterator it = children.cbegin();
     346                 :          0 :   Node child = *it;
     347                 :          0 :   d_state->registerBag(child);
     348                 :          0 :   Node unionDisjoints = child;
     349                 :          0 :   Node card = d_nm->mkNode(Kind::BAG_CARD, child);
     350                 :          0 :   std::vector<Node> lemmas;
     351                 :          0 :   Node sum = registerAndAssertSkolemLemma(card);
     352                 :          0 :   ++it;
     353         [ -  - ]:          0 :   while (it != children.end())
     354                 :            :   {
     355                 :          0 :     child = *it;
     356                 :          0 :     d_state->registerBag(child);
     357                 :            :     unionDisjoints =
     358                 :          0 :         d_nm->mkNode(Kind::BAG_UNION_DISJOINT, unionDisjoints, child);
     359                 :          0 :     card = d_nm->mkNode(Kind::BAG_CARD, child);
     360                 :          0 :     Node skolem = registerAndAssertSkolemLemma(card);
     361                 :          0 :     sum = d_nm->mkNode(Kind::ADD, sum, skolem);
     362                 :          0 :     ++it;
     363                 :          0 :   }
     364                 :          0 :   Node parentCard = d_nm->mkNode(Kind::BAG_CARD, parent);
     365                 :          0 :   Node parentSkolem = registerAndAssertSkolemLemma(parentCard);
     366                 :            : 
     367                 :          0 :   Node bags = parent.eqNode(unionDisjoints);
     368                 :          0 :   lemmas.push_back(bags);
     369                 :          0 :   Node cards = parentSkolem.eqNode(sum);
     370                 :          0 :   lemmas.push_back(cards);
     371                 :          0 :   Node conclusion = d_nm->mkNode(Kind::AND, lemmas);
     372                 :          0 :   inferInfo.d_conclusion = premise.notNode().orNode(conclusion);
     373                 :          0 :   return inferInfo;
     374                 :          0 : }
     375                 :            : 
     376                 :     198257 : Node InferenceGenerator::getMultiplicityTerm(Node element, Node bag)
     377                 :            : {
     378                 :     396514 :   Node count = d_nm->mkNode(Kind::BAG_COUNT, element, bag);
     379                 :     198257 :   return count;
     380                 :            : }
     381                 :            : 
     382                 :         48 : std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDown(Node n, Node e)
     383                 :            : {
     384                 :         48 :   Assert(n.getKind() == Kind::BAG_MAP && n[1].getType().isBag());
     385                 :         48 :   Assert(n[0].getType().isFunction()
     386                 :            :          && n[0].getType().getArgTypes().size() == 1);
     387 [ -  + ][ -  + ]:        192 :   AssertEqual(e.getType(), n[0].getType().getRangeType());
                 [ -  - ]
     388                 :            : 
     389                 :         48 :   InferInfo inferInfo(d_im, InferenceId::BAGS_MAP_DOWN);
     390                 :            : 
     391                 :         48 :   Node f = n[0];
     392                 :         48 :   Node A = n[1];
     393                 :            :   // declare an uninterpreted function uf: Int -> T
     394                 :         48 :   Node uf = d_sm->mkSkolemFunction(SkolemId::BAGS_DISTINCT_ELEMENTS, {A});
     395                 :            : 
     396                 :            :   // declare uninterpreted function sum: Int -> Int
     397                 :        240 :   Node sum = d_sm->mkSkolemFunction(SkolemId::BAGS_MAP_SUM, {f, A, e});
     398                 :            : 
     399                 :            :   // (= (sum 0) 0)
     400                 :         96 :   Node sum_zero = d_nm->mkNode(Kind::APPLY_UF, sum, d_zero);
     401                 :         96 :   Node baseCase = d_nm->mkNode(Kind::EQUAL, sum_zero, d_zero);
     402                 :            : 
     403                 :            :   // guess the size of distinct elements in A
     404                 :            :   Node size =
     405                 :         48 :       d_sm->mkSkolemFunction(SkolemId::BAGS_DISTINCT_ELEMENTS_SIZE, {A});
     406                 :            : 
     407                 :            :   // (= (sum size) (bag.count e skolem))
     408                 :         48 :   Node mapSkolem = registerAndAssertSkolemLemma(n);
     409                 :         96 :   Node countE = getMultiplicityTerm(e, mapSkolem);
     410                 :         96 :   Node totalSum = d_nm->mkNode(Kind::APPLY_UF, sum, size);
     411                 :         96 :   Node totalSumEqualCountE = d_nm->mkNode(Kind::EQUAL, totalSum, countE);
     412                 :            : 
     413                 :         48 :   BoundVarManager* bvm = d_nm->getBoundVarManager();
     414                 :            :   Node i = bvm->mkBoundVar(
     415                 :         96 :       BoundVarId::BAGS_FIRST_INDEX, n, "i", d_nm->integerType());
     416                 :            :   Node j = bvm->mkBoundVar(
     417                 :         96 :       BoundVarId::BAGS_SECOND_INDEX, n, "j", d_nm->integerType());
     418                 :         48 :   Node iList = d_nm->mkNode(Kind::BOUND_VAR_LIST, i);
     419                 :         48 :   Node jList = d_nm->mkNode(Kind::BOUND_VAR_LIST, j);
     420                 :         96 :   Node iPlusOne = d_nm->mkNode(Kind::ADD, i, d_one);
     421                 :         96 :   Node iMinusOne = d_nm->mkNode(Kind::SUB, i, d_one);
     422                 :         96 :   Node uf_i = d_nm->mkNode(Kind::APPLY_UF, uf, i);
     423                 :         96 :   Node uf_j = d_nm->mkNode(Kind::APPLY_UF, uf, j);
     424                 :         96 :   Node f_uf_i = d_nm->mkNode(Kind::APPLY_UF, f, uf_i);
     425                 :         96 :   Node uf_iPlusOne = d_nm->mkNode(Kind::APPLY_UF, uf, iPlusOne);
     426                 :         96 :   Node uf_iMinusOne = d_nm->mkNode(Kind::APPLY_UF, uf, iMinusOne);
     427                 :        144 :   Node interval_i = d_nm->mkNode(
     428                 :            :       Kind::AND,
     429                 :         96 :       {d_nm->mkNode(Kind::GEQ, i, d_one), d_nm->mkNode(Kind::LEQ, i, size)});
     430                 :         96 :   Node sum_i = d_nm->mkNode(Kind::APPLY_UF, sum, i);
     431                 :         96 :   Node sum_iPlusOne = d_nm->mkNode(Kind::APPLY_UF, sum, iPlusOne);
     432                 :         96 :   Node sum_iMinusOne = d_nm->mkNode(Kind::APPLY_UF, sum, iMinusOne);
     433                 :         96 :   Node count_iMinusOne = d_nm->mkNode(Kind::BAG_COUNT, uf_iMinusOne, A);
     434                 :         96 :   Node count_uf_i = d_nm->mkNode(Kind::BAG_COUNT, uf_i, A);
     435                 :            :   Node addMultiplicity = d_nm->mkNode(
     436                 :         96 :       Kind::EQUAL, sum_i, d_nm->mkNode(Kind::ADD, sum_iMinusOne, count_uf_i));
     437                 :         96 :   Node previousValue = d_nm->mkNode(Kind::EQUAL, sum_i, sum_iMinusOne);
     438                 :         96 :   Node f_iEqualE = d_nm->mkNode(Kind::EQUAL, f_uf_i, e);
     439                 :         96 :   Node distinct = d_nm->mkNode(Kind::DISTINCT, f_uf_i, e);
     440                 :         96 :   Node geqOne = d_nm->mkNode(Kind::GEQ, count_uf_i, d_one);
     441                 :            : 
     442                 :            :   // i < j <= size
     443                 :        144 :   Node interval_j = d_nm->mkNode(
     444                 :            :       Kind::AND,
     445                 :         96 :       {d_nm->mkNode(Kind::LT, i, j), d_nm->mkNode(Kind::LEQ, j, size)});
     446                 :            :   // uf(i) != uf(j)
     447                 :         96 :   Node uf_i_equals_uf_j = d_nm->mkNode(Kind::EQUAL, uf_i, uf_j);
     448                 :         96 :   Node notEqual = d_nm->mkNode(Kind::EQUAL, uf_i, uf_j).negate();
     449                 :         96 :   Node body_j = d_nm->mkNode(Kind::OR, interval_j.negate(), notEqual);
     450                 :            :   Node forAll_j =
     451                 :         96 :       quantifiers::BoundedIntegers::mkBoundedForall(d_nm, jList, body_j);
     452                 :        144 :   Node disjunct1 = d_nm->mkNode(Kind::AND, {f_iEqualE, addMultiplicity});
     453                 :        144 :   Node disjunct2 = d_nm->mkNode(Kind::AND, {distinct, previousValue});
     454                 :         48 :   Node orNode = disjunct1.orNode(disjunct2);
     455                 :        192 :   Node andNode = d_nm->mkNode(Kind::AND, {forAll_j, geqOne, orNode});
     456                 :         96 :   Node body_i = d_nm->mkNode(Kind::OR, interval_i.negate(), andNode);
     457                 :            :   Node forAll_i =
     458                 :         96 :       quantifiers::BoundedIntegers::mkBoundedForall(d_nm, iList, body_i);
     459                 :         96 :   Node sizeGTE_zero = d_nm->mkNode(Kind::GEQ, size, d_zero);
     460                 :        240 :   Node conclusion = d_nm->mkNode(
     461                 :         48 :       Kind::AND, {baseCase, totalSumEqualCountE, forAll_i, sizeGTE_zero});
     462                 :         48 :   inferInfo.d_conclusion = conclusion;
     463                 :            : 
     464         [ +  - ]:         96 :   Trace("bags::InferenceGenerator::mapDown")
     465                 :         48 :       << "conclusion: " << inferInfo.d_conclusion << std::endl;
     466                 :         96 :   return std::tuple(inferInfo, uf, size);
     467                 :         48 : }
     468                 :            : 
     469                 :         70 : InferInfo InferenceGenerator::mapDownInjective(Node n, Node y)
     470                 :            : {
     471                 :         70 :   Assert(n.getKind() == Kind::BAG_MAP && n[1].getType().isBag());
     472                 :         70 :   Assert(n[0].getType().isFunction()
     473                 :            :          && n[0].getType().getArgTypes().size() == 1);
     474 [ -  + ][ -  + ]:        280 :   AssertEqual(y.getType(), n[0].getType().getRangeType());
                 [ -  - ]
     475                 :            : 
     476                 :         70 :   InferInfo inferInfo(d_im, InferenceId::BAGS_MAP_DOWN_INJECTIVE);
     477                 :            : 
     478                 :         70 :   Node f = n[0];
     479                 :         70 :   Node A = n[1];
     480                 :            :   // declare a fresh skolem of type T
     481                 :            :   Node x =
     482                 :        350 :       d_sm->mkSkolemFunction(SkolemId::BAGS_MAP_PREIMAGE_INJECTIVE, {f, A, y});
     483                 :            : 
     484                 :         70 :   Node mapSkolem = registerAndAssertSkolemLemma(n);
     485                 :        140 :   Node countY = getMultiplicityTerm(y, mapSkolem);
     486                 :        140 :   Node countX = getMultiplicityTerm(x, A);
     487                 :            : 
     488                 :        140 :   Node f_x = d_nm->mkNode(Kind::APPLY_UF, f, x);
     489                 :         70 :   Node y_equals_f_x = y.eqNode(f_x);
     490                 :        140 :   Node member = d_nm->mkNode(Kind::GEQ, countY, d_one);
     491                 :         70 :   inferInfo.d_premises.push_back(member);
     492                 :            : 
     493                 :         70 :   Node count_x_equals_count_y = countX.eqNode(countY);
     494                 :         70 :   Node conclusion = y_equals_f_x.andNode(count_x_equals_count_y);
     495                 :         70 :   inferInfo.d_conclusion = conclusion;
     496                 :            : 
     497         [ +  - ]:        140 :   Trace("bags::InferenceGenerator::mapDown")
     498                 :         70 :       << "conclusion: " << inferInfo.d_conclusion << std::endl;
     499                 :        140 :   return inferInfo;
     500                 :         70 : }
     501                 :            : 
     502                 :        536 : InferInfo InferenceGenerator::mapUp1(Node n, Node x)
     503                 :            : {
     504                 :        536 :   Assert(n.getKind() == Kind::BAG_MAP && n[1].getType().isBag());
     505                 :        536 :   Assert(n[0].getType().isFunction()
     506                 :            :          && n[0].getType().getArgTypes().size() == 1);
     507                 :            : 
     508                 :        536 :   InferInfo inferInfo(d_im, InferenceId::BAGS_MAP_UP1);
     509                 :        536 :   Node f = n[0];
     510                 :        536 :   Node A = n[1];
     511                 :            : 
     512                 :       1072 :   Node countA = getMultiplicityTerm(x, A);
     513                 :        536 :   registerCountTerm(countA);
     514                 :       1072 :   Node f_x = d_nm->mkNode(Kind::APPLY_UF, f, x);
     515                 :        536 :   Node mapSkolem = registerAndAssertSkolemLemma(n);
     516                 :       1072 :   Node countN = getMultiplicityTerm(f_x, mapSkolem);
     517                 :        536 :   registerCountTerm(countN);
     518                 :       1072 :   Node leq = d_nm->mkNode(Kind::LEQ, countA, countN);
     519                 :        536 :   inferInfo.d_conclusion = leq;
     520                 :       1072 :   return inferInfo;
     521                 :        536 : }
     522                 :            : 
     523                 :        820 : InferInfo InferenceGenerator::mapUp2(Node n, Node uf, Node size, Node y, Node x)
     524                 :            : {
     525                 :        820 :   Assert(n.getKind() == Kind::BAG_MAP && n[1].getType().isBag());
     526                 :        820 :   Assert(n[0].getType().isFunction()
     527                 :            :          && n[0].getType().getArgTypes().size() == 1);
     528                 :            : 
     529                 :        820 :   InferInfo inferInfo(d_im, InferenceId::BAGS_MAP_UP2);
     530                 :        820 :   Node f = n[0];
     531                 :        820 :   Node A = n[1];
     532                 :            : 
     533                 :       1640 :   Node countA = getMultiplicityTerm(x, A);
     534                 :       1640 :   Node xInA = d_nm->mkNode(Kind::GEQ, countA, d_one);
     535                 :            :   Node notEqual =
     536                 :       1640 :       d_nm->mkNode(Kind::EQUAL, d_nm->mkNode(Kind::APPLY_UF, f, x), y).negate();
     537                 :            : 
     538                 :            :   Node k =
     539                 :       5740 :       d_sm->mkSkolemFunction(SkolemId::BAGS_MAP_INDEX, {n, uf, size, y, x});
     540                 :       2460 :   Node inRange = d_nm->mkNode(
     541                 :            :       Kind::AND,
     542                 :       1640 :       {d_nm->mkNode(Kind::GEQ, k, d_one), d_nm->mkNode(Kind::LEQ, k, size)});
     543                 :            :   Node equal =
     544                 :       1640 :       d_nm->mkNode(Kind::EQUAL, d_nm->mkNode(Kind::APPLY_UF, uf, k), x);
     545                 :       1640 :   Node andNode = d_nm->mkNode(Kind::AND, inRange, equal);
     546                 :       1640 :   Node orNode = d_nm->mkNode(Kind::OR, notEqual, andNode);
     547                 :       1640 :   Node implies = d_nm->mkNode(Kind::IMPLIES, xInA, orNode);
     548                 :        820 :   inferInfo.d_conclusion = implies;
     549                 :       1640 :   return inferInfo;
     550                 :        820 : }
     551                 :            : 
     552                 :        916 : InferInfo InferenceGenerator::filterDown(Node n, Node e)
     553                 :            : {
     554                 :        916 :   Assert(n.getKind() == Kind::BAG_FILTER && n[1].getType().isBag());
     555 [ -  + ][ -  + ]:       3664 :   AssertEqual(e.getType(), n[1].getType().getBagElementType());
                 [ -  - ]
     556                 :            : 
     557                 :        916 :   Node P = n[0];
     558                 :        916 :   Node A = n[1];
     559                 :        916 :   InferInfo inferInfo(d_im, InferenceId::BAGS_FILTER_DOWN);
     560                 :            : 
     561                 :       1832 :   Node countA = getMultiplicityTerm(e, A);
     562                 :        916 :   Node skolem = registerAndAssertSkolemLemma(n);
     563                 :       1832 :   Node count = getMultiplicityTerm(e, skolem);
     564                 :            : 
     565                 :       1832 :   Node member = d_nm->mkNode(Kind::GEQ, count, d_one);
     566                 :       1832 :   Node pOfe = d_nm->mkNode(Kind::APPLY_UF, P, e);
     567                 :        916 :   Node equal = count.eqNode(countA);
     568                 :            : 
     569                 :        916 :   inferInfo.d_conclusion = pOfe.andNode(equal);
     570                 :        916 :   inferInfo.d_premises.push_back(member);
     571                 :       1832 :   return inferInfo;
     572                 :        916 : }
     573                 :            : 
     574                 :        916 : InferInfo InferenceGenerator::filterUp(Node n, Node e)
     575                 :            : {
     576                 :        916 :   Assert(n.getKind() == Kind::BAG_FILTER && n[1].getType().isBag());
     577 [ -  + ][ -  + ]:       3664 :   AssertEqual(e.getType(), n[1].getType().getBagElementType());
                 [ -  - ]
     578                 :            : 
     579                 :        916 :   Node P = n[0];
     580                 :        916 :   Node A = n[1];
     581                 :        916 :   InferInfo inferInfo(d_im, InferenceId::BAGS_FILTER_UP);
     582                 :            : 
     583                 :       1832 :   Node countA = getMultiplicityTerm(e, A);
     584                 :        916 :   Node skolem = registerAndAssertSkolemLemma(n);
     585                 :       1832 :   Node count = getMultiplicityTerm(e, skolem);
     586                 :            : 
     587                 :       1832 :   Node member = d_nm->mkNode(Kind::GEQ, countA, d_one);
     588                 :       1832 :   Node pOfe = d_nm->mkNode(Kind::APPLY_UF, P, e);
     589                 :        916 :   Node equal = count.eqNode(countA);
     590                 :        916 :   Node included = pOfe.andNode(equal);
     591                 :        916 :   Node equalZero = count.eqNode(d_zero);
     592                 :        916 :   Node excluded = pOfe.notNode().andNode(equalZero);
     593                 :        916 :   inferInfo.d_conclusion = included.orNode(excluded);
     594                 :        916 :   inferInfo.d_premises.push_back(member);
     595                 :       1832 :   return inferInfo;
     596                 :        916 : }
     597                 :            : 
     598                 :        118 : InferInfo InferenceGenerator::productUp(Node n, Node e1, Node e2)
     599                 :            : {
     600 [ -  + ][ -  + ]:        118 :   Assert(n.getKind() == Kind::TABLE_PRODUCT);
                 [ -  - ]
     601                 :        118 :   Node A = n[0];
     602                 :        118 :   Node B = n[1];
     603                 :        236 :   Node tuple = BagsUtils::constructProductTuple(n, e1, e2);
     604                 :            : 
     605                 :        118 :   InferInfo inferInfo(d_im, InferenceId::TABLES_PRODUCT_UP);
     606                 :            : 
     607                 :        236 :   Node countA = getMultiplicityTerm(e1, A);
     608                 :        236 :   Node countB = getMultiplicityTerm(e2, B);
     609                 :            : 
     610                 :        118 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, countA, d_one));
     611                 :        118 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, countB, d_one));
     612                 :            : 
     613                 :        118 :   Node skolem = registerAndAssertSkolemLemma(n);
     614                 :        236 :   Node count = getMultiplicityTerm(tuple, skolem);
     615                 :            : 
     616                 :        236 :   Node multiply = d_nm->mkNode(Kind::MULT, countA, countB);
     617                 :        118 :   inferInfo.d_conclusion = count.eqNode(multiply);
     618                 :            : 
     619                 :        236 :   return inferInfo;
     620                 :        118 : }
     621                 :            : 
     622                 :        114 : InferInfo InferenceGenerator::productDown(Node n, Node e)
     623                 :            : {
     624 [ -  + ][ -  + ]:        114 :   Assert(n.getKind() == Kind::TABLE_PRODUCT);
                 [ -  - ]
     625 [ -  + ][ -  + ]:        456 :   AssertEqual(e.getType(), n.getType().getBagElementType());
                 [ -  - ]
     626                 :            : 
     627                 :        114 :   Node A = n[0];
     628                 :        114 :   Node B = n[1];
     629                 :            : 
     630                 :        114 :   TypeNode tupleBType = B.getType().getBagElementType();
     631                 :        114 :   TypeNode tupleAType = A.getType().getBagElementType();
     632                 :        114 :   size_t tupleALength = tupleAType.getTupleLength();
     633                 :        114 :   size_t productTupleLength = n.getType().getBagElementType().getTupleLength();
     634                 :            : 
     635                 :        114 :   std::vector<Node> elements = TupleUtils::getTupleElements(e);
     636                 :            :   Node a = TupleUtils::constructTupleFromElements(
     637                 :        114 :       tupleAType, elements, 0, tupleALength - 1);
     638                 :            :   Node b = TupleUtils::constructTupleFromElements(
     639                 :        114 :       tupleBType, elements, tupleALength, productTupleLength - 1);
     640                 :            : 
     641                 :        114 :   InferInfo inferInfo(d_im, InferenceId::TABLES_PRODUCT_DOWN);
     642                 :            : 
     643                 :        228 :   Node countA = getMultiplicityTerm(a, A);
     644                 :        228 :   Node countB = getMultiplicityTerm(b, B);
     645                 :            : 
     646                 :        114 :   Node skolem = registerAndAssertSkolemLemma(n);
     647                 :        228 :   Node count = getMultiplicityTerm(e, skolem);
     648                 :        114 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count, d_one));
     649                 :            : 
     650                 :        228 :   Node multiply = d_nm->mkNode(Kind::MULT, countA, countB);
     651                 :        114 :   inferInfo.d_conclusion = count.eqNode(multiply);
     652                 :            : 
     653                 :        228 :   return inferInfo;
     654                 :        114 : }
     655                 :            : 
     656                 :        174 : InferInfo InferenceGenerator::joinUp(Node n, Node e1, Node e2)
     657                 :            : {
     658 [ -  + ][ -  + ]:        174 :   Assert(n.getKind() == Kind::TABLE_JOIN);
                 [ -  - ]
     659                 :        174 :   Node A = n[0];
     660                 :        174 :   Node B = n[1];
     661                 :        348 :   Node tuple = BagsUtils::constructProductTuple(n, e1, e2);
     662                 :            : 
     663                 :        174 :   std::vector<Node> aElements = TupleUtils::getTupleElements(e1);
     664                 :        174 :   std::vector<Node> bElements = TupleUtils::getTupleElements(e2);
     665                 :            :   const std::vector<uint32_t>& indices =
     666                 :        174 :       n.getOperator().getConst<ProjectOp>().getIndices();
     667                 :            : 
     668                 :        174 :   InferInfo inferInfo(d_im, InferenceId::TABLES_PRODUCT_UP);
     669                 :            : 
     670         [ +  + ]:        348 :   for (size_t i = 0; i < indices.size(); i += 2)
     671                 :            :   {
     672                 :        174 :     Node x = aElements[indices[i]];
     673                 :        174 :     Node y = bElements[indices[i + 1]];
     674                 :        174 :     Node equal = x.eqNode(y);
     675                 :        174 :     inferInfo.d_premises.push_back(equal);
     676                 :        174 :   }
     677                 :            : 
     678                 :        348 :   Node countA = getMultiplicityTerm(e1, A);
     679                 :        348 :   Node countB = getMultiplicityTerm(e2, B);
     680                 :            : 
     681                 :        174 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, countA, d_one));
     682                 :        174 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, countB, d_one));
     683                 :            : 
     684                 :        174 :   Node skolem = registerAndAssertSkolemLemma(n);
     685                 :        348 :   Node count = getMultiplicityTerm(tuple, skolem);
     686                 :            : 
     687                 :        348 :   Node multiply = d_nm->mkNode(Kind::MULT, countA, countB);
     688                 :        174 :   inferInfo.d_conclusion = count.eqNode(multiply);
     689                 :        348 :   return inferInfo;
     690                 :        174 : }
     691                 :            : 
     692                 :        142 : InferInfo InferenceGenerator::joinDown(Node n, Node e)
     693                 :            : {
     694 [ -  + ][ -  + ]:        142 :   Assert(n.getKind() == Kind::TABLE_JOIN);
                 [ -  - ]
     695 [ -  + ][ -  + ]:        568 :   AssertEqual(e.getType(), n.getType().getBagElementType());
                 [ -  - ]
     696                 :            : 
     697                 :        142 :   Node A = n[0];
     698                 :        142 :   Node B = n[1];
     699                 :            : 
     700                 :        142 :   TypeNode tupleBType = B.getType().getBagElementType();
     701                 :        142 :   TypeNode tupleAType = A.getType().getBagElementType();
     702                 :        142 :   size_t tupleALength = tupleAType.getTupleLength();
     703                 :        142 :   size_t productTupleLength = n.getType().getBagElementType().getTupleLength();
     704                 :            : 
     705                 :        142 :   std::vector<Node> elements = TupleUtils::getTupleElements(e);
     706                 :            :   Node a = TupleUtils::constructTupleFromElements(
     707                 :        142 :       tupleAType, elements, 0, tupleALength - 1);
     708                 :            :   Node b = TupleUtils::constructTupleFromElements(
     709                 :        142 :       tupleBType, elements, tupleALength, productTupleLength - 1);
     710                 :            : 
     711                 :        142 :   InferInfo inferInfo(d_im, InferenceId::TABLES_JOIN_DOWN);
     712                 :            : 
     713                 :        284 :   Node countA = getMultiplicityTerm(a, A);
     714                 :        284 :   Node countB = getMultiplicityTerm(b, B);
     715                 :            : 
     716                 :        142 :   Node skolem = registerAndAssertSkolemLemma(n);
     717                 :        284 :   Node count = getMultiplicityTerm(e, skolem);
     718                 :        142 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count, d_one));
     719                 :            : 
     720                 :        284 :   Node multiply = d_nm->mkNode(Kind::MULT, countA, countB);
     721                 :        142 :   Node multiplicityConstraint = count.eqNode(multiply);
     722                 :            :   const std::vector<uint32_t>& indices =
     723                 :        142 :       n.getOperator().getConst<ProjectOp>().getIndices();
     724                 :        142 :   Node joinConstraints = d_true;
     725         [ +  + ]:        284 :   for (size_t i = 0; i < indices.size(); i += 2)
     726                 :            :   {
     727                 :        142 :     Node x = elements[indices[i]];
     728                 :        142 :     Node y = elements[tupleALength + indices[i + 1]];
     729                 :        142 :     Node equal = x.eqNode(y);
     730                 :        142 :     joinConstraints = joinConstraints.andNode(equal);
     731                 :        142 :   }
     732                 :        142 :   inferInfo.d_conclusion = joinConstraints.andNode(multiplicityConstraint);
     733                 :            : 
     734                 :        284 :   return inferInfo;
     735                 :        142 : }
     736                 :            : 
     737                 :        286 : InferInfo InferenceGenerator::groupNotEmpty(Node n)
     738                 :            : {
     739 [ -  + ][ -  + ]:        286 :   Assert(n.getKind() == Kind::TABLE_GROUP);
                 [ -  - ]
     740                 :            : 
     741                 :        286 :   TypeNode bagType = n.getType();
     742                 :        286 :   Node A = n[0];
     743                 :        572 :   Node emptyPart = d_nm->mkConst(EmptyBag(A.getType()));
     744                 :        286 :   Node skolem = registerAndAssertSkolemLemma(n);
     745                 :        286 :   InferInfo inferInfo(d_im, InferenceId::TABLES_GROUP_NOT_EMPTY);
     746                 :        286 :   Node A_isEmpty = A.eqNode(emptyPart);
     747                 :        286 :   inferInfo.d_premises.push_back(A_isEmpty);
     748                 :        572 :   Node singleton = d_nm->mkNode(Kind::BAG_MAKE, emptyPart, d_one);
     749                 :        286 :   Node groupIsSingleton = skolem.eqNode(singleton);
     750                 :            : 
     751                 :        286 :   inferInfo.d_conclusion = groupIsSingleton;
     752                 :        572 :   return inferInfo;
     753                 :        286 : }
     754                 :            : 
     755                 :       1492 : InferInfo InferenceGenerator::groupUp1(Node n, Node x, Node part)
     756                 :            : {
     757 [ -  + ][ -  + ]:       1492 :   Assert(n.getKind() == Kind::TABLE_GROUP);
                 [ -  - ]
     758 [ -  + ][ -  + ]:       5968 :   AssertEqual(x.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     759                 :            : 
     760                 :       1492 :   Node A = n[0];
     761                 :       1492 :   TypeNode bagType = A.getType();
     762                 :            : 
     763                 :       1492 :   InferInfo inferInfo(d_im, InferenceId::TABLES_GROUP_UP1);
     764                 :       2984 :   Node count_x_A = getMultiplicityTerm(x, A);
     765                 :       2984 :   Node x_member_A = d_nm->mkNode(Kind::GEQ, count_x_A, d_one);
     766                 :       1492 :   inferInfo.d_premises.push_back(x_member_A);
     767                 :            : 
     768                 :       2984 :   Node part_x = d_nm->mkNode(Kind::APPLY_UF, part, x);
     769                 :       1492 :   part_x = registerAndAssertSkolemLemma(part_x);
     770                 :            : 
     771                 :       2984 :   Node count_x_part_x = getMultiplicityTerm(x, part_x);
     772                 :            : 
     773                 :       1492 :   Node sameMultiplicity = count_x_part_x.eqNode(count_x_A);
     774                 :       1492 :   Node skolem = registerAndAssertSkolemLemma(n);
     775                 :       2984 :   Node count_part_x = getMultiplicityTerm(part_x, skolem);
     776                 :       2984 :   Node part_x_member = d_nm->mkNode(Kind::EQUAL, count_part_x, d_one);
     777                 :            : 
     778                 :       1492 :   Node emptyPart = d_nm->mkConst(EmptyBag(bagType));
     779                 :       2984 :   Node count_emptyPart = getMultiplicityTerm(emptyPart, skolem);
     780                 :       1492 :   Node emptyPart_not_member = count_emptyPart.eqNode(d_zero);
     781                 :            : 
     782 [ +  + ][ -  - ]:       7460 :   inferInfo.d_conclusion = d_nm->mkNode(
     783                 :       1492 :       Kind::AND, {sameMultiplicity, part_x_member, emptyPart_not_member});
     784                 :       2984 :   return inferInfo;
     785                 :       1492 : }
     786                 :            : 
     787                 :       1492 : InferInfo InferenceGenerator::groupUp2(Node n, Node x, Node part)
     788                 :            : {
     789 [ -  + ][ -  + ]:       1492 :   Assert(n.getKind() == Kind::TABLE_GROUP);
                 [ -  - ]
     790 [ -  + ][ -  + ]:       5968 :   AssertEqual(x.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     791                 :            : 
     792                 :       1492 :   Node A = n[0];
     793                 :       1492 :   TypeNode bagType = A.getType();
     794                 :            : 
     795                 :       1492 :   InferInfo inferInfo(d_im, InferenceId::TABLES_GROUP_UP2);
     796                 :       2984 :   Node count_x_A = getMultiplicityTerm(x, A);
     797                 :       2984 :   Node x_not_in_A = d_nm->mkNode(Kind::EQUAL, count_x_A, d_zero);
     798                 :       1492 :   inferInfo.d_premises.push_back(x_not_in_A);
     799                 :            : 
     800                 :       2984 :   Node part_x = d_nm->mkNode(Kind::APPLY_UF, part, x);
     801                 :       1492 :   part_x = registerAndAssertSkolemLemma(part_x);
     802                 :       2984 :   Node part_x_is_empty = part_x.eqNode(d_nm->mkConst(EmptyBag(bagType)));
     803                 :       1492 :   inferInfo.d_conclusion = part_x_is_empty;
     804                 :       2984 :   return inferInfo;
     805                 :       1492 : }
     806                 :            : 
     807                 :       3936 : InferInfo InferenceGenerator::groupDown(Node n, Node B, Node x, Node part)
     808                 :            : {
     809 [ -  + ][ -  + ]:       3936 :   Assert(n.getKind() == Kind::TABLE_GROUP);
                 [ -  - ]
     810 [ -  + ][ -  + ]:      15744 :   AssertEqual(B.getType(), n.getType().getBagElementType());
                 [ -  - ]
     811 [ -  + ][ -  + ]:      15744 :   AssertEqual(x.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     812                 :            : 
     813                 :       3936 :   Node A = n[0];
     814                 :       3936 :   TypeNode bagType = A.getType();
     815                 :            : 
     816                 :       3936 :   InferInfo inferInfo(d_im, InferenceId::TABLES_GROUP_DOWN);
     817                 :       7872 :   Node count_x_B = getMultiplicityTerm(x, B);
     818                 :            : 
     819                 :       3936 :   Node skolem = registerAndAssertSkolemLemma(n);
     820                 :       7872 :   Node count_B_n = getMultiplicityTerm(B, skolem);
     821                 :       3936 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_B_n, d_one));
     822                 :       3936 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_x_B, d_one));
     823                 :       7872 :   Node count_x_A = getMultiplicityTerm(x, A);
     824                 :       3936 :   Node sameMultiplicity = count_x_B.eqNode(count_x_A);
     825                 :       7872 :   Node part_x = d_nm->mkNode(Kind::APPLY_UF, part, x);
     826                 :       3936 :   part_x = registerAndAssertSkolemLemma(part_x);
     827                 :       3936 :   Node part_x_is_B = part_x.eqNode(B);
     828                 :            :   inferInfo.d_conclusion =
     829                 :       3936 :       d_nm->mkNode(Kind::AND, sameMultiplicity, part_x_is_B);
     830                 :       7872 :   return inferInfo;
     831                 :       3936 : }
     832                 :            : 
     833                 :        154 : InferInfo InferenceGenerator::groupPartCount(Node n, Node B, Node part)
     834                 :            : {
     835 [ -  + ][ -  + ]:        154 :   Assert(n.getKind() == Kind::TABLE_GROUP);
                 [ -  - ]
     836 [ -  + ][ -  + ]:        616 :   AssertEqual(B.getType(), n.getType().getBagElementType());
                 [ -  - ]
     837                 :            : 
     838                 :        154 :   Node A = n[0];
     839                 :        154 :   TypeNode bagType = A.getType();
     840                 :        154 :   Node empty = d_nm->mkConst(EmptyBag(bagType));
     841                 :            : 
     842                 :        154 :   InferInfo inferInfo(d_im, InferenceId::TABLES_GROUP_PART_COUNT);
     843                 :            : 
     844                 :        154 :   Node skolem = registerAndAssertSkolemLemma(n);
     845                 :        308 :   Node count_B_n = getMultiplicityTerm(B, skolem);
     846                 :        154 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_B_n, d_one));
     847                 :        154 :   Node A_notEmpty = A.eqNode(empty).notNode();
     848                 :        154 :   inferInfo.d_premises.push_back(A_notEmpty);
     849                 :            : 
     850                 :        616 :   Node x = d_sm->mkSkolemFunction(SkolemId::TABLES_GROUP_PART_ELEMENT, {n, B});
     851                 :        154 :   d_state->registerPartElementSkolem(n, x);
     852                 :        308 :   Node part_x = d_nm->mkNode(Kind::APPLY_UF, part, x);
     853                 :        154 :   part_x = registerAndAssertSkolemLemma(part_x);
     854                 :        154 :   Node B_is_part_x = B.eqNode(part_x);
     855                 :        308 :   Node count_x_A = getMultiplicityTerm(x, A);
     856                 :        308 :   Node count_x_B = getMultiplicityTerm(x, B);
     857                 :        154 :   Node sameMultiplicity = count_x_A.eqNode(count_x_B);
     858                 :        308 :   Node x_in_B = d_nm->mkNode(Kind::GEQ, count_x_B, d_one);
     859                 :        154 :   Node count_B_n_is_one = count_B_n.eqNode(d_one);
     860 [ +  + ][ -  - ]:        924 :   inferInfo.d_conclusion = d_nm->mkNode(Kind::AND,
     861                 :            :                                         {
     862                 :            :                                             count_B_n_is_one,
     863                 :            :                                             B_is_part_x,
     864                 :            :                                             x_in_B,
     865                 :            :                                             sameMultiplicity,
     866                 :        154 :                                         });
     867                 :        308 :   return inferInfo;
     868                 :        154 : }
     869                 :            : 
     870                 :      13740 : InferInfo InferenceGenerator::groupSameProjection(
     871                 :            :     Node n, Node B, Node x, Node y, Node part)
     872                 :            : {
     873 [ -  + ][ -  + ]:      13740 :   Assert(n.getKind() == Kind::TABLE_GROUP);
                 [ -  - ]
     874 [ -  + ][ -  + ]:      54960 :   AssertEqual(B.getType(), n.getType().getBagElementType());
                 [ -  - ]
     875 [ -  + ][ -  + ]:      54960 :   AssertEqual(x.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     876 [ -  + ][ -  + ]:      54960 :   AssertEqual(y.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     877                 :            : 
     878                 :      13740 :   Node A = n[0];
     879                 :      13740 :   TypeNode bagType = A.getType();
     880                 :            : 
     881                 :      13740 :   InferInfo inferInfo(d_im, InferenceId::TABLES_GROUP_SAME_PROJECTION);
     882                 :      27480 :   Node count_x_B = getMultiplicityTerm(x, B);
     883                 :      27480 :   Node count_y_B = getMultiplicityTerm(y, B);
     884                 :            : 
     885                 :      13740 :   Node skolem = registerAndAssertSkolemLemma(n);
     886                 :      27480 :   Node count_B_n = getMultiplicityTerm(B, skolem);
     887                 :            : 
     888                 :            :   // premises
     889                 :      13740 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_B_n, d_one));
     890                 :      13740 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_x_B, d_one));
     891                 :      13740 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_y_B, d_one));
     892                 :      13740 :   inferInfo.d_premises.push_back(x.eqNode(y).notNode());
     893                 :            : 
     894                 :            :   const std::vector<uint32_t>& indices =
     895                 :      13740 :       n.getOperator().getConst<ProjectOp>().getIndices();
     896                 :            : 
     897                 :      13740 :   Node xProjection = TupleUtils::getTupleProjection(indices, x);
     898                 :      13740 :   Node yProjection = TupleUtils::getTupleProjection(indices, y);
     899                 :      13740 :   Node sameProjection = xProjection.eqNode(yProjection);
     900                 :      27480 :   Node part_x = d_nm->mkNode(Kind::APPLY_UF, part, x);
     901                 :      13740 :   part_x = registerAndAssertSkolemLemma(part_x);
     902                 :      27480 :   Node part_y = d_nm->mkNode(Kind::APPLY_UF, part, y);
     903                 :      13740 :   part_y = registerAndAssertSkolemLemma(part_y);
     904                 :      13740 :   Node samePart = part_x.eqNode(part_y);
     905                 :      13740 :   Node part_x_is_B = part_x.eqNode(B);
     906                 :            :   inferInfo.d_conclusion =
     907                 :      13740 :       d_nm->mkNode(Kind::AND, sameProjection, samePart, part_x_is_B);
     908                 :      27480 :   return inferInfo;
     909                 :      13740 : }
     910                 :            : 
     911                 :      28624 : InferInfo InferenceGenerator::groupSamePart(
     912                 :            :     Node n, Node B, Node x, Node y, Node part)
     913                 :            : {
     914 [ -  + ][ -  + ]:      28624 :   Assert(n.getKind() == Kind::TABLE_GROUP);
                 [ -  - ]
     915 [ -  + ][ -  + ]:     114496 :   AssertEqual(B.getType(), n.getType().getBagElementType());
                 [ -  - ]
     916 [ -  + ][ -  + ]:     114496 :   AssertEqual(x.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     917 [ -  + ][ -  + ]:     114496 :   AssertEqual(y.getType(), n[0].getType().getBagElementType());
                 [ -  - ]
     918                 :            : 
     919                 :      28624 :   Node A = n[0];
     920                 :      28624 :   TypeNode bagType = A.getType();
     921                 :            : 
     922                 :      28624 :   InferInfo inferInfo(d_im, InferenceId::TABLES_GROUP_SAME_PART);
     923                 :      57248 :   Node count_x_B = getMultiplicityTerm(x, B);
     924                 :      57248 :   Node count_y_A = getMultiplicityTerm(y, A);
     925                 :      57248 :   Node count_y_B = getMultiplicityTerm(y, B);
     926                 :            : 
     927                 :      28624 :   Node skolem = registerAndAssertSkolemLemma(n);
     928                 :      57248 :   Node count_B_n = getMultiplicityTerm(B, skolem);
     929                 :            :   const std::vector<uint32_t>& indices =
     930                 :      28624 :       n.getOperator().getConst<ProjectOp>().getIndices();
     931                 :            : 
     932                 :      28624 :   Node xProjection = TupleUtils::getTupleProjection(indices, x);
     933                 :      28624 :   Node yProjection = TupleUtils::getTupleProjection(indices, y);
     934                 :            : 
     935                 :            :   // premises
     936                 :      28624 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_B_n, d_one));
     937                 :      28624 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_x_B, d_one));
     938                 :      28624 :   inferInfo.d_premises.push_back(d_nm->mkNode(Kind::GEQ, count_y_A, d_one));
     939                 :      28624 :   inferInfo.d_premises.push_back(x.eqNode(y).notNode());
     940                 :      28624 :   inferInfo.d_premises.push_back(xProjection.eqNode(yProjection));
     941                 :            : 
     942                 :      28624 :   Node sameMultiplicity = count_y_B.eqNode(count_y_A);
     943                 :      57248 :   Node part_x = d_nm->mkNode(Kind::APPLY_UF, part, x);
     944                 :      28624 :   part_x = registerAndAssertSkolemLemma(part_x);
     945                 :      57248 :   Node part_y = d_nm->mkNode(Kind::APPLY_UF, part, y);
     946                 :      28624 :   part_y = registerAndAssertSkolemLemma(part_y);
     947                 :      28624 :   Node samePart = part_x.eqNode(part_y);
     948                 :      28624 :   Node part_x_is_B = part_x.eqNode(B);
     949                 :            :   inferInfo.d_conclusion =
     950                 :      28624 :       d_nm->mkNode(Kind::AND, sameMultiplicity, samePart, part_x_is_B);
     951                 :            : 
     952                 :      57248 :   return inferInfo;
     953                 :      28624 : }
     954                 :            : 
     955                 :        286 : Node InferenceGenerator::defineSkolemPartFunction(Node n)
     956                 :            : {
     957 [ -  + ][ -  + ]:        286 :   Assert(n.getKind() == Kind::TABLE_GROUP);
                 [ -  - ]
     958                 :        286 :   Node A = n[0];
     959                 :        286 :   TypeNode tableType = A.getType();
     960                 :        286 :   TypeNode elementType = tableType.getBagElementType();
     961                 :            : 
     962                 :            :   // declare an uninterpreted function part: T -> (Table T)
     963                 :        286 :   Node part = d_sm->mkSkolemFunction(SkolemId::TABLES_GROUP_PART, {n});
     964                 :        572 :   return part;
     965                 :        286 : }
     966                 :            : 
     967                 :            : }  // namespace bags
     968                 :            : }  // namespace theory
     969                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14