LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/smt - sygus_solver.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 313 328 95.4 %
Date: 2025-02-08 13:33:28 Functions: 19 19 100.0 %
Branches: 187 246 76.0 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Haniel Barbosa, Aina Niemetz
       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                 :            :  * The solver for SyGuS queries.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include "smt/sygus_solver.h"
      17                 :            : 
      18                 :            : #include <sstream>
      19                 :            : 
      20                 :            : #include "base/modal_exception.h"
      21                 :            : #include "expr/dtype.h"
      22                 :            : #include "expr/dtype_cons.h"
      23                 :            : #include "expr/node_algorithm.h"
      24                 :            : #include "expr/skolem_manager.h"
      25                 :            : #include "options/base_options.h"
      26                 :            : #include "options/option_exception.h"
      27                 :            : #include "options/quantifiers_options.h"
      28                 :            : #include "options/smt_options.h"
      29                 :            : #include "smt/logic_exception.h"
      30                 :            : #include "smt/preprocessor.h"
      31                 :            : #include "smt/smt_driver.h"
      32                 :            : #include "smt/smt_solver.h"
      33                 :            : #include "theory/datatypes/sygus_datatype_utils.h"
      34                 :            : #include "theory/quantifiers/quantifiers_attributes.h"
      35                 :            : #include "theory/quantifiers/sygus/sygus_utils.h"
      36                 :            : #include "theory/quantifiers_engine.h"
      37                 :            : #include "theory/rewriter.h"
      38                 :            : #include "theory/smt_engine_subsolver.h"
      39                 :            : #include "theory/trust_substitutions.h"
      40                 :            : 
      41                 :            : using namespace cvc5::internal::theory;
      42                 :            : using namespace cvc5::internal::kind;
      43                 :            : 
      44                 :            : namespace cvc5::internal {
      45                 :            : namespace smt {
      46                 :            : 
      47                 :      71513 : SygusSolver::SygusSolver(Env& env, SmtSolver& sms)
      48                 :            :     : EnvObj(env),
      49                 :            :       d_smtSolver(sms),
      50                 :     143026 :       d_sygusVars(userContext()),
      51                 :     143026 :       d_sygusConstraints(userContext()),
      52                 :     143026 :       d_sygusAssumps(userContext()),
      53                 :     143026 :       d_sygusFunSymbols(userContext()),
      54                 :          0 :       d_sygusConjectureStale(userContext(), true),
      55                 :      71513 :       d_subsolverCd(userContext(), nullptr)
      56                 :            : {
      57                 :      71513 : }
      58                 :            : 
      59                 :     133902 : SygusSolver::~SygusSolver() {}
      60                 :            : 
      61                 :       2699 : void SygusSolver::declareSygusVar(Node var)
      62                 :            : {
      63         [ +  - ]:       5398 :   Trace("smt") << "SygusSolver::declareSygusVar: " << var << " "
      64 [ -  + ][ -  - ]:       2699 :                << var.getType() << "\n";
      65                 :       2699 :   d_sygusVars.push_back(var);
      66                 :            :   // don't need to set that the conjecture is stale
      67                 :       2699 : }
      68                 :            : 
      69                 :       2858 : void SygusSolver::declareSynthFun(Node fn,
      70                 :            :                                   TypeNode sygusType,
      71                 :            :                                   bool isInv,
      72                 :            :                                   const std::vector<Node>& vars)
      73                 :            : {
      74         [ +  - ]:       2858 :   Trace("smt") << "SygusSolver::declareSynthFun: " << fn << "\n";
      75                 :       2858 :   NodeManager* nm = nodeManager();
      76                 :       2858 :   d_sygusFunSymbols.push_back(fn);
      77         [ +  + ]:       2858 :   if (!vars.empty())
      78                 :            :   {
      79                 :       1774 :     Node bvl = nm->mkNode(Kind::BOUND_VAR_LIST, vars);
      80                 :            :     // use an attribute to mark its bound variable list
      81                 :       1774 :     quantifiers::SygusUtils::setSygusArgumentList(fn, bvl);
      82                 :            :   }
      83                 :            :   // whether sygus type encodes syntax restrictions
      84         [ +  + ]:       5442 :   if (!sygusType.isNull() && sygusType.isDatatype()
      85 [ +  + ][ +  + ]:       5442 :       && sygusType.getDType().isSygus())
                 [ +  + ]
      86                 :            :   {
      87                 :            :     // use an attribute to mark its grammar
      88                 :       1381 :     quantifiers::SygusUtils::setSygusType(fn, sygusType);
      89                 :            :     // we now check for free variables for sygus operators in the block
      90                 :       1383 :     checkDefinitionsSygusDt(fn, sygusType);
      91                 :            :   }
      92                 :            : 
      93                 :            :   // sygus conjecture is now stale
      94                 :       2856 :   d_sygusConjectureStale = true;
      95                 :       2856 : }
      96                 :            : 
      97                 :       3282 : void SygusSolver::assertSygusConstraint(Node n, bool isAssume)
      98                 :            : {
      99         [ +  + ]:       3282 :   if (n.getKind() == Kind::AND)
     100                 :            :   {
     101                 :            :     // miniscope, to account for forall handling below as child of AND
     102         [ +  + ]:       1024 :     for (const Node& nc : n)
     103                 :            :     {
     104                 :        688 :       assertSygusConstraint(nc, isAssume);
     105                 :            :     }
     106                 :        336 :     return;
     107                 :            :   }
     108         [ +  + ]:       2946 :   else if (n.getKind() == Kind::FORALL)
     109                 :            :   {
     110                 :            :     // forall as constraint is equivalent to introducing its variables and
     111                 :            :     // using a quantifier-free constraint.
     112         [ +  + ]:          6 :     for (const Node& v : n[0])
     113                 :            :     {
     114                 :          4 :       declareSygusVar(v);
     115                 :            :     }
     116                 :          2 :     n = n[1];
     117                 :            :   }
     118         [ +  - ]:       5892 :   Trace("smt") << "SygusSolver::assertSygusConstrant: " << n
     119                 :       2946 :                << ", isAssume=" << isAssume << "\n";
     120         [ +  + ]:       2946 :   if (isAssume)
     121                 :            :   {
     122                 :        329 :     d_sygusAssumps.push_back(n);
     123                 :            :   }
     124                 :            :   else
     125                 :            :   {
     126                 :       2617 :     d_sygusConstraints.push_back(n);
     127                 :            :   }
     128                 :            : 
     129                 :            :   // sygus conjecture is now stale
     130                 :       2946 :   d_sygusConjectureStale = true;
     131                 :            : }
     132                 :            : 
     133                 :         58 : std::vector<Node> SygusSolver::getSygusConstraints() const
     134                 :            : {
     135                 :         58 :   return listToVector(d_sygusConstraints);
     136                 :            : }
     137                 :            : 
     138                 :         53 : std::vector<Node> SygusSolver::getSygusAssumptions() const
     139                 :            : {
     140                 :         53 :   return listToVector(d_sygusAssumps);
     141                 :            : }
     142                 :            : 
     143                 :        263 : void SygusSolver::assertSygusInvConstraint(Node inv,
     144                 :            :                                            Node pre,
     145                 :            :                                            Node trans,
     146                 :            :                                            Node post)
     147                 :            : {
     148         [ +  - ]:        526 :   Trace("smt") << "SygusSolver::assertSygusInvConstrant: " << inv << " " << pre
     149                 :        263 :                << " " << trans << " " << post << "\n";
     150                 :            :   // build invariant constraint
     151                 :            : 
     152                 :            :   // get variables (regular and their respective primed versions)
     153                 :        526 :   std::vector<Node> terms;
     154                 :        526 :   std::vector<Node> vars;
     155                 :        526 :   std::vector<Node> primed_vars;
     156                 :        263 :   terms.push_back(inv);
     157                 :        263 :   terms.push_back(pre);
     158                 :        263 :   terms.push_back(trans);
     159                 :        263 :   terms.push_back(post);
     160                 :            :   // variables are built based on the invariant type
     161                 :        263 :   NodeManager* nm = nodeManager();
     162                 :        526 :   std::vector<TypeNode> argTypes = inv.getType().getArgTypes();
     163         [ +  + ]:        684 :   for (const TypeNode& tn : argTypes)
     164                 :            :   {
     165                 :        421 :     vars.push_back(NodeManager::mkBoundVar(tn));
     166                 :        421 :     d_sygusVars.push_back(vars.back());
     167                 :        842 :     std::stringstream ss;
     168                 :        421 :     ss << vars.back() << "'";
     169                 :        421 :     primed_vars.push_back(NodeManager::mkBoundVar(ss.str(), tn));
     170                 :        421 :     d_sygusVars.push_back(primed_vars.back());
     171                 :            :   }
     172                 :            : 
     173                 :            :   // make relevant terms; 0 -> Inv, 1 -> Pre, 2 -> Trans, 3 -> Post
     174         [ +  + ]:       1315 :   for (unsigned i = 0; i < 4; ++i)
     175                 :            :   {
     176                 :       2104 :     Node op = terms[i];
     177         [ +  - ]:       2104 :     Trace("smt-debug") << "Make inv-constraint term #" << i << " : " << op
     178 [ -  + ][ -  - ]:       1052 :                        << " with type " << op.getType() << "...\n";
     179                 :       2104 :     std::vector<Node> children;
     180                 :       1052 :     children.push_back(op);
     181                 :            :     // transition relation applied over both variable lists
     182         [ +  + ]:       1052 :     if (i == 2)
     183                 :            :     {
     184                 :        263 :       children.insert(children.end(), vars.begin(), vars.end());
     185                 :        263 :       children.insert(children.end(), primed_vars.begin(), primed_vars.end());
     186                 :            :     }
     187                 :            :     else
     188                 :            :     {
     189                 :        789 :       children.insert(children.end(), vars.begin(), vars.end());
     190                 :            :     }
     191                 :       1052 :     terms[i] = nm->mkNode(Kind::APPLY_UF, children);
     192                 :            :     // make application of Inv on primed variables
     193         [ +  + ]:       1052 :     if (i == 0)
     194                 :            :     {
     195                 :        263 :       children.clear();
     196                 :        263 :       children.push_back(op);
     197                 :        263 :       children.insert(children.end(), primed_vars.begin(), primed_vars.end());
     198                 :        263 :       terms.push_back(nm->mkNode(Kind::APPLY_UF, children));
     199                 :            :     }
     200                 :            :   }
     201                 :            :   // make constraints
     202                 :        526 :   std::vector<Node> conj;
     203                 :        263 :   conj.push_back(nm->mkNode(Kind::IMPLIES, terms[1], terms[0]));
     204                 :        789 :   Node term0_and_2 = nm->mkNode(Kind::AND, terms[0], terms[2]);
     205                 :        263 :   conj.push_back(nm->mkNode(Kind::IMPLIES, term0_and_2, terms[4]));
     206                 :        263 :   conj.push_back(nm->mkNode(Kind::IMPLIES, terms[0], terms[3]));
     207                 :        263 :   Node constraint = nm->mkNode(Kind::AND, conj);
     208                 :            : 
     209                 :        263 :   d_sygusConstraints.push_back(constraint);
     210                 :            : 
     211                 :            :   // sygus conjecture is now stale
     212                 :        263 :   d_sygusConjectureStale = true;
     213                 :        263 : }
     214                 :            : 
     215                 :       1368 : SynthResult SygusSolver::checkSynth(bool isNext)
     216                 :            : {
     217         [ +  - ]:       1368 :   Trace("smt") << "SygusSolver::checkSynth" << std::endl;
     218                 :            :   // if applicable, check if the subsolver is the correct one
     219         [ +  + ]:       1368 :   if (!isNext)
     220                 :            :   {
     221                 :            :     // if we are not using check-synth-next, we always reconstruct the solver.
     222                 :       1248 :     d_sygusConjectureStale = true;
     223                 :            :   }
     224 [ +  + ][ +  + ]:       1368 :   if (usingSygusSubsolver() && d_subsolverCd.get() != d_subsolver.get())
                 [ +  + ]
     225                 :            :   {
     226                 :            :     // this can occur if we backtrack to a place where we were using a different
     227                 :            :     // subsolver than the current one. In this case, we should reconstruct
     228                 :            :     // the subsolver.
     229                 :          2 :     d_sygusConjectureStale = true;
     230                 :            :   }
     231         [ +  + ]:       1368 :   if (d_sygusConjectureStale)
     232                 :            :   {
     233                 :       1248 :     NodeManager* nm = nodeManager();
     234                 :            :     // build synthesis conjecture from asserted constraints and declared
     235                 :            :     // variables/functions
     236         [ +  - ]:       1248 :     Trace("smt") << "Sygus : Constructing sygus constraint...\n";
     237                 :       2496 :     Node body = nm->mkAnd(listToVector(d_sygusConstraints));
     238                 :            :     // note that if there are no constraints, then assumptions are irrelevant
     239 [ +  + ][ +  + ]:       1248 :     if (!d_sygusConstraints.empty() && !d_sygusAssumps.empty())
                 [ +  + ]
     240                 :            :     {
     241                 :          6 :       Node bodyAssump = nm->mkAnd(listToVector(d_sygusAssumps));
     242                 :          6 :       body = nm->mkNode(Kind::IMPLIES, bodyAssump, body);
     243                 :            :     }
     244                 :       1248 :     body = body.notNode();
     245         [ +  - ]:       2496 :     Trace("smt-debug") << "...constructed sygus constraint " << body
     246                 :       1248 :                        << std::endl;
     247         [ +  + ]:       1248 :     if (!d_sygusVars.empty())
     248                 :            :     {
     249                 :            :       Node boundVars =
     250                 :        597 :           nm->mkNode(Kind::BOUND_VAR_LIST, listToVector(d_sygusVars));
     251                 :        597 :       body = nm->mkNode(Kind::EXISTS, boundVars, body);
     252         [ +  - ]:        597 :       Trace("smt-debug") << "...constructed exists " << body << std::endl;
     253                 :            :     }
     254                 :       1248 :     bool inferTrivial = true;
     255                 :            :     // cannot omit unused functions if in incremental or sygus-stream
     256 [ +  + ][ +  + ]:       1248 :     if (options().quantifiers.sygusStream || options().base.incrementalSolving)
                 [ +  + ]
     257                 :            :     {
     258                 :        525 :       inferTrivial = false;
     259                 :            :     }
     260                 :            :     // Mark functions that do not occur in the conjecture as trivial,
     261                 :            :     // and do not solve for them.
     262                 :       2496 :     std::vector<Node> ntrivSynthFuns;
     263         [ +  + ]:       1248 :     if (inferTrivial)
     264                 :            :     {
     265                 :            :       // must expand definitions first
     266                 :            :       // We consider free variables in the rewritten form of the *body* of
     267                 :            :       // the existential, not the rewritten form of the existential itself,
     268                 :            :       // which could permit eliminating variables that are equal to terms
     269                 :            :       // involving functions to synthesize.
     270         [ +  + ]:       1446 :       Node ppBody = body.getKind()==Kind::EXISTS ? body[1] : body;
     271                 :        723 :       ppBody = d_smtSolver.getPreprocessor()->applySubstitutions(ppBody);
     272                 :        723 :       ppBody = rewrite(ppBody);
     273                 :       1446 :       std::unordered_set<Node> vs;
     274                 :        723 :       expr::getVariables(ppBody, vs);
     275         [ +  - ]:        734 :       for (size_t i = 0; i < 2; i++)
     276                 :            :       {
     277                 :        734 :         d_trivialFuns.clear();
     278         [ +  + ]:       1809 :         for (const Node& f : d_sygusFunSymbols)
     279                 :            :         {
     280         [ +  + ]:       1075 :           if (vs.find(f) != vs.end())
     281                 :            :           {
     282                 :        894 :             ntrivSynthFuns.push_back(f);
     283                 :            :           }
     284                 :            :           else
     285                 :            :           {
     286         [ +  - ]:        181 :             Trace("smt-debug") << "...trivial function: " << f << std::endl;
     287                 :        181 :             d_trivialFuns.push_back(f);
     288                 :            :           }
     289                 :            :         }
     290                 :            :         // we could have dependencies from the grammars of
     291                 :            :         // functions-to-synthesize to trivial functions, account for this as
     292                 :            :         // well
     293 [ +  + ][ +  + ]:        734 :         if (i == 0 && !d_trivialFuns.empty())
                 [ +  + ]
     294                 :            :         {
     295                 :        122 :           size_t prevSize = vs.size();
     296         [ +  + ]:        220 :           for (const Node& f : ntrivSynthFuns)
     297                 :            :           {
     298                 :         98 :             TypeNode tnp = quantifiers::SygusUtils::getSygusType(f);
     299         [ +  + ]:         98 :             if (tnp.isNull())
     300                 :            :             {
     301                 :         87 :               continue;
     302                 :            :             }
     303                 :         11 :             theory::datatypes::utils::getFreeVariablesSygusType(tnp, vs);
     304                 :            :           }
     305         [ +  + ]:        122 :           if (vs.size() == prevSize)
     306                 :            :           {
     307                 :            :             // no new symbols found
     308                 :        111 :             break;
     309                 :            :           }
     310                 :            :         }
     311                 :            :         else
     312                 :            :         {
     313                 :        612 :           break;
     314                 :            :         }
     315                 :            :       }
     316                 :            :     }
     317                 :            :     else
     318                 :            :     {
     319                 :        525 :       ntrivSynthFuns = listToVector(d_sygusFunSymbols);
     320                 :            :     }
     321         [ +  + ]:       1248 :     if (!ntrivSynthFuns.empty())
     322                 :            :     {
     323                 :       2212 :       body = quantifiers::SygusUtils::mkSygusConjecture(
     324                 :       1106 :           nodeManager(), ntrivSynthFuns, body);
     325                 :            :     }
     326         [ +  - ]:       1248 :     Trace("smt-debug") << "...constructed forall " << body << std::endl;
     327                 :            : 
     328         [ +  - ]:       1248 :     Trace("smt") << "Check synthesis conjecture: " << body << std::endl;
     329                 :            : 
     330                 :       1248 :     d_sygusConjectureStale = false;
     331                 :            : 
     332                 :       1248 :     d_conj = body;
     333                 :            : 
     334                 :            :     // if we are using a subsolver, initialize it now
     335         [ +  + ]:       1248 :     if (usingSygusSubsolver())
     336                 :            :     {
     337                 :            :       // we generate a new solver engine to do the SyGuS query
     338                 :        521 :       Assertions& as = d_smtSolver.getAssertions();
     339                 :        521 :       initializeSygusSubsolver(d_subsolver, as);
     340                 :            : 
     341                 :            :       // store the pointer (context-dependent)
     342                 :        521 :       d_subsolverCd = d_subsolver.get();
     343                 :            : 
     344                 :            :       // also assert the internal SyGuS conjecture
     345                 :        521 :       d_subsolver->assertFormula(d_conj);
     346                 :            :     }
     347                 :            :   }
     348                 :            :   else
     349                 :            :   {
     350 [ -  + ][ -  + ]:        120 :     Assert(d_subsolver != nullptr);
                 [ -  - ]
     351                 :            :   }
     352                 :       2736 :   Result r;
     353         [ +  + ]:       1368 :   if (usingSygusSubsolver())
     354                 :            :   {
     355         [ +  - ]:        641 :     Trace("smt-sygus") << "SygusSolver: check sat with subsolver..." << std::endl;
     356                 :        641 :     r = d_subsolver->checkSat();
     357                 :            :   }
     358                 :            :   else
     359                 :            :   {
     360         [ +  - ]:        727 :     Trace("smt-sygus") << "SygusSolver: check sat with main solver..." << std::endl;
     361                 :       1454 :     std::vector<Node> query;
     362                 :        727 :     query.push_back(d_conj);
     363                 :            :     // use a single call driver
     364                 :        731 :     SmtDriverSingleCall sdsc(d_env, d_smtSolver);
     365                 :        727 :     r = sdsc.checkSat(query);
     366                 :            :   }
     367         [ +  - ]:       1364 :   Trace("smt-sygus") << "...got " << r << std::endl;
     368                 :            :   // The result returned by the above call is typically "unknown", which may
     369                 :            :   // or may not correspond to a state in which we solved the conjecture
     370                 :            :   // successfully. Instead we call getSynthSolutions below. If this returns
     371                 :            :   // true, then we were successful. In this case, we set the synthesis result to
     372                 :            :   // "solution".
     373                 :            :   //
     374                 :            :   // This behavior is done for 2 reasons:
     375                 :            :   // (1) if we do not negate the synthesis conjecture, the subsolver in some
     376                 :            :   // cases cannot answer "sat", e.g. in the presence of recursive function
     377                 :            :   // definitions. Instead the SyGuS language standard itself indicates that
     378                 :            :   // a correct solution for a conjecture is one where the synthesis conjecture
     379                 :            :   // is *T-valid* (in the presence of defined recursive functions). In other
     380                 :            :   // words, a SyGuS query asks to prove that the conjecture is valid when
     381                 :            :   // witnessed by the given solution.
     382                 :            :   // (2) we do not want the solver to explicitly answer "unsat" by giving an
     383                 :            :   // unsatisfiable set of formulas to the underlying PropEngine, or otherwise
     384                 :            :   // we will not be able to ask for further solutions. This is critical for
     385                 :            :   // incremental solving where multiple solutions are returned for the same
     386                 :            :   // set of constraints. Thus, the internal SyGuS solver will mark unknown
     387                 :            :   // with IncompleteId::QUANTIFIERS_SYGUS_SOLVED. Furthermore, this id may be
     388                 :            :   // overwritten by other means of incompleteness, so we cannot rely on this
     389                 :            :   // identifier being the final reason for unknown.
     390                 :            :   //
     391                 :            :   // Thus, we use getSynthSolutions as means of knowing the conjecture was
     392                 :            :   // solved.
     393                 :       1364 :   SynthResult sr;
     394                 :       1364 :   std::map<Node, Node> sol_map;
     395         [ +  + ]:       1364 :   if (getSynthSolutions(sol_map))
     396                 :            :   {
     397                 :            :     // if we have solutions, we return "solution"
     398                 :       1280 :     sr = SynthResult(SynthResult::SOLUTION);
     399                 :            :     // Check that synthesis solutions satisfy the conjecture
     400         [ +  + ]:       1280 :     if (options().smt.checkSynthSol)
     401                 :            :     {
     402                 :        216 :       Assertions& as = d_smtSolver.getAssertions();
     403                 :        216 :       checkSynthSolution(as, sol_map);
     404                 :            :     }
     405                 :            :   }
     406         [ +  + ]:         84 :   else if (r.getStatus() == Result::UNSAT)
     407                 :            :   {
     408                 :            :     // unsat means no solution
     409                 :         74 :     sr = SynthResult(SynthResult::NO_SOLUTION);
     410                 :            :   }
     411                 :            :   else
     412                 :            :   {
     413                 :            :     // otherwise, we return "unknown"
     414                 :         10 :     sr = SynthResult(SynthResult::UNKNOWN, UnknownExplanation::UNKNOWN_REASON);
     415                 :            :   }
     416                 :       2728 :   return sr;
     417                 :            : }
     418                 :            : 
     419                 :       2265 : bool SygusSolver::getSynthSolutions(std::map<Node, Node>& solMap)
     420                 :            : {
     421                 :       2265 :   bool ret = false;
     422         [ +  - ]:       2265 :   Trace("smt") << "SygusSolver::getSynthSolutions" << std::endl;
     423         [ +  + ]:       2265 :   if (usingSygusSubsolver())
     424                 :            :   {
     425                 :            :     // use the call to get the synth solutions from the subsolver
     426         [ +  + ]:       1206 :     if (d_subsolver)
     427                 :            :     {
     428                 :       1202 :       ret = d_subsolver->getSubsolverSynthSolutions(solMap);
     429                 :            :     }
     430                 :            :   }
     431                 :            :   else
     432                 :            :   {
     433                 :       1059 :     ret = getSubsolverSynthSolutions(solMap);
     434                 :            :   }
     435         [ +  + ]:       2265 :   if (ret)
     436                 :            :   {
     437                 :            :     // also get solutions for trivial functions to synthesize
     438         [ +  + ]:       2470 :     for (const Node& f : d_trivialFuns)
     439                 :            :     {
     440                 :        586 :       Node sf = quantifiers::SygusUtils::mkSygusTermFor(f);
     441         [ +  - ]:        586 :       Trace("smt-debug") << "Got " << sf << " for trivial function " << f
     442                 :        293 :                         << std::endl;
     443 [ -  + ][ -  + ]:        293 :       Assert(f.getType() == sf.getType());
                 [ -  - ]
     444                 :        293 :       solMap[f] = sf;
     445                 :            :     }
     446                 :            :   }
     447                 :       2265 :   return ret;
     448                 :            : }
     449                 :            : 
     450                 :       3003 : bool SygusSolver::getSubsolverSynthSolutions(std::map<Node, Node>& solMap)
     451                 :            : {
     452         [ +  - ]:       3003 :   Trace("smt") << "SygusSolver::getSubsolverSynthSolutions" << std::endl;
     453                 :       6006 :   std::map<Node, std::map<Node, Node>> solMapn;
     454                 :            :   // fail if the theory engine does not have synthesis solutions
     455                 :       3003 :   QuantifiersEngine* qe = d_smtSolver.getQuantifiersEngine();
     456 [ +  - ][ +  + ]:       3003 :   if (qe == nullptr || !qe->getSynthSolutions(solMapn))
                 [ +  + ]
     457                 :            :   {
     458                 :        139 :     return false;
     459                 :            :   }
     460         [ +  + ]:       5445 :   for (std::pair<const Node, std::map<Node, Node>>& cs : solMapn)
     461                 :            :   {
     462         [ +  + ]:       5486 :     for (std::pair<const Node, Node>& s : cs.second)
     463                 :            :     {
     464                 :       2905 :       solMap[s.first] = s.second;
     465                 :            :     }
     466                 :            :   }
     467                 :       2864 :   return true;
     468                 :            : }
     469                 :            : 
     470                 :        263 : bool SygusSolver::canTrustSynthesisResult(const Options& opts)
     471                 :            : {
     472         [ +  + ]:        263 :   if (opts.quantifiers.cegisSample == options::CegisSampleMode::TRUST)
     473                 :            :   {
     474                 :          3 :     return false;
     475                 :            :   }
     476                 :        260 :   return true;
     477                 :            : }
     478                 :            : 
     479                 :        216 : void SygusSolver::checkSynthSolution(Assertions& as,
     480                 :            :                                      const std::map<Node, Node>& sol_map)
     481                 :            : {
     482         [ +  + ]:        216 :   if (isVerboseOn(1))
     483                 :            :   {
     484                 :          1 :     verbose(1) << "SyGuS::checkSynthSolution: checking synthesis solution"
     485                 :          1 :                << std::endl;
     486                 :            :   }
     487                 :        216 :   bool canTrustResult = canTrustSynthesisResult(options());
     488         [ -  + ]:        216 :   if (!canTrustResult)
     489                 :            :   {
     490                 :          0 :     warning() << "Running check-synth-sol is not guaranteed to pass with the "
     491                 :          0 :                  "current options."
     492                 :          0 :               << std::endl;
     493                 :            :   }
     494         [ -  + ]:        216 :   if (sol_map.empty())
     495                 :            :   {
     496                 :          0 :     InternalError() << "SygusSolver::checkSynthSolution(): Got empty solution!";
     497                 :            :     return;
     498                 :            :   }
     499         [ +  - ]:        216 :   Trace("check-synth-sol") << "Got solution map:\n";
     500                 :            :   // the set of synthesis conjectures in our assertions
     501                 :        432 :   std::unordered_set<Node> conjs;
     502                 :        216 :   conjs.insert(d_conj);
     503                 :            :   // For each of the above conjectures, the functions-to-synthesis and their
     504                 :            :   // solutions. This is used as a substitution below.
     505                 :        432 :   Subs fsubs;
     506                 :        432 :   Subs psubs;
     507                 :        432 :   std::vector<Node> eqs;
     508         [ +  + ]:        591 :   for (const std::pair<const Node, Node>& pair : sol_map)
     509                 :            :   {
     510         [ +  - ]:        750 :     Trace("check-synth-sol")
     511                 :        375 :         << "  " << pair.first << " --> " << pair.second << "\n";
     512                 :        375 :     fsubs.add(pair.first, pair.second);
     513                 :        375 :     psubs.add(pair.first);
     514                 :        375 :     eqs.push_back(pair.first.eqNode(pair.second));
     515                 :            :   }
     516                 :            : 
     517         [ +  - ]:        216 :   Trace("check-synth-sol") << "Starting new SMT Engine\n";
     518                 :            : 
     519         [ +  - ]:        216 :   Trace("check-synth-sol") << "Retrieving assertions\n";
     520                 :            :   // Build conjecture from original assertions
     521                 :            :   // check all conjectures
     522                 :        216 :   NodeManager* nm = nodeManager();
     523         [ +  + ]:        432 :   for (const Node& conj : conjs)
     524                 :            :   {
     525                 :            :     // Start new SMT engine to check solutions
     526                 :          0 :     std::unique_ptr<SolverEngine> solChecker;
     527                 :        216 :     initializeSygusSubsolver(solChecker, as);
     528                 :        216 :     solChecker->getOptions().write_smt().checkSynthSol = false;
     529                 :        216 :     solChecker->getOptions().write_quantifiers().sygusRecFun = false;
     530                 :        216 :     Node conjBody = conj;
     531         [ +  + ]:        216 :     if (conj.getKind() == Kind::FORALL)
     532                 :            :     {
     533                 :        206 :       conjBody = conjBody[1];
     534                 :            :     }
     535                 :            :     // we must apply substitutions here, since define-fun may contain the
     536                 :            :     // function-to-synthesize, which needs to be substituted.
     537                 :        216 :     conjBody = d_smtSolver.getPreprocessor()->applySubstitutions(conjBody);
     538                 :            :     // Apply solution map to conjecture body
     539                 :        216 :     conjBody = rewrite(fsubs.apply(conjBody));
     540                 :            :     // if fwd-decls, the above may contain functions-to-synthesize as free
     541                 :            :     // variables. In this case, we add (higher-order) equalities and replace
     542                 :            :     // functions-to-synthesize with skolems.
     543         [ +  + ]:        216 :     if (expr::hasFreeVar(conjBody))
     544                 :            :     {
     545                 :          2 :       std::vector<Node> conjAndSol;
     546                 :          2 :       conjAndSol.push_back(conjBody);
     547                 :          2 :       conjAndSol.insert(conjAndSol.end(), eqs.begin(), eqs.end());
     548                 :          2 :       conjBody = nm->mkAnd(conjAndSol);
     549                 :          2 :       conjBody = rewrite(psubs.apply(conjBody));
     550                 :            :     }
     551                 :            : 
     552         [ +  + ]:        216 :     if (isVerboseOn(1))
     553                 :            :     {
     554                 :          1 :       verbose(1) << "SyGuS::checkSynthSolution: -- body substitutes to "
     555                 :          1 :                  << conjBody << std::endl;
     556                 :            :     }
     557         [ +  - ]:        432 :     Trace("check-synth-sol")
     558                 :        216 :         << "Substituted body of assertion to " << conjBody << "\n";
     559                 :        216 :     solChecker->assertFormula(conjBody);
     560                 :        216 :     Result r = solChecker->checkSat();
     561         [ +  + ]:        216 :     if (isVerboseOn(1))
     562                 :            :     {
     563                 :          1 :       verbose(1) << "SyGuS::checkSynthSolution: result is " << r << std::endl;
     564                 :            :     }
     565         [ +  - ]:        216 :     Trace("check-synth-sol") << "Satsifiability check: " << r << "\n";
     566         [ +  - ]:        216 :     if (r.getStatus() == Result::UNSAT)
     567                 :            :     {
     568                 :        216 :       continue;
     569                 :            :     }
     570                 :          0 :     std::stringstream ss;
     571                 :          0 :     bool hardFailure = canTrustResult;
     572         [ -  - ]:          0 :     if (r.getStatus() == Result::SAT)
     573                 :            :     {
     574                 :            :       ss << "SygusSolver::checkSynthSolution(): produced solution leads to "
     575                 :          0 :             "satisfiable negated conjecture.";
     576                 :            :     }
     577                 :            :     else
     578                 :            :     {
     579                 :          0 :       hardFailure = false;
     580                 :            :       ss << "SygusSolver::checkSynthSolution(): could not check "
     581                 :          0 :             "solution, result unknown.";
     582                 :            :     }
     583         [ -  - ]:          0 :     if (hardFailure)
     584                 :            :     {
     585                 :          0 :       InternalError() << ss.str();
     586                 :            :     }
     587                 :            :     else
     588                 :            :     {
     589                 :          0 :       warning() << ss.str() << std::endl;
     590                 :            :     }
     591                 :            :   }
     592                 :            : }
     593                 :            : 
     594                 :        737 : void SygusSolver::initializeSygusSubsolver(std::unique_ptr<SolverEngine>& se,
     595                 :            :                                            Assertions& as)
     596                 :            : {
     597                 :        737 :   initializeSubsolver(se, d_env);
     598                 :       1474 :   std::unordered_set<Node> processed;
     599                 :            :   // if we did not spawn a subsolver for the main check, the overall SyGuS
     600                 :            :   // conjecture has been added as an assertion. Do not add it here, which
     601                 :            :   // is important for check-synth-sol. Adding this also has no impact
     602                 :            :   // when spawning a subsolver for the main check.
     603                 :        737 :   processed.insert(d_conj);
     604                 :            :   // carry the ordinary define-fun definitions
     605                 :        737 :   const context::CDList<Node>& alistDefs = as.getAssertionListDefinitions();
     606         [ +  + ]:       1021 :   for (const Node& def : alistDefs)
     607                 :            :   {
     608                 :            :     // only consider define-fun, represented as (= f (lambda ...)).
     609         [ +  + ]:        284 :     if (def.getKind() == Kind::EQUAL)
     610                 :            :     {
     611 [ -  + ][ -  + ]:        276 :       Assert(def[0].isVar());
                 [ -  - ]
     612                 :        552 :       std::vector<Node> formals;
     613                 :        552 :       Node dbody = def[1];
     614         [ +  + ]:        276 :       if (def[1].getKind() == Kind::LAMBDA)
     615                 :            :       {
     616                 :        260 :         formals.insert(formals.end(), def[1][0].begin(), def[1][0].end());
     617                 :        260 :         dbody = dbody[1];
     618                 :            :       }
     619                 :        276 :       se->defineFunction(def[0], formals, dbody);
     620                 :        276 :       processed.insert(def);
     621                 :            :     }
     622                 :            :   }
     623                 :            :   // Also assert auxiliary assertions, which typically correspond to
     624                 :            :   // quantified formulas for define-fun-rec only.
     625                 :        737 :   const context::CDList<Node>& alist = as.getAssertionList();
     626         [ +  + ]:       1227 :   for (size_t i = 0, asize = alist.size(); i < asize; ++i)
     627                 :            :   {
     628                 :        980 :     Node a = alist[i];
     629                 :            :     // ignore definitions here
     630         [ +  + ]:        490 :     if (processed.find(a) == processed.end())
     631                 :            :     {
     632                 :          8 :       se->assertFormula(a);
     633                 :            :     }
     634                 :            :   }
     635                 :        737 : }
     636                 :            : 
     637                 :       6249 : bool SygusSolver::usingSygusSubsolver() const
     638                 :            : {
     639                 :            :   // use SyGuS subsolver if in incremental mode
     640                 :       6249 :   return options().base.incrementalSolving;
     641                 :            : }
     642                 :            : 
     643                 :       1381 : void SygusSolver::checkDefinitionsSygusDt(const Node& fn, TypeNode tn) const
     644                 :            : {
     645                 :       2762 :   std::unordered_set<TypeNode> processed;
     646                 :       2762 :   std::vector<TypeNode> toProcess;
     647                 :       1381 :   toProcess.push_back(tn);
     648                 :       1381 :   size_t index = 0;
     649         [ +  + ]:       4188 :   while (index < toProcess.size())
     650                 :            :   {
     651                 :       5618 :     TypeNode tnp = toProcess[index];
     652                 :       2809 :     index++;
     653 [ -  + ][ -  + ]:       2809 :     Assert(tnp.isDatatype());
                 [ -  - ]
     654 [ -  + ][ -  + ]:       2809 :     Assert(tnp.getDType().isSygus());
                 [ -  - ]
     655                 :       2809 :     const DType& dt = tnp.getDType();
     656                 :            :     const std::vector<std::shared_ptr<DTypeConstructor>>& cons =
     657                 :       2809 :         dt.getConstructors();
     658                 :       5618 :     std::unordered_set<TNode> scope;
     659                 :            :     // we allow other functions
     660                 :       2809 :     scope.insert(d_sygusFunSymbols.begin(), d_sygusFunSymbols.end());
     661                 :       5618 :     Node dtl = dt.getSygusVarList();
     662         [ +  + ]:       2809 :     if (!dtl.isNull())
     663                 :            :     {
     664                 :       2284 :       scope.insert(dtl.begin(), dtl.end());
     665                 :            :     }
     666         [ +  + ]:      14208 :     for (const std::shared_ptr<DTypeConstructor>& c : cons)
     667                 :            :     {
     668                 :      22802 :       Node op = c->getSygusOp();
     669                 :            :       // check for free variables here
     670         [ +  + ]:      11401 :       if (expr::hasFreeVariablesScope(op, scope))
     671                 :            :       {
     672                 :          4 :         std::stringstream ss;
     673                 :          2 :         ss << "ERROR: cannot process term " << op
     674                 :          2 :            << " with free variables in grammar of " << fn;
     675                 :          2 :         throw LogicException(ss.str());
     676                 :            :       }
     677                 :            :       // also must consider the arguments
     678         [ +  + ]:      22494 :       for (unsigned j = 0, nargs = c->getNumArgs(); j < nargs; ++j)
     679                 :            :       {
     680                 :      22190 :         TypeNode tnc = c->getArgType(j);
     681 [ +  + ][ +  + ]:      11095 :         if (tnc.isSygusDatatype() && processed.find(tnc) == processed.end())
                 [ +  + ]
     682                 :            :         {
     683                 :       1428 :           toProcess.push_back(tnc);
     684                 :       1428 :           processed.insert(tnc);
     685                 :            :         }
     686                 :            :       }
     687                 :            :     }
     688                 :            :   }
     689                 :       1379 : }
     690                 :            : 
     691                 :       2487 : std::vector<Node> SygusSolver::listToVector(const NodeList& list)
     692                 :            : {
     693                 :       2487 :   std::vector<Node> vec;
     694         [ +  + ]:       7624 :   for (const Node& n : list)
     695                 :            :   {
     696                 :       5137 :     vec.push_back(n);
     697                 :            :   }
     698                 :       2487 :   return vec;
     699                 :            : }
     700                 :            : 
     701                 :         50 : std::vector<std::pair<Node, TypeNode>> SygusSolver::getSynthFunctions() const
     702                 :            : {
     703                 :         50 :   std::vector<std::pair<Node, TypeNode>> funs;
     704         [ +  + ]:        100 :   for (const Node& f : d_sygusFunSymbols)
     705                 :            :   {
     706                 :        100 :     TypeNode st = quantifiers::SygusUtils::getSygusType(f);
     707                 :         50 :     funs.emplace_back(f, st);
     708                 :            :   }
     709                 :         50 :   return funs;
     710                 :            : }
     711                 :            : 
     712                 :            : }  // namespace smt
     713                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14