LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers - entailment_check.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 191 198 96.5 %
Date: 2026-06-29 10:35:02 Functions: 12 12 100.0 %
Branches: 201 258 77.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 entailment check class.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/quantifiers/entailment_check.h"
      14                 :            : 
      15                 :            : #include "theory/quantifiers/quantifiers_state.h"
      16                 :            : #include "theory/quantifiers/term_database.h"
      17                 :            : 
      18                 :            : using namespace cvc5::internal::kind;
      19                 :            : using namespace cvc5::context;
      20                 :            : 
      21                 :            : namespace cvc5::internal {
      22                 :            : namespace theory {
      23                 :            : namespace quantifiers {
      24                 :            : 
      25                 :      51315 : EntailmentCheck::EntailmentCheck(Env& env, QuantifiersState& qs, TermDb& tdb)
      26                 :      51315 :     : EnvObj(env), d_qstate(qs), d_tdb(tdb)
      27                 :            : {
      28                 :      51315 :   d_true = nodeManager()->mkConst(true);
      29                 :      51315 :   d_false = nodeManager()->mkConst(false);
      30                 :      51315 : }
      31                 :            : 
      32                 :     101934 : EntailmentCheck::~EntailmentCheck() {}
      33                 :            : 
      34                 :     125012 : Node EntailmentCheck::evaluateTerm2(TNode n,
      35                 :            :                                     std::map<TNode, Node>& visited,
      36                 :            :                                     std::map<TNode, TNode>& subs,
      37                 :            :                                     bool subsRep,
      38                 :            :                                     bool useEntailmentTests,
      39                 :            :                                     bool reqHasTerm)
      40                 :            : {
      41                 :     125012 :   std::map<TNode, Node>::iterator itv = visited.find(n);
      42         [ +  + ]:     125012 :   if (itv != visited.end())
      43                 :            :   {
      44                 :      18653 :     return itv->second;
      45                 :            :   }
      46         [ +  - ]:     106359 :   Trace("term-db-eval") << "evaluate term : " << n << std::endl;
      47                 :     106359 :   Node ret = n;
      48                 :     106359 :   Kind k = n.getKind();
      49         [ +  + ]:     106359 :   if (k == Kind::FORALL)
      50                 :            :   {
      51                 :            :     // do nothing
      52                 :            :   }
      53         [ +  + ]:     106319 :   else if (k == Kind::BOUND_VARIABLE)
      54                 :            :   {
      55                 :      44241 :     std::map<TNode, TNode>::iterator it = subs.find(n);
      56         [ +  + ]:      44241 :     if (it != subs.end())
      57                 :            :     {
      58         [ +  - ]:      20351 :       if (!subsRep)
      59                 :            :       {
      60                 :      20351 :         ret = d_qstate.getRepresentative(it->second);
      61                 :            :       }
      62                 :            :       else
      63                 :            :       {
      64                 :          0 :         ret = it->second;
      65                 :            :       }
      66                 :            :     }
      67                 :            :   }
      68         [ +  + ]:      62078 :   else if (d_qstate.hasTerm(n))
      69                 :            :   {
      70         [ +  - ]:       2902 :     Trace("term-db-eval") << "...exists in ee, return rep" << std::endl;
      71                 :       2902 :     ret = d_qstate.getRepresentative(n);
      72                 :       2902 :     reqHasTerm = false;
      73                 :            :   }
      74         [ +  + ]:      59176 :   else if (n.hasOperator())
      75                 :            :   {
      76                 :      58488 :     std::vector<TNode> args;
      77                 :      58488 :     bool ret_set = false;
      78         [ +  + ]:     157039 :     for (unsigned i = 0, nchild = n.getNumChildren(); i < nchild; i++)
      79                 :            :     {
      80                 :     209168 :       TNode c = evaluateTerm2(
      81                 :     104584 :           n[i], visited, subs, subsRep, useEntailmentTests, reqHasTerm);
      82         [ +  + ]:     104584 :       if (c.isNull())
      83                 :            :       {
      84                 :       6027 :         ret = Node::null();
      85                 :       6027 :         ret_set = true;
      86                 :       6027 :         break;
      87                 :            :       }
      88 [ +  + ][ +  + ]:      98557 :       else if (c == d_true || c == d_false)
                 [ +  + ]
      89                 :            :       {
      90                 :            :         // short-circuiting
      91 [ +  + ][ -  + ]:        604 :         if ((k == Kind::AND && c == d_false) || (k == Kind::OR && c == d_true))
         [ +  + ][ -  + ]
                 [ +  + ]
      92                 :            :         {
      93                 :          6 :           ret = c;
      94                 :          6 :           ret_set = true;
      95                 :          6 :           reqHasTerm = false;
      96                 :          6 :           break;
      97                 :            :         }
      98 [ -  + ][ -  - ]:        598 :         else if (k == Kind::ITE && i == 0)
      99                 :            :         {
     100         [ -  - ]:          0 :           ret = evaluateTerm2(n[c == d_true ? 1 : 2],
     101                 :            :                               visited,
     102                 :            :                               subs,
     103                 :            :                               subsRep,
     104                 :            :                               useEntailmentTests,
     105                 :          0 :                               reqHasTerm);
     106                 :          0 :           ret_set = true;
     107                 :          0 :           reqHasTerm = false;
     108                 :          0 :           break;
     109                 :            :         }
     110                 :            :       }
     111         [ +  - ]:      98551 :       Trace("term-db-eval") << "  child " << i << " : " << c << std::endl;
     112                 :      98551 :       args.push_back(c);
     113         [ +  + ]:     104584 :     }
     114         [ +  + ]:      58488 :     if (!ret_set)
     115                 :            :     {
     116                 :            :       // get the (indexed) operator of n, if it exists
     117                 :     104910 :       TNode f = d_tdb.getMatchOperator(n);
     118                 :            :       // if it is an indexed term, return the congruent term
     119         [ +  + ]:      52455 :       if (!f.isNull())
     120                 :            :       {
     121                 :            :         // if f is congruent to a term indexed by this class
     122                 :      49361 :         TNode nn = d_tdb.getCongruentTerm(f, args);
     123         [ +  - ]:      98722 :         Trace("term-db-eval") << "  got congruent term " << nn
     124                 :      49361 :                               << " from DB for " << n << std::endl;
     125         [ +  + ]:      49361 :         if (!nn.isNull())
     126                 :            :         {
     127                 :      23371 :           ret = d_qstate.getRepresentative(nn);
     128         [ +  - ]:      23371 :           Trace("term-db-eval") << "return rep" << std::endl;
     129                 :      23371 :           ret_set = true;
     130                 :      23371 :           reqHasTerm = false;
     131 [ -  + ][ -  + ]:      23371 :           Assert(!ret.isNull());
                 [ -  - ]
     132                 :            :         }
     133                 :      49361 :       }
     134         [ +  + ]:      52455 :       if (!ret_set)
     135                 :            :       {
     136         [ +  - ]:      29084 :         Trace("term-db-eval") << "return rewrite" << std::endl;
     137                 :            :         // a theory symbol or a new UF term
     138         [ +  + ]:      29084 :         if (n.getMetaKind() == metakind::PARAMETERIZED)
     139                 :            :         {
     140                 :      25990 :           args.insert(args.begin(), n.getOperator());
     141                 :            :         }
     142                 :      29084 :         ret = nodeManager()->mkNode(n.getKind(), args);
     143                 :      29084 :         ret = rewrite(ret);
     144         [ +  + ]:      29084 :         if (ret.getKind() == Kind::EQUAL)
     145                 :            :         {
     146         [ -  + ]:         72 :           if (d_qstate.areDisequal(ret[0], ret[1]))
     147                 :            :           {
     148                 :          0 :             ret = d_false;
     149                 :            :           }
     150                 :            :         }
     151         [ +  + ]:      29084 :         if (useEntailmentTests)
     152                 :            :         {
     153 [ +  - ][ +  + ]:        478 :           if (ret.getKind() == Kind::EQUAL || ret.getKind() == Kind::GEQ)
                 [ +  + ]
     154                 :            :           {
     155                 :          6 :             Valuation& val = d_qstate.getValuation();
     156         [ +  - ]:         12 :             for (unsigned j = 0; j < 2; j++)
     157                 :            :             {
     158                 :            :               std::pair<bool, Node> et = val.entailmentCheck(
     159                 :            :                   options::TheoryOfMode::THEORY_OF_TYPE_BASED,
     160         [ +  + ]:         24 :                   j == 0 ? ret : ret.negate());
     161         [ +  + ]:         12 :               if (et.first)
     162                 :            :               {
     163         [ -  + ]:          6 :                 ret = j == 0 ? d_true : d_false;
     164                 :          6 :                 break;
     165                 :            :               }
     166         [ +  + ]:         12 :             }
     167                 :            :           }
     168                 :            :         }
     169                 :            :       }
     170                 :      52455 :     }
     171                 :      58488 :   }
     172                 :            :   // must have the term
     173 [ +  + ][ +  + ]:     106359 :   if (reqHasTerm && !ret.isNull())
                 [ +  + ]
     174                 :            :   {
     175                 :      27534 :     Kind rk = ret.getKind();
     176 [ +  - ][ +  - ]:      27534 :     if (rk != Kind::OR && rk != Kind::AND && rk != Kind::EQUAL
                 [ +  + ]
     177 [ +  - ][ +  - ]:      27462 :         && rk != Kind::ITE && rk != Kind::NOT && rk != Kind::FORALL)
                 [ +  + ]
     178                 :            :     {
     179         [ +  + ]:      27382 :       if (!d_qstate.hasTerm(ret))
     180                 :            :       {
     181                 :       4049 :         ret = Node::null();
     182                 :            :       }
     183                 :            :     }
     184                 :            :   }
     185         [ +  - ]:     212718 :   Trace("term-db-eval") << "evaluated term : " << n << ", got : " << ret
     186                 :     106359 :                         << ", reqHasTerm = " << reqHasTerm << std::endl;
     187                 :     106359 :   visited[n] = ret;
     188                 :     106359 :   return ret;
     189                 :     106359 : }
     190                 :            : 
     191                 :   35847827 : TNode EntailmentCheck::getEntailedTerm2(TNode n,
     192                 :            :                                         std::map<TNode, TNode>& subs,
     193                 :            :                                         bool subsRep)
     194                 :            : {
     195         [ +  - ]:   35847827 :   Trace("term-db-entail") << "get entailed term : " << n << std::endl;
     196         [ +  + ]:   35847827 :   if (d_qstate.hasTerm(n))
     197                 :            :   {
     198         [ +  - ]:    2654086 :     Trace("term-db-entail") << "...exists in ee, return rep " << std::endl;
     199                 :    2654086 :     return n;
     200                 :            :   }
     201         [ +  + ]:   33193741 :   else if (n.getKind() == Kind::BOUND_VARIABLE)
     202                 :            :   {
     203                 :   17144048 :     std::map<TNode, TNode>::iterator it = subs.find(n);
     204         [ +  + ]:   17144048 :     if (it != subs.end())
     205                 :            :     {
     206         [ +  - ]:   12429488 :       Trace("term-db-entail")
     207                 :    6214744 :           << "...substitution is : " << it->second << std::endl;
     208         [ +  + ]:    6214744 :       if (subsRep)
     209                 :            :       {
     210 [ -  + ][ -  + ]:    4031969 :         Assert(d_qstate.hasTerm(it->second));
                 [ -  - ]
     211 [ -  + ][ -  + ]:    4031969 :         Assert(d_qstate.getRepresentative(it->second) == it->second);
                 [ -  - ]
     212                 :   10246713 :         return it->second;
     213                 :            :       }
     214                 :    2182775 :       return getEntailedTerm2(it->second, subs, subsRep);
     215                 :            :     }
     216                 :            :   }
     217         [ +  + ]:   16049693 :   else if (n.getKind() == Kind::ITE)
     218                 :            :   {
     219         [ +  + ]:     112950 :     for (uint32_t i = 0; i < 2; i++)
     220                 :            :     {
     221         [ +  + ]:      85834 :       if (isEntailed2(n[0], subs, subsRep, i == 0))
     222                 :            :       {
     223         [ +  + ]:      18148 :         return getEntailedTerm2(n[i == 0 ? 1 : 2], subs, subsRep);
     224                 :            :       }
     225                 :            :     }
     226                 :            :   }
     227                 :            :   else
     228                 :            :   {
     229         [ +  + ]:   16004429 :     if (n.hasOperator())
     230                 :            :     {
     231                 :   31985666 :       TNode f = d_tdb.getMatchOperator(n);
     232         [ +  + ]:   15992833 :       if (!f.isNull())
     233                 :            :       {
     234                 :   15976456 :         std::vector<TNode> args;
     235         [ +  + ]:   22873214 :         for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++)
     236                 :            :         {
     237                 :   21784264 :           TNode c = getEntailedTerm2(n[i], subs, subsRep);
     238         [ +  + ]:   21784264 :           if (c.isNull())
     239                 :            :           {
     240                 :   14887506 :             return TNode::null();
     241                 :            :           }
     242                 :    6896758 :           c = d_qstate.getRepresentative(c);
     243         [ +  - ]:    6896758 :           Trace("term-db-entail") << "  child " << i << " : " << c << std::endl;
     244                 :    6896758 :           args.push_back(c);
     245         [ +  + ]:   21784264 :         }
     246                 :    1088950 :         TNode nn = d_tdb.getCongruentTerm(f, args);
     247         [ +  - ]:    2177900 :         Trace("term-db-entail")
     248                 :    1088950 :             << "  got congruent term " << nn << " for " << n << std::endl;
     249                 :    1088950 :         return nn;
     250                 :   15976456 :       }
     251         [ +  + ]:   15992833 :     }
     252                 :            :   }
     253                 :   10984393 :   return TNode::null();
     254                 :            : }
     255                 :            : 
     256                 :       6897 : Node EntailmentCheck::evaluateTerm(TNode n,
     257                 :            :                                    std::map<TNode, TNode>& subs,
     258                 :            :                                    bool subsRep,
     259                 :            :                                    bool useEntailmentTests,
     260                 :            :                                    bool reqHasTerm)
     261                 :            : {
     262                 :       6897 :   std::map<TNode, Node> visited;
     263                 :            :   return evaluateTerm2(
     264                 :      13794 :       n, visited, subs, subsRep, useEntailmentTests, reqHasTerm);
     265                 :       6897 : }
     266                 :            : 
     267                 :      13531 : Node EntailmentCheck::evaluateTerm(TNode n,
     268                 :            :                                    bool useEntailmentTests,
     269                 :            :                                    bool reqHasTerm)
     270                 :            : {
     271                 :      13531 :   std::map<TNode, Node> visited;
     272                 :      13531 :   std::map<TNode, TNode> subs;
     273                 :      27062 :   return evaluateTerm2(n, visited, subs, false, useEntailmentTests, reqHasTerm);
     274                 :      13531 : }
     275                 :            : 
     276                 :   10930955 : TNode EntailmentCheck::getEntailedTerm(TNode n,
     277                 :            :                                        std::map<TNode, TNode>& subs,
     278                 :            :                                        bool subsRep)
     279                 :            : {
     280                 :   10930955 :   return getEntailedTerm2(n, subs, subsRep);
     281                 :            : }
     282                 :            : 
     283                 :     205054 : TNode EntailmentCheck::getEntailedTerm(TNode n)
     284                 :            : {
     285                 :     205054 :   std::map<TNode, TNode> subs;
     286                 :     410108 :   return getEntailedTerm2(n, subs, false);
     287                 :     205054 : }
     288                 :            : 
     289                 :    1372137 : bool EntailmentCheck::isEntailed2(TNode n,
     290                 :            :                                   std::map<TNode, TNode>& subs,
     291                 :            :                                   bool subsRep,
     292                 :            :                                   bool pol)
     293                 :            : {
     294         [ +  - ]:    2744274 :   Trace("term-db-entail") << "Check entailed : " << n << ", pol = " << pol
     295                 :    1372137 :                           << std::endl;
     296 [ -  + ][ -  + ]:    1372137 :   Assert(n.getType().isBoolean());
                 [ -  - ]
     297                 :    1372137 :   Kind k = n.getKind();
     298                 :    1372137 :   if (k == Kind::EQUAL && !n[0].getType().isBoolean())
     299                 :            :   {
     300 [ +  + ][ +  + ]:     433369 :     TNode n1 = n[0].isConst() ? n[0] : getEntailedTerm2(n[0], subs, subsRep);
                 [ -  - ]
     301         [ +  + ]:     235736 :     if (!n1.isNull())
     302                 :            :     {
     303 [ +  + ][ +  + ]:     344964 :       TNode n2 = n[1].isConst() ? n[1] : getEntailedTerm2(n[1], subs, subsRep);
                 [ -  - ]
     304         [ +  + ]:     179557 :       if (!n2.isNull())
     305                 :            :       {
     306         [ +  + ]:     120772 :         if (pol)
     307                 :            :         {
     308                 :            :           // must check for equality here
     309                 :      69998 :           return d_qstate.areEqual(n1, n2);
     310                 :            :         }
     311                 :      50774 :         return d_qstate.areDisequal(n1, n2);
     312                 :            :       }
     313         [ +  + ]:     179557 :     }
     314         [ +  + ]:     235736 :   }
     315         [ +  + ]:    1136401 :   else if (k == Kind::NOT)
     316                 :            :   {
     317                 :     406629 :     return isEntailed2(n[0], subs, subsRep, !pol);
     318                 :            :   }
     319 [ +  + ][ +  + ]:     729772 :   else if (k == Kind::OR || k == Kind::AND)
     320                 :            :   {
     321 [ +  + ][ +  + ]:     136610 :     bool simPol = (pol && k == Kind::OR) || (!pol && k == Kind::AND);
         [ +  + ][ +  + ]
     322         [ +  + ]:     646741 :     for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++)
     323                 :            :     {
     324         [ +  + ]:     559776 :       if (isEntailed2(n[i], subs, subsRep, pol))
     325                 :            :       {
     326         [ +  + ]:      29662 :         if (simPol)
     327                 :            :         {
     328                 :      21932 :           return true;
     329                 :            :         }
     330                 :            :       }
     331                 :            :       else
     332                 :            :       {
     333         [ +  + ]:     530114 :         if (!simPol)
     334                 :            :         {
     335                 :      27713 :           return false;
     336                 :            :         }
     337                 :            :       }
     338                 :            :     }
     339                 :      86965 :     return !simPol;
     340                 :            :     // Boolean equality here
     341                 :            :   }
     342 [ +  + ][ +  + ]:     593162 :   else if (k == Kind::EQUAL || k == Kind::ITE)
     343                 :            :   {
     344 [ -  + ][ -  + ]:      35928 :     Assert(n[0].getType().isBoolean());
                 [ -  - ]
     345         [ +  + ]:      74797 :     for (size_t i = 0; i < 2; i++)
     346                 :            :     {
     347         [ +  + ]:      57644 :       if (isEntailed2(n[0], subs, subsRep, i == 0))
     348                 :            :       {
     349 [ +  + ][ +  + ]:      18775 :         size_t ch = (k == Kind::EQUAL || i == 0) ? 1 : 2;
     350 [ +  + ][ +  + ]:      18775 :         bool reqPol = (k == Kind::ITE || i == 0) ? pol : !pol;
     351                 :      18775 :         return isEntailed2(n[ch], subs, subsRep, reqPol);
     352                 :            :       }
     353                 :            :     }
     354                 :      17153 :   }
     355         [ +  + ]:     557234 :   else if (k == Kind::FORALL)
     356                 :            :   {
     357         [ +  + ]:      21031 :     if (!pol)
     358                 :            :     {
     359                 :      13655 :       return isEntailed2(n[1], subs, subsRep, pol);
     360                 :            :     }
     361                 :            :   }
     362 [ +  + ][ +  + ]:     536203 :   else if (k == Kind::BOUND_VARIABLE || k == Kind::APPLY_UF)
     363                 :            :   {
     364                 :            :     // handles APPLY_UF, Boolean variable cases
     365                 :     363591 :     TNode n1 = getEntailedTerm2(n, subs, subsRep);
     366         [ +  + ]:     363591 :     if (!n1.isNull())
     367                 :            :     {
     368 [ -  + ][ -  + ]:     172849 :       Assert(d_qstate.hasTerm(n1));
                 [ -  - ]
     369                 :     172849 :       n1 = d_qstate.getRepresentative(n1);
     370         [ +  + ]:     172849 :       if (n1.isConst())
     371                 :            :       {
     372                 :     172363 :         return n1.getConst<bool>() == pol;
     373                 :            :       }
     374                 :            :     }
     375         [ +  + ]:     363591 :   }
     376                 :     503333 :   return false;
     377                 :            : }
     378                 :            : 
     379                 :       4314 : bool EntailmentCheck::isEntailed(TNode n, bool pol)
     380                 :            : {
     381                 :       4314 :   std::map<TNode, TNode> subs;
     382                 :       8628 :   return isEntailed2(n, subs, false, pol);
     383                 :       4314 : }
     384                 :            : 
     385                 :     225510 : bool EntailmentCheck::isEntailed(TNode n,
     386                 :            :                                  std::map<TNode, TNode>& subs,
     387                 :            :                                  bool subsRep,
     388                 :            :                                  bool pol)
     389                 :            : {
     390                 :     225510 :   return isEntailed2(n, subs, subsRep, pol);
     391                 :            : }
     392                 :            : 
     393                 :            : }  // namespace quantifiers
     394                 :            : }  // namespace theory
     395                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14