LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers - oracle_checker.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 33 72 45.8 %
Date: 2026-04-22 10:35:54 Functions: 4 9 44.4 %
Branches: 16 50 32.0 %

           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                 :            :  * Oracle checker
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/quantifiers/oracle_checker.h"
      14                 :            : 
      15                 :            : #include "expr/node_algorithm.h"
      16                 :            : #include "options/base_options.h"
      17                 :            : #include "smt/env.h"
      18                 :            : #include "smt/logic_exception.h"
      19                 :            : #include "theory/rewriter.h"
      20                 :            : 
      21                 :            : namespace cvc5::internal {
      22                 :            : namespace theory {
      23                 :            : namespace quantifiers {
      24                 :            : 
      25                 :       1070 : OracleChecker::OracleChecker(Env& env)
      26                 :       1070 :     : EnvObj(env), NodeConverter(env.getNodeManager())
      27                 :            : {
      28                 :       1070 : }
      29                 :            : 
      30                 :       1182 : Node OracleChecker::checkConsistent(Node app, Node val)
      31                 :            : {
      32                 :       1184 :   Node result = evaluateApp(app);
      33         [ +  - ]:       2360 :   Trace("oracle-calls") << "checkConsistent " << app << " == " << result
      34                 :       1180 :                         << " vs " << val << std::endl;
      35         [ +  + ]:       1180 :   if (result != val)
      36                 :            :   {
      37                 :        966 :     return result;
      38                 :            :   }
      39                 :        214 :   return Node::null();
      40                 :       1180 : }
      41                 :            : 
      42                 :       1182 : Node OracleChecker::evaluateApp(Node app)
      43                 :            : {
      44 [ -  + ][ -  + ]:       1182 :   Assert(app.getKind() == Kind::APPLY_UF);
                 [ -  - ]
      45                 :       1182 :   Node f = app.getOperator();
      46 [ -  + ][ -  + ]:       1182 :   Assert(OracleCaller::isOracleFunction(f));
                 [ -  - ]
      47                 :            :   // get oracle caller
      48         [ +  + ]:       1182 :   if (d_callers.find(f) == d_callers.end())
      49                 :            :   {
      50                 :        326 :     d_callers.insert(std::pair<Node, OracleCaller>(f, OracleCaller(f)));
      51                 :            :   }
      52                 :       1182 :   OracleCaller& caller = d_callers.at(f);
      53                 :            : 
      54                 :            :   // get oracle result
      55                 :       1182 :   std::vector<Node> retv;
      56                 :       1182 :   bool ranOracle = caller.callOracle(app, retv);
      57         [ -  + ]:       1182 :   if (retv.size() != 1)
      58                 :            :   {
      59                 :          0 :     DebugUnhandled() << "Failed to evaluate " << app
      60                 :          0 :                      << " to a single return value, got: " << retv << std::endl;
      61                 :            :     return app;
      62                 :            :   }
      63                 :       1182 :   Node ret = retv[0];
      64                 :       1182 :   ret = rewrite(ret);
      65         [ +  - ]:       1182 :   if (ranOracle)
      66                 :            :   {
      67                 :            :     // prints the result of the oracle, if it was computed in the call above.
      68                 :            :     // this prints the original application, its result, and the exit code
      69                 :            :     // of the binary.
      70                 :       1182 :     d_env.output(options::OutputTag::ORACLES)
      71                 :       1182 :         << "(oracle-call " << app << " " << ret << ")" << std::endl;
      72                 :            :   }
      73         [ +  + ]:       1182 :   if (ret.getNodeManager() != app.getNodeManager())
      74                 :            :   {
      75                 :          2 :     throw LogicException(
      76                 :            :         "Evaluated an oracle call that is not associated with the term manager "
      77                 :          4 :         "of this solver");
      78                 :            :   }
      79         [ -  + ]:       3540 :   if (!CVC5_EQUAL(ret.getType(), app.getType()))
      80                 :            :   {
      81                 :          0 :     std::stringstream ss;
      82                 :          0 :     ss << "Evaluated an oracle call with an unexpected type: " << app << " = "
      83                 :          0 :        << ret << " whose type is " << ret.getType() << ", expected "
      84                 :          0 :        << app.getType();
      85                 :          0 :     throw LogicException(ss.str());
      86                 :          0 :   }
      87 [ -  + ][ -  + ]:       1180 :   Assert(!ret.isNull());
                 [ -  - ]
      88                 :       1180 :   return ret;
      89                 :       1186 : }
      90                 :            : 
      91                 :          0 : Node OracleChecker::evaluate(Node n)
      92                 :            : {
      93                 :            :   // same as convert
      94                 :          0 :   return convert(n);
      95                 :            : }
      96                 :            : 
      97                 :          0 : Node OracleChecker::postConvert(Node n)
      98                 :            : {
      99         [ -  - ]:          0 :   Trace("oracle-checker-debug") << "postConvert: " << n << std::endl;
     100                 :            :   // if it is an oracle function applied to constant arguments
     101                 :          0 :   if (n.getKind() == Kind::APPLY_UF
     102                 :          0 :       && OracleCaller::isOracleFunction(n.getOperator()))
     103                 :            :   {
     104                 :          0 :     bool allConst = true;
     105         [ -  - ]:          0 :     for (const Node& nc : n)
     106                 :            :     {
     107         [ -  - ]:          0 :       if (nc.isConst())
     108                 :            :       {
     109                 :          0 :         continue;
     110                 :            :       }
     111                 :            :       // special case: assume all closed lambdas are constants
     112         [ -  - ]:          0 :       if (nc.getKind() == Kind::LAMBDA)
     113                 :            :       {
     114                 :            :         // if the lambda does not have a free variable (BOUND_VARIABLE)
     115         [ -  - ]:          0 :         if (!expr::hasFreeVar(nc))
     116                 :            :         {
     117                 :            :           // it also cannot have any free symbol
     118                 :          0 :           std::unordered_set<Node> syms;
     119                 :          0 :           expr::getSymbols(nc, syms);
     120         [ -  - ]:          0 :           if (syms.empty())
     121                 :            :           {
     122                 :          0 :             continue;
     123                 :            :           }
     124         [ -  - ]:          0 :         }
     125                 :            :       }
     126                 :            :       // non-constant argument, fail
     127                 :          0 :       allConst = false;
     128                 :          0 :       break;
     129         [ -  - ]:          0 :     }
     130         [ -  - ]:          0 :     if (allConst)
     131                 :            :     {
     132                 :            :       // evaluate the application
     133                 :          0 :       return evaluateApp(n);
     134                 :            :     }
     135                 :            :   }
     136                 :            :   // otherwise, always rewrite
     137                 :          0 :   return rewrite(n);
     138                 :            : }
     139                 :          0 : bool OracleChecker::hasOracles() const { return !d_callers.empty(); }
     140                 :          0 : bool OracleChecker::hasOracleCalls(Node f) const
     141                 :            : {
     142                 :          0 :   std::map<Node, OracleCaller>::const_iterator it = d_callers.find(f);
     143                 :          0 :   return it != d_callers.end();
     144                 :            : }
     145                 :          0 : const std::map<Node, std::vector<Node>>& OracleChecker::getOracleCalls(
     146                 :            :     Node f) const
     147                 :            : {
     148                 :          0 :   Assert(hasOracleCalls(f));
     149                 :          0 :   std::map<Node, OracleCaller>::const_iterator it = d_callers.find(f);
     150                 :          0 :   return it->second.getCachedResults();
     151                 :            : }
     152                 :            : 
     153                 :            : }  // namespace quantifiers
     154                 :            : }  // namespace theory
     155                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14