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: 552 592 93.2 %
Date: 2024-10-23 11:38:32 Functions: 22 23 95.7 %
Branches: 339 578 58.7 %

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

Generated by: LCOV version 1.14