LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/sets - cardinality_extension.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 591 646 91.5 %
Date: 2026-03-05 11:40:39 Functions: 17 17 100.0 %
Branches: 449 645 69.6 %

           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                 :            :  * Implementation of an extension of the theory sets for handling
      11                 :            :  * cardinality constraints.
      12                 :            :  */
      13                 :            : 
      14                 :            : #include "theory/sets/cardinality_extension.h"
      15                 :            : 
      16                 :            : #include "expr/emptyset.h"
      17                 :            : #include "expr/node_algorithm.h"
      18                 :            : #include "expr/skolem_manager.h"
      19                 :            : #include "options/sets_options.h"
      20                 :            : #include "smt/logic_exception.h"
      21                 :            : #include "theory/rewriter.h"
      22                 :            : #include "theory/sets/normal_form.h"
      23                 :            : #include "theory/theory_model.h"
      24                 :            : #include "theory/valuation.h"
      25                 :            : #include "util/cardinality.h"
      26                 :            : #include "util/rational.h"
      27                 :            : 
      28                 :            : using namespace std;
      29                 :            : using namespace cvc5::internal::kind;
      30                 :            : 
      31                 :            : namespace cvc5::internal {
      32                 :            : namespace theory {
      33                 :            : namespace sets {
      34                 :            : 
      35                 :      49982 : CardinalityExtension::CardinalityExtension(Env& env,
      36                 :            :                                            SolverState& s,
      37                 :            :                                            InferenceManager& im,
      38                 :      49982 :                                            TermRegistry& treg)
      39                 :            :     : EnvObj(env),
      40                 :      49982 :       d_state(s),
      41                 :      49982 :       d_im(im),
      42                 :      49982 :       d_treg(treg),
      43                 :      49982 :       d_card_processed(userContext()),
      44                 :      99964 :       d_finite_type_constants_processed(false)
      45                 :            : {
      46                 :      49982 :   d_true = nodeManager()->mkConst(true);
      47                 :      49982 :   d_zero = nodeManager()->mkConstInt(Rational(0));
      48                 :      49982 : }
      49                 :            : 
      50                 :      59270 : void CardinalityExtension::reset()
      51                 :            : {
      52                 :      59270 :   d_eqc_to_card_term.clear();
      53                 :      59270 :   d_t_card_enabled.clear();
      54                 :      59270 :   d_finite_type_elements.clear();
      55                 :      59270 :   d_finite_type_constants_processed = false;
      56                 :      59270 :   d_finite_type_slack_elements.clear();
      57                 :      59270 :   d_univProxy.clear();
      58                 :      59270 : }
      59                 :     138912 : void CardinalityExtension::registerTerm(Node n)
      60                 :            : {
      61         [ +  - ]:     138912 :   Trace("sets-card-debug") << "Register term : " << n << std::endl;
      62 [ -  + ][ -  + ]:     138912 :   Assert(n.getKind() == Kind::SET_CARD);
                 [ -  - ]
      63                 :     277824 :   TypeNode tnc = n[0].getType().getSetElementType();
      64                 :     138912 :   d_t_card_enabled[tnc] = true;
      65                 :     277824 :   Node r = d_state.getRepresentative(n[0]);
      66         [ +  + ]:     138912 :   if (d_eqc_to_card_term.find(r) == d_eqc_to_card_term.end())
      67                 :            :   {
      68                 :      85017 :     d_eqc_to_card_term[r] = n;
      69                 :      85017 :     registerCardinalityTerm(n[0]);
      70                 :            :   }
      71         [ +  - ]:     138912 :   Trace("sets-card-debug") << "...finished register term" << std::endl;
      72                 :     138912 : }
      73                 :            : 
      74                 :       3668 : void CardinalityExtension::checkCardinalityExtended()
      75                 :            : {
      76         [ +  + ]:       7335 :   for (std::pair<const TypeNode, bool>& pair : d_t_card_enabled)
      77                 :            :   {
      78                 :       3668 :     TypeNode type = pair.first;
      79         [ +  - ]:       3668 :     if (pair.second)
      80                 :            :     {
      81                 :       3668 :       checkCardinalityExtended(type);
      82                 :            :     }
      83                 :       3668 :   }
      84                 :       3667 : }
      85                 :            : 
      86                 :       3668 : void CardinalityExtension::checkCardinalityExtended(TypeNode& t)
      87                 :            : {
      88                 :       3668 :   NodeManager* nm = nodeManager();
      89                 :       3668 :   TypeNode setType = nm->mkSetType(t);
      90                 :       3668 :   bool finiteType = d_env.isFiniteType(t);
      91                 :            :   // skip infinite types that do not have univset terms
      92                 :       3668 :   if (!finiteType && d_state.getUnivSetEqClass(setType).isNull())
      93                 :            :   {
      94                 :       2045 :     return;
      95                 :            :   }
      96                 :            : 
      97                 :            :   // get the cardinality of the finite type t
      98                 :       1623 :   Cardinality card = t.getCardinality();
      99                 :            : 
     100                 :            :   // cardinality of an interpreted finite type t is infinite when t
     101                 :            :   // is infinite without --fmf
     102 [ +  + ][ +  + ]:       1623 :   if (finiteType && card.isInfinite())
                 [ +  + ]
     103                 :            :   {
     104                 :            :     // TODO (#1123): support uninterpreted sorts with --finite-model-find
     105                 :          1 :     std::stringstream message;
     106                 :          1 :     message << "The cardinality " << card << " of the finite type " << t
     107                 :          1 :             << " is not supported yet.";
     108                 :          1 :     throw LogicException(message.str());
     109                 :          1 :   }
     110                 :            : 
     111                 :            :   // here we call getUnivSet instead of getUnivSetEqClass to generate
     112                 :            :   // a univset term for finite types even if they are not used in the input
     113                 :       1622 :   Node univ = d_treg.getUnivSet(setType);
     114                 :       1622 :   std::map<Node, Node>::iterator it = d_univProxy.find(univ);
     115                 :            : 
     116                 :       1622 :   Node proxy;
     117                 :            : 
     118         [ +  - ]:       1622 :   if (it == d_univProxy.end())
     119                 :            :   {
     120                 :            :     // Force cvc5 to build the cardinality graph for the universe set
     121                 :       1622 :     proxy = d_treg.getProxy(univ);
     122                 :       1622 :     d_univProxy[univ] = proxy;
     123                 :            :   }
     124                 :            :   else
     125                 :            :   {
     126                 :          0 :     proxy = it->second;
     127                 :            :   }
     128                 :            : 
     129                 :            :   // get all equivalent classes of type t
     130                 :       1622 :   vector<Node> representatives = d_state.getSetsEqClasses(t);
     131                 :            : 
     132         [ +  + ]:       1622 :   if (finiteType)
     133                 :            :   {
     134                 :            :     Node typeCardinality =
     135                 :       2370 :         nm->mkConstInt(Rational(card.getFiniteCardinality()));
     136                 :       1185 :     Node cardUniv = nm->mkNode(Kind::SET_CARD, proxy);
     137                 :       2370 :     Node leq = nm->mkNode(Kind::LEQ, cardUniv, typeCardinality);
     138                 :            : 
     139                 :            :     // (=> true (<= (card (as univset t)) cardUniv)
     140         [ +  - ]:       1185 :     if (!d_state.isEntailed(leq, true))
     141                 :            :     {
     142                 :       1185 :       d_im.assertInference(leq, InferenceId::SETS_CARD_UNIV_TYPE, d_true, 1);
     143                 :            :     }
     144                 :       1185 :   }
     145                 :            : 
     146                 :            :   // add subset lemmas for sets and membership lemmas for negative members
     147         [ +  + ]:      15668 :   for (Node& representative : representatives)
     148                 :            :   {
     149                 :            :     // the universe set is a subset of itself
     150         [ +  + ]:      14046 :     if (representative != d_state.getRepresentative(univ))
     151                 :            :     {
     152                 :            :       // here we only add representatives with variables to avoid adding
     153                 :            :       // infinite equivalent generated terms to the cardinality graph
     154                 :      12445 :       Node variable = d_state.getVariableSet(representative);
     155         [ +  + ]:      12445 :       if (variable.isNull())
     156                 :            :       {
     157                 :       9289 :         continue;
     158                 :            :       }
     159                 :            : 
     160                 :            :       // (=> true (subset representative (as univset t))
     161                 :       6312 :       Node subset = nm->mkNode(Kind::SET_SUBSET, variable, proxy);
     162                 :            :       // subset terms are rewritten as union terms: (subset A B) implies (=
     163                 :            :       // (union A B) B)
     164                 :       3156 :       subset = rewrite(subset);
     165         [ +  + ]:       3156 :       if (!d_state.isEntailed(subset, true))
     166                 :            :       {
     167                 :        215 :         d_im.assertInference(
     168                 :        215 :             subset, InferenceId::SETS_CARD_UNIV_SUPERSET, d_true, 1);
     169                 :            :       }
     170                 :            : 
     171                 :            :       // negative members are members in the universe set
     172                 :            :       const std::map<Node, Node>& negativeMembers =
     173                 :       3156 :           d_state.getNegativeMembers(representative);
     174                 :            : 
     175         [ +  + ]:       7424 :       for (const auto& negativeMember : negativeMembers)
     176                 :            :       {
     177                 :       8536 :         Node member = nm->mkNode(Kind::SET_MEMBER, negativeMember.first, univ);
     178                 :            :         // negativeMember.second is the reason for the negative membership and
     179                 :            :         // has kind SET_MEMBER. So we specify the negation as the reason for the
     180                 :            :         // negative membership lemma
     181                 :       4268 :         Node notMember = nm->mkNode(Kind::NOT, negativeMember.second);
     182                 :            :         // (=>
     183                 :            :         //    (not (member negativeMember representative)))
     184                 :            :         //    (member negativeMember (as univset t)))
     185                 :       4268 :         d_im.assertInference(
     186                 :            :             member, InferenceId::SETS_CARD_NEGATIVE_MEMBER, notMember, 1);
     187                 :       4268 :       }
     188         [ +  + ]:      12445 :     }
     189                 :            :   }
     190         [ +  + ]:       3669 : }
     191                 :            : 
     192                 :       3668 : void CardinalityExtension::check()
     193                 :            : {
     194                 :       3668 :   checkCardinalityExtended();
     195                 :       3667 :   checkRegister();
     196         [ +  + ]:       3667 :   if (d_im.hasSent())
     197                 :            :   {
     198                 :       3540 :     return;
     199                 :            :   }
     200                 :       3073 :   checkMinCard();
     201         [ +  + ]:       3073 :   if (d_im.hasSent())
     202                 :            :   {
     203                 :        958 :     return;
     204                 :            :   }
     205                 :       2115 :   checkCardCycles();
     206         [ +  + ]:       2115 :   if (d_im.hasSent())
     207                 :            :   {
     208                 :        827 :     return;
     209                 :            :   }
     210                 :            :   // The last step will either do nothing (in which case we are SAT), or request
     211                 :            :   // that a new set term is introduced.
     212                 :       1288 :   std::vector<Node> intro_sets;
     213                 :       1288 :   checkNormalForms(intro_sets);
     214         [ +  + ]:       1288 :   if (intro_sets.empty())
     215                 :            :   {
     216                 :       1161 :     return;
     217                 :            :   }
     218 [ -  + ][ -  + ]:        127 :   Assert(intro_sets.size() == 1);
                 [ -  - ]
     219         [ +  - ]:        127 :   Trace("sets-intro") << "Introduce term : " << intro_sets[0] << std::endl;
     220         [ +  - ]:        127 :   Trace("sets-intro") << "  Actual Intro : ";
     221                 :        127 :   d_treg.debugPrintSet(intro_sets[0], "sets-nf");
     222         [ +  - ]:        127 :   Trace("sets-nf") << std::endl;
     223                 :        127 :   Node k = d_treg.getProxy(intro_sets[0]);
     224 [ -  + ][ -  + ]:        127 :   AlwaysAssert(!k.isNull());
                 [ -  - ]
     225         [ +  + ]:       1288 : }
     226                 :            : 
     227                 :       3667 : void CardinalityExtension::checkRegister()
     228                 :            : {
     229         [ +  - ]:       3667 :   Trace("sets") << "Cardinality graph..." << std::endl;
     230                 :       3667 :   NodeManager* nm = nodeManager();
     231                 :            :   // first, ensure cardinality relationships are added as lemmas for all
     232                 :            :   // non-basic set terms
     233                 :       3667 :   const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
     234         [ +  + ]:      42550 :   for (const Node& eqc : setEqc)
     235                 :            :   {
     236                 :      38883 :     const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
     237         [ +  + ]:      89775 :     for (Node n : nvsets)
     238                 :            :     {
     239         [ +  + ]:      50892 :       if (!d_state.isCongruent(n))
     240                 :            :       {
     241                 :            :         // if setminus, do for intersection instead
     242         [ +  + ]:      49559 :         if (n.getKind() == Kind::SET_MINUS)
     243                 :            :         {
     244                 :      25162 :           n = rewrite(nm->mkNode(Kind::SET_INTER, n[0], n[1]));
     245                 :            :         }
     246                 :      49559 :         registerCardinalityTerm(n);
     247                 :            :       }
     248                 :      50892 :     }
     249                 :            :   }
     250         [ +  - ]:       3667 :   Trace("sets") << "Done cardinality graph" << std::endl;
     251                 :       3667 : }
     252                 :            : 
     253                 :     134576 : void CardinalityExtension::registerCardinalityTerm(Node n)
     254                 :            : {
     255                 :     134576 :   TypeNode tnc = n.getType().getSetElementType();
     256         [ +  + ]:     134576 :   if (d_t_card_enabled.find(tnc) == d_t_card_enabled.end())
     257                 :            :   {
     258                 :            :     // if no cardinality constraints for sets of this type, we can ignore
     259                 :        238 :     return;
     260                 :            :   }
     261         [ +  + ]:     134338 :   if (d_card_processed.find(n) != d_card_processed.end())
     262                 :            :   {
     263                 :            :     // already processed
     264                 :     130981 :     return;
     265                 :            :   }
     266                 :       3357 :   d_card_processed.insert(n);
     267                 :       3357 :   NodeManager* nm = nodeManager();
     268         [ +  - ]:       3357 :   Trace("sets-card") << "Cardinality lemmas for " << n << " : " << std::endl;
     269                 :       3357 :   std::vector<Node> cterms;
     270         [ +  + ]:       3357 :   if (n.getKind() == Kind::SET_INTER)
     271                 :            :   {
     272         [ +  + ]:       1905 :     for (unsigned e = 0; e < 2; e++)
     273                 :            :     {
     274                 :       2540 :       Node s = nm->mkNode(Kind::SET_MINUS, n[e], n[1 - e]);
     275                 :       1270 :       cterms.push_back(s);
     276                 :       1270 :     }
     277                 :       1270 :     Node pos_lem = nm->mkNode(Kind::GEQ, nm->mkNode(Kind::SET_CARD, n), d_zero);
     278                 :        635 :     d_im.assertInference(
     279                 :        635 :         pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1);
     280                 :        635 :   }
     281                 :            :   else
     282                 :            :   {
     283                 :       2722 :     cterms.push_back(n);
     284                 :            :   }
     285         [ +  + ]:       7349 :   for (unsigned k = 0, csize = cterms.size(); k < csize; k++)
     286                 :            :   {
     287                 :       3992 :     Node nn = cterms[k];
     288                 :       3992 :     Node nk = d_treg.getProxy(nn);
     289                 :            :     Node pos_lem =
     290                 :       7984 :         nm->mkNode(Kind::GEQ, nm->mkNode(Kind::SET_CARD, nk), d_zero);
     291                 :       3992 :     d_im.assertInference(
     292                 :       3992 :         pos_lem, InferenceId::SETS_CARD_POSITIVE, d_emp_exp, 1);
     293         [ +  + ]:       3992 :     if (nn != nk)
     294                 :            :     {
     295                 :            :       Node lem = nm->mkNode(Kind::EQUAL,
     296                 :       3916 :                             nm->mkNode(Kind::SET_CARD, nk),
     297                 :       7832 :                             nm->mkNode(Kind::SET_CARD, nn));
     298                 :       1958 :       lem = rewrite(lem);
     299         [ +  - ]:       1958 :       Trace("sets-card") << "  " << k << " : " << lem << std::endl;
     300                 :       1958 :       d_im.assertInference(lem, InferenceId::SETS_CARD_EQUAL, d_emp_exp, 1);
     301                 :       1958 :     }
     302                 :       3992 :   }
     303                 :       3357 :   d_im.doPendingLemmas();
     304         [ +  + ]:     134576 : }
     305                 :            : 
     306                 :       2115 : void CardinalityExtension::checkCardCycles()
     307                 :            : {
     308         [ +  - ]:       2115 :   Trace("sets") << "Check cardinality cycles..." << std::endl;
     309                 :            :   // build order of equivalence classes, also build cardinality graph
     310                 :       2115 :   const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
     311                 :       2115 :   d_oSetEqc.clear();
     312                 :       2115 :   d_cardParent.clear();
     313         [ +  + ]:      19224 :   for (const Node& s : setEqc)
     314                 :            :   {
     315                 :      17936 :     std::vector<Node> curr;
     316                 :      17936 :     std::vector<Node> exp;
     317                 :      17936 :     checkCardCyclesRec(s, curr, exp);
     318         [ +  + ]:      17936 :     if (d_im.hasSent())
     319                 :            :     {
     320                 :        827 :       return;
     321                 :            :     }
     322 [ +  + ][ +  + ]:      18763 :   }
     323                 :            : 
     324         [ +  - ]:       1288 :   Trace("sets") << "d_oSetEqc: " << d_oSetEqc << std::endl;
     325         [ +  - ]:       1288 :   Trace("sets") << "Done check cardinality cycles" << std::endl;
     326                 :            : }
     327                 :            : 
     328                 :      33094 : void CardinalityExtension::checkCardCyclesRec(Node eqc,
     329                 :            :                                               std::vector<Node>& curr,
     330                 :            :                                               std::vector<Node>& exp)
     331                 :            : {
     332         [ +  - ]:      33094 :   Trace("sets-cycle-debug") << "Traverse eqc " << eqc << std::endl;
     333                 :      33094 :   NodeManager* nm = nodeManager();
     334         [ -  + ]:      33094 :   if (std::find(curr.begin(), curr.end(), eqc) != curr.end())
     335                 :            :   {
     336         [ -  - ]:          0 :     Trace("sets-debug") << "Found venn region loop..." << std::endl;
     337         [ -  - ]:          0 :     if (curr.size() > 1)
     338                 :            :     {
     339                 :            :       // all regions must be equal
     340                 :          0 :       std::vector<Node> conc;
     341                 :          0 :       bool foundLoopStart = false;
     342         [ -  - ]:          0 :       for (const Node& cc : curr)
     343                 :            :       {
     344         [ -  - ]:          0 :         if (cc == eqc)
     345                 :            :         {
     346                 :          0 :           foundLoopStart = true;
     347                 :            :         }
     348                 :          0 :         else if (foundLoopStart && eqc != cc)
     349                 :            :         {
     350                 :          0 :           conc.push_back(eqc.eqNode(cc));
     351                 :            :         }
     352                 :            :       }
     353         [ -  - ]:          0 :       Node fact = conc.size() == 1 ? conc[0] : nm->mkNode(Kind::AND, conc);
     354         [ -  - ]:          0 :       Trace("sets-cycle-debug")
     355                 :          0 :           << "CYCLE: " << fact << " from " << exp << std::endl;
     356                 :          0 :       d_im.assertInference(fact, InferenceId::SETS_CARD_CYCLE, exp);
     357                 :          0 :       d_im.doPendingLemmas();
     358                 :          0 :     }
     359                 :            :     else
     360                 :            :     {
     361                 :            :       // should be guaranteed based on not exploring equal parents
     362                 :          0 :       DebugUnhandled();
     363                 :            :     }
     364                 :      18811 :     return;
     365                 :            :   }
     366         [ +  + ]:      33094 :   if (std::find(d_oSetEqc.begin(), d_oSetEqc.end(), eqc) != d_oSetEqc.end())
     367                 :            :   {
     368                 :            :     // already processed
     369                 :      15080 :     return;
     370                 :            :   }
     371                 :      18014 :   const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
     372         [ +  + ]:      18014 :   if (nvsets.empty())
     373                 :            :   {
     374                 :            :     // no non-variable sets, trivial
     375                 :       2894 :     d_oSetEqc.push_back(eqc);
     376                 :       2894 :     return;
     377                 :            :   }
     378                 :      15120 :   curr.push_back(eqc);
     379                 :      15120 :   TypeNode tn = eqc.getType();
     380                 :      15120 :   bool is_empty = eqc == d_state.getEmptySetEqClass(tn);
     381                 :      15120 :   Node emp_set = d_treg.getEmptySet(tn);
     382         [ +  + ]:      39418 :   for (const Node& n : nvsets)
     383                 :            :   {
     384                 :      25135 :     Kind nk = n.getKind();
     385 [ +  + ][ +  + ]:      25135 :     if (nk != Kind::SET_INTER && nk != Kind::SET_MINUS)
     386                 :            :     {
     387                 :      10153 :       continue;
     388                 :            :     }
     389                 :            :     // should not have universe as children here, since this is either
     390                 :            :     // rewritten, or eliminated via purification from the first argument of
     391                 :            :     // set minus.
     392         [ +  - ]:      37190 :     Trace("sets-debug") << "Build cardinality parents for " << n << "..."
     393                 :      18595 :                         << std::endl;
     394                 :      18595 :     std::vector<Node> sib;
     395                 :      18595 :     unsigned true_sib = 0;
     396                 :            :     // Note that we use the rewriter to get the form of the siblings here.
     397                 :            :     // This is required to ensure that the lookups in the equality engine are
     398                 :            :     // accurate. However, it may lead to issues if the rewritten form of a
     399                 :            :     // node leads to unexpected relationships in the graph. To avoid this,
     400                 :            :     // we ensure that universe is not a child of a set in the assertions above.
     401         [ +  + ]:      18595 :     if (n.getKind() == Kind::SET_INTER)
     402                 :            :     {
     403                 :       6848 :       d_localBase[n] = n;
     404         [ +  + ]:      20544 :       for (unsigned e = 0; e < 2; e++)
     405                 :            :       {
     406                 :      27392 :         Node sm = rewrite(nm->mkNode(Kind::SET_MINUS, n[e], n[1 - e]));
     407                 :      13696 :         sib.push_back(sm);
     408                 :      13696 :       }
     409                 :       6848 :       true_sib = 2;
     410                 :            :     }
     411                 :            :     else
     412                 :            :     {
     413                 :      23494 :       Node si = rewrite(nm->mkNode(Kind::SET_INTER, n[0], n[1]));
     414                 :      11747 :       sib.push_back(si);
     415                 :      11747 :       d_localBase[n] = si;
     416                 :      23494 :       Node osm = rewrite(nm->mkNode(Kind::SET_MINUS, n[1], n[0]));
     417                 :      11747 :       sib.push_back(osm);
     418                 :      11747 :       true_sib = 1;
     419                 :      11747 :     }
     420                 :      37190 :     Node u = rewrite(nm->mkNode(Kind::SET_UNION, n[0], n[1]));
     421         [ +  + ]:      18595 :     if (!d_state.hasTerm(u))
     422                 :            :     {
     423                 :      12550 :       u = Node::null();
     424                 :            :     }
     425         [ +  + ]:      18595 :     unsigned n_parents = true_sib + (u.isNull() ? 0 : 1);
     426                 :            :     // if this set is empty
     427         [ +  + ]:      18595 :     if (is_empty)
     428                 :            :     {
     429 [ -  + ][ -  + ]:       3928 :       Assert(d_state.areEqual(n, emp_set));
                 [ -  - ]
     430         [ +  - ]:       3928 :       Trace("sets-debug") << "  empty, parents equal siblings" << std::endl;
     431                 :       3928 :       std::vector<Node> conc;
     432                 :            :       // parent equal siblings
     433         [ +  + ]:       9048 :       for (unsigned e = 0; e < true_sib; e++)
     434                 :            :       {
     435                 :       5120 :         if (d_state.hasTerm(sib[e]) && !d_state.areEqual(n[e], sib[e]))
     436                 :            :         {
     437                 :        435 :           conc.push_back(n[e].eqNode(sib[e]));
     438                 :            :         }
     439                 :            :       }
     440                 :       3928 :       d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EMP, n.eqNode(emp_set));
     441                 :       3928 :       d_im.doPendingLemmas();
     442         [ +  + ]:       3928 :       if (d_im.hasSent())
     443                 :            :       {
     444                 :        315 :         return;
     445                 :            :       }
     446                 :       3613 :       continue;
     447         [ +  + ]:       3928 :     }
     448                 :      14667 :     std::vector<Node> card_parents;
     449                 :      14667 :     std::vector<int> card_parent_ids;
     450                 :            :     // check if equal to a parent
     451         [ +  + ]:      38530 :     for (unsigned e = 0; e < n_parents; e++)
     452                 :            :     {
     453         [ +  - ]:      48230 :       Trace("sets-debug") << "  check parent " << e << "/" << n_parents
     454                 :      24115 :                           << std::endl;
     455                 :      24115 :       bool is_union = e == true_sib;
     456         [ +  + ]:      24115 :       Node p = (e == true_sib) ? u : n[e];
     457         [ +  - ]:      48230 :       Trace("sets-debug") << "  check relation to parent " << p
     458                 :      24115 :                           << ", isu=" << is_union << "..." << std::endl;
     459                 :            :       // if parent is empty
     460         [ +  + ]:      24115 :       if (d_state.areEqual(p, emp_set))
     461                 :            :       {
     462         [ +  - ]:          2 :         Trace("sets-debug") << "  it is empty..." << std::endl;
     463 [ -  + ][ -  + ]:          2 :         Assert(!d_state.areEqual(n, emp_set));
                 [ -  - ]
     464                 :          2 :         d_im.assertInference(
     465                 :          4 :             n.eqNode(emp_set), InferenceId::SETS_CARD_GRAPH_EMP_PARENT, p.eqNode(emp_set));
     466                 :          2 :         d_im.doPendingLemmas();
     467         [ +  - ]:          2 :         if (d_im.hasSent())
     468                 :            :         {
     469                 :          2 :           return;
     470                 :            :         }
     471                 :            :         // if we are equal to a parent
     472                 :            :       }
     473         [ +  + ]:      24113 :       else if (d_state.areEqual(p, n))
     474                 :            :       {
     475         [ +  - ]:       5304 :         Trace("sets-debug") << "  it is equal to this..." << std::endl;
     476                 :       5304 :         std::vector<Node> conc;
     477                 :       5304 :         std::vector<int> sib_emp_indices;
     478         [ +  + ]:       5304 :         if (is_union)
     479                 :            :         {
     480         [ +  + ]:        555 :           for (unsigned s = 0; s < sib.size(); s++)
     481                 :            :           {
     482                 :        370 :             sib_emp_indices.push_back(s);
     483                 :            :           }
     484                 :            :         }
     485                 :            :         else
     486                 :            :         {
     487                 :       5119 :           sib_emp_indices.push_back(e);
     488                 :            :         }
     489                 :            :         // sibling(s) are empty
     490         [ +  + ]:      10793 :         for (unsigned si : sib_emp_indices)
     491                 :            :         {
     492         [ +  + ]:       5489 :           if (!d_state.areEqual(sib[si], emp_set))
     493                 :            :           {
     494                 :        232 :             conc.push_back(sib[si].eqNode(emp_set));
     495                 :            :           }
     496                 :            :           else
     497                 :            :           {
     498         [ +  - ]:      10514 :             Trace("sets-debug")
     499                 :       5257 :                 << "Sibling " << sib[si] << " is already empty." << std::endl;
     500                 :            :           }
     501                 :            :         }
     502 [ +  + ][ +  + ]:       5304 :         if (!is_union && nk == Kind::SET_INTER && !u.isNull())
         [ +  + ][ +  + ]
     503                 :            :         {
     504                 :            :           // union is equal to other parent
     505         [ +  + ]:       2073 :           if (!d_state.areEqual(u, n[1 - e]))
     506                 :            :           {
     507                 :         20 :             conc.push_back(u.eqNode(n[1 - e]));
     508                 :            :           }
     509                 :            :         }
     510         [ +  - ]:      10608 :         Trace("sets-debug")
     511                 :       5304 :             << "...derived " << conc.size() << " conclusions" << std::endl;
     512                 :       5304 :         d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_EQ_PARENT, n.eqNode(p));
     513                 :       5304 :         d_im.doPendingLemmas();
     514         [ +  + ]:       5304 :         if (d_im.hasSent())
     515                 :            :         {
     516                 :        250 :           return;
     517                 :            :         }
     518 [ +  + ][ +  + ]:       5554 :       }
     519                 :            :       else
     520                 :            :       {
     521         [ +  - ]:      18809 :         Trace("sets-cdg") << "Card graph : " << n << " -> " << p << std::endl;
     522                 :            :         // otherwise, we a syntactic subset of p
     523                 :      18809 :         card_parents.push_back(p);
     524         [ +  + ]:      18809 :         card_parent_ids.push_back(is_union ? 2 : e);
     525                 :            :       }
     526         [ +  + ]:      24115 :     }
     527 [ -  + ][ -  + ]:      14415 :     Assert(d_cardParent[n].empty());
                 [ -  - ]
     528         [ +  - ]:      14415 :     Trace("sets-debug") << "get parent representatives..." << std::endl;
     529                 :            :     // for each parent, take their representatives
     530         [ +  + ]:      32864 :     for (unsigned k = 0, numcp = card_parents.size(); k < numcp; k++)
     531                 :            :     {
     532                 :      18709 :       Node cpk = card_parents[k];
     533                 :      37418 :       Node eqcc = d_state.getRepresentative(cpk);
     534         [ +  - ]:      37418 :       Trace("sets-debug") << "Check card parent " << k << "/"
     535                 :      18709 :                           << card_parents.size() << std::endl;
     536                 :            : 
     537                 :            :       // if parent is singleton, then we should either be empty to equal to it
     538                 :      18709 :       Node eqccSingleton = d_state.getSingletonEqClass(eqcc);
     539         [ +  + ]:      18709 :       if (!eqccSingleton.isNull())
     540                 :            :       {
     541                 :         65 :         bool eq_parent = false;
     542                 :         65 :         std::vector<Node> exps;
     543                 :         65 :         d_state.addEqualityToExp(cpk, eqccSingleton, exps);
     544         [ -  + ]:         65 :         if (d_state.areDisequal(n, emp_set))
     545                 :            :         {
     546                 :            :           // ensure we can explain the disequality
     547                 :          0 :           d_state.explainDisequal(n, emp_set, exps);
     548                 :          0 :           eq_parent = true;
     549                 :            :         }
     550                 :            :         else
     551                 :            :         {
     552                 :         65 :           const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc);
     553         [ +  + ]:         65 :           if (!pmemsE.empty())
     554                 :            :           {
     555                 :         43 :             Node pmem = pmemsE.begin()->second;
     556                 :         43 :             exps.push_back(pmem);
     557                 :         43 :             d_state.addEqualityToExp(n, pmem[1], exps);
     558                 :         43 :             eq_parent = true;
     559                 :         43 :           }
     560                 :            :         }
     561                 :            :         // must be equal to parent
     562         [ +  + ]:         65 :         if (eq_parent)
     563                 :            :         {
     564                 :         43 :           Node conc = n.eqNode(cpk);
     565                 :         43 :           d_im.assertInference(conc, InferenceId::SETS_CARD_GRAPH_PARENT_SINGLETON, exps);
     566                 :         43 :           d_im.doPendingLemmas();
     567                 :         43 :         }
     568                 :            :         else
     569                 :            :         {
     570                 :            :           // split on empty
     571         [ +  - ]:         22 :           Trace("sets-nf") << "Split empty : " << n << std::endl;
     572                 :         22 :           d_im.split(n.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY, 1);
     573                 :            :         }
     574 [ -  + ][ -  + ]:         65 :         Assert(d_im.hasSent());
                 [ -  - ]
     575                 :         65 :         return;
     576                 :         65 :       }
     577                 :            :       else
     578                 :            :       {
     579                 :      18644 :         bool dup = false;
     580         [ +  + ]:      24765 :         for (unsigned l = 0, numcpn = d_cardParent[n].size(); l < numcpn; l++)
     581                 :            :         {
     582                 :       6316 :           Node cpnl = d_cardParent[n][l].first;
     583         [ +  + ]:       6316 :           if (eqcc != cpnl)
     584                 :            :           {
     585                 :       3253 :             continue;
     586                 :            :           }
     587         [ +  - ]:       6126 :           Trace("sets-debug") << "  parents " << l << " and " << k
     588                 :          0 :                               << " are equal, ids = " << card_parent_ids[l]
     589                 :       3063 :                               << " " << card_parent_ids[k] << std::endl;
     590                 :       3063 :           dup = true;
     591         [ +  + ]:       3063 :           if (n.getKind() != Kind::SET_INTER)
     592                 :            :           {
     593                 :       1328 :             continue;
     594                 :            :           }
     595 [ -  + ][ -  + ]:       1735 :           Assert(card_parent_ids[l] != 2);
                 [ -  - ]
     596                 :       1735 :           std::vector<Node> conc;
     597         [ +  + ]:       1735 :           if (card_parent_ids[k] == 2)
     598                 :            :           {
     599                 :            :             // intersection is equal to other parent
     600                 :       1731 :             unsigned pid = 1 - card_parent_ids[l];
     601         [ +  + ]:       1731 :             if (!d_state.areEqual(n[pid], n))
     602                 :            :             {
     603         [ +  - ]:        382 :               Trace("sets-debug")
     604                 :          0 :                   << "  one of them is union, make equal to other..."
     605                 :        191 :                   << std::endl;
     606                 :        191 :               conc.push_back(n[pid].eqNode(n));
     607                 :            :             }
     608                 :            :           }
     609                 :            :           else
     610                 :            :           {
     611         [ +  - ]:          4 :             if (!d_state.areEqual(cpk, n))
     612                 :            :             {
     613         [ +  - ]:          8 :               Trace("sets-debug")
     614                 :          0 :                   << "  neither is union, make equal to one parent..."
     615                 :          4 :                   << std::endl;
     616                 :            :               // intersection is equal to one of the parents
     617                 :          4 :               conc.push_back(cpk.eqNode(n));
     618                 :            :             }
     619                 :            :           }
     620                 :            :           // use the original term, not the representative.
     621                 :            :           // for example, we conclude T = (union T S) => (intersect T S) = S
     622                 :            :           // here where we do not use the representative of T or (union T S).
     623                 :       1735 :           Node cpnlb = d_cardParent[n][l].second;
     624                 :       1735 :           d_im.assertInference(conc,
     625                 :            :                                InferenceId::SETS_CARD_GRAPH_EQ_PARENT_2,
     626                 :       3470 :                                cpk.eqNode(cpnlb));
     627                 :       1735 :           d_im.doPendingLemmas();
     628         [ +  + ]:       1735 :           if (d_im.hasSent())
     629                 :            :           {
     630                 :        195 :             return;
     631                 :            :           }
     632 [ +  + ][ +  + ]:       6706 :         }
            [ +  + ][ + ]
     633         [ +  + ]:      18449 :         if (!dup)
     634                 :            :         {
     635                 :      15581 :           d_cardParent[n].emplace_back(eqcc, cpk);
     636                 :            :         }
     637                 :            :       }
     638 [ +  + ][ +  + ]:      19229 :     }
                 [ +  + ]
     639                 :            :     // now recurse on parents (to ensure their normal will be computed after
     640                 :            :     // this eqc)
     641                 :      14155 :     bool needExp = (eqc != n);
     642         [ +  + ]:      14155 :     if (needExp)
     643                 :            :     {
     644                 :       4870 :       exp.push_back(eqc.eqNode(n));
     645                 :            :     }
     646         [ +  + ]:      29303 :     for (const std::pair<Node, Node>& cpnc : d_cardParent[n])
     647                 :            :     {
     648         [ +  - ]:      30316 :       Trace("sets-cycle-debug") << "Traverse card parent " << eqc << " -> "
     649                 :      15158 :                                 << cpnc.first << std::endl;
     650                 :      15158 :       checkCardCyclesRec(cpnc.first, curr, exp);
     651         [ +  + ]:      15158 :       if (d_im.hasSent())
     652                 :            :       {
     653                 :         10 :         return;
     654                 :            :       }
     655                 :            :     }
     656         [ +  + ]:      14145 :     if (needExp)
     657                 :            :     {
     658                 :       4870 :       exp.pop_back();
     659                 :            :     }
     660 [ +  + ][ +  + ]:      24089 :   }
         [ +  + ][ +  + ]
                 [ +  + ]
     661                 :      14283 :   curr.pop_back();
     662                 :            :   // parents now processed, can add to ordered list
     663                 :      14283 :   d_oSetEqc.push_back(eqc);
     664 [ +  + ][ +  + ]:      15957 : }
     665                 :            : 
     666                 :       1288 : void CardinalityExtension::checkNormalForms(std::vector<Node>& intro_sets)
     667                 :            : {
     668         [ +  - ]:       1288 :   Trace("sets") << "Check normal forms..." << std::endl;
     669                 :            :   // now, build normal form for each equivalence class
     670                 :            :   // d_oSetEqc is now sorted such that for each d_oSetEqc[i], d_oSetEqc[j],
     671                 :            :   // if d_oSetEqc[i] is a strict syntactic subterm of d_oSetEqc[j], then i<j.
     672                 :       1288 :   d_ff.clear();
     673                 :       1288 :   d_nf.clear();
     674         [ +  + ]:       8349 :   for (int i = (int)(d_oSetEqc.size() - 1); i >= 0; i--)
     675                 :            :   {
     676                 :       8054 :     checkNormalForm(d_oSetEqc[i], intro_sets);
     677 [ +  + ][ +  + ]:       8054 :     if (d_im.hasSent() || !intro_sets.empty())
                 [ +  + ]
     678                 :            :     {
     679                 :        993 :       return;
     680                 :            :     }
     681                 :            :   }
     682         [ +  - ]:        295 :   Trace("sets") << "Done check normal forms" << std::endl;
     683                 :            : }
     684                 :            : 
     685                 :       8054 : void CardinalityExtension::checkNormalForm(Node eqc,
     686                 :            :                                            std::vector<Node>& intro_sets)
     687                 :            : {
     688                 :       8054 :   TypeNode tn = eqc.getType();
     689         [ +  - ]:       8054 :   Trace("sets") << "Compute normal form for " << eqc << std::endl;
     690         [ +  - ]:       8054 :   Trace("sets-nf") << "Compute N " << eqc << "..." << std::endl;
     691         [ +  + ]:       8054 :   if (eqc == d_state.getEmptySetEqClass(tn))
     692                 :            :   {
     693                 :       1035 :     d_nf[eqc].clear();
     694         [ +  - ]:       1035 :     Trace("sets-nf") << "----> N " << eqc << " => {}" << std::endl;
     695                 :       1035 :     return;
     696                 :            :   }
     697                 :            :   // flat/normal forms are sets of equivalence classes
     698                 :       7019 :   Node base;
     699                 :       7019 :   std::vector<Node> comps;
     700                 :            :   std::map<Node, std::map<Node, std::vector<Node> > >::iterator it =
     701                 :       7019 :       d_ff.find(eqc);
     702         [ +  + ]:       7019 :   if (it != d_ff.end())
     703                 :            :   {
     704         [ +  + ]:       4269 :     for (std::pair<const Node, std::vector<Node> >& itf : it->second)
     705                 :            :     {
     706                 :       2534 :       std::sort(itf.second.begin(), itf.second.end());
     707         [ +  + ]:       2534 :       if (base.isNull())
     708                 :            :       {
     709                 :       1735 :         base = itf.first;
     710                 :            :       }
     711                 :            :       else
     712                 :            :       {
     713                 :        799 :         comps.push_back(itf.first);
     714                 :            :       }
     715         [ +  - ]:       5068 :       Trace("sets-nf") << "  F " << itf.first << " : " << itf.second
     716                 :       2534 :                        << std::endl;
     717         [ +  - ]:       2534 :       Trace("sets-nf-debug") << " ...";
     718                 :       2534 :       d_treg.debugPrintSet(itf.first, "sets-nf-debug");
     719         [ +  - ]:       2534 :       Trace("sets-nf-debug") << std::endl;
     720                 :            :     }
     721                 :            :   }
     722                 :            :   else
     723                 :            :   {
     724         [ +  - ]:       5284 :     Trace("sets-nf") << "(no flat forms)" << std::endl;
     725                 :            :   }
     726                 :       7019 :   std::map<Node, std::vector<Node> >& ffeqc = d_ff[eqc];
     727 [ -  + ][ -  + ]:       7019 :   Assert(d_nf.find(eqc) == d_nf.end());
                 [ -  - ]
     728                 :       7019 :   std::vector<Node>& nfeqc = d_nf[eqc];
     729                 :       7019 :   NodeManager* nm = nodeManager();
     730                 :       7019 :   bool success = true;
     731                 :       7019 :   Node emp_set = d_treg.getEmptySet(tn);
     732         [ +  + ]:       7019 :   if (!base.isNull())
     733                 :            :   {
     734         [ +  + ]:       2066 :     for (unsigned j = 0, csize = comps.size(); j < csize; j++)
     735                 :            :     {
     736                 :            :       // compare if equal
     737                 :        748 :       std::vector<Node> c;
     738                 :        748 :       c.push_back(base);
     739                 :        748 :       c.push_back(comps[j]);
     740         [ +  + ]:       4488 :       std::vector<Node> only[2];
     741                 :        748 :       std::vector<Node> common;
     742         [ +  - ]:       1496 :       Trace("sets-nf-debug") << "Compare venn regions of " << base << " vs "
     743                 :        748 :                              << comps[j] << std::endl;
     744                 :        748 :       unsigned k[2] = {0, 0};
     745 [ +  + ][ +  + ]:       3452 :       while (k[0] < ffeqc[c[0]].size() || k[1] < ffeqc[c[1]].size())
                 [ +  + ]
     746                 :            :       {
     747                 :       2704 :         bool proc = true;
     748         [ +  + ]:       8112 :         for (unsigned e = 0; e < 2; e++)
     749                 :            :         {
     750         [ +  + ]:       5408 :           if (k[e] == ffeqc[c[e]].size())
     751                 :            :           {
     752         [ +  + ]:       1162 :             for (; k[1 - e] < ffeqc[c[1 - e]].size(); ++k[1 - e])
     753                 :            :             {
     754                 :        483 :               only[1 - e].push_back(ffeqc[c[1 - e]][k[1 - e]]);
     755                 :            :             }
     756                 :        679 :             proc = false;
     757                 :            :           }
     758                 :            :         }
     759         [ +  + ]:       2704 :         if (proc)
     760                 :            :         {
     761         [ +  + ]:       2287 :           if (ffeqc[c[0]][k[0]] == ffeqc[c[1]][k[1]])
     762                 :            :           {
     763                 :       1265 :             common.push_back(ffeqc[c[0]][k[0]]);
     764                 :       1265 :             k[0]++;
     765                 :       1265 :             k[1]++;
     766                 :            :           }
     767         [ +  + ]:       1022 :           else if (ffeqc[c[0]][k[0]] < ffeqc[c[1]][k[1]])
     768                 :            :           {
     769                 :        573 :             only[0].push_back(ffeqc[c[0]][k[0]]);
     770                 :        573 :             k[0]++;
     771                 :            :           }
     772                 :            :           else
     773                 :            :           {
     774                 :        449 :             only[1].push_back(ffeqc[c[1]][k[1]]);
     775                 :        449 :             k[1]++;
     776                 :            :           }
     777                 :            :         }
     778                 :            :       }
     779 [ +  + ][ -  + ]:        748 :       if (!only[0].empty() || !only[1].empty())
                 [ +  + ]
     780                 :            :       {
     781         [ -  + ]:        417 :         if (TraceIsOn("sets-nf-debug"))
     782                 :            :         {
     783         [ -  - ]:          0 :           Trace("sets-nf-debug") << "Unique venn regions : " << std::endl;
     784         [ -  - ]:          0 :           for (unsigned e = 0; e < 2; e++)
     785                 :            :           {
     786         [ -  - ]:          0 :             Trace("sets-nf-debug") << "  " << c[e] << " : { ";
     787         [ -  - ]:          0 :             for (unsigned l = 0; l < only[e].size(); l++)
     788                 :            :             {
     789         [ -  - ]:          0 :               if (l > 0)
     790                 :            :               {
     791         [ -  - ]:          0 :                 Trace("sets-nf-debug") << ", ";
     792                 :            :               }
     793         [ -  - ]:          0 :               Trace("sets-nf-debug") << "[" << only[e][l] << "]";
     794                 :            :             }
     795         [ -  - ]:          0 :             Trace("sets-nf-debug") << " }" << std::endl;
     796                 :            :           }
     797                 :            :         }
     798                 :            :         // try to make one empty, prefer the unique ones first
     799         [ +  + ]:       1668 :         for (unsigned e = 0; e < 3; e++)
     800                 :            :         {
     801         [ +  + ]:       1251 :           unsigned sz = e == 2 ? common.size() : only[e].size();
     802         [ +  + ]:       3104 :           for (unsigned l = 0; l < sz; l++)
     803                 :            :           {
     804         [ +  + ]:       1853 :             Node r = e == 2 ? common[l] : only[e][l];
     805         [ +  - ]:       1853 :             Trace("sets-nf-debug") << "Try split empty : " << r << std::endl;
     806         [ +  - ]:       1853 :             Trace("sets-nf-debug") << "         actual : ";
     807                 :       1853 :             d_treg.debugPrintSet(r, "sets-nf-debug");
     808         [ +  - ]:       1853 :             Trace("sets-nf-debug") << std::endl;
     809 [ -  + ][ -  + ]:       1853 :             Assert(!d_state.areEqual(r, emp_set));
                 [ -  - ]
     810                 :       1853 :             if (!d_state.areDisequal(r, emp_set) && !d_state.hasMembers(r))
     811                 :            :             {
     812                 :            :               // guess that its equal empty if it has no explicit members
     813         [ -  - ]:          0 :               Trace("sets-nf") << " Split empty : " << r << std::endl;
     814         [ -  - ]:          0 :               Trace("sets-nf") << "Actual Split : ";
     815                 :          0 :               d_treg.debugPrintSet(r, "sets-nf");
     816         [ -  - ]:          0 :               Trace("sets-nf") << std::endl;
     817                 :          0 :               d_im.split(
     818                 :          0 :                   r.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY, 1);
     819                 :          0 :               Assert(d_im.hasSent());
     820                 :          0 :               return;
     821                 :            :             }
     822         [ +  - ]:       1853 :           }
     823                 :            :         }
     824         [ +  - ]:        417 :         for (const Node& o0 : only[0])
     825                 :            :         {
     826         [ +  - ]:        534 :           for (const Node& o1 : only[1])
     827                 :            :           {
     828                 :        534 :             bool disjoint = false;
     829         [ +  - ]:       1068 :             Trace("sets-nf-debug")
     830                 :        534 :                 << "Try split " << o0 << " against " << o1 << std::endl;
     831         [ +  + ]:        534 :             if (!d_state.areDisequal(o0, o1))
     832                 :            :             {
     833                 :            :               // Just try to make them equal. This is analogous
     834                 :            :               // to the STRINGS_LEN_SPLIT inference in strings.
     835                 :        290 :               d_im.split(
     836                 :        580 :                   o0.eqNode(o1), InferenceId::SETS_CARD_SPLIT_EQ, 1);
     837 [ -  + ][ -  + ]:        290 :               Assert(d_im.hasSent());
                 [ -  - ]
     838                 :        417 :               return;
     839                 :            :             }
     840                 :            :             else
     841                 :            :             {
     842                 :            :               // split them by introducing an intersection term, which is
     843                 :            :               // analogous to e.g. STRINGS_SSPLIT_VAR in strings.
     844         [ +  + ]:        545 :               for (unsigned e = 0; e < 2; e++)
     845                 :            :               {
     846         [ +  + ]:        418 :                 Node r1 = e == 0 ? o0 : o1;
     847         [ +  + ]:        418 :                 Node r2 = e == 0 ? o1 : o0;
     848                 :            :                 // check if their intersection exists modulo equality
     849                 :        836 :                 Node r1r2i = d_state.getBinaryOpTerm(Kind::SET_INTER, r1, r2);
     850         [ +  + ]:        418 :                 if (!r1r2i.isNull())
     851                 :            :                 {
     852         [ +  - ]:        234 :                   Trace("sets-nf-debug")
     853                 :            :                       << "Split term already exists, but not in cardinality "
     854                 :          0 :                         "graph : "
     855                 :        117 :                       << r1r2i << ", should be empty." << std::endl;
     856                 :            :                   // their intersection is empty (probably?)
     857                 :            :                   // e.g. these are two disjoint venn regions, proceed to next
     858                 :            :                   // pair
     859 [ -  + ][ -  + ]:        117 :                   Assert(d_state.areEqual(emp_set, r1r2i));
                 [ -  - ]
     860                 :        117 :                   disjoint = true;
     861                 :        117 :                   break;
     862                 :            :                 }
     863 [ +  + ][ +  + ]:        652 :               }
                 [ +  + ]
     864         [ +  + ]:        244 :               if (!disjoint)
     865                 :            :               {
     866                 :            :                 // simply introduce their intersection
     867 [ -  + ][ -  + ]:        127 :                 Assert(o0 != o1);
                 [ -  - ]
     868                 :        127 :                 Node kca = d_treg.getProxy(o0);
     869                 :        127 :                 Node kcb = d_treg.getProxy(o1);
     870                 :        254 :                 Node intro = rewrite(nm->mkNode(Kind::SET_INTER, kca, kcb));
     871         [ +  - ]:        254 :                 Trace("sets-nf") << "   Intro split : " << o0 << " against " << o1
     872                 :        127 :                                 << ", term is " << intro << std::endl;
     873                 :        127 :                 intro_sets.push_back(intro);
     874 [ -  + ][ -  + ]:        127 :                 Assert(!d_state.hasTerm(intro));
                 [ -  - ]
     875                 :        127 :                 return;
     876                 :        127 :               }
     877                 :            :             }
     878                 :            :           }
     879                 :            :         }
     880                 :            :         // should never get here
     881                 :          0 :         success = false;
     882                 :            :       }
     883 [ +  + ][ +  + ]:       3740 :     }
         [ +  + ][ -  - ]
     884         [ +  - ]:       1318 :     if (success)
     885                 :            :     {
     886                 :            :       // normal form is flat form of base
     887                 :       1318 :       nfeqc.insert(nfeqc.end(), ffeqc[base].begin(), ffeqc[base].end());
     888         [ +  - ]:       1318 :       Trace("sets-nf") << "----> N " << eqc << " => F " << base << std::endl;
     889                 :            :     }
     890                 :            :     else
     891                 :            :     {
     892         [ -  - ]:          0 :       Trace("sets-nf") << "failed to build N " << eqc << std::endl;
     893                 :            :     }
     894                 :            :   }
     895                 :            :   else
     896                 :            :   {
     897                 :            :     // must ensure disequal from empty
     898                 :      10464 :     if (!eqc.isConst() && !d_state.areDisequal(eqc, emp_set)
     899 [ +  + ][ +  + ]:      10464 :         && !d_state.hasMembers(eqc))
         [ +  + ][ +  + ]
                 [ -  - ]
     900                 :            :     {
     901         [ +  - ]:        576 :       Trace("sets-nf-debug") << "Split on leaf " << eqc << std::endl;
     902                 :        576 :       d_im.split(eqc.eqNode(emp_set), InferenceId::SETS_CARD_SPLIT_EMPTY);
     903                 :        576 :       success = false;
     904                 :            :     }
     905                 :            :     else
     906                 :            :     {
     907                 :            :       // normal form is this equivalence class
     908                 :       4708 :       nfeqc.push_back(eqc);
     909         [ +  - ]:       9416 :       Trace("sets-nf") << "----> N " << eqc << " => { " << eqc << " }"
     910                 :       4708 :                        << std::endl;
     911                 :            :     }
     912                 :            :   }
     913         [ +  + ]:       6602 :   if (!success)
     914                 :            :   {
     915 [ -  + ][ -  + ]:        576 :     Assert(d_im.hasSent())
                 [ -  - ]
     916                 :          0 :         << "failed to send a lemma to resolve why Venn regions are different";
     917                 :        576 :     return;
     918                 :            :   }
     919                 :            :   // Send to parents (a parent is a set that contains a term in this equivalence
     920                 :            :   // class as a direct child).
     921                 :       6026 :   const std::vector<Node>& nvsets = d_state.getNonVariableSets(eqc);
     922         [ +  + ]:       6026 :   if (nvsets.empty())
     923                 :            :   {
     924                 :            :     // no non-variable sets
     925                 :        680 :     return;
     926                 :            :   }
     927                 :       5346 :   std::map<Node, std::map<Node, bool> > parents_proc;
     928         [ +  + ]:      13199 :   for (const Node& n : nvsets)
     929                 :            :   {
     930         [ +  - ]:       7853 :     Trace("sets-nf-debug") << "Carry nf for term " << n << std::endl;
     931         [ +  + ]:       7853 :     if (d_cardParent[n].empty())
     932                 :            :     {
     933                 :            :       // nothing to do
     934                 :       1846 :       continue;
     935                 :            :     }
     936 [ -  + ][ -  + ]:       6007 :     Assert(d_localBase.find(n) != d_localBase.end());
                 [ -  - ]
     937                 :       6007 :     Node cbase = d_localBase[n];
     938         [ +  - ]:       6007 :     Trace("sets-nf-debug") << "Card base is " << cbase << std::endl;
     939         [ +  + ]:      13013 :     for (const std::pair<Node, Node>& cp : d_cardParent[n])
     940                 :            :     {
     941                 :       7006 :       Node p = cp.first;
     942         [ +  - ]:       7006 :       Trace("sets-nf-debug") << "Check parent " << p << std::endl;
     943         [ -  + ]:       7006 :       if (parents_proc[cbase].find(p) != parents_proc[cbase].end())
     944                 :            :       {
     945         [ -  - ]:          0 :         Trace("sets-nf-debug") << "..already processed parent " << p << " for "
     946                 :          0 :                                << cbase << std::endl;
     947                 :          0 :         continue;
     948                 :            :       }
     949                 :       7006 :       parents_proc[cbase][p] = true;
     950         [ +  - ]:      14012 :       Trace("sets-nf-debug") << "Carry nf to parent ( " << cbase << ", [" << p
     951                 :       7006 :                              << "] ), from " << n << "..." << std::endl;
     952                 :            : 
     953                 :       7006 :       std::vector<Node>& ffpc = d_ff[p][cbase];
     954         [ +  + ]:      15310 :       for (const Node& nfeqci : nfeqc)
     955                 :            :       {
     956         [ +  - ]:       8304 :         if (std::find(ffpc.begin(), ffpc.end(), nfeqci) == ffpc.end())
     957                 :            :         {
     958         [ +  - ]:      16608 :           Trace("sets-nf-debug") << "Add to flat form " << nfeqci << " to "
     959                 :       8304 :                                  << cbase << " in " << p << std::endl;
     960                 :       8304 :           ffpc.push_back(nfeqci);
     961                 :            :         }
     962                 :            :         else
     963                 :            :         {
     964                 :            :           // if it is a duplicate venn region, it must be empty since it is
     965                 :            :           // coming from syntactically disjoint siblings
     966                 :            :         }
     967                 :            :       }
     968         [ +  - ]:       7006 :     }
     969                 :       6007 :   }
     970 [ +  + ][ +  + ]:      13073 : }
         [ +  + ][ +  + ]
     971                 :            : 
     972                 :       3073 : void CardinalityExtension::checkMinCard()
     973                 :            : {
     974                 :       3073 :   NodeManager* nm = nodeManager();
     975                 :       3073 :   const std::vector<Node>& setEqc = d_state.getSetsEqClasses();
     976         [ +  + ]:      37208 :   for (int i = (int)(setEqc.size() - 1); i >= 0; i--)
     977                 :            :   {
     978                 :      34135 :     Node eqc = setEqc[i];
     979                 :      34135 :     TypeNode tn = eqc.getType().getSetElementType();
     980         [ +  + ]:      34135 :     if (d_t_card_enabled.find(tn) == d_t_card_enabled.end())
     981                 :            :     {
     982                 :            :       // cardinality is not enabled for this type, skip
     983                 :        232 :       continue;
     984                 :            :     }
     985                 :            :     // get members in class
     986                 :      33903 :     const std::map<Node, Node>& pmemsE = d_state.getMembers(eqc);
     987         [ +  + ]:      33903 :     if (pmemsE.empty())
     988                 :            :     {
     989                 :            :       // no members, trivial
     990                 :      11666 :       continue;
     991                 :            :     }
     992                 :      22237 :     std::vector<Node> exp;
     993                 :      22237 :     std::vector<Node> members;
     994                 :      22237 :     Node cardTerm;
     995                 :      22237 :     std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc);
     996         [ +  + ]:      22237 :     if (it != d_eqc_to_card_term.end())
     997                 :            :     {
     998                 :      22235 :       cardTerm = it->second;
     999                 :            :     }
    1000                 :            :     else
    1001                 :            :     {
    1002                 :          2 :       cardTerm = nm->mkNode(Kind::SET_CARD, eqc);
    1003                 :            :     }
    1004         [ +  + ]:      75823 :     for (const std::pair<const Node, Node>& itmm : pmemsE)
    1005                 :            :     {
    1006                 :      53586 :       members.push_back(itmm.first);
    1007                 :      53586 :       exp.push_back(nm->mkNode(Kind::SET_MEMBER, itmm.first, cardTerm[0]));
    1008                 :            :     }
    1009         [ +  + ]:      22237 :     if (members.size() > 1)
    1010                 :            :     {
    1011                 :      11740 :       exp.push_back(nm->mkNode(Kind::DISTINCT, members));
    1012                 :            :     }
    1013         [ +  - ]:      22237 :     if (!members.empty())
    1014                 :            :     {
    1015                 :            :       Node conc = nm->mkNode(
    1016                 :      44474 :           Kind::GEQ, cardTerm, nm->mkConstInt(Rational(members.size())));
    1017         [ +  + ]:      22237 :       Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(Kind::AND, exp);
    1018                 :      22237 :       d_im.assertInference(conc, InferenceId::SETS_CARD_MINIMAL, expn, 1);
    1019                 :      22237 :     }
    1020 [ +  + ][ +  + ]:      46033 :   }
    1021                 :            :   // flush the lemmas
    1022                 :       3073 :   d_im.doPendingLemmas();
    1023                 :       3073 : }
    1024                 :            : 
    1025                 :       1117 : bool CardinalityExtension::isModelValueBasic(Node eqc)
    1026                 :            : {
    1027 [ +  + ][ +  + ]:       1117 :   return d_nf[eqc].size() == 1 && d_nf[eqc][0] == eqc;
    1028                 :            : }
    1029                 :            : 
    1030                 :        534 : void CardinalityExtension::mkModelValueElementsFor(
    1031                 :            :     Valuation& val,
    1032                 :            :     Node eqc,
    1033                 :            :     std::vector<Node>& els,
    1034                 :            :     const std::map<Node, Node>& mvals,
    1035                 :            :     TheoryModel* model)
    1036                 :            : {
    1037                 :        534 :   TypeNode elementType = eqc.getType().getSetElementType();
    1038                 :        534 :   bool elementTypeFinite = d_env.isFiniteType(elementType);
    1039                 :        534 :   bool isBasic = isModelValueBasic(eqc);
    1040         [ +  - ]:       1068 :   Trace("sets-model") << "mkModelValueElementsFor: " << eqc
    1041                 :          0 :                       << ", isBasic = " << isBasic
    1042                 :          0 :                       << ", isFinite = " << elementTypeFinite
    1043                 :        534 :                       << ", els = " << els << std::endl;
    1044         [ +  + ]:        534 :   if (isBasic)
    1045                 :            :   {
    1046                 :        286 :     std::map<Node, Node>::iterator it = d_eqc_to_card_term.find(eqc);
    1047         [ +  + ]:        286 :     if (it != d_eqc_to_card_term.end())
    1048                 :            :     {
    1049                 :            :       // slack elements from cardinality value
    1050                 :        267 :       Node v = val.getCandidateModelValue(it->second);
    1051         [ +  - ]:        534 :       Trace("sets-model") << "Cardinality of " << eqc << " is " << v
    1052                 :        267 :                           << std::endl;
    1053         [ -  + ]:        267 :       if (v.getConst<Rational>() > UINT32_MAX)
    1054                 :            :       {
    1055                 :          0 :         std::stringstream ss;
    1056                 :          0 :         ss << "The model for " << eqc << " was computed to have cardinality "
    1057                 :          0 :            << v << ". We only allow sets up to cardinality " << UINT32_MAX;
    1058                 :          0 :         throw LogicException(ss.str());
    1059                 :          0 :       }
    1060                 :        267 :       std::uint32_t vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
    1061 [ -  + ][ -  + ]:        267 :       Assert(els.size() <= vu);
                 [ -  - ]
    1062                 :        267 :       NodeManager* nm = nodeManager();
    1063         [ +  + ]:        267 :       if (elementTypeFinite)
    1064                 :            :       {
    1065                 :            :         // get all members of this finite type
    1066                 :         22 :         collectFiniteTypeSetElements(model);
    1067                 :            :       }
    1068         [ +  + ]:        403 :       while (els.size() < vu)
    1069                 :            :       {
    1070         [ +  + ]:        136 :         if (elementTypeFinite)
    1071                 :            :         {
    1072                 :            :           // At this point we are sure the formula is satisfiable and all
    1073                 :            :           // cardinality constraints are satisfied. Since this type is finite,
    1074                 :            :           // there is only one single cardinality graph for all sets of this
    1075                 :            :           // type because the universe cardinality constraint has been added by
    1076                 :            :           // CardinalityExtension::checkCardinalityExtended. This means we have
    1077                 :            :           // enough slack elements of this finite type for all disjoint leaves
    1078                 :            :           // in the cardinality graph. Therefore we can safely add new distinct
    1079                 :            :           // slack elements for the leaves without worrying about conflicts with
    1080                 :            :           // the current members of this finite type.
    1081                 :            : 
    1082                 :         94 :           Node slack = NodeManager::mkDummySkolem("slack", elementType);
    1083                 :         47 :           Node singleton = nm->mkNode(Kind::SET_SINGLETON, slack);
    1084                 :         47 :           els.push_back(singleton);
    1085                 :         47 :           d_finite_type_slack_elements[elementType].push_back(slack);
    1086         [ +  - ]:         94 :           Trace("sets-model") << "Added slack element " << slack << " to set "
    1087                 :         47 :                               << eqc << std::endl;
    1088                 :         47 :         }
    1089                 :            :         else
    1090                 :            :         {
    1091                 :         89 :           els.push_back(
    1092                 :        178 :               nm->mkNode(Kind::SET_SINGLETON,
    1093                 :        178 :                          NodeManager::mkDummySkolem("msde", elementType)));
    1094                 :            :         }
    1095                 :            :       }
    1096                 :        267 :     }
    1097                 :            :     else
    1098                 :            :     {
    1099         [ +  - ]:         19 :       Trace("sets-model") << "No slack elements for " << eqc << std::endl;
    1100                 :            :     }
    1101                 :            :   }
    1102                 :            :   else
    1103                 :            :   {
    1104         [ +  - ]:        496 :     Trace("sets-model") << "Build value for " << eqc
    1105                 :        248 :                         << " based on normal form, size = " << d_nf[eqc].size()
    1106                 :        248 :                         << std::endl;
    1107                 :            :     // it is union of venn regions
    1108         [ +  + ]:        506 :     for (unsigned j = 0; j < d_nf[eqc].size(); j++)
    1109                 :            :     {
    1110                 :        258 :       std::map<Node, Node>::const_iterator itm = mvals.find(d_nf[eqc][j]);
    1111         [ +  - ]:        258 :       if (itm != mvals.end())
    1112                 :            :       {
    1113                 :        258 :         els.push_back(itm->second);
    1114                 :            :       }
    1115                 :            :       else
    1116                 :            :       {
    1117                 :          0 :         DebugUnhandled();
    1118                 :            :       }
    1119                 :            :     }
    1120                 :            :   }
    1121                 :        534 : }
    1122                 :            : 
    1123                 :         22 : void CardinalityExtension::collectFiniteTypeSetElements(TheoryModel* model)
    1124                 :            : {
    1125         [ +  + ]:         22 :   if (d_finite_type_constants_processed)
    1126                 :            :   {
    1127                 :         10 :     return;
    1128                 :            :   }
    1129         [ +  - ]:         12 :   Trace("sets-model-finite") << "Collect finite elements" << std::endl;
    1130         [ +  + ]:         61 :   for (const Node& set : getOrderedSetsEqClasses())
    1131                 :            :   {
    1132         [ +  - ]:         49 :     Trace("sets-model-finite") << "eqc: " << set << std::endl;
    1133         [ -  + ]:         49 :     if (!d_env.isFiniteType(set.getType()))
    1134                 :            :     {
    1135         [ -  - ]:          0 :       Trace("sets-model-finite") << "...not finite" << std::endl;
    1136                 :          0 :       continue;
    1137                 :            :     }
    1138         [ +  + ]:         49 :     if (!isModelValueBasic(set))
    1139                 :            :     {
    1140                 :            :       // only consider leaves in the cardinality graph
    1141         [ +  - ]:         27 :       Trace("sets-model-finite") << "...not basic value" << std::endl;
    1142                 :         27 :       continue;
    1143                 :            :     }
    1144         [ +  + ]:         44 :     for (const std::pair<const Node, Node>& pair : d_state.getMembers(set))
    1145                 :            :     {
    1146                 :         22 :       Node member = pair.first;
    1147                 :         22 :       Node modelRepresentative = model->getRepresentative(member);
    1148         [ +  - ]:         22 :       Trace("sets-model-finite") << "  member: " << member << std::endl;
    1149                 :         22 :       std::vector<Node>& elements = d_finite_type_elements[member.getType()];
    1150                 :         22 :       if (std::find(elements.begin(), elements.end(), modelRepresentative)
    1151         [ +  - ]:         44 :           == elements.end())
    1152                 :            :       {
    1153                 :         22 :         elements.push_back(modelRepresentative);
    1154                 :            :       }
    1155                 :         22 :     }
    1156                 :            :   }
    1157                 :         12 :   d_finite_type_constants_processed = true;
    1158         [ +  - ]:         12 :   Trace("sets-model-finite") << "End Collect finite elements" << std::endl;
    1159                 :            : }
    1160                 :            : 
    1161                 :         12 : const std::vector<Node>& CardinalityExtension::getFiniteTypeMembers(
    1162                 :            :     TypeNode typeNode)
    1163                 :            : {
    1164                 :         12 :   return d_finite_type_elements[typeNode];
    1165                 :            : }
    1166                 :            : 
    1167                 :            : }  // namespace sets
    1168                 :            : }  // namespace theory
    1169                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14