LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers/cegqi - nested_qe.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 73 81 90.1 %
Date: 2026-02-08 14:07:57 Functions: 6 7 85.7 %
Branches: 30 56 53.6 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Aina Niemetz, Mathias Preiner
       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                 :            :  * Methods for counterexample-guided quantifier instantiation
      14                 :            :  * based on nested quantifier elimination.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include "theory/quantifiers/cegqi/nested_qe.h"
      18                 :            : 
      19                 :            : #include "expr/node_algorithm.h"
      20                 :            : #include "expr/subs.h"
      21                 :            : #include "smt/env.h"
      22                 :            : #include "theory/rewriter.h"
      23                 :            : #include "theory/smt_engine_subsolver.h"
      24                 :            : #include "smt/set_defaults.h"
      25                 :            : 
      26                 :            : namespace cvc5::internal {
      27                 :            : namespace theory {
      28                 :            : namespace quantifiers {
      29                 :            : 
      30                 :         50 : NestedQe::NestedQe(Env& env) : d_env(env), d_qnqe(d_env.getUserContext()) {}
      31                 :            : 
      32                 :         89 : bool NestedQe::process(Node q, std::vector<Node>& lems)
      33                 :            : {
      34                 :         89 :   NodeNodeMap::iterator it = d_qnqe.find(q);
      35         [ +  + ]:         89 :   if (it != d_qnqe.end())
      36                 :            :   {
      37                 :            :     // already processed
      38                 :         35 :     return (*it).second != q;
      39                 :            :   }
      40         [ +  - ]:         54 :   Trace("cegqi-nested-qe") << "Check nested QE on " << q << std::endl;
      41                 :        108 :   Node qqe = doNestedQe(d_env, q, true);
      42                 :         54 :   d_qnqe[q] = qqe;
      43         [ +  + ]:         54 :   if (qqe == q)
      44                 :            :   {
      45         [ +  - ]:         31 :     Trace("cegqi-nested-qe") << "...did not apply nested QE" << std::endl;
      46                 :         31 :     return false;
      47                 :            :   }
      48         [ +  - ]:         23 :   Trace("cegqi-nested-qe") << "...applied nested QE" << std::endl;
      49         [ +  - ]:         23 :   Trace("cegqi-nested-qe") << "Result is " << qqe << std::endl;
      50                 :            : 
      51                 :            :   // add as lemma
      52                 :         23 :   lems.push_back(q.eqNode(qqe));
      53                 :         23 :   return true;
      54                 :            : }
      55                 :            : 
      56                 :          0 : bool NestedQe::hasProcessed(Node q) const
      57                 :            : {
      58                 :          0 :   return d_qnqe.find(q) != d_qnqe.end();
      59                 :            : }
      60                 :            : 
      61                 :        561 : bool NestedQe::getNestedQuantification(Node q, std::unordered_set<Node>& nqs)
      62                 :            : {
      63                 :        561 :   expr::getKindSubterms(q[1], Kind::FORALL, true, nqs);
      64                 :        561 :   return !nqs.empty();
      65                 :            : }
      66                 :            : 
      67                 :         66 : bool NestedQe::hasNestedQuantification(Node q)
      68                 :            : {
      69                 :         66 :   std::unordered_set<Node> nqs;
      70                 :        132 :   return getNestedQuantification(q, nqs);
      71                 :            : }
      72                 :            : 
      73                 :        495 : Node NestedQe::doNestedQe(Env& env, Node q, bool keepTopLevel)
      74                 :            : {
      75                 :        495 :   NodeManager* nm = env.getNodeManager();
      76                 :        990 :   Node qOrig = q;
      77                 :        495 :   bool inputExists = false;
      78         [ +  + ]:        495 :   if (q.getKind() == Kind::EXISTS)
      79                 :            :   {
      80                 :         42 :     q = nm->mkNode(Kind::FORALL, q[0], q[1].negate());
      81                 :         42 :     inputExists = true;
      82                 :            :   }
      83 [ -  + ][ -  + ]:        495 :   Assert(q.getKind() == Kind::FORALL);
                 [ -  - ]
      84                 :        990 :   std::unordered_set<Node> nqs;
      85         [ +  + ]:        495 :   if (!getNestedQuantification(q, nqs))
      86                 :            :   {
      87         [ +  - ]:        930 :     Trace("cegqi-nested-qe-debug")
      88                 :        465 :         << "...no nested quantification" << std::endl;
      89         [ +  + ]:        465 :     if (keepTopLevel)
      90                 :            :     {
      91                 :        442 :       return qOrig;
      92                 :            :     }
      93                 :            :     // just do ordinary quantifier elimination
      94                 :         46 :     Node qqe = doQe(env, q);
      95         [ +  - ]:         23 :     Trace("cegqi-nested-qe-debug") << "...did ordinary qe" << std::endl;
      96                 :         23 :     return qqe;
      97                 :            :   }
      98         [ +  - ]:         60 :   Trace("cegqi-nested-qe-debug")
      99                 :         30 :       << "..." << nqs.size() << " nested quantifiers" << std::endl;
     100                 :            :   // otherwise, skolemize the arguments of this and apply
     101                 :         90 :   std::vector<Node> vars(q[0].begin(), q[0].end());
     102                 :         60 :   Subs sk;
     103                 :         30 :   sk.add(vars);
     104                 :            :   // do nested quantifier elimination on each nested quantifier, skolemizing the
     105                 :            :   // free variables
     106                 :         60 :   Subs snqe;
     107         [ +  + ]:         60 :   for (const Node& nq : nqs)
     108                 :            :   {
     109                 :         30 :     Node nqk = sk.apply(nq);
     110                 :         30 :     Node nqqe = doNestedQe(env, nqk);
     111         [ -  + ]:         30 :     if (nqqe == nqk)
     112                 :            :     {
     113                 :            :       // failed
     114         [ -  - ]:          0 :       Trace("cegqi-nested-qe-debug")
     115                 :          0 :           << "...failed to apply to nested" << std::endl;
     116                 :          0 :       return q;
     117                 :            :     }
     118                 :         30 :     snqe.add(nqk, nqqe);
     119                 :            :   }
     120                 :            :   // get the result of nested quantifier elimination
     121                 :         60 :   Node qeBody = sk.apply(q[1]);
     122                 :         30 :   qeBody = snqe.apply(qeBody);
     123                 :            :   // undo the skolemization
     124                 :         30 :   qeBody = sk.rapply(qeBody);
     125                 :         30 :   qeBody = env.getRewriter()->rewrite(qeBody);
     126                 :            :   // reconstruct the body
     127                 :         60 :   std::vector<Node> qargs;
     128                 :         30 :   qargs.push_back(q[0]);
     129         [ -  + ]:         30 :   qargs.push_back(inputExists ? qeBody.negate() : qeBody);
     130         [ -  + ]:         30 :   if (q.getNumChildren() == 3)
     131                 :            :   {
     132                 :          0 :     qargs.push_back(q[2]);
     133                 :            :   }
     134         [ -  + ]:         30 :   return nm->mkNode(inputExists ? Kind::EXISTS : Kind::FORALL, qargs);
     135                 :            : }
     136                 :            : 
     137                 :         23 : Node NestedQe::doQe(Env& env, Node q)
     138                 :            : {
     139 [ -  + ][ -  + ]:         23 :   Assert(q.getKind() == Kind::FORALL);
                 [ -  - ]
     140         [ +  - ]:         23 :   Trace("cegqi-nested-qe") << "  Apply qe to " << q << std::endl;
     141                 :         23 :   q = NodeManager::mkNode(Kind::EXISTS, q[0], q[1].negate());
     142                 :         23 :   std::unique_ptr<SolverEngine> smt_qe;
     143                 :         46 :   Options subOptions;
     144                 :         23 :   subOptions.copyValues(env.getOptions());
     145                 :         23 :   smt::SetDefaults::disableChecking(subOptions);
     146                 :         46 :   SubsolverSetupInfo ssi(env, subOptions);
     147                 :         23 :   initializeSubsolver(env.getNodeManager(), smt_qe, ssi);
     148                 :         46 :   Node qqe = smt_qe->getQuantifierElimination(q, true);
     149         [ -  + ]:         23 :   if (expr::hasBoundVar(qqe))
     150                 :            :   {
     151         [ -  - ]:          0 :     Trace("cegqi-nested-qe") << "  ...failed QE" << std::endl;
     152                 :            :     //...failed to apply
     153                 :          0 :     return q;
     154                 :            :   }
     155                 :         46 :   Node res = qqe.negate();
     156         [ +  - ]:         23 :   Trace("cegqi-nested-qe") << "  ...success, result = " << res << std::endl;
     157                 :         23 :   return res;
     158                 :            : }
     159                 :            : 
     160                 :            : }  // namespace quantifiers
     161                 :            : }  // namespace theory
     162                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14