LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/sets - infer_proof_cons.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 182 197 92.4 %
Date: 2025-02-20 12:45:24 Functions: 7 7 100.0 %
Branches: 137 266 51.5 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2025 by the authors listed in the file AUTHORS
       8                 :            :  * in the top-level source directory and their institutional affiliations.
       9                 :            :  * All rights reserved.  See the file COPYING in the top-level source
      10                 :            :  * directory for licensing information.
      11                 :            :  * ****************************************************************************
      12                 :            :  *
      13                 :            :  * Inference to proof conversion for sets.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "theory/sets/infer_proof_cons.h"
      17                 :            : 
      18                 :            : #include "expr/skolem_manager.h"
      19                 :            : #include "proof/proof_node_algorithm.h"
      20                 :            : #include "proof/proof_node_manager.h"
      21                 :            : #include "proof/theory_proof_step_buffer.h"
      22                 :            : #include "theory/builtin/proof_checker.h"
      23                 :            : #include "theory/sets/theory_sets_rewriter.h"
      24                 :            : 
      25                 :            : namespace cvc5::internal {
      26                 :            : namespace theory {
      27                 :            : namespace sets {
      28                 :            : 
      29                 :      11044 : InferProofCons::InferProofCons(Env& env, TheorySetsRewriter* tsr)
      30                 :            :     : EnvObj(env),
      31                 :            :       d_tsr(tsr),
      32                 :      22088 :       d_uimap(userContext()),
      33                 :            :       d_fmap(context()),
      34                 :      11044 :       d_expMap(context())
      35                 :            : {
      36                 :      11044 :   d_false = nodeManager()->mkConst(false);
      37                 :      11044 : }
      38                 :            : 
      39                 :       4397 : void InferProofCons::notifyFact(const Node& conc,
      40                 :            :                                 const Node& exp,
      41                 :            :                                 InferenceId id)
      42                 :            : {
      43 [ +  - ][ +  - ]:       8794 :   Assert(conc.getKind() != Kind::AND && conc.getKind() != Kind::IMPLIES);
         [ -  + ][ -  - ]
      44         [ +  + ]:       4397 :   if (d_fmap.find(conc) != d_fmap.end())
      45                 :            :   {
      46                 :            :     // already exists, redundant
      47                 :        433 :     return;
      48                 :            :   }
      49                 :       3964 :   d_fmap[conc] = id;
      50                 :       3964 :   d_expMap[conc] = exp;
      51                 :            : }
      52                 :            : 
      53                 :        384 : void InferProofCons::notifyConflict(const Node& conf, InferenceId id)
      54                 :            : {
      55         [ +  - ]:        768 :   Trace("sets-ipc-debug") << "SetsIpc::conflict " << conf << " " << id
      56                 :        384 :                           << std::endl;
      57                 :        384 :   d_uimap[conf.notNode()] = id;
      58                 :        384 : }
      59                 :            : 
      60                 :      29313 : void InferProofCons::notifyLemma(const Node& lem, InferenceId id)
      61                 :            : {
      62         [ +  - ]:      29313 :   Trace("sets-ipc-debug") << "SetsIpc::lemma " << lem << " " << id << std::endl;
      63                 :      29313 :   d_uimap[lem] = id;
      64                 :      29313 : }
      65                 :            : 
      66                 :       2397 : std::shared_ptr<ProofNode> InferProofCons::getProofFor(Node fact)
      67                 :            : {
      68                 :       2397 :   NodeInferenceMap::iterator it = d_uimap.find(fact);
      69         [ +  + ]:       2397 :   if (it == d_uimap.end())
      70                 :            :   {
      71                 :            :     // should be a fact
      72                 :        174 :     it = d_fmap.find(fact);
      73 [ -  + ][ -  + ]:        174 :     Assert(it != d_fmap.end());
                 [ -  - ]
      74                 :            :   }
      75                 :       2397 :   InferenceId id = it->second;
      76                 :            : 
      77                 :            :   // temporary proof
      78                 :       7191 :   CDProof cdp(d_env);
      79                 :       4794 :   std::vector<Node> assumps;
      80                 :       2397 :   Node conc = fact;
      81                 :            :   // First split into conclusion and assumptions.
      82 [ +  + ][ +  + ]:       2397 :   if (fact.getKind() == Kind::IMPLIES || fact.getKind() == Kind::NOT)
                 [ +  + ]
      83                 :            :   {
      84         [ +  + ]:       1515 :     if (fact[0].getKind() == Kind::AND)
      85                 :            :     {
      86                 :        931 :       assumps.insert(assumps.begin(), fact[0].begin(), fact[0].end());
      87                 :            :     }
      88                 :            :     else
      89                 :            :     {
      90                 :        584 :       assumps.push_back(fact[0]);
      91                 :            :     }
      92         [ +  + ]:       1515 :     if (fact.getKind() == Kind::IMPLIES)
      93                 :            :     {
      94                 :       1343 :       conc = fact[1];
      95                 :            :     }
      96                 :            :     else
      97                 :            :     {
      98                 :        172 :       conc = d_false;
      99                 :            :     }
     100                 :       3030 :     cdp.addStep(fact, ProofRule::SCOPE, {conc}, {assumps});
     101                 :            :   }
     102                 :            :   else
     103                 :            :   {
     104                 :            :     // should be a fact
     105                 :        882 :     NodeExpMap::iterator itex = d_expMap.find(fact);
     106         [ +  + ]:        882 :     if (itex != d_expMap.end())
     107                 :            :     {
     108                 :        348 :       Node exp = itex->second;
     109         [ +  + ]:        174 :       if (exp.getKind() == Kind::AND)
     110                 :            :       {
     111                 :        134 :         assumps.insert(assumps.end(), exp.begin(), exp.end());
     112                 :            :       }
     113                 :            :       else
     114                 :            :       {
     115                 :         40 :         assumps.push_back(exp);
     116                 :            :       }
     117                 :            :     }
     118                 :            :   }
     119                 :            :   // Try to convert.
     120         [ +  + ]:       2397 :   if (!convert(cdp, id, assumps, conc))
     121                 :            :   {
     122                 :       1090 :     cdp.addTrustedStep(conc, TrustId::THEORY_INFERENCE_SETS, assumps, {});
     123                 :            :   }
     124                 :       4794 :   return cdp.getProofFor(fact);
     125                 :            : }
     126                 :            : 
     127                 :       2397 : bool InferProofCons::convert(CDProof& cdp,
     128                 :            :                              InferenceId id,
     129                 :            :                              const std::vector<Node>& assumps,
     130                 :            :                              const Node& conc)
     131                 :            : {
     132                 :            :   // these are handled manually
     133 [ +  - ][ +  - ]:       4794 :   Assert(id != InferenceId::SETS_PROXY
         [ -  + ][ -  - ]
     134                 :            :          && id != InferenceId::SETS_PROXY_SINGLETON);
     135         [ +  - ]:       2397 :   Trace("sets-ipc") << "InferProofCons::convert " << id << std::endl;
     136         [ +  - ]:       2397 :   Trace("sets-ipc") << "- assumptions: " << assumps << std::endl;
     137         [ +  - ]:       2397 :   Trace("sets-ipc") << "- conclusion:  " << conc << std::endl;
     138                 :       2397 :   bool success = false;
     139                 :       2397 :   TheoryProofStepBuffer psb(cdp.getManager()->getChecker(), true);
     140 [ +  + ][ +  + ]:       2397 :   switch (id)
         [ +  + ][ +  + ]
     141                 :            :   {
     142                 :        410 :     case InferenceId::SETS_DOWN_CLOSURE:
     143                 :            :     case InferenceId::SETS_MEM_EQ:
     144                 :            :     case InferenceId::SETS_MEM_EQ_CONFLICT:
     145                 :            :     {
     146 [ -  + ][ -  + ]:        410 :       Assert(assumps.size() >= 1);
                 [ -  - ]
     147 [ -  + ][ -  + ]:        410 :       Assert(assumps[0].getKind() == Kind::SET_MEMBER);
                 [ -  - ]
     148 [ +  - ][ -  + ]:        410 :       Assert(assumps.size() == 1 || assumps[1].getKind() == Kind::EQUAL);
         [ -  + ][ -  - ]
     149                 :            :       // (and (set.member x S) (= S (op T1 T2))) =>
     150                 :            :       // rewrite((set.member x (op T1 T2)))
     151                 :            :       // this holds by applying the equality as a substitution to the first
     152                 :            :       // assumption and rewriting.
     153                 :        820 :       std::vector<Node> exp(assumps.begin() + 1, assumps.end());
     154                 :        410 :       Node aelim = psb.applyPredElim(assumps[0], exp);
     155                 :        410 :       success = true;
     156         [ +  + ]:        410 :       if (!CDProof::isSame(aelim, conc))
     157                 :            :       {
     158                 :          5 :         success = psb.applyPredTransform(aelim, conc, {});
     159                 :            :       }
     160                 :            :       // should never fail
     161 [ -  + ][ -  + ]:        410 :       Assert(success);
                 [ -  - ]
     162                 :            :     }
     163                 :        410 :     break;
     164                 :        468 :     case InferenceId::SETS_UP_CLOSURE:
     165                 :            :     case InferenceId::SETS_UP_CLOSURE_2:
     166                 :            :     {
     167                 :        468 :       NodeManager* nm = nodeManager();
     168                 :            :       // An example inference is:
     169                 :            :       // (set.member x A) ^ (set.member y B) ^ (= x y) => (set.member x k)
     170                 :            :       // where k is the purification skolem for (set.inter A B).
     171 [ -  + ][ -  + ]:        468 :       Assert(conc.getKind() == Kind::SET_MEMBER);
                 [ -  - ]
     172                 :        468 :       Node so = SkolemManager::getUnpurifiedForm(conc[1]);
     173         [ +  - ]:        468 :       Trace("sets-ipc") << "Unpurified form " << so << std::endl;
     174                 :            :       // We first compute the single step rewriting of the conclusion.
     175                 :            :       // For the above example, memor would be:
     176                 :            :       // (and (set.member x A) (set.member x B)).
     177                 :        936 :       Node memo = nm->mkNode(Kind::SET_MEMBER, conc[0], so);
     178                 :        468 :       Node memor = d_tsr->rewriteMembershipBinaryOp(memo);
     179         [ +  - ]:        936 :       Trace("sets-ipc") << "Single step rewriting of membership " << memor
     180                 :        468 :                         << std::endl;
     181 [ -  + ][ -  + ]:        468 :       Assert(memo != memor);
                 [ -  - ]
     182                 :            :       // collect the memberships in the premise
     183                 :        468 :       std::vector<Node> assumpMem;
     184                 :        468 :       std::vector<Node> assumpOther;
     185                 :            :       // We now partition the antecedant to the membership
     186                 :            :       // part (assumpMem) and the substitution part (assumpOther). The
     187                 :            :       // membership part will be equivalent via rewriting to the conclusion.
     188         [ +  + ]:       1488 :       for (const Node& a : assumps)
     189                 :            :       {
     190         [ +  + ]:       2040 :         Node aa = a.getKind() == Kind::NOT ? a[0] : a;
     191         [ +  + ]:       1020 :         if (aa.getKind() == Kind::SET_MEMBER)
     192                 :            :         {
     193                 :        738 :           assumpMem.push_back(a);
     194                 :            :         }
     195                 :            :         else
     196                 :            :         {
     197                 :        282 :           assumpOther.push_back(a);
     198                 :            :         }
     199                 :            :       }
     200 [ +  + ][ -  + ]:        468 :       Assert(assumpMem.size() == 1 || assumpMem.size() == 2);
         [ -  + ][ -  - ]
     201                 :        468 :       Node msrc;
     202                 :            :       // Use AND_INTRO to put the memberships together if necessary.
     203         [ +  + ]:        468 :       if (assumpMem.size() == 2)
     204                 :            :       {
     205                 :        270 :         msrc = nm->mkAnd(assumpMem);
     206                 :        270 :         psb.addStep(ProofRule::AND_INTRO, {assumpMem}, {}, msrc);
     207                 :            :       }
     208                 :            :       else
     209                 :            :       {
     210                 :        198 :         msrc = assumpMem[0];
     211                 :            :       }
     212                 :            :       // Now, prove the equivalence between the memberships and the
     213                 :            :       // conclusion, possibly using the substituion in assumpOther.
     214                 :        468 :       bool isOr = (memor.getKind() == Kind::OR);
     215         [ +  + ]:        468 :       size_t ntgts = isOr ? 2 : 1;
     216         [ +  - ]:        575 :       for (size_t i = 0; i < ntgts; i++)
     217                 :            :       {
     218         [ +  + ]:        575 :         Node mtgt = isOr ? memor[i] : memor;
     219         [ +  - ]:        575 :         Trace("sets-ipc") << "...try target " << mtgt << std::endl;
     220         [ +  + ]:        575 :         if (psb.applyPredTransform(msrc, mtgt, assumpOther))
     221                 :            :         {
     222                 :        468 :           success = true;
     223         [ +  + ]:        468 :           if (isOr)
     224                 :            :           {
     225                 :            :             // if union, we get the desired (left or right) conclusion
     226                 :        396 :             success = psb.applyPredIntro(memor, {mtgt}, MethodId::SB_FORMULA);
     227                 :            :             // should never fail
     228 [ -  + ][ -  + ]:        198 :             Assert(success);
                 [ -  - ]
     229                 :            :           }
     230         [ +  - ]:        468 :           Trace("sets-ipc") << "......success" << std::endl;
     231                 :        468 :           break;
     232                 :            :         }
     233                 :            :       }
     234                 :            :       // If successful, we have proven:
     235                 :            :       //
     236                 :            :       // (set.member x A)   (set.member y B)
     237                 :            :       // --------------------------------------- AND_INTRO
     238                 :            :       // (and (set.member x A) (set.member y B))    (= x y)
     239                 :            :       // ------------------------------------------------- MACRO_SR_PRED_TRANS
     240                 :            :       // (set.member x (set.inter A B))
     241         [ -  + ]:        468 :       if (!success)
     242                 :            :       {
     243                 :          0 :         Assert(success);
     244                 :          0 :         break;
     245                 :            :       }
     246                 :            :       // If successful, go back and show memor holds.
     247         [ +  - ]:        936 :       Trace("sets-ipc") << "* Prove transform " << memor << " to " << memo
     248                 :        468 :                         << std::endl;
     249         [ -  + ]:        468 :       if (!psb.applyPredTransform(memor, memo, {}))
     250                 :            :       {
     251                 :            :         // should never fail
     252                 :          0 :         success = false;
     253                 :          0 :         Assert(success);
     254                 :          0 :         break;
     255                 :            :       }
     256         [ +  - ]:        468 :       if (so != conc[1])
     257                 :            :       {
     258                 :        468 :         std::vector<Node> ceqs;
     259                 :        936 :         Node ceq = conc[0].eqNode(conc[0]);
     260                 :        936 :         psb.addStep(ProofRule::REFL, {}, {conc[0]}, ceq);
     261                 :        468 :         ceqs.push_back(ceq);
     262                 :        468 :         ceq = so.eqNode(conc[1]);
     263         [ +  - ]:        936 :         Trace("sets-ipc") << "* Prove equal (by original forms) " << ceq
     264                 :        468 :                           << std::endl;
     265 [ +  + ][ -  + ]:        936 :         if (!psb.addStep(ProofRule::MACRO_SR_PRED_INTRO, {}, {ceq}, ceq))
                 [ -  - ]
     266                 :            :         {
     267                 :            :           // should never fail
     268                 :          0 :           success = false;
     269                 :          0 :           Assert(success);
     270                 :          0 :           break;
     271                 :            :         }
     272                 :        468 :         ceqs.push_back(ceq);
     273                 :        468 :         std::vector<Node> cargs;
     274                 :        468 :         Node cequiv = memo.eqNode(conc);
     275                 :        468 :         ProofRule cr = expr::getCongRule(memo, cargs);
     276         [ -  + ]:        468 :         if (!psb.addStep(cr, ceqs, cargs, cequiv))
     277                 :            :         {
     278                 :            :           // should never fail
     279                 :          0 :           success = false;
     280                 :          0 :           Assert(success);
     281                 :          0 :           break;
     282                 :            :         }
     283 [ +  + ][ -  + ]:       1404 :         if (!psb.addStep(ProofRule::EQ_RESOLVE, {memo, cequiv}, {}, conc))
                 [ -  - ]
     284                 :            :         {
     285                 :            :           // should never fail
     286                 :          0 :           success = false;
     287                 :          0 :           Assert(success);
     288                 :          0 :           break;
     289                 :            :         }
     290                 :            :       }
     291                 :            :       // Final proof now is,using A^B as shorthand for (set.inter A B):
     292                 :            :       //
     293                 :            :       //                    ----- REFL  ---------- MACRO_SR_PRED_INTRO
     294                 :            :       // ...                x = x       A^B = k
     295                 :            :       // ------------------ -------------------------------------- CONG
     296                 :            :       // (set.member x A^B) (set.member x A^B) = (set.member x k)
     297                 :            :       // --------------------------------------------------------- EQ_RESOLVE
     298                 :            :       // (set.member x k)
     299                 :            :       //
     300                 :            :       // where ... is the proof from above.
     301                 :            :     }
     302                 :        468 :     break;
     303                 :         48 :     case InferenceId::SETS_SKOLEM:
     304                 :            :     {
     305 [ -  + ][ -  + ]:         48 :       Assert(assumps.empty());
                 [ -  - ]
     306                 :         48 :       success = psb.applyPredIntro(conc, {});
     307 [ -  + ][ -  + ]:         48 :       Assert(success);
                 [ -  - ]
     308                 :            :     }
     309                 :         48 :     break;
     310                 :        206 :     case InferenceId::SETS_DEQ:
     311                 :            :     {
     312 [ -  + ][ -  + ]:        206 :       Assert(assumps.size() == 1);
                 [ -  - ]
     313                 :        412 :       Node exp = assumps[0];
     314                 :            :       // ensure we are properly ordered
     315                 :        412 :       Assert(exp.getKind() == Kind::NOT && exp[0].getKind() == Kind::EQUAL
     316                 :            :              && exp[0][0] < exp[0][1]);
     317                 :        824 :       Node res = psb.tryStep(ProofRule::SETS_EXT, {exp}, {}, conc);
     318                 :        206 :       success = CDProof::isSame(res, conc);
     319 [ -  + ][ -  + ]:        206 :       Assert(success);
                 [ -  - ]
     320                 :            :     }
     321                 :        206 :     break;
     322                 :         40 :     case InferenceId::SETS_SINGLETON_EQ:
     323                 :            :     {
     324                 :            :       // SINGLETON_INJ
     325 [ -  + ][ -  + ]:         40 :       Assert(assumps.size() == 1);
                 [ -  - ]
     326                 :            :       Node res =
     327                 :        160 :           psb.tryStep(ProofRule::SETS_SINGLETON_INJ, {assumps[0]}, {}, conc);
     328                 :         40 :       success = CDProof::isSame(res, conc);
     329 [ -  + ][ -  + ]:         40 :       Assert(success);
                 [ -  - ]
     330                 :            :     }
     331                 :         40 :     break;
     332                 :         30 :     case InferenceId::SETS_FILTER_UP:
     333                 :            :     case InferenceId::SETS_FILTER_DOWN:
     334                 :            :     {
     335                 :         60 :       Node mem = assumps[0];
     336         [ +  + ]:         30 :       if (assumps.size() == 2)
     337                 :            :       {
     338                 :            :         // Transform based on the second equality A = B:
     339                 :            :         //
     340                 :            :         //                  ------ REFL
     341                 :            :         //                   x = x               A = B
     342                 :            :         //                  ----------------------------------- CONG
     343                 :            :         // (set.member x A) (set.member x A) = (set.member x B)
     344                 :            :         // ---------------------------------------------------- EQ_RESOLVE
     345                 :            :         // (set.member x B)
     346 [ -  + ][ -  + ]:         10 :         Assert(assumps[0].getKind() == Kind::SET_MEMBER);
                 [ -  - ]
     347 [ -  + ][ -  + ]:         10 :         Assert(assumps[1].getKind() == Kind::EQUAL);
                 [ -  - ]
     348                 :         50 :         Node refl = psb.tryStep(ProofRule::REFL, {}, {assumps[0][0]});
     349                 :         20 :         std::vector<Node> cargs;
     350                 :         10 :         ProofRule cr = expr::getCongRule(assumps[0], cargs);
     351                 :         20 :         Node aeq = assumps[1];
     352         [ +  - ]:         10 :         if (aeq[1] == assumps[0][1])
     353                 :            :         {
     354                 :            :           // flip?
     355                 :         10 :           aeq = aeq[1].eqNode(aeq[0]);
     356                 :         20 :           psb.tryStep(ProofRule::SYMM, {assumps[1]}, {});
     357                 :            :         }
     358                 :         50 :         Node eq = psb.tryStep(cr, {refl, aeq}, cargs);
     359         [ +  - ]:         20 :         Trace("sets-ipc") << "...via CONG is " << eq << ", now try with " << mem
     360                 :         10 :                           << std::endl;
     361 [ +  + ][ -  - ]:         30 :         mem = psb.tryStep(ProofRule::EQ_RESOLVE, {mem, eq}, {});
     362 [ -  + ][ -  + ]:         10 :         Assert(!mem.isNull());
                 [ -  - ]
     363                 :            :       }
     364                 :         60 :       ProofRule pr = (id == InferenceId::SETS_FILTER_UP)
     365         [ +  + ]:         30 :                          ? ProofRule::SETS_FILTER_UP
     366                 :            :                          : ProofRule::SETS_FILTER_DOWN;
     367                 :         60 :       std::vector<Node> pfArgs;
     368         [ +  + ]:         30 :       if (id == InferenceId::SETS_FILTER_UP)
     369                 :            :       {
     370                 :         40 :         Assert(conc.getKind() == Kind::EQUAL
     371                 :            :                && conc[0].getKind() == Kind::SET_MEMBER
     372                 :            :                && conc[0][1].getKind() == Kind::SET_FILTER);
     373                 :         60 :         Node pred = conc[0][1][0];
     374                 :         20 :         pfArgs.push_back(pred);
     375                 :            :       }
     376                 :        120 :       Node res = psb.tryStep(pr, {mem}, pfArgs);
     377         [ +  - ]:         60 :       Trace("sets-ipc") << "Filter rule " << id << " returns " << res
     378                 :         30 :                         << ", expects " << conc << std::endl;
     379                 :         30 :       success = CDProof::isSame(res, conc);
     380 [ -  + ][ -  + ]:         30 :       Assert(success);
                 [ -  - ]
     381                 :            :     }
     382                 :         30 :     break;
     383                 :        105 :     case InferenceId::SETS_EQ_MEM_CONFLICT:
     384                 :            :     case InferenceId::SETS_EQ_MEM:
     385                 :            :     {
     386                 :            :       // Handles cases:
     387                 :            :       // (and (= S set.empty) (set.member x S)) => false
     388                 :            :       // (and (= S (set.singleton y)) (set.member x S)) => (= x y)
     389 [ -  + ][ -  + ]:        105 :       Assert(assumps.size()==2);
                 [ -  - ]
     390 [ -  + ][ -  + ]:        105 :       Assert(assumps[0].getKind() == Kind::EQUAL);
                 [ -  - ]
     391 [ -  + ][ -  + ]:        105 :       Assert(assumps[1].getKind() == Kind::SET_MEMBER);
                 [ -  - ]
     392                 :        210 :       success = psb.applyPredTransform(assumps[1], conc, {assumps[0]});
     393                 :            :     }
     394                 :        105 :       break;
     395                 :       1090 :     case InferenceId::SETS_EQ_CONFLICT:
     396         [ +  - ]:       1090 :     default: Trace("sets-ipc") << "Unhandled " << id; break;
     397                 :            :   }
     398         [ +  + ]:       2397 :   if (success)
     399                 :            :   {
     400         [ -  + ]:       1307 :     if (!cdp.addSteps(psb))
     401                 :            :     {
     402                 :            :       // should not fail if success was computed correctly above
     403                 :          0 :       Assert(false);
     404                 :            :       success = false;
     405                 :            :     }
     406                 :            :   }
     407         [ +  - ]:       2397 :   Trace("sets-ipc") << "...success = " << success << std::endl;
     408                 :       4794 :   return success;
     409                 :            : }
     410                 :            : 
     411                 :         16 : std::string InferProofCons::identify() const { return "sets::InferProofCons"; }
     412                 :            : 
     413                 :            : }  // namespace sets
     414                 :            : }  // namespace theory
     415                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14