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

Generated by: LCOV version 1.14