LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers/sygus - synth_conjecture.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 556 596 93.3 %
Date: 2026-01-25 11:16:35 Functions: 22 23 95.7 %
Branches: 341 580 58.8 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Gereon Kremer, 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                 :            :  * Implementation of class that encapsulates techniques for a single
      14                 :            :  * (SyGuS) synthesis conjecture.
      15                 :            :  */
      16                 :            : #include "theory/quantifiers/sygus/synth_conjecture.h"
      17                 :            : 
      18                 :            : #include "base/configuration.h"
      19                 :            : #include "expr/node_algorithm.h"
      20                 :            : #include "expr/skolem_manager.h"
      21                 :            : #include "options/base_options.h"
      22                 :            : #include "options/datatypes_options.h"
      23                 :            : #include "options/quantifiers_options.h"
      24                 :            : #include "printer/printer.h"
      25                 :            : #include "smt/logic_exception.h"
      26                 :            : #include "theory/datatypes/sygus_datatype_utils.h"
      27                 :            : #include "theory/quantifiers/first_order_model.h"
      28                 :            : #include "theory/quantifiers/instantiate.h"
      29                 :            : #include "theory/quantifiers/quantifiers_attributes.h"
      30                 :            : #include "theory/quantifiers/sygus/embedding_converter.h"
      31                 :            : #include "theory/quantifiers/sygus/enum_value_manager.h"
      32                 :            : #include "theory/quantifiers/sygus/print_sygus_to_builtin.h"
      33                 :            : #include "theory/quantifiers/sygus/sygus_enumerator.h"
      34                 :            : #include "theory/quantifiers/sygus/sygus_pbe.h"
      35                 :            : #include "theory/quantifiers/sygus/synth_engine.h"
      36                 :            : #include "theory/quantifiers/sygus/term_database_sygus.h"
      37                 :            : #include "theory/quantifiers/term_util.h"
      38                 :            : #include "theory/rewriter.h"
      39                 :            : #include "theory/smt_engine_subsolver.h"
      40                 :            : 
      41                 :            : using namespace cvc5::internal::kind;
      42                 :            : using namespace std;
      43                 :            : 
      44                 :            : namespace cvc5::internal {
      45                 :            : namespace theory {
      46                 :            : namespace quantifiers {
      47                 :            : 
      48                 :       6664 : SynthConjecture::SynthConjecture(Env& env,
      49                 :            :                                  QuantifiersState& qs,
      50                 :            :                                  QuantifiersInferenceManager& qim,
      51                 :            :                                  QuantifiersRegistry& qr,
      52                 :            :                                  TermRegistry& tr,
      53                 :       6664 :                                  SygusStatistics& s)
      54                 :            :     : EnvObj(env),
      55                 :            :       d_qstate(qs),
      56                 :            :       d_qim(qim),
      57                 :            :       d_qreg(qr),
      58                 :            :       d_treg(tr),
      59                 :            :       d_stats(s),
      60                 :      13328 :       d_tds(tr.getTermDatabaseSygus()),
      61                 :            :       d_verify(env, d_tds),
      62                 :            :       d_hasSolution(false),
      63                 :            :       d_computedSolution(false),
      64                 :      13328 :       d_runExprMiner(options().quantifiers.sygusFilterSolMode
      65                 :       6664 :                      != options::SygusFilterSolMode::NONE),
      66                 :       6664 :       d_ceg_si(new CegSingleInv(env, tr, s)),
      67                 :       6664 :       d_templInfer(new SygusTemplateInfer(env)),
      68                 :       6664 :       d_ceg_proc(new SynthConjectureProcess(env)),
      69                 :       6664 :       d_embConv(new EmbeddingConverter(env, d_tds, this)),
      70                 :       6664 :       d_sygus_rconst(new SygusRepairConst(env, d_tds)),
      71                 :       6664 :       d_exampleInfer(new ExampleInfer(nodeManager())),
      72                 :       6664 :       d_ceg_pbe(new SygusPbe(env, qs, qim, d_tds, this)),
      73                 :       6664 :       d_ceg_cegis(new Cegis(env, qs, qim, d_tds, this)),
      74                 :       6664 :       d_ceg_cegisUnif(new CegisUnif(env, qs, qim, d_tds, this)),
      75                 :       6664 :       d_sygus_ccore(new CegisCoreConnective(env, qs, qim, d_tds, this)),
      76                 :            :       d_master(nullptr),
      77                 :            :       d_repair_index(0),
      78                 :      73304 :       d_verifyWarned(false)
      79                 :            : {
      80                 :       6664 :   if (options().datatypes.sygusSymBreakPbe
      81 [ -  + ][ -  - ]:       6664 :       || options().quantifiers.sygusUnifPbe)
                 [ +  - ]
      82                 :            :   {
      83                 :       6664 :     d_modules.push_back(d_ceg_pbe.get());
      84                 :            :   }
      85         [ +  + ]:       6664 :   if (options().quantifiers.sygusUnifPi != options::SygusUnifPiMode::NONE)
      86                 :            :   {
      87                 :         45 :     d_modules.push_back(d_ceg_cegisUnif.get());
      88                 :            :   }
      89         [ +  + ]:       6664 :   if (options().quantifiers.sygusCoreConnective)
      90                 :            :   {
      91                 :       6658 :     d_modules.push_back(d_sygus_ccore.get());
      92                 :            :   }
      93                 :       6664 :   d_modules.push_back(d_ceg_cegis.get());
      94                 :       6664 : }
      95                 :            : 
      96                 :      13036 : SynthConjecture::~SynthConjecture() {}
      97                 :            : 
      98                 :       4730 : void SynthConjecture::presolve()
      99                 :            : {
     100                 :            :   // If we previously had a solution, block it. Notice that
     101                 :            :   // excludeCurrentSolution in the block below ensures we implement a
     102                 :            :   // policy where a *new* solution is generated for check-synth if the set of
     103                 :            :   // SyGuS constraints has not changed. This call will block solutions for
     104                 :            :   // *smart* enumerators only. This behavior makes smart enumeration have
     105                 :            :   // a consistent policy with *fast* enumerators, which will generate
     106                 :            :   // a new, next solution in their enumeration.
     107         [ +  + ]:       4730 :   if (d_hasSolution)
     108                 :            :   {
     109                 :        222 :     excludeCurrentSolution(d_solutionValues.back(),
     110                 :            :                            InferenceId::QUANTIFIERS_SYGUS_INC_EXCLUDE_CURRENT);
     111                 :            :     // we don't have a solution yet
     112                 :        222 :     d_hasSolution = false;
     113                 :        222 :     d_computedSolution = false;
     114                 :        222 :     d_sol.clear();
     115                 :        222 :     d_solStatus.clear();
     116                 :            :   }
     117                 :       4730 : }
     118                 :            : 
     119                 :       1385 : void SynthConjecture::assign(Node q)
     120                 :            : {
     121 [ -  + ][ -  + ]:       1385 :   Assert(d_embed_quant.isNull());
                 [ -  - ]
     122 [ -  + ][ -  + ]:       1385 :   Assert(q.getKind() == Kind::FORALL);
                 [ -  - ]
     123         [ +  - ]:       1385 :   Trace("cegqi") << "SynthConjecture : assign : " << q << std::endl;
     124                 :       1385 :   d_quant = q;
     125                 :       1385 :   NodeManager* nm = nodeManager();
     126                 :       1385 :   SkolemManager* sm = nm->getSkolemManager();
     127                 :            : 
     128                 :            :   // pre-simplify the quantified formula based on the process utility
     129                 :       1385 :   d_simp_quant = d_ceg_proc->preSimplify(d_quant);
     130                 :            : 
     131                 :            :   // compute its attributes
     132                 :       1385 :   QAttributes qa;
     133                 :       1385 :   QuantAttributes::computeQuantAttributes(q, qa);
     134                 :            : 
     135                 :       1385 :   Node sc = qa.d_sygusSideCondition;
     136                 :            :   // we check whether the conjecture is single invocation if we are marked
     137                 :            :   // with the sygus attribute and don't have a side condition
     138 [ +  - ][ +  + ]:       1385 :   bool checkSingleInvocation = qa.d_sygus && sc.isNull();
     139                 :            : 
     140                 :       1385 :   std::map<Node, Node> templates;
     141                 :       1385 :   std::map<Node, Node> templates_arg;
     142                 :            :   // register with single invocation if applicable
     143         [ +  + ]:       1385 :   if (checkSingleInvocation)
     144                 :            :   {
     145                 :        972 :     d_ceg_si->initialize(d_simp_quant);
     146                 :        972 :     d_simp_quant = d_ceg_si->getSimplifiedConjecture();
     147         [ +  - ]:        972 :     if (!d_ceg_si->isSingleInvocation())
     148                 :            :     {
     149                 :        972 :       d_templInfer->initialize(d_simp_quant);
     150                 :            :     }
     151                 :            :     // carry the templates
     152         [ +  + ]:       2284 :     for (const Node& v : q[0])
     153                 :            :     {
     154                 :       2624 :       Node templ = d_templInfer->getTemplate(v);
     155         [ +  + ]:       1312 :       if (!templ.isNull())
     156                 :            :       {
     157                 :         45 :         templates[v] = templ;
     158                 :         45 :         templates_arg[v] = d_templInfer->getTemplateArg(v);
     159                 :            :       }
     160                 :            :     }
     161                 :            :   }
     162                 :            : 
     163                 :            :   // post-simplify the quantified formula based on the process utility
     164                 :       1385 :   d_simp_quant = d_ceg_proc->postSimplify(d_simp_quant);
     165                 :            : 
     166                 :            :   // finished simplifying the quantified formula at this point
     167                 :            : 
     168                 :            :   // convert to deep embedding and finalize single invocation here
     169                 :       1385 :   d_embed_quant = d_embConv->process(d_simp_quant, templates, templates_arg);
     170         [ +  - ]:       2770 :   Trace("cegqi") << "SynthConjecture : converted to embedding : "
     171                 :       1385 :                  << d_embed_quant << std::endl;
     172                 :            :   // In very rare cases, the above call will return null if we construct a
     173                 :            :   // well-founded grammar. In this case, we fail immediately with "unknown".
     174         [ +  + ]:       1385 :   if (d_embed_quant.isNull())
     175                 :            :   {
     176                 :          1 :     d_qim.lemma(d_quant.negate(), InferenceId::QUANTIFIERS_SYGUS_NO_WF_GRAMMAR);
     177                 :          1 :     d_qim.setRefutationUnsound(IncompleteId::QUANTIFIERS_SYGUS_NO_WF_GRAMMAR);
     178                 :          1 :     return;
     179                 :            :   }
     180                 :            : 
     181         [ +  + ]:       1384 :   if (!sc.isNull())
     182                 :            :   {
     183         [ +  - ]:        413 :     Trace("cegqi-debug") << "Side condition is: " << sc << std::endl;
     184                 :            :     // Immediately check if unsat, use lambda returning true for functions
     185                 :            :     // to synthesize.
     186                 :        413 :     std::vector<Node> vars;
     187                 :        413 :     std::vector<Node> subs;
     188         [ +  + ]:        826 :     for (const Node& v : q[0])
     189                 :            :     {
     190                 :        413 :       vars.push_back(v);
     191                 :        826 :       TypeNode vtype = v.getType();
     192                 :        817 :       Assert(vtype.isBoolean()
     193                 :            :              || (vtype.isFunction() && vtype.getRangeType().isBoolean()));
     194                 :        826 :       Node s = nm->mkConst(true);
     195         [ +  + ]:        413 :       if (vtype.isFunction())
     196                 :            :       {
     197                 :        808 :         std::vector<TypeNode> atypes = vtype.getArgTypes();
     198                 :        404 :         std::vector<Node> lvars;
     199         [ +  + ]:       1147 :         for (const TypeNode& tn : atypes)
     200                 :            :         {
     201                 :        743 :           lvars.push_back(NodeManager::mkBoundVar(tn));
     202                 :            :         }
     203                 :       1616 :         s = nm->mkNode(
     204                 :       1212 :             Kind::LAMBDA, nm->mkNode(Kind::BOUND_VAR_LIST, lvars), s);
     205                 :            :       }
     206                 :        413 :       subs.push_back(s);
     207                 :            :     }
     208                 :            :     Node ksc =
     209                 :        413 :         sc.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
     210                 :        413 :     Result r = d_verify.verify(ksc);
     211                 :            :     // if infeasible, we are done
     212         [ +  + ]:        413 :     if (r.getStatus() == Result::UNSAT)
     213                 :            :     {
     214                 :          5 :       d_qim.lemma(d_quant.negate(),
     215                 :            :                   InferenceId::QUANTIFIERS_SYGUS_SC_INFEASIBLE);
     216                 :          5 :       return;
     217                 :            :     }
     218                 :            :     // convert to deep embedding
     219                 :        408 :     d_embedSideCondition = d_embConv->convertToEmbedding(sc);
     220         [ +  - ]:        816 :     Trace("cegqi") << "SynthConjecture : side condition : "
     221                 :        408 :                    << d_embedSideCondition << std::endl;
     222                 :            :   }
     223                 :            : 
     224                 :            :   // we now finalize the single invocation module, based on the syntax
     225                 :            :   // restrictions
     226         [ +  + ]:       1379 :   if (checkSingleInvocation)
     227                 :            :   {
     228                 :        971 :     d_ceg_si->finishInit(d_embConv->isSyntaxRestricted());
     229                 :            :   }
     230                 :            : 
     231 [ -  + ][ -  + ]:       1379 :   Assert(d_candidates.empty());
                 [ -  - ]
     232                 :       1379 :   std::vector<Node> vars;
     233         [ +  + ]:       3097 :   for (size_t i = 0, nvars = d_embed_quant[0].getNumChildren(); i < nvars; i++)
     234                 :            :   {
     235                 :       3436 :     Node v = d_embed_quant[0][i];
     236                 :       1718 :     vars.push_back(v);
     237                 :            :     Node e = sm->mkInternalSkolemFunction(
     238                 :            :         InternalSkolemId::QUANTIFIERS_SYNTH_FUN_EMBED,
     239                 :       3436 :         v.getType(),
     240                 :      10308 :         {d_simp_quant[0][i]});
     241                 :       1718 :     d_candidates.push_back(e);
     242                 :            :   }
     243         [ +  - ]:       2758 :   Trace("cegqi") << "Base quantified formula is : " << d_embed_quant
     244                 :       1379 :                  << std::endl;
     245                 :            :   // construct base instantiation
     246                 :       1379 :   Subs bsubs;
     247                 :       1379 :   bsubs.add(vars, d_candidates);
     248                 :       1379 :   d_base_inst = d_tds->rewriteNode(bsubs.apply(d_embed_quant[1]));
     249                 :       1379 :   d_checkBody = d_embed_quant[1];
     250                 :       4137 :   if (d_checkBody.getKind() == Kind::NOT
     251 [ +  + ][ +  + ]:       1379 :       && d_checkBody[0].getKind() == Kind::FORALL)
         [ +  + ][ +  + ]
                 [ -  - ]
     252                 :            :   {
     253         [ +  + ]:       3109 :     for (const Node& v : d_checkBody[0][0])
     254                 :            :     {
     255                 :       6873 :       Node sk = NodeManager::mkDummySkolem("rsk", v.getType());
     256                 :       2291 :       bsubs.add(v, sk);
     257                 :       2291 :       d_innerVars.push_back(v);
     258                 :       2291 :       d_innerSks.push_back(sk);
     259                 :            :     }
     260                 :        818 :     d_checkBody = d_checkBody[0][1].negate();
     261                 :            :   }
     262                 :       1379 :   d_checkBody = bsubs.apply(d_checkBody);
     263                 :       1379 :   d_checkBody = d_tds->rewriteNode(d_checkBody);
     264 [ +  + ][ +  - ]:       1379 :   if (!d_embedSideCondition.isNull() && !vars.empty())
                 [ +  + ]
     265                 :            :   {
     266                 :        816 :     d_embedSideCondition = d_embedSideCondition.substitute(
     267                 :        408 :         vars.begin(), vars.end(), d_candidates.begin(), d_candidates.end());
     268                 :            :   }
     269         [ +  - ]:       1379 :   Trace("cegqi") << "Base instantiation is :      " << d_base_inst << std::endl;
     270                 :            : 
     271                 :            :   // initialize the sygus constant repair utility
     272         [ +  + ]:       1379 :   if (options().quantifiers.sygusRepairConst)
     273                 :            :   {
     274                 :       1371 :     d_sygus_rconst->initialize(d_base_inst.negate(), d_candidates);
     275         [ -  + ]:       1371 :     if (options().quantifiers.sygusConstRepairAbort)
     276                 :            :     {
     277         [ -  - ]:          0 :       if (!d_sygus_rconst->isActive())
     278                 :            :       {
     279                 :            :         // no constant repair is possible: abort
     280                 :          0 :         std::stringstream ss;
     281                 :          0 :         ss << "Grammar does not allow repair constants." << std::endl;
     282                 :          0 :         throw LogicException(ss.str());
     283                 :            :       }
     284                 :            :     }
     285                 :            :   }
     286                 :            :   // initialize the example inference utility
     287                 :            :   // Notice that we must also consider the side condition when inferring
     288                 :            :   // whether the conjecture is PBE. This ensures we do not prune solutions
     289                 :            :   // that may satisfy the side condition based on equivalence-up-to-examples
     290                 :            :   // with solutions that do not.
     291                 :       1379 :   Node conjForExamples = d_base_inst;
     292         [ +  + ]:       1379 :   if (!d_embedSideCondition.isNull())
     293                 :            :   {
     294                 :        408 :     conjForExamples = nm->mkNode(Kind::AND, d_embedSideCondition, d_base_inst);
     295                 :            :   }
     296 [ +  - ][ +  + ]:       1379 :   if (d_exampleInfer!=nullptr && !d_exampleInfer->initialize(conjForExamples, d_candidates))
         [ +  - ][ +  + ]
                 [ -  - ]
     297                 :            :   {
     298                 :            :     // there is a contradictory example pair, the conjecture is infeasible.
     299                 :          2 :     Node infLem = d_quant.negate();
     300                 :          2 :     d_qim.lemma(infLem, InferenceId::QUANTIFIERS_SYGUS_EXAMPLE_INFER_CONTRA);
     301                 :            :     // we don't need to continue initialization in this case
     302                 :          2 :     return;
     303                 :            :   }
     304                 :            : 
     305                 :            :   // register this term with sygus database and other utilities that impact
     306                 :            :   // the enumerative sygus search
     307         [ +  + ]:       1377 :   if (!isSingleInvocation())
     308                 :            :   {
     309                 :       1235 :     d_ceg_proc->initialize(d_base_inst, d_candidates);
     310         [ +  - ]:       3294 :     for (unsigned i = 0, size = d_modules.size(); i < size; i++)
     311                 :            :     {
     312         [ +  + ]:       3294 :       if (d_modules[i]->initialize(d_simp_quant, d_base_inst, d_candidates))
     313                 :            :       {
     314                 :       1235 :         d_master = d_modules[i];
     315                 :       1235 :         break;
     316                 :            :       }
     317                 :            :     }
     318 [ -  + ][ -  + ]:       1235 :     Assert(d_master != nullptr);
                 [ -  - ]
     319                 :            :   }
     320                 :            : 
     321 [ -  + ][ -  + ]:       1377 :   Assert(d_qreg.getQuantAttributes().isSygus(q));
                 [ -  - ]
     322                 :            : 
     323         [ +  - ]:       2754 :   Trace("cegqi") << "...finished, single invocation = " << isSingleInvocation()
     324                 :       1377 :                  << std::endl;
     325                 :            : }
     326                 :            : 
     327                 :            : 
     328                 :     117638 : bool SynthConjecture::isSingleInvocation() const
     329                 :            : {
     330                 :     117638 :   return d_ceg_si->isSingleInvocation();
     331                 :            : }
     332                 :            : 
     333                 :      13204 : bool SynthConjecture::needsCheck()
     334                 :            : {
     335                 :      13204 :   return true;
     336                 :            : }
     337                 :            : 
     338                 :     113499 : bool SynthConjecture::doCheck()
     339                 :            : {
     340         [ +  + ]:     113499 :   if (d_hasSolution)
     341                 :            :   {
     342                 :          4 :     return true;
     343                 :            :   }
     344         [ +  + ]:     113495 :   if (isSingleInvocation())
     345                 :            :   {
     346                 :            :     // We now try to solve with the single invocation solver, which may or may
     347                 :            :     // not succeed in solving the conjecture. In either case,  we are done and
     348                 :            :     // return true.
     349                 :        142 :     Result res = d_ceg_si->solve();
     350         [ +  + ]:        142 :     if (res.getStatus() == Result::UNSAT)
     351                 :            :     {
     352                 :        129 :       d_hasSolution = true;
     353                 :            :       // the conjecture has a solution, we set incomplete
     354                 :        129 :       d_qim.setModelUnsound(IncompleteId::QUANTIFIERS_SYGUS_SOLVED);
     355                 :            :     }
     356         [ +  - ]:         13 :     else if (res.getStatus() == Result::SAT)
     357                 :            :     {
     358                 :            :       // the conjecture is definitely infeasible
     359                 :         13 :       d_qim.lemma(d_quant.negate(),
     360                 :            :                   InferenceId::QUANTIFIERS_SYGUS_SI_INFEASIBLE);
     361                 :            :     }
     362                 :        142 :     return true;
     363                 :            :   }
     364 [ -  + ][ -  + ]:     113353 :   Assert(d_master != nullptr);
                 [ -  - ]
     365                 :            : 
     366                 :            :   // get the list of terms that the master strategy is interested in
     367                 :     226706 :   std::vector<Node> terms;
     368                 :     113353 :   d_master->getTermList(d_candidates, terms);
     369                 :            : 
     370 [ -  + ][ -  + ]:     113353 :   Assert(!d_candidates.empty());
                 [ -  - ]
     371                 :            : 
     372         [ +  - ]:     226706 :   Trace("sygus-engine-debug")
     373                 :     113353 :       << "CegConjuncture : check, build candidates..." << std::endl;
     374                 :     226706 :   std::vector<Node> candidate_values;
     375                 :     113353 :   bool constructed_cand = false;
     376                 :            : 
     377                 :            :   // If a module is not trying to repair constants in solutions and the option
     378                 :            :   // sygusRepairConst  is true, we use a default scheme for trying to repair
     379                 :            :   // constants here.
     380                 :            :   bool doRepairConst =
     381 [ +  + ][ +  + ]:     113353 :       options().quantifiers.sygusRepairConst && !d_master->usingRepairConst();
     382         [ +  + ]:     113353 :   if (doRepairConst)
     383                 :            :   {
     384                 :            :     // have we tried to repair the previous solution?
     385                 :            :     // if not, call the repair constant utility
     386                 :      11632 :     size_t ninst = d_solutionValues.size();
     387         [ -  + ]:      11632 :     if (d_repair_index < ninst)
     388                 :            :     {
     389                 :          0 :       std::vector<Node> fail_cvs = d_solutionValues[d_repair_index];
     390         [ -  - ]:          0 :       if (TraceIsOn("sygus-engine"))
     391                 :            :       {
     392         [ -  - ]:          0 :         Trace("sygus-engine") << "CegConjuncture : repair previous solution ";
     393         [ -  - ]:          0 :         for (const Node& fc : fail_cvs)
     394                 :            :         {
     395                 :          0 :           std::stringstream ss;
     396                 :          0 :           TermDbSygus::toStreamSygus(ss, fc);
     397                 :          0 :           Trace("sygus-engine") << ss.str() << " ";
     398                 :            :         }
     399         [ -  - ]:          0 :         Trace("sygus-engine") << std::endl;
     400                 :            :       }
     401                 :          0 :       d_repair_index++;
     402         [ -  - ]:          0 :       if (d_sygus_rconst->repairSolution(
     403                 :          0 :               d_candidates, fail_cvs, candidate_values))
     404                 :            :       {
     405                 :          0 :         constructed_cand = true;
     406                 :            :       }
     407                 :            :     }
     408                 :            :     else
     409                 :            :     {
     410         [ +  - ]:      11632 :       Trace("sygus-engine-debug") << "...no candidates to repair" << std::endl;
     411                 :            :     }
     412                 :            :   }
     413                 :            :   else
     414                 :            :   {
     415         [ +  - ]:     101721 :     Trace("sygus-engine-debug") << "...not repairing" << std::endl;
     416                 :            :   }
     417                 :            : 
     418                 :     113353 :   bool printDebug = isOutputOn(OutputTag::SYGUS);
     419         [ +  - ]:     113353 :   if (!constructed_cand)
     420                 :            :   {
     421                 :            :     // get the model value of the relevant terms from the master module
     422                 :     113357 :     std::vector<Node> enum_values;
     423                 :     113353 :     bool activeIncomplete = false;
     424                 :     113353 :     bool fullModel = getEnumeratedValues(terms, enum_values, activeIncomplete);
     425                 :            : 
     426                 :            :     // if the master requires a full model and the model is partial, we fail
     427 [ +  + ][ +  + ]:     113349 :     if (!d_master->allowPartialModel() && !fullModel)
                 [ +  + ]
     428                 :            :     {
     429                 :            :       // we retain the values in d_ev_active_gen_waiting
     430         [ +  - ]:      55885 :       Trace("sygus-engine-debug") << "...partial model, fail." << std::endl;
     431                 :            :       // if we are partial due to an active enumerator, we may still succeed
     432                 :            :       // on the next call
     433                 :      55885 :       return !activeIncomplete;
     434                 :            :     }
     435                 :            :     // determine if we had at least one value for an enumerator
     436 [ -  + ][ -  + ]:      57464 :     Assert(terms.size() == enum_values.size());
                 [ -  - ]
     437                 :      57464 :     bool modelSuccess = false;
     438         [ +  + ]:     192386 :     for (unsigned i = 0, size = terms.size(); i < size; i++)
     439                 :            :     {
     440         [ +  + ]:     134922 :       if (!enum_values[i].isNull())
     441                 :            :       {
     442                 :     122847 :         modelSuccess = true;
     443                 :            :       }
     444                 :            :     }
     445         [ +  + ]:      57464 :     if (modelSuccess)
     446                 :            :     {
     447                 :            :       // Must separately compute whether trace is on due to compilation of
     448                 :            :       // TraceIsOn.
     449                 :      47135 :       bool traceIsOn = TraceIsOn("sygus-engine");
     450 [ +  + ][ -  + ]:      47135 :       if (printDebug || traceIsOn)
     451                 :            :       {
     452         [ +  - ]:          4 :         Trace("sygus-engine") << "  * Value is : ";
     453                 :          8 :         std::stringstream sygusEnumOut;
     454                 :          4 :         FirstOrderModel* m = d_treg.getModel();
     455         [ +  + ]:          8 :         for (unsigned i = 0, size = terms.size(); i < size; i++)
     456                 :            :         {
     457                 :          8 :           Node nv = enum_values[i];
     458 [ -  + ][ -  + ]:          8 :           Node onv = nv.isNull() ? m->getValue(terms[i]) : nv;
                 [ -  - ]
     459                 :          8 :           TypeNode tn = onv.getType();
     460                 :          8 :           std::stringstream ss;
     461                 :          4 :           TermDbSygus::toStreamSygus(ss, onv);
     462         [ +  - ]:          4 :           if (printDebug)
     463                 :            :           {
     464                 :          4 :             sygusEnumOut << " " << ss.str();
     465                 :            :           }
     466         [ +  - ]:          4 :           Trace("sygus-engine") << terms[i] << " -> ";
     467         [ -  + ]:          4 :           if (nv.isNull())
     468                 :            :           {
     469                 :          0 :             Trace("sygus-engine") << "[EXC: " << ss.str() << "] ";
     470                 :            :           }
     471                 :            :           else
     472                 :            :           {
     473 [ +  - ][ -  + ]:          4 :             Trace("sygus-engine") << ss.str() << " ";
                 [ -  - ]
     474         [ -  + ]:          4 :             if (TraceIsOn("sygus-engine-rr"))
     475                 :            :             {
     476                 :          0 :               Node bv = d_tds->sygusToBuiltin(nv, tn);
     477                 :          0 :               bv = d_tds->rewriteNode(bv);
     478         [ -  - ]:          0 :               Trace("sygus-engine-rr") << " -> " << bv << std::endl;
     479                 :            :             }
     480                 :            :           }
     481                 :            :         }
     482         [ +  - ]:          4 :         Trace("sygus-engine") << std::endl;
     483         [ +  - ]:          4 :         if (d_env.isOutputOn(OutputTag::SYGUS))
     484                 :            :         {
     485                 :          4 :           d_env.output(OutputTag::SYGUS)
     486                 :          4 :               << "(sygus-enum" << sygusEnumOut.str() << ")" << std::endl;
     487                 :            :         }
     488                 :            :       }
     489 [ -  + ][ -  + ]:      47135 :       Assert(candidate_values.empty());
                 [ -  - ]
     490                 :      47135 :       constructed_cand = d_master->constructCandidates(
     491                 :      47135 :           terms, enum_values, d_candidates, candidate_values);
     492                 :            :     }
     493                 :            :     // notify the enumerator managers of the status of the candidate
     494                 :     138820 :     for (std::pair<const Node, std::unique_ptr<EnumValueManager>>& ecp :
     495         [ +  + ]:     335104 :          d_enumManager)
     496                 :            :     {
     497                 :     138820 :       ecp.second->notifyCandidate(modelSuccess);
     498                 :            :     }
     499                 :            :     // if we did not generate a candidate, return now
     500         [ +  + ]:      57464 :     if (!modelSuccess)
     501                 :            :     {
     502         [ +  - ]:      10329 :       Trace("sygus-engine-debug") << "...empty model, fail." << std::endl;
     503                 :      10329 :       return !activeIncomplete;
     504                 :            :     }
     505                 :            :   }
     506                 :            : 
     507         [ +  + ]:      47135 :   if (constructed_cand)
     508                 :            :   {
     509                 :            :     // check the side condition if we constructed a candidate
     510         [ +  + ]:       4154 :     if (!checkSideCondition(candidate_values))
     511                 :            :     {
     512                 :         35 :       excludeCurrentSolution(candidate_values,
     513                 :            :                              InferenceId::QUANTIFIERS_SYGUS_SC_EXCLUDE_CURRENT);
     514         [ +  - ]:         35 :       Trace("sygus-engine") << "...failed side condition" << std::endl;
     515                 :         35 :       return false;
     516                 :            :     }
     517                 :            :   }
     518                 :            :   else
     519                 :            :   {
     520                 :      42981 :     return false;
     521                 :            :   }
     522                 :            : 
     523                 :            :   // must get a counterexample to the value of the current candidate
     524                 :       8238 :   Node query;
     525         [ -  + ]:       4119 :   if (TraceIsOn("sygus-engine-debug"))
     526                 :            :   {
     527         [ -  - ]:          0 :     Trace("sygus-engine-debug")
     528                 :          0 :         << "CegConjuncture : check candidate : " << std::endl;
     529         [ -  - ]:          0 :     for (unsigned i = 0, size = candidate_values.size(); i < size; i++)
     530                 :            :     {
     531         [ -  - ]:          0 :       Trace("sygus-engine-debug") << "  " << i << " : " << d_candidates[i]
     532                 :          0 :                                   << " -> " << candidate_values[i] << std::endl;
     533                 :            :     }
     534                 :            :   }
     535 [ -  + ][ -  + ]:       4119 :   Assert(candidate_values.size() == d_candidates.size());
                 [ -  - ]
     536                 :       8238 :   query = d_checkBody.substitute(d_candidates.begin(),
     537                 :            :                                  d_candidates.end(),
     538                 :            :                                  candidate_values.begin(),
     539                 :       4119 :                                  candidate_values.end());
     540                 :       4119 :   query = rewrite(query);
     541         [ +  - ]:       4119 :   Trace("sygus-engine-debug") << "Rewritten query is " << query << std::endl;
     542         [ +  + ]:       4119 :   if (expr::hasFreeVar(query))
     543                 :            :   {
     544         [ +  - ]:         12 :     Trace("sygus-engine-debug")
     545                 :          6 :         << "Free variable, from fwd-decls?" << std::endl;
     546                 :          6 :     NodeManager* nm = nodeManager();
     547                 :         12 :     std::vector<Node> qconj;
     548                 :          6 :     qconj.push_back(query);
     549                 :          6 :     Subs psubs;
     550         [ +  + ]:         18 :     for (size_t i = 0, size = d_candidates.size(); i < size; i++)
     551                 :            :     {
     552                 :         24 :       Node bsol = datatypes::utils::sygusToBuiltin(candidate_values[i], false);
     553                 :            :       // convert to lambda
     554                 :         24 :       TypeNode tn = d_candidates[i].getType();
     555                 :         12 :       const DType& dt = tn.getDType();
     556                 :         24 :       Node fvar = d_quant[0][i];
     557                 :         12 :       Node bvl = dt.getSygusVarList();
     558         [ +  + ]:         12 :       if (!bvl.isNull())
     559                 :            :       {
     560                 :            :         // since we don't have function subtyping, this assertion should only
     561                 :            :         // check the return type
     562 [ -  + ][ -  + ]:          8 :         Assert(fvar.getType().isFunction());
                 [ -  - ]
     563 [ -  + ][ -  + ]:          8 :         Assert(fvar.getType().getRangeType() == bsol.getType());
                 [ -  - ]
     564                 :          8 :         bsol = nm->mkNode(Kind::LAMBDA, bvl, bsol);
     565                 :            :       }
     566         [ +  - ]:         24 :       Trace("sygus-engine-debug")
     567                 :         12 :           << "Builtin sol: " << d_quant[0][i] << " -> " << bsol << std::endl;
     568                 :            :       // add purifying substitution, in case the dependencies are recusive
     569                 :         12 :       psubs.add(d_quant[0][i]);
     570                 :            :       // conjoin higher-order equality
     571                 :         12 :       qconj.push_back(d_quant[0][i].eqNode(bsol));
     572                 :            :     }
     573                 :          6 :     query = nm->mkAnd(qconj);
     574                 :          6 :     query = rewrite(psubs.apply(query));
     575                 :            :   }
     576                 :            : 
     577                 :            :   // if we trust the sampling we ran, we terminate now
     578         [ +  + ]:       4119 :   if (options().quantifiers.cegisSample == options::CegisSampleMode::TRUST)
     579                 :            :   {
     580                 :            :     // we have that the current candidate passed a sample test
     581                 :            :     // since we trust sampling in this mode, we assume there is a solution here
     582                 :            :     // and set incomplete.
     583                 :          4 :     d_hasSolution = true;
     584                 :          4 :     d_qim.setModelUnsound(IncompleteId::QUANTIFIERS_SYGUS_SOLVED);
     585                 :          4 :     recordSolution(candidate_values);
     586                 :          4 :     return true;
     587                 :            :   }
     588                 :            : 
     589                 :            :   // print the candidate solution for debugging
     590 [ +  - ][ +  + ]:       4115 :   if (constructed_cand && printDebug)
     591                 :            :   {
     592                 :          4 :     std::ostream& out = output(OutputTag::SYGUS);
     593                 :          4 :     out << "(sygus-candidate ";
     594 [ -  + ][ -  + ]:          4 :     Assert(d_quant[0].getNumChildren() == candidate_values.size());
                 [ -  - ]
     595         [ +  + ]:          8 :     for (size_t i = 0, ncands = candidate_values.size(); i < ncands; i++)
     596                 :            :     {
     597                 :          8 :       Node v = candidate_values[i];
     598                 :          4 :       out << "(" << d_quant[0][i] << " ";
     599                 :          4 :       TermDbSygus::toStreamSygus(out, v);
     600                 :          4 :       out << ")";
     601                 :            :     }
     602                 :          4 :     out << ")" << std::endl;
     603                 :            :   }
     604                 :            : 
     605                 :            :   // Record the solution, which may be falsified below. We require recording
     606                 :            :   // here since the result of the satisfiability test may be unknown.
     607                 :       4115 :   recordSolution(candidate_values);
     608                 :            : 
     609                 :       8230 :   std::vector<Node> skModel;
     610                 :       8230 :   Result r = d_verify.verify(query, d_innerSks, skModel);
     611                 :            : 
     612         [ +  + ]:       4115 :   if (r.getStatus() == Result::SAT)
     613                 :            :   {
     614                 :            :     // we have a counterexample
     615                 :       1692 :     return processCounterexample(skModel);
     616                 :            :   }
     617         [ +  + ]:       2423 :   else if (r.getStatus() != Result::UNSAT)
     618                 :            :   {
     619         [ +  + ]:        116 :     if (!d_verifyWarned)
     620                 :            :     {
     621                 :          6 :       d_verifyWarned = true;
     622                 :          6 :       std::stringstream ss;
     623                 :            :       ss << "Warning: The SyGuS solver failed to verify a candidate solution, "
     624                 :          6 :             "likely due to the base logic being undecidable.";
     625         [ +  - ]:          6 :       if (!options().quantifiers.fullSygusVerify)
     626                 :            :       {
     627                 :            :         ss << " The option --full-sygus-verify can be used to put more effort "
     628                 :          6 :               "into verifying individual candidate solutions.";
     629                 :            :       }
     630                 :          6 :       ss << " Use -q to silence this warning.";
     631 [ +  - ][ -  + ]:          6 :       Warning() << ss.str() << std::endl;
                 [ -  - ]
     632                 :            :     }
     633                 :            :     // In the rare case that the subcall is unknown, we simply exclude the
     634                 :            :     // solution, without adding a counterexample point. This should only
     635                 :            :     // happen if the quantifier free logic is undecidable.
     636                 :        116 :     excludeCurrentSolution(
     637                 :            :         candidate_values,
     638                 :            :         InferenceId::QUANTIFIERS_SYGUS_NO_VERIFY_EXCLUDE_CURRENT);
     639                 :            :     // We should set refutation unsound, since an "unsat" answer should not be
     640                 :            :     // interpreted as "infeasible", which would make a difference in the rare
     641                 :            :     // case where e.g. we had a finite grammar and exhausted the grammar.
     642                 :            :     // In other words, we are unsound by excluding the current candidate
     643                 :            :     // which we could not verify whether or not it was a solution.
     644                 :        116 :     d_qim.setRefutationUnsound(IncompleteId::QUANTIFIERS_SYGUS_NO_VERIFY);
     645                 :        116 :     return false;
     646                 :            :   }
     647                 :            :   // otherwise we are unsat, and we will process the solution below
     648                 :            : 
     649                 :            :   // now mark that we have a solution
     650                 :       2307 :   d_hasSolution = true;
     651                 :       2307 :   ++(d_stats.d_solutions);
     652                 :            :   // determine if we should filter this solution, e.g. based on expression
     653                 :            :   // mining or sygus stream
     654         [ +  + ]:       2307 :   if (runExprMiner())
     655                 :            :   {
     656                 :            :     // excluded due to expression mining
     657                 :        902 :     excludeCurrentSolution(
     658                 :            :         candidate_values,
     659                 :            :         InferenceId::QUANTIFIERS_SYGUS_STREAM_EXCLUDE_CURRENT);
     660                 :            :     // streaming means now we immediately are looking for a new solution
     661                 :        902 :     d_hasSolution = false;
     662                 :        902 :     d_computedSolution = false;
     663                 :        902 :     d_sol.clear();
     664                 :        902 :     d_solStatus.clear();
     665                 :        902 :     return false;
     666                 :            :   }
     667                 :            :   // We set incomplete and terminate with unknown.
     668                 :       1405 :   d_qim.setModelUnsound(IncompleteId::QUANTIFIERS_SYGUS_SOLVED);
     669                 :       1405 :   return true;
     670                 :            : }
     671                 :            : 
     672                 :       4154 : bool SynthConjecture::checkSideCondition(const std::vector<Node>& cvals)
     673                 :            : {
     674         [ +  + ]:       4154 :   if (d_embedSideCondition.isNull())
     675                 :            :   {
     676                 :       2697 :     return true;
     677                 :            :   }
     678                 :       2914 :   Node sc = d_embedSideCondition;
     679         [ +  - ]:       1457 :   if (!cvals.empty())
     680                 :            :   {
     681                 :       2914 :     sc = sc.substitute(
     682                 :       1457 :         d_candidates.begin(), d_candidates.end(), cvals.begin(), cvals.end());
     683                 :            :   }
     684         [ +  - ]:       1457 :   Trace("sygus-engine") << "Check side condition..." << std::endl;
     685                 :       2914 :   Result r = d_verify.verify(sc);
     686         [ +  - ]:       2914 :   Trace("sygus-engine") << "...result of check side condition : " << r
     687                 :       1457 :                         << std::endl;
     688         [ +  + ]:       1457 :   if (r == Result::UNSAT)
     689                 :            :   {
     690                 :         35 :     return false;
     691                 :            :   }
     692         [ +  - ]:       1422 :   Trace("sygus-engine") << "...passed side condition" << std::endl;
     693                 :       1422 :   return true;
     694                 :            : }
     695                 :            : 
     696                 :       1692 : bool SynthConjecture::processCounterexample(const std::vector<Node>& skModel)
     697                 :            : {
     698         [ +  - ]:       3384 :   Trace("cegqi-refine") << "doRefine : Construct refinement lemma..."
     699                 :       1692 :                         << std::endl;
     700         [ +  - ]:       3384 :   Trace("cegqi-refine-debug")
     701                 :       1692 :       << "  For counterexample skolems : " << d_innerSks << std::endl;
     702                 :       1692 :   Node base_lem = d_checkBody.negate();
     703                 :            : 
     704 [ -  + ][ -  + ]:       1692 :   Assert(d_innerSks.size() == skModel.size());
                 [ -  - ]
     705                 :            : 
     706         [ +  - ]:       1692 :   Trace("cegqi-refine") << "doRefine : substitute..." << std::endl;
     707                 :       3384 :   base_lem = base_lem.substitute(
     708                 :       1692 :       d_innerSks.begin(), d_innerSks.end(), skModel.begin(), skModel.end());
     709         [ +  - ]:       1692 :   Trace("cegqi-refine") << "doRefine : rewrite..." << std::endl;
     710                 :       1692 :   base_lem = d_tds->rewriteNode(base_lem);
     711         [ +  - ]:       3384 :   Trace("cegqi-refine") << "doRefine : register refinement lemma " << base_lem
     712                 :       1692 :                         << "..." << std::endl;
     713                 :       1692 :   size_t prevPending = d_qim.numPendingLemmas();
     714                 :       1692 :   d_master->registerRefinementLemma(d_innerSks, base_lem);
     715         [ +  - ]:       1692 :   Trace("cegqi-refine") << "doRefine : finished" << std::endl;
     716                 :            : 
     717                 :            :   // check if we added a lemma
     718                 :       1692 :   bool addedLemma = d_qim.numPendingLemmas() > prevPending;
     719         [ +  + ]:       1692 :   if (addedLemma)
     720                 :            :   {
     721         [ +  - ]:       1097 :     Trace("sygus-engine-debug") << "  ...refine candidate." << std::endl;
     722                 :            :   }
     723                 :            :   else
     724                 :            :   {
     725         [ +  - ]:       1190 :     Trace("sygus-engine-debug") << "  ...(warning) failed to refine candidate, "
     726                 :          0 :                                    "manually exclude candidate."
     727                 :        595 :                                 << std::endl;
     728                 :       1190 :     std::vector<Node> cvals = d_solutionValues.back();
     729                 :            :     // something went wrong, exclude the current candidate
     730                 :        595 :     excludeCurrentSolution(
     731                 :            :         cvals, InferenceId::QUANTIFIERS_SYGUS_REPEAT_CEX_EXCLUDE_CURRENT);
     732                 :            :     // Note this happens when evaluation is incapable of disproving a candidate
     733                 :            :     // for counterexample point c, but satisfiability checking happened to find
     734                 :            :     // the the same point c is indeed a true counterexample. It is sound
     735                 :            :     // to exclude the candidate in this case.
     736                 :            :   }
     737                 :       3384 :   return addedLemma;
     738                 :            : }
     739                 :            : 
     740                 :       1385 : void SynthConjecture::ppNotifyConjecture(Node q)
     741                 :            : {
     742                 :       1385 :   d_ceg_si->ppNotifyConjecture(q);
     743                 :       1385 : }
     744                 :            : 
     745                 :     113353 : bool SynthConjecture::getEnumeratedValues(std::vector<Node>& n,
     746                 :            :                                           std::vector<Node>& v,
     747                 :            :                                           bool& activeIncomplete)
     748                 :            : {
     749         [ +  - ]:     113353 :   Trace("sygus-engine-debug") << "getEnumeratedValues" << std::endl;
     750                 :     113357 :   std::vector<Node> ncheck = n;
     751                 :     113353 :   n.clear();
     752                 :     113353 :   bool ret = true;
     753         [ +  + ]:     309518 :   for (unsigned i = 0, size = ncheck.size(); i < size; i++)
     754                 :            :   {
     755                 :     196173 :     Node e = ncheck[i];
     756                 :            :     // if it is not active, we return null
     757                 :     196173 :     Node g = d_tds->getActiveGuardForEnumerator(e);
     758         [ +  + ]:     196169 :     if (!g.isNull())
     759                 :            :     {
     760                 :     105935 :       Node gstatus = d_qstate.getValuation().getSatValue(g);
     761 [ +  - ][ +  + ]:     105935 :       if (gstatus.isNull() || !gstatus.getConst<bool>())
                 [ +  + ]
     762                 :            :       {
     763         [ +  - ]:        664 :         Trace("sygus-engine-debug")
     764                 :        332 :             << "Enumerator " << e << " is inactive." << std::endl;
     765                 :        332 :         continue;
     766                 :            :       }
     767                 :            :     }
     768                 :     195837 :     EnumValueManager* eman = getEnumValueManagerFor(e);
     769         [ +  - ]:     195837 :     Trace("sygus-engine-debug2") << "- get value for " << e << std::endl;
     770                 :     195837 :     Node nv = eman->getEnumeratedValue(activeIncomplete);
     771         [ +  - ]:     195833 :     Trace("sygus-engine-debug2") << "  ...return " << nv << std::endl;
     772                 :     195833 :     n.push_back(e);
     773                 :     195833 :     v.push_back(nv);
     774 [ +  + ][ +  + ]:     195833 :     ret = ret && !nv.isNull();
     775                 :            :   }
     776                 :     226698 :   return ret;
     777                 :            : }
     778                 :            : 
     779                 :     243940 : EnumValueManager* SynthConjecture::getEnumValueManagerFor(Node e)
     780                 :            : {
     781                 :            :   std::map<Node, std::unique_ptr<EnumValueManager>>::iterator it =
     782                 :     243940 :       d_enumManager.find(e);
     783         [ +  + ]:     243940 :   if (it != d_enumManager.end())
     784                 :            :   {
     785                 :     242335 :     return it->second.get();
     786                 :            :   }
     787                 :            :   // otherwise, allocate it
     788                 :       1605 :   Node f = d_tds->getSynthFunForEnumerator(e);
     789 [ +  + ][ -  - ]:       3210 :   bool hasExamples = (d_exampleInfer != nullptr && d_exampleInfer->hasExamples(f)
     790 [ +  - ][ +  + ]:       3210 :                       && d_exampleInfer->getNumExamples(f) != 0);
         [ +  + ][ +  - ]
                 [ -  - ]
     791                 :       3210 :   d_enumManager[e].reset(
     792                 :       1605 :       new EnumValueManager(d_env, d_qim, d_treg, d_stats, e, hasExamples));
     793                 :       1605 :   EnumValueManager* eman = d_enumManager[e].get();
     794                 :            :   // set up the examples
     795         [ +  + ]:       1605 :   if (hasExamples)
     796                 :            :   {
     797                 :        358 :     ExampleEvalCache* eec = eman->getExampleEvalCache();
     798 [ -  + ][ -  + ]:        358 :     Assert(eec != nullptr);
                 [ -  - ]
     799         [ +  + ]:       1442 :     for (unsigned i = 0, nex = d_exampleInfer->getNumExamples(f); i < nex; i++)
     800                 :            :     {
     801                 :       2168 :       std::vector<Node> input;
     802                 :       1084 :       d_exampleInfer->getExample(f, i, input);
     803                 :       1084 :       eec->addExample(input);
     804                 :            :     }
     805                 :            :   }
     806                 :       1605 :   return eman;
     807                 :            : }
     808                 :            : 
     809                 :       1390 : ExpressionMinerManager* SynthConjecture::getExprMinerManagerFor(Node e)
     810                 :            : {
     811         [ +  + ]:       1390 :   if (!d_runExprMiner)
     812                 :            :   {
     813                 :          8 :     return nullptr;
     814                 :            :   }
     815                 :            :   std::map<Node, std::unique_ptr<ExpressionMinerManager>>::iterator its =
     816                 :       1382 :       d_exprm.find(e);
     817         [ +  + ]:       1382 :   if (its != d_exprm.end())
     818                 :            :   {
     819                 :        982 :     return its->second.get();
     820                 :            :   }
     821                 :        400 :   d_exprm[e].reset(new ExpressionMinerManager(d_env));
     822                 :        400 :   ExpressionMinerManager* emm = d_exprm[e].get();
     823                 :        400 :   emm->initializeSygus(e.getType());
     824                 :        400 :   return emm;
     825                 :            : }
     826                 :            : 
     827                 :      25696 : Node SynthConjecture::getModelValue(Node n)
     828                 :            : {
     829         [ +  - ]:      25696 :   Trace("cegqi-mv") << "getModelValue for : " << n << std::endl;
     830                 :      25696 :   return d_treg.getModel()->getValue(n);
     831                 :            : }
     832                 :            : 
     833                 :          0 : void SynthConjecture::debugPrint(const char* c)
     834                 :            : {
     835         [ -  - ]:          0 :   Trace(c) << "Synthesis conjecture : " << d_embed_quant << std::endl;
     836         [ -  - ]:          0 :   Trace(c) << "  * Candidate programs : " << d_candidates << std::endl;
     837         [ -  - ]:          0 :   Trace(c) << "  * Counterexample skolems : " << d_innerSks << std::endl;
     838                 :          0 : }
     839                 :            : 
     840                 :       1870 : void SynthConjecture::excludeCurrentSolution(const std::vector<Node>& values,
     841                 :            :                                              InferenceId id)
     842                 :            : {
     843 [ -  + ][ -  + ]:       1870 :   Assert(values.size() == d_candidates.size());
                 [ -  - ]
     844         [ +  - ]:       1870 :   Trace("cegqi-debug") << "Exclude current solution: " << values << std::endl;
     845                 :            :   // However, we need to exclude the current solution using an explicit
     846                 :            :   // blocking clause, so that we proceed to the next solution. We do this only
     847                 :            :   // for passively-generated enumerators (TermDbSygus::isPassiveEnumerator).
     848                 :       1870 :   std::vector<Node> exp;
     849         [ +  + ]:       2030 :   for (size_t i = 0, tsize = d_candidates.size(); i < tsize; i++)
     850                 :            :   {
     851                 :       1876 :     Node cprog = d_candidates[i];
     852 [ -  + ][ -  + ]:       1876 :     Assert(d_tds->isEnumerator(cprog));
                 [ -  - ]
     853         [ +  + ]:       1876 :     if (!d_tds->isPassiveEnumerator(cprog))
     854                 :            :     {
     855                 :            :       // If any candidate is actively generated, then we should not add the
     856                 :            :       // lemma below. We never mix fast and smart enumerators.
     857                 :       1716 :       return;
     858                 :            :     }
     859                 :        160 :     Node cval = values[i];
     860                 :            :     // add to explanation of exclusion
     861                 :        160 :     d_tds->getExplain()->getExplanationForEquality(cprog, cval, exp);
     862                 :            :   }
     863         [ +  - ]:        154 :   if (!exp.empty())
     864                 :            :   {
     865                 :            :     Node exc_lem =
     866         [ +  + ]:        154 :         exp.size() == 1 ? exp[0] : nodeManager()->mkNode(Kind::AND, exp);
     867                 :        154 :     exc_lem = exc_lem.negate();
     868         [ +  - ]:        308 :     Trace("cegqi-lemma") << "Cegqi::Lemma : exclude current solution : "
     869                 :        154 :                          << exc_lem << " by " << id << std::endl;
     870                 :        154 :     d_qim.lemma(exc_lem, id);
     871                 :            :   }
     872                 :            : }
     873                 :            : 
     874                 :       2307 : bool SynthConjecture::runExprMiner()
     875                 :            : {
     876                 :            :   // if not using expression mining and sygus stream
     877 [ +  + ][ +  + ]:       2307 :   if (!d_runExprMiner && !options().quantifiers.sygusStream)
                 [ +  + ]
     878                 :            :   {
     879                 :        917 :     return false;
     880                 :            :   }
     881         [ +  - ]:       1390 :   Trace("cegqi-sol-debug") << "Run expression mining..." << std::endl;
     882 [ -  + ][ -  + ]:       1390 :   Assert(d_quant[0].getNumChildren() == d_embed_quant[0].getNumChildren());
                 [ -  - ]
     883                 :       2780 :   std::vector<Node> sols;
     884                 :       2780 :   std::vector<int8_t> statuses;
     885         [ -  + ]:       1390 :   if (!getSynthSolutionsInternal(sols, statuses))
     886                 :            :   {
     887                 :          0 :     return false;
     888                 :            :   }
     889                 :            :   // always exclude if sygus stream is enabled
     890                 :       1390 :   bool doExclude = options().quantifiers.sygusStream;
     891                 :       1390 :   NodeManager* nm = nodeManager();
     892                 :       1390 :   std::ostream& out = options().base.out;
     893         [ +  + ]:       2780 :   for (size_t i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
     894                 :            :   {
     895                 :       1390 :     Node sol = sols[i];
     896         [ -  + ]:       1390 :     if (sol.isNull())
     897                 :            :     {
     898                 :            :       // failed to reconstruct to syntax, skip
     899                 :          0 :       continue;
     900                 :            :     }
     901                 :       1390 :     Node e = d_embed_quant[0][i];
     902                 :       1390 :     int8_t status = statuses[i];
     903                 :            :     // run expression mining
     904         [ +  - ]:       1390 :     if (status != 0)
     905                 :            :     {
     906                 :       1390 :       ExpressionMinerManager* emm = getExprMinerManagerFor(e);
     907         [ +  + ]:       1390 :       if (emm != nullptr)
     908                 :            :       {
     909                 :       1382 :         bool ret = emm->addTerm(sol);
     910         [ +  + ]:       1382 :         if (!ret)
     911                 :            :         {
     912                 :            :           // count the number of filtered solutions
     913                 :        868 :           ++(d_stats.d_filtered_solutions);
     914                 :            :           // if any term is excluded due to mining, its output is excluded
     915                 :            :           // from sygus stream, and the entire solution is excluded.
     916                 :        868 :           doExclude = true;
     917                 :        868 :           continue;
     918                 :            :         }
     919                 :            :       }
     920                 :            :     }
     921                 :            :     // print to stream
     922         [ +  + ]:        522 :     if (options().quantifiers.sygusStream)
     923                 :            :     {
     924                 :         68 :       TypeNode tn = e.getType();
     925                 :         34 :       const DType& dt = tn.getDType();
     926                 :         68 :       std::stringstream ss;
     927                 :         34 :       ss << e;
     928                 :         68 :       std::string f(ss.str());
     929                 :         34 :       f.erase(f.begin());
     930                 :         34 :       out << "(define-fun " << f << " ";
     931                 :            :       // Only include variables that are truly bound variables of the
     932                 :            :       // function-to-synthesize. This means we exclude variables that encode
     933                 :            :       // external terms. This ensures that --sygus-stream prints
     934                 :            :       // solutions with no arguments on the predicate for responses to
     935                 :            :       // the get-abduct command.
     936                 :            :       // pvs stores the variables that will be printed in the argument list
     937                 :            :       // below.
     938                 :         68 :       std::vector<Node> pvs;
     939                 :         68 :       Node vl = dt.getSygusVarList();
     940         [ +  - ]:         34 :       if (!vl.isNull())
     941                 :            :       {
     942 [ -  + ][ -  + ]:         34 :         Assert(vl.getKind() == Kind::BOUND_VAR_LIST);
                 [ -  - ]
     943                 :            :         SygusVarToTermAttribute sta;
     944         [ +  + ]:        154 :         for (const Node& v : vl)
     945                 :            :         {
     946         [ +  + ]:        120 :           if (!v.hasAttribute(sta))
     947                 :            :           {
     948                 :         16 :             pvs.push_back(v);
     949                 :            :           }
     950                 :            :         }
     951                 :            :       }
     952         [ +  + ]:         34 :       if (pvs.empty())
     953                 :            :       {
     954                 :         26 :         out << "() ";
     955                 :            :       }
     956                 :            :       else
     957                 :            :       {
     958                 :          8 :         vl = nm->mkNode(Kind::BOUND_VAR_LIST, pvs);
     959                 :          8 :         out << vl << " ";
     960                 :            :       }
     961                 :         34 :       out << dt.getSygusType() << " ";
     962         [ -  + ]:         34 :       if (status == 0)
     963                 :            :       {
     964                 :          0 :         out << sol;
     965                 :            :       }
     966                 :            :       else
     967                 :            :       {
     968                 :         34 :         Node bsol = datatypes::utils::sygusToBuiltin(sol, true);
     969                 :         34 :         out << bsol;
     970                 :            :       }
     971                 :         34 :       out << ")" << std::endl;
     972                 :            :     }
     973                 :            :   }
     974                 :       1390 :   return doExclude;
     975                 :            : }
     976                 :            : 
     977                 :       2171 : bool SynthConjecture::getSynthSolutions(
     978                 :            :     std::map<Node, std::map<Node, Node> >& sol_map)
     979                 :            : {
     980                 :       2171 :   NodeManager* nm = nodeManager();
     981                 :       4342 :   std::vector<Node> sols;
     982                 :       4342 :   std::vector<int8_t> statuses;
     983         [ +  - ]:       2171 :   Trace("cegqi-debug") << "getSynthSolutions..." << std::endl;
     984         [ +  + ]:       2171 :   if (!getSynthSolutionsInternal(sols, statuses))
     985                 :            :   {
     986         [ +  - ]:         64 :     Trace("cegqi-debug") << "...failed internal" << std::endl;
     987                 :         64 :     return false;
     988                 :            :   }
     989                 :            :   // we add it to the solution map, indexed by this conjecture
     990                 :       2107 :   std::map<Node, Node>& smc = sol_map[d_quant];
     991         [ +  + ]:       4544 :   for (unsigned i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
     992                 :            :   {
     993                 :       4874 :     Node sol = sols[i];
     994                 :       2437 :     int8_t status = statuses[i];
     995         [ +  - ]:       4874 :     Trace("cegqi-debug") << "...got " << i << ": " << sol
     996                 :       2437 :                          << ", status=" << status << std::endl;
     997                 :            :     // get the builtin solution
     998                 :       4874 :     Node bsol = sol;
     999         [ +  + ]:       2437 :     if (status != 0)
    1000                 :            :     {
    1001                 :            :       // Convert sygus to builtin here.
    1002                 :            :       // We must use the external representation to ensure bsol matches the
    1003                 :            :       // grammar.
    1004                 :       2089 :       bsol = datatypes::utils::sygusToBuiltin(sol, true);
    1005                 :            :     }
    1006                 :            :     // convert to lambda
    1007                 :       7311 :     TypeNode tn = d_embed_quant[0][i].getType();
    1008                 :       2437 :     const DType& dt = tn.getDType();
    1009                 :       4874 :     Node fvar = d_quant[0][i];
    1010                 :       2437 :     Node bvl = dt.getSygusVarList();
    1011         [ +  + ]:       2437 :     if (!bvl.isNull())
    1012                 :            :     {
    1013                 :            :       // since we don't have function subtyping, this assertion should only
    1014                 :            :       // check the return type
    1015 [ -  + ][ -  + ]:       1977 :       Assert(fvar.getType().isFunction());
                 [ -  - ]
    1016 [ -  + ][ -  + ]:       1977 :       Assert(fvar.getType().getRangeType() == bsol.getType());
                 [ -  - ]
    1017                 :       1977 :       bsol = nm->mkNode(Kind::LAMBDA, bvl, bsol);
    1018                 :            :     }
    1019                 :            :     else
    1020                 :            :     {
    1021 [ -  + ][ -  + ]:        460 :       Assert(fvar.getType() == bsol.getType());
                 [ -  - ]
    1022                 :            :     }
    1023                 :            :     // store in map
    1024                 :       2437 :     smc[fvar] = bsol;
    1025         [ +  - ]:       2437 :     Trace("cegqi-debug") << "...return " << bsol << std::endl;
    1026                 :            :   }
    1027                 :       2107 :   return true;
    1028                 :            : }
    1029                 :            : 
    1030                 :       4119 : void SynthConjecture::recordSolution(const std::vector<Node>& vs)
    1031                 :            : {
    1032 [ -  + ][ -  + ]:       4119 :   Assert(vs.size() == d_candidates.size());
                 [ -  - ]
    1033                 :       4119 :   d_solutionValues.clear();
    1034                 :       4119 :   d_solutionValues.push_back(vs);
    1035                 :       4119 : }
    1036                 :            : 
    1037                 :       3561 : bool SynthConjecture::getSynthSolutionsInternal(std::vector<Node>& sols,
    1038                 :            :                                                 std::vector<int8_t>& statuses)
    1039                 :            : {
    1040         [ +  + ]:       3561 :   if (!d_hasSolution)
    1041                 :            :   {
    1042                 :         60 :     return false;
    1043                 :            :   }
    1044         [ +  + ]:       3501 :   if (d_computedSolution)
    1045                 :            :   {
    1046                 :       1061 :     sols.insert(sols.end(), d_sol.begin(), d_sol.end());
    1047                 :       1061 :     statuses.insert(statuses.end(), d_solStatus.begin(), d_solStatus.end());
    1048                 :       1061 :     return true;
    1049                 :            :   }
    1050                 :       2440 :   d_computedSolution = true;
    1051                 :            :   // get the (SyGuS datatype) values of the solutions, if they exist
    1052                 :       4880 :   std::vector<Node> svals;
    1053         [ +  + ]:       2440 :   if (!d_solutionValues.empty())
    1054                 :            :   {
    1055                 :       2311 :     svals = d_solutionValues.back();
    1056                 :            :   }
    1057         [ +  + ]:       5202 :   for (size_t i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
    1058                 :            :   {
    1059                 :       2766 :     Node prog = d_embed_quant[0][i];
    1060         [ +  - ]:       2766 :     Trace("cegqi-debug") << "  get solution for " << prog << std::endl;
    1061                 :       2766 :     TypeNode tn = prog.getType();
    1062 [ -  + ][ -  + ]:       2766 :     Assert(tn.isDatatype());
                 [ -  - ]
    1063                 :            :     // get the solution
    1064                 :       2766 :     Node sol;
    1065                 :       2766 :     int8_t status = -1;
    1066         [ +  + ]:       2766 :     if (isSingleInvocation())
    1067                 :            :     {
    1068 [ -  + ][ -  + ]:        359 :       Assert(d_ceg_si != NULL);
                 [ -  - ]
    1069                 :        359 :       sol = d_ceg_si->getSolution(i, tn, status, true);
    1070         [ +  + ]:        359 :       if (sol.isNull())
    1071                 :            :       {
    1072                 :          4 :         return false;
    1073                 :            :       }
    1074         [ +  + ]:        355 :       sol = sol.getKind() == Kind::LAMBDA ? sol[1] : sol;
    1075                 :            :     }
    1076                 :            :     else
    1077                 :            :     {
    1078                 :       4814 :       Node cprog = d_candidates[i];
    1079         [ +  - ]:       2407 :       if (!svals.empty())
    1080                 :            :       {
    1081                 :            :         // the solution is the value of the last term
    1082                 :       2407 :         sol = svals[i];
    1083                 :       2407 :         status = 1;
    1084                 :            : 
    1085                 :            :         // check if there was a template
    1086                 :       4814 :         Node sf = d_quant[0][i];
    1087                 :       4814 :         Node templ = d_templInfer->getTemplate(sf);
    1088         [ +  + ]:       2407 :         if (!templ.isNull())
    1089                 :            :         {
    1090         [ +  - ]:         66 :           Trace("cegqi-inv-debug")
    1091                 :         33 :               << sf << " used template : " << templ << std::endl;
    1092                 :         99 :           TNode templa = d_templInfer->getTemplateArg(sf);
    1093                 :            :           // make the builtin version of the full solution
    1094                 :         33 :           sol = d_tds->sygusToBuiltin(sol, sol.getType());
    1095         [ +  - ]:         66 :           Trace("cegqi-inv") << "Builtin version of solution is : " << sol
    1096 [ -  + ][ -  - ]:         33 :                              << ", type : " << sol.getType() << std::endl;
    1097                 :         33 :           TNode tsol = sol;
    1098                 :         33 :           sol = templ.substitute(templa, tsol);
    1099         [ +  - ]:         33 :           Trace("cegqi-inv-debug") << "With template : " << sol << std::endl;
    1100                 :         33 :           sol = rewrite(sol);
    1101         [ +  - ]:         33 :           Trace("cegqi-inv-debug") << "Simplified : " << sol << std::endl;
    1102                 :            :           // now, reconstruct to the syntax
    1103                 :         33 :           sol = d_ceg_si->reconstructToSyntax(sol, tn, status, true);
    1104         [ -  + ]:         33 :           sol = sol.getKind() == Kind::LAMBDA ? sol[1] : sol;
    1105         [ +  - ]:         66 :           Trace("cegqi-inv-debug")
    1106                 :         33 :               << "Reconstructed to syntax : " << sol << std::endl;
    1107                 :            :         }
    1108                 :            :         else
    1109                 :            :         {
    1110         [ +  - ]:       4748 :           Trace("cegqi-inv-debug")
    1111                 :       2374 :               << sf << " did not use template" << std::endl;
    1112                 :            :         }
    1113                 :            :       }
    1114                 :            :       else
    1115                 :            :       {
    1116         [ -  - ]:          0 :         Trace("cegqi-warn") << "WARNING : No recorded instantiations for "
    1117                 :          0 :                                "syntax-guided solution!"
    1118                 :          0 :                             << std::endl;
    1119                 :            :       }
    1120                 :            :     }
    1121                 :       2762 :     d_sol.push_back(sol);
    1122                 :       2762 :     d_solStatus.push_back(status);
    1123                 :            :     // Note that this assumes that the name of the resulting datatype matches
    1124                 :            :     // the original name from the user. This is usually the case, although
    1125                 :            :     // if grammar normalization is used, it is not. If it is not, the names
    1126                 :            :     // in the annotation will not match, but no failures will occur.
    1127                 :            :     // Also note that we do not print annotations if the solution was not
    1128                 :            :     // reconstructed to the grammar (status != 1), which is the case if the
    1129                 :            :     // grammar is ignored by single invocation above. On the other hand,
    1130                 :            :     // annotations will be printed correctly if the solution was successfully
    1131                 :            :     // reconstructed by single invocation (status == 1).
    1132 [ +  + ][ +  - ]:       2762 :     if (isOutputOn(OutputTag::SYGUS_SOL_GTERM) && status == 1)
                 [ +  + ]
    1133                 :            :     {
    1134                 :          2 :       Node psol = getPrintableSygusToBuiltin(sol);
    1135                 :          2 :       d_env.output(OutputTag::SYGUS_SOL_GTERM)
    1136                 :          4 :           << "(sygus-sol-gterm (" << d_quant[0][i] << " " << psol << "))"
    1137                 :          2 :           << std::endl;
    1138                 :            :     }
    1139                 :            :   }
    1140                 :       2436 :   sols.insert(sols.end(), d_sol.begin(), d_sol.end());
    1141                 :       2436 :   statuses.insert(statuses.end(), d_solStatus.begin(), d_solStatus.end());
    1142                 :       2436 :   return true;
    1143                 :            : }
    1144                 :            : 
    1145                 :      18043 : Node SynthConjecture::getSymmetryBreakingPredicate(
    1146                 :            :     Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth)
    1147                 :            : {
    1148                 :      36086 :   std::vector<Node> sb_lemmas;
    1149                 :            : 
    1150                 :            :   // based on simple preprocessing
    1151                 :            :   Node ppred =
    1152                 :      54129 :       d_ceg_proc->getSymmetryBreakingPredicate(x, e, tn, tindex, depth);
    1153         [ -  + ]:      18043 :   if (!ppred.isNull())
    1154                 :            :   {
    1155                 :          0 :     sb_lemmas.push_back(ppred);
    1156                 :            :   }
    1157                 :            : 
    1158                 :            :   // other static conjecture-dependent symmetry breaking goes here
    1159                 :            : 
    1160         [ -  + ]:      18043 :   if (!sb_lemmas.empty())
    1161                 :            :   {
    1162                 :          0 :     return sb_lemmas.size() == 1 ? sb_lemmas[0]
    1163         [ -  - ]:          0 :                                  : nodeManager()->mkNode(Kind::AND, sb_lemmas);
    1164                 :            :   }
    1165                 :            :   else
    1166                 :            :   {
    1167                 :      18043 :     return Node::null();
    1168                 :            :   }
    1169                 :            : }
    1170                 :            : 
    1171                 :      48103 : ExampleEvalCache* SynthConjecture::getExampleEvalCache(Node e)
    1172                 :            : {
    1173                 :      48103 :   EnumValueManager* eman = getEnumValueManagerFor(e);
    1174                 :      48103 :   return eman->getExampleEvalCache();
    1175                 :            : }
    1176                 :            : 
    1177                 :            : }  // namespace quantifiers
    1178                 :            : }  // namespace theory
    1179                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14