LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/smt - assertions.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 93 107 86.9 %
Date: 2026-04-20 10:41:59 Functions: 12 13 92.3 %
Branches: 65 90 72.2 %

           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                 :            :  * The module for storing assertions for an SMT engine.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "smt/assertions.h"
      14                 :            : 
      15                 :            : #include <sstream>
      16                 :            : 
      17                 :            : #include "base/modal_exception.h"
      18                 :            : #include "expr/node_algorithm.h"
      19                 :            : #include "expr/subtype_elim_node_converter.h"
      20                 :            : #include "options/base_options.h"
      21                 :            : #include "options/expr_options.h"
      22                 :            : #include "options/language.h"
      23                 :            : #include "options/smt_options.h"
      24                 :            : #include "proof/lazy_proof.h"
      25                 :            : #include "proof/proof_node_algorithm.h"
      26                 :            : #include "smt/env.h"
      27                 :            : #include "theory/trust_substitutions.h"
      28                 :            : #include "util/result.h"
      29                 :            : 
      30                 :            : using namespace cvc5::internal::theory;
      31                 :            : using namespace cvc5::internal::kind;
      32                 :            : 
      33                 :            : namespace cvc5::internal {
      34                 :            : namespace smt {
      35                 :            : 
      36                 :      75664 : Assertions::Assertions(Env& env)
      37                 :            :     : EnvObj(env),
      38                 :      75664 :       d_assertionList(userContext()),
      39                 :      75664 :       d_assertionListDefs(userContext()),
      40                 :     151328 :       d_globalDefineFunLemmasIndex(userContext(), 0)
      41                 :            : {
      42                 :      75664 : }
      43                 :            : 
      44                 :      70636 : Assertions::~Assertions() {}
      45                 :            : 
      46                 :      67182 : void Assertions::refresh()
      47                 :            : {
      48                 :            :   // Global definitions are asserted now to ensure they always exist. This is
      49                 :            :   // done at the beginning of preprocessing, to ensure that definitions take
      50                 :            :   // priority over, e.g. solving during preprocessing. See issue #7479.
      51                 :      67182 :   size_t numGlobalDefs = d_globalDefineFunLemmas.size();
      52         [ +  + ]:      69980 :   for (size_t i = d_globalDefineFunLemmasIndex.get(); i < numGlobalDefs; i++)
      53                 :            :   {
      54                 :       2798 :     addFormula(d_globalDefineFunLemmas[i], true, false);
      55                 :            :   }
      56                 :      67182 :   d_globalDefineFunLemmasIndex = numGlobalDefs;
      57                 :      67182 : }
      58                 :            : 
      59                 :      50416 : void Assertions::setAssumptions(const std::vector<Node>& assumptions)
      60                 :            : {
      61                 :      50416 :   d_assumptions.clear();
      62                 :      50416 :   d_assumptions = assumptions;
      63                 :            : 
      64         [ +  + ]:      57832 :   for (const Node& n : d_assumptions)
      65                 :            :   {
      66                 :            :     // Ensure expr is type-checked at this point.
      67                 :       7416 :     ensureBoolean(n);
      68                 :       7416 :     addFormula(n, false, false);
      69                 :            :   }
      70                 :      50416 : }
      71                 :            : 
      72                 :     182729 : void Assertions::assertFormula(const Node& n)
      73                 :            : {
      74                 :     182729 :   ensureBoolean(n);
      75                 :     182729 :   bool maybeHasFv = language::isLangSygus(options().base.inputLanguage);
      76                 :     182729 :   addFormula(n, false, maybeHasFv);
      77                 :     182729 : }
      78                 :            : 
      79                 :        250 : std::vector<Node>& Assertions::getAssumptions() { return d_assumptions; }
      80                 :            : 
      81                 :     130821 : const context::CDList<Node>& Assertions::getAssertionList() const
      82                 :            : {
      83                 :     130821 :   return d_assertionList;
      84                 :            : }
      85                 :            : 
      86                 :       6652 : const context::CDList<Node>& Assertions::getAssertionListDefinitions() const
      87                 :            : {
      88                 :       6652 :   return d_assertionListDefs;
      89                 :            : }
      90                 :            : 
      91                 :       2188 : std::unordered_set<Node> Assertions::getCurrentAssertionListDefitions() const
      92                 :            : {
      93                 :       2188 :   std::unordered_set<Node> defSet;
      94         [ +  + ]:       2822 :   for (const Node& a : d_assertionListDefs)
      95                 :            :   {
      96                 :        634 :     defSet.insert(a);
      97                 :            :   }
      98                 :       2188 :   return defSet;
      99                 :          0 : }
     100                 :            : 
     101                 :     205842 : void Assertions::addFormula(TNode n, bool isFunDef, bool maybeHasFv)
     102                 :            : {
     103                 :            :   // add to assertion list
     104                 :     205842 :   d_assertionList.push_back(n);
     105 [ +  + ][ +  + ]:     205842 :   if (n.isConst() && n.getConst<bool>())
                 [ +  + ]
     106                 :            :   {
     107                 :            :     // true, nothing to do
     108                 :       5033 :     return;
     109                 :            :   }
     110         [ +  - ]:     401618 :   Trace("smt") << "Assertions::addFormula(" << n << ", isFunDef = " << isFunDef
     111                 :     200809 :                << std::endl;
     112                 :            :   // In non-incremental, we treat higher-order equality as define-fun
     113 [ +  + ][ +  + ]:     200809 :   if (!options().base.incrementalSolving || isFunDef)
                 [ +  + ]
     114                 :            :   {
     115                 :            :     // if a non-recursive define-fun, just add as a top-level substitution
     116 [ +  + ][ +  + ]:     166912 :     if (n.getKind() == Kind::EQUAL && n[0].isVar())
         [ +  + ][ +  + ]
                 [ -  - ]
     117                 :            :     {
     118         [ +  - ]:      45666 :       Trace("smt-define-fun")
     119                 :      22833 :           << "Define fun: " << n[0] << " = " << n[1] << std::endl;
     120                 :      22833 :       NodeManager* nm = nodeManager();
     121                 :      22833 :       TrustSubstitutionMap& tsm = d_env.getTopLevelSubstitutions();
     122                 :      45666 :       if (!isFunDef
     123 [ +  + ][ +  + ]:      57335 :           && (tsm.get().hasSubstitution(n[0])
         [ +  + ][ -  - ]
     124 [ +  + ][ +  + ]:      34502 :               || n[1].getKind() != Kind::LAMBDA))
         [ +  + ][ -  - ]
     125                 :            :       {
     126                 :      11479 :         return;
     127                 :            :       }
     128                 :            :       // If it is a lambda, we rewrite the body, otherwise we rewrite itself.
     129                 :            :       // For lambdas, we prefer rewriting only the body since we don't want
     130                 :            :       // higher-order rewrites (e.g. value normalization) to apply by default.
     131                 :      11354 :       TrustNode defRewBody;
     132                 :            :       // For efficiency, we only do this if it is a lambda.
     133                 :            :       // Note this is important since some benchmarks treat define-fun as a
     134                 :            :       // global let. We should not eagerly rewrite in these cases.
     135         [ +  + ]:      11354 :       if (n[1].getKind() == Kind::LAMBDA)
     136                 :            :       {
     137                 :            :         // Rewrite the body of the lambda.
     138                 :       6554 :         defRewBody = tsm.applyTrusted(n[1][1], d_env.getRewriter());
     139                 :            :       }
     140                 :      11354 :       Node defRew = n[1];
     141                 :            :       // If we rewrote the body
     142         [ +  + ]:      11354 :       if (!defRewBody.isNull())
     143                 :            :       {
     144                 :            :         // The rewritten form is the rewritten body with original variable list.
     145                 :       3265 :         defRew = defRewBody.getNode();
     146                 :       3265 :         defRew = nm->mkNode(Kind::LAMBDA, n[1][0], defRew);
     147                 :            :       }
     148                 :      11354 :       if (!isFunDef && expr::hasSubterm(defRew, n[0]))
     149                 :            :       {
     150                 :         13 :         return;
     151                 :            :       }
     152                 :            :       // if we need to track proofs
     153         [ +  + ]:      11341 :       if (d_env.isProofProducing())
     154                 :            :       {
     155                 :            :         // initialize the proof generator if not already done so
     156         [ +  + ]:       3554 :         if (d_defFunRewPf == nullptr)
     157                 :            :         {
     158                 :        587 :           d_defFunRewPf = std::make_shared<LazyCDProof>(d_env);
     159                 :            :         }
     160                 :            :         // A define-fun is an assumption in the overall proof, thus
     161                 :            :         // we justify the substitution with ASSUME here.
     162                 :       7108 :         d_defFunRewPf->addStep(n, ProofRule::ASSUME, {}, {n});
     163                 :            :         // If changed, prove the rewrite
     164         [ +  + ]:       3554 :         if (defRew != n[1])
     165                 :            :         {
     166                 :       1247 :           Node eqBody = defRewBody.getProven();
     167                 :       1247 :           d_defFunRewPf->addLazyStep(eqBody, defRewBody.getGenerator());
     168                 :       1247 :           Node eqRew = n[1].eqNode(defRew);
     169 [ -  + ][ -  + ]:       1247 :           Assert(n[1].getKind() == Kind::LAMBDA);
                 [ -  - ]
     170                 :            :           // congruence over the binder
     171                 :       1247 :           std::vector<Node> cargs;
     172                 :       1247 :           ProofRule cr = expr::getCongRule(n[1], cargs);
     173                 :       2494 :           d_defFunRewPf->addStep(eqRew, cr, {eqBody}, cargs);
     174                 :            :           // Proof is:
     175                 :            :           //                            ------ from tsm
     176                 :            :           //                            t = t'
     177                 :            :           // ------------------ ASSUME  -------------------------- CONG
     178                 :            :           // n = lambda x. t            lambda x. t = lambda x. t'
     179                 :            :           // ------------------------------------------------------ TRANS
     180                 :            :           // n = lambda x. t'
     181                 :       1247 :           Node eqFinal = n[0].eqNode(defRew);
     182 [ +  + ][ -  - ]:       3741 :           d_defFunRewPf->addStep(eqFinal, ProofRule::TRANS, {n, eqRew}, {});
     183                 :       1247 :         }
     184                 :            :       }
     185         [ +  - ]:      11341 :       Trace("smt-define-fun") << "...rewritten to " << defRew << std::endl;
     186                 :      11341 :       d_assertionListDefs.push_back(n);
     187         [ +  + ]:      22682 :       d_env.getTopLevelSubstitutions().addSubstitution(
     188                 :      11341 :           n[0], defRew, d_defFunRewPf.get());
     189                 :      11341 :       return;
     190                 :      11354 :     }
     191                 :            :   }
     192                 :            : 
     193                 :            :   // Ensure that it does not contain free variables
     194         [ +  + ]:     177976 :   if (maybeHasFv)
     195                 :            :   {
     196                 :            :     // Note that API users and the smt2 parser may generate assertions with
     197                 :            :     // shadowed variables, which are resolved during rewriting. Hence we do not
     198                 :            :     // check for this here.
     199         [ -  + ]:       1767 :     if (expr::hasFreeVar(n))
     200                 :            :     {
     201                 :          0 :       std::stringstream se;
     202         [ -  - ]:          0 :       if (isFunDef)
     203                 :            :       {
     204                 :          0 :         se << "Cannot process function definition with free variable.";
     205                 :            :       }
     206                 :            :       else
     207                 :            :       {
     208                 :          0 :         se << "Cannot process assertion with free variable.";
     209         [ -  - ]:          0 :         if (language::isLangSygus(options().base.inputLanguage))
     210                 :            :         {
     211                 :            :           // Common misuse of SyGuS is to use top-level assert instead of
     212                 :            :           // constraint when defining the synthesis conjecture.
     213                 :          0 :           se << " Perhaps you meant `constraint` instead of `assert`?";
     214                 :            :         }
     215                 :            :       }
     216                 :          0 :       throw ModalException(se.str().c_str());
     217                 :          0 :     }
     218                 :            :   }
     219                 :            : }
     220                 :            : 
     221                 :      14344 : void Assertions::addDefineFunDefinition(Node n, bool global)
     222                 :            : {
     223         [ +  + ]:      14344 :   if (global)
     224                 :            :   {
     225                 :            :     // Global definitions are asserted at check-sat-time because we have to
     226                 :            :     // make sure that they are always present
     227 [ -  + ][ -  + ]:       1445 :     Assert(!language::isLangSygus(options().base.inputLanguage));
                 [ -  - ]
     228                 :       1445 :     d_globalDefineFunLemmas.emplace_back(n);
     229                 :            :   }
     230                 :            :   else
     231                 :            :   {
     232                 :            :     // We don't permit functions-to-synthesize within recursive function
     233                 :            :     // definitions currently. Thus, we should check for free variables if the
     234                 :            :     // input language is SyGuS.
     235                 :      12899 :     bool maybeHasFv = language::isLangSygus(options().base.inputLanguage);
     236                 :      12899 :     addFormula(n, true, maybeHasFv);
     237                 :            :   }
     238                 :      14344 : }
     239                 :            : 
     240                 :     190145 : void Assertions::ensureBoolean(const Node& n)
     241                 :            : {
     242                 :     190145 :   TypeNode type = n.getType(options().expr.typeChecking);
     243         [ -  + ]:     190145 :   if (!type.isBoolean())
     244                 :            :   {
     245                 :          0 :     std::stringstream ss;
     246                 :            :     ss << "Expected Boolean type\n"
     247                 :          0 :        << "The assertion : " << n << "\n"
     248                 :          0 :        << "Its type      : " << type;
     249                 :          0 :     throw TypeCheckingExceptionPrivate(n, ss.str());
     250                 :          0 :   }
     251                 :     190145 : }
     252                 :            : 
     253                 :            : }  // namespace smt
     254                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14