LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers - inst_strategy_mbqi.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 347 382 90.8 %
Date: 2026-03-01 11:40:25 Functions: 12 14 85.7 %
Branches: 238 356 66.9 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * Model-based quantifier instantiation
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/quantifiers/inst_strategy_mbqi.h"
      14                 :            : 
      15                 :            : #include "expr/node_algorithm.h"
      16                 :            : #include "expr/skolem_manager.h"
      17                 :            : #include "expr/subs.h"
      18                 :            : #include "options/arrays_options.h"
      19                 :            : #include "printer/smt2/smt2_printer.h"
      20                 :            : #include "smt/set_defaults.h"
      21                 :            : #include "theory/quantifiers/first_order_model.h"
      22                 :            : #include "theory/quantifiers/instantiate.h"
      23                 :            : #include "theory/quantifiers/mbqi_enum.h"
      24                 :            : #include "theory/quantifiers/quantifiers_rewriter.h"
      25                 :            : #include "theory/quantifiers/skolemize.h"
      26                 :            : #include "theory/quantifiers/term_util.h"
      27                 :            : #include "theory/strings/theory_strings_utils.h"
      28                 :            : #include "theory/uf/function_const.h"
      29                 :            : 
      30                 :            : using namespace std;
      31                 :            : using namespace cvc5::internal::kind;
      32                 :            : 
      33                 :            : namespace cvc5::internal {
      34                 :            : namespace theory {
      35                 :            : namespace quantifiers {
      36                 :            : 
      37                 :        540 : InstStrategyMbqi::InstStrategyMbqi(Env& env,
      38                 :            :                                    QuantifiersState& qs,
      39                 :            :                                    QuantifiersInferenceManager& qim,
      40                 :            :                                    QuantifiersRegistry& qr,
      41                 :        540 :                                    TermRegistry& tr)
      42                 :        540 :     : QuantifiersModule(env, qs, qim, qr, tr), d_globalSyms(userContext())
      43                 :            : {
      44                 :            :   // some kinds may appear in model values that cannot be asserted
      45                 :            :   // if arraysExp is enabled, we allow STORE_ALL terms in assertions.
      46         [ +  - ]:        540 :   if (!options().arrays.arraysExp)
      47                 :            :   {
      48                 :        540 :     d_nonClosedKinds.insert(Kind::STORE_ALL);
      49                 :            :   }
      50                 :        540 :   d_nonClosedKinds.insert(Kind::CODATATYPE_BOUND_VARIABLE);
      51                 :        540 :   d_nonClosedKinds.insert(Kind::UNINTERPRETED_SORT_VALUE);
      52                 :            :   // may appear in certain models e.g. strings of excessive length
      53                 :        540 :   d_nonClosedKinds.insert(Kind::WITNESS);
      54                 :            : 
      55         [ +  + ]:        540 :   if (options().quantifiers.mbqiEnum)
      56                 :            :   {
      57                 :        353 :     d_msenum.reset(new MbqiEnum(env, *this));
      58                 :            :   }
      59                 :        540 :   d_subOptions.copyValues(options());
      60                 :        540 :   d_subOptions.write_quantifiers().instMaxRounds = 5;
      61                 :        540 :   smt::SetDefaults::disableChecking(d_subOptions);
      62                 :        540 : }
      63                 :            : 
      64                 :       1174 : void InstStrategyMbqi::ppNotifyAssertions(const std::vector<Node>& assertions)
      65                 :            : {
      66                 :            :   // collecting global symbols from all available assertions
      67                 :       1174 :   Skolemize* sk = d_qim.getSkolemize();
      68         [ +  + ]:       5244 :   for (const Node& a : assertions)
      69                 :            :   {
      70                 :       4070 :     std::unordered_set<Node> cur_syms;
      71                 :       4070 :     expr::getSymbols(a, cur_syms);
      72                 :            :     // Iterate over the symbols in the current assertion
      73         [ +  + ]:       9710 :     for (const Node& s : cur_syms)
      74                 :            :     {
      75                 :            :       // Add the symbol to syms if it's not already present
      76                 :       5640 :       d_globalSyms.insert(s);
      77                 :            :     }
      78         [ +  + ]:       4070 :     if (a.getKind() == Kind::FORALL)
      79                 :            :     {
      80                 :        416 :       continue;
      81                 :            :     }
      82                 :            :     // also consider skolems for (non-top-level) quantified formulas.
      83                 :       3654 :     std::unordered_set<Node> qs;
      84                 :       3654 :     expr::getSubtermsKind(Kind::FORALL, a, qs, false);
      85         [ +  + ]:       3910 :     for (const Node& q : qs)
      86                 :            :     {
      87                 :        256 :       std::vector<Node> ks = sk->getSkolemConstants(q);
      88         [ +  + ]:        722 :       for (const Node& s : ks)
      89                 :            :       {
      90                 :        466 :         d_globalSyms.insert(s);
      91                 :            :       }
      92                 :        256 :     }
      93         [ +  + ]:       4070 :   }
      94                 :       1174 : }
      95                 :            : 
      96                 :          0 : const context::CDHashSet<Node>& InstStrategyMbqi::getGlobalSyms() const
      97                 :            : {
      98                 :          0 :   return d_globalSyms;
      99                 :            : }
     100                 :            : 
     101                 :        874 : void InstStrategyMbqi::reset_round(CVC5_UNUSED Theory::Effort e)
     102                 :            : {
     103                 :        874 :   d_quantChecked.clear();
     104                 :        874 : }
     105                 :            : 
     106                 :       1276 : bool InstStrategyMbqi::needsCheck(Theory::Effort e)
     107                 :            : {
     108                 :       1276 :   return e >= Theory::EFFORT_LAST_CALL;
     109                 :            : }
     110                 :            : 
     111                 :        354 : QuantifiersModule::QEffort InstStrategyMbqi::needsModel(
     112                 :            :     CVC5_UNUSED Theory::Effort e)
     113                 :            : {
     114                 :        354 :   return QEFFORT_MODEL;
     115                 :            : }
     116                 :            : 
     117                 :        998 : void InstStrategyMbqi::check(Theory::Effort e, QEffort quant_e)
     118                 :            : {
     119 [ +  - ][ +  + ]:        998 :   if (e != Theory::EFFORT_LAST_CALL || quant_e != QEFFORT_MODEL)
     120                 :            :   {
     121                 :        717 :     return;
     122                 :            :   }
     123                 :        281 :   beginCallDebug();
     124                 :        281 :   FirstOrderModel* fm = d_treg.getModel();
     125         [ -  + ]:        281 :   if (TraceIsOn("mbqi-model-exp"))
     126                 :            :   {
     127                 :          0 :     eq::EqualityEngine* ee = fm->getEqualityEngine();
     128         [ -  - ]:          0 :     Trace("mbqi-model-exp") << "=== InstStrategyMbqi::check" << std::endl;
     129         [ -  - ]:          0 :     Trace("mbqi-model-exp") << "Ground model:" << std::endl;
     130                 :          0 :     Trace("mbqi-model-exp") << ee->debugPrintEqc() << std::endl;
     131         [ -  - ]:          0 :     Trace("mbqi-model-exp") << std::endl;
     132                 :            :   }
     133                 :            :   // see if the negation of each quantified formula is satisfiable in the model
     134                 :        281 :   std::vector<Node> disj;
     135                 :        281 :   std::vector<TNode> visit;
     136         [ +  + ]:        623 :   for (size_t i = 0, nquant = fm->getNumAssertedQuantifiers(); i < nquant; i++)
     137                 :            :   {
     138                 :        342 :     Node q = fm->getAssertedQuantifier(i);
     139         [ -  + ]:        342 :     if (!d_qreg.hasOwnership(q, this))
     140                 :            :     {
     141                 :          0 :       continue;
     142                 :            :     }
     143                 :        342 :     process(q);
     144         [ +  - ]:        342 :   }
     145         [ +  - ]:        562 :   Trace("mbqi-model-exp") << "=== InstStrategyMbqi::check finished"
     146                 :        281 :                           << std::endl;
     147                 :        281 :   endCallDebug();
     148                 :        281 : }
     149                 :            : 
     150                 :         41 : bool InstStrategyMbqi::checkCompleteFor(Node q)
     151                 :            : {
     152                 :         41 :   return d_quantChecked.find(q) != d_quantChecked.end();
     153                 :            : }
     154                 :            : 
     155                 :        342 : void InstStrategyMbqi::process(Node q)
     156                 :            : {
     157 [ -  + ][ -  + ]:        342 :   Assert(q.getKind() == Kind::FORALL);
                 [ -  - ]
     158         [ +  - ]:        342 :   Trace("mbqi-model-exp") << "* Process quantified formula: " << q << std::endl;
     159         [ +  - ]:        342 :   Trace("mbqi") << "Process quantified formula: " << q << std::endl;
     160                 :            :   // Cache mapping terms in the skolemized body of q to the form passed to
     161                 :            :   // the subsolver. This is local to this call.
     162                 :        342 :   std::unordered_map<Node, Node> tmpConvertMap;
     163                 :            :   // list of fresh variables per type
     164                 :        342 :   std::map<TypeNode, std::unordered_set<Node> > freshVarType;
     165                 :            :   // model values to the fresh variables
     166                 :        342 :   std::map<Node, Node> mvToFreshVar;
     167                 :            : 
     168                 :        342 :   NodeManager* nm = nodeManager();
     169                 :        342 :   const RepSet* rs = d_treg.getModel()->getRepSet();
     170                 :        342 :   FirstOrderModel* fm = d_treg.getModel();
     171                 :            : 
     172                 :            :   // allocate the skolem variables
     173                 :        342 :   Subs skolems;
     174         [ +  + ]:        813 :   for (const Node& v : q[0])
     175                 :            :   {
     176                 :        471 :     Node k = mkMbqiSkolem(v);
     177                 :        471 :     skolems.add(v, k);
     178                 :            :     // do not take its model value (which does not exist) in conversion below
     179                 :        471 :     tmpConvertMap[k] = k;
     180                 :        813 :   }
     181                 :            :   // compute the skolemization in a separate traversal instead of mapping
     182                 :            :   // bound variables to skolems. This is to ensure we avoid variable shadowing
     183                 :            :   // for model values for functions
     184                 :        342 :   Node skq = skolems.apply(q[1]);
     185                 :            :   // convert to query
     186                 :        342 :   Node cbody = convertToQuery(skq, tmpConvertMap, freshVarType);
     187         [ +  - ]:        342 :   Trace("mbqi") << "- converted body: " << cbody << std::endl;
     188                 :            : 
     189                 :            :   // check if there are any bad kinds
     190         [ +  + ]:        342 :   if (cbody.isNull())
     191                 :            :   {
     192         [ +  - ]:          4 :     Trace("mbqi-model-exp") << "...INTERNAL FAIL" << std::endl;
     193         [ +  - ]:          4 :     Trace("mbqi") << "...failed to convert to query" << std::endl;
     194                 :          4 :     return;
     195                 :            :   }
     196 [ -  + ][ -  + ]:        338 :   Assert(!expr::hasSubtermKinds(d_nonClosedKinds, cbody));
                 [ -  - ]
     197                 :            : 
     198                 :        338 :   std::vector<Node> constraints;
     199                 :            : 
     200                 :            :   // constraint: the negation of the skolemized body
     201                 :        676 :   Node bquery = rewrite(cbody.negate());
     202         [ +  + ]:        338 :   if (!bquery.isConst())
     203                 :            :   {
     204                 :            :     // if no nested check, don't assert the subquery if it contains quantifiers
     205                 :        891 :     if (options().quantifiers.mbqiNestedCheck
     206 [ -  + ][ -  - ]:        297 :         || !expr::hasSubtermKind(Kind::FORALL, bquery))
         [ -  + ][ +  - ]
                 [ -  - ]
     207                 :            :     {
     208                 :        297 :       constraints.push_back(bquery);
     209                 :            :     }
     210                 :            :   }
     211         [ +  + ]:         41 :   else if (!bquery.getConst<bool>())
     212                 :            :   {
     213                 :         39 :     d_quantChecked.insert(q);
     214         [ +  - ]:         39 :     Trace("mbqi-model-exp") << "...SUCCESS, by rewriting" << std::endl;
     215         [ +  - ]:         39 :     Trace("mbqi") << "...success, by rewriting" << std::endl;
     216                 :         39 :     return;
     217                 :            :   }
     218                 :            :   // ensure the entire domain of uninterpreted sorts are converted
     219                 :        299 :   std::unordered_set<TypeNode> processedUsort;
     220         [ +  + ]:        721 :   for (const Node& k : skolems.d_subs)
     221                 :            :   {
     222                 :        422 :     TypeNode tn = k.getType();
     223                 :        422 :     if (!tn.isUninterpretedSort()
     224 [ +  + ][ +  + ]:        422 :         || processedUsort.find(tn) != processedUsort.end())
                 [ +  + ]
     225                 :            :     {
     226                 :        369 :       continue;
     227                 :            :     }
     228                 :         53 :     processedUsort.insert(tn);
     229                 :         53 :     const std::vector<Node>* treps = rs->getTypeRepsOrNull(tn);
     230         [ +  + ]:         53 :     if (treps != nullptr)
     231                 :            :     {
     232         [ +  + ]:        229 :       for (const Node& r : *treps)
     233                 :            :       {
     234                 :        183 :         Node rv = fm->getValue(r);
     235 [ -  + ][ -  + ]:        183 :         Assert(rv.getKind() == Kind::UNINTERPRETED_SORT_VALUE);
                 [ -  - ]
     236                 :        183 :         convertToQuery(rv, tmpConvertMap, freshVarType);
     237                 :        183 :       }
     238                 :            :     }
     239         [ +  + ]:        422 :   }
     240                 :            :   // constraint: the skolems of the given type are equal to one of the variables
     241                 :            :   // introduced for uninterpreted sorts
     242                 :        299 :   std::map<TypeNode, std::unordered_set<Node> >::iterator itk;
     243         [ +  + ]:        721 :   for (const Node& k : skolems.d_subs)
     244                 :            :   {
     245                 :        422 :     TypeNode tn = k.getType();
     246         [ +  + ]:        422 :     if (!tn.isUninterpretedSort())
     247                 :            :     {
     248                 :            :       // not an uninterpreted sort, continue
     249                 :        341 :       continue;
     250                 :            :     }
     251                 :         81 :     itk = freshVarType.find(tn);
     252 [ +  - ][ -  + ]:         81 :     if (itk == freshVarType.end() || itk->second.empty())
                 [ -  + ]
     253                 :            :     {
     254         [ -  - ]:          0 :       Trace("mbqi") << "warning: failed to get vars for type " << tn
     255                 :          0 :                     << std::endl;
     256                 :            :       // this should never happen but we explicitly guard for it, since
     257                 :            :       // otherwise we would be model unsound below
     258                 :          0 :       DebugUnhandled();
     259                 :            :       continue;
     260                 :            :     }
     261                 :         81 :     std::vector<Node> disj;
     262         [ +  + ]:        411 :     for (const Node& fv : itk->second)
     263                 :            :     {
     264                 :        330 :       disj.push_back(k.eqNode(fv));
     265                 :            :     }
     266                 :         81 :     Node instCardCons = nm->mkOr(disj);
     267                 :         81 :     constraints.push_back(instCardCons);
     268         [ +  + ]:        422 :   }
     269                 :            : 
     270                 :            :   // constraint: distinctness of variables introduced for uninterpreted
     271                 :            :   // constants
     272                 :        299 :   std::vector<Node> allVars;
     273                 :        299 :   for (const std::pair<const TypeNode, std::unordered_set<Node> >& fv :
     274         [ +  + ]:        686 :        freshVarType)
     275                 :            :   {
     276 [ -  + ][ -  + ]:         88 :     Assert(!fv.second.empty());
                 [ -  - ]
     277                 :         88 :     allVars.insert(allVars.end(), fv.second.begin(), fv.second.end());
     278         [ +  + ]:         88 :     if (fv.second.size() > 1)
     279                 :            :     {
     280                 :         53 :       std::vector<Node> fvars(fv.second.begin(), fv.second.end());
     281                 :         53 :       constraints.push_back(nm->mkNode(Kind::DISTINCT, fvars));
     282                 :         53 :     }
     283                 :            :   }
     284                 :            : 
     285                 :            :   // make the query
     286                 :        299 :   Node query = nm->mkAnd(constraints);
     287                 :        299 :   query = extendedRewrite(query);
     288                 :            : 
     289                 :        299 :   std::unique_ptr<SolverEngine> mbqiChecker;
     290                 :        299 :   SubsolverSetupInfo ssi(d_env, d_subOptions);
     291                 :        299 :   initializeSubsolver(d_env.getNodeManager(), mbqiChecker, ssi);
     292                 :        299 :   mbqiChecker->setOption("produce-models", "true");
     293                 :            :   // set the time limit if applicable
     294         [ +  - ]:        299 :   if (options().quantifiers.mbqiCheckTimeout != 0)
     295                 :            :   {
     296                 :        299 :     mbqiChecker->setTimeLimit(options().quantifiers.mbqiCheckTimeout);
     297                 :            :   }
     298                 :        299 :   mbqiChecker->assertFormula(query);
     299         [ +  - ]:        299 :   Trace("mbqi") << "*** Check sat..." << std::endl;
     300                 :        598 :   Trace("mbqi") << "  query is : " << SkolemManager::getOriginalForm(query)
     301                 :        299 :                 << std::endl;
     302                 :        299 :   Result r = mbqiChecker->checkSat();
     303         [ +  - ]:        299 :   Trace("mbqi") << "  ...got : " << r << std::endl;
     304         [ +  + ]:        299 :   if (r.getStatus() == Result::UNSAT)
     305                 :            :   {
     306         [ +  - ]:         14 :     Trace("mbqi-model-exp") << "...SUCCESS" << std::endl;
     307                 :         14 :     d_quantChecked.insert(q);
     308         [ +  - ]:         14 :     Trace("mbqi") << "...success, SAT" << std::endl;
     309                 :         14 :     return;
     310                 :            :   }
     311         [ +  - ]:        285 :   Trace("mbqi-model-exp") << "...FAIL, will instantiate" << std::endl;
     312                 :            : 
     313                 :            :   // get the model values for all fresh variables
     314         [ +  + ]:        489 :   for (const Node& v : allVars)
     315                 :            :   {
     316                 :        204 :     Node mv = mbqiChecker->getValue(v);
     317                 :        204 :     mvToFreshVar[mv] = v;
     318         [ +  - ]:        204 :     Trace("mbqi-debug") << "mvToFreshVar " << mv << " is " << v << std::endl;
     319                 :        204 :   }
     320                 :            : 
     321                 :            :   // get the model values for skolems
     322                 :        285 :   std::vector<Node> vars = skolems.d_subs;
     323                 :        285 :   std::vector<Node> mvs;
     324                 :        285 :   getModelFromSubsolver(*mbqiChecker.get(), vars, mvs);
     325         [ -  + ]:        285 :   if (TraceIsOn("mbqi"))
     326                 :            :   {
     327         [ -  - ]:          0 :     Trace("mbqi") << "...model from subsolver is: " << std::endl;
     328         [ -  - ]:          0 :     for (size_t i = 0, nterms = skolems.size(); i < nterms; i++)
     329                 :            :     {
     330         [ -  - ]:          0 :       Trace("mbqi") << "  " << skolems.d_subs[i] << " -> " << mvs[i]
     331                 :          0 :                     << std::endl;
     332                 :            :     }
     333                 :            :   }
     334         [ +  + ]:        285 :   if (options().quantifiers.mbqiEnum)
     335                 :            :   {
     336                 :        204 :     std::vector<Node> smvs(mvs);
     337         [ +  + ]:        204 :     if (d_msenum->constructInstantiation(q, query, vars, smvs, mvToFreshVar))
     338                 :            :     {
     339         [ +  - ]:        197 :       Trace("mbqi-enum") << "Successfully added instantiation." << std::endl;
     340                 :        197 :       return;
     341                 :            :     }
     342         [ +  - ]:         14 :     Trace("mbqi-enum")
     343                 :          7 :         << "Failed to add instantiation, revert to normal MBQI..." << std::endl;
     344         [ +  + ]:        204 :   }
     345                 :         88 :   tryInstantiation(q, mvs, InferenceId::QUANTIFIERS_INST_MBQI, mvToFreshVar);
     346 [ +  + ][ +  + ]:       3772 : }
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
         [ +  + ][ +  + ]
     347                 :            : 
     348                 :        292 : bool InstStrategyMbqi::tryInstantiation(
     349                 :            :     const Node& q,
     350                 :            :     const std::vector<Node>& mvs,
     351                 :            :     InferenceId id,
     352                 :            :     const std::map<Node, Node>& mvToFreshVar)
     353                 :            : {
     354                 :        292 :   const RepSet* rs = d_treg.getModel()->getRepSet();
     355                 :        292 :   std::vector<Node> terms;
     356                 :            :   // try to convert those terms to an instantiation
     357                 :        292 :   std::unordered_map<Node, Node> tmpConvertMap;
     358         [ +  + ]:        693 :   for (const Node& v : mvs)
     359                 :            :   {
     360                 :        401 :     Node vc = convertFromModel(v, tmpConvertMap, mvToFreshVar);
     361         [ -  + ]:        401 :     if (vc.isNull())
     362                 :            :     {
     363         [ -  - ]:          0 :       Trace("mbqi") << "...failed to convert " << v << " from model" << std::endl;
     364                 :          0 :       return false;
     365                 :            :     }
     366         [ +  + ]:        401 :     if (expr::hasSubtermKinds(d_nonClosedKinds, vc))
     367                 :            :     {
     368         [ +  - ]:          8 :       Trace("mbqi") << "warning: failed to process model value " << vc
     369                 :          0 :                     << ", from " << v
     370                 :          4 :                     << ", use arbitrary term for instantiation" << std::endl;
     371                 :          4 :       vc = NodeManager::mkGroundTerm(v.getType());
     372                 :            :     }
     373                 :        401 :     terms.push_back(vc);
     374         [ +  - ]:        401 :   }
     375                 :            : 
     376                 :            :   // get a term that has the same model value as the value each fresh variable
     377                 :            :   // represents
     378                 :        292 :   NodeManager* nm = nodeManager();
     379                 :        292 :   SkolemManager* sm = nm->getSkolemManager();
     380                 :        292 :   Subs fvToInst;
     381         [ +  + ]:        503 :   for (const std::pair<const Node, Node>& mvf : mvToFreshVar)
     382                 :            :   {
     383                 :        211 :     Node v = mvf.second;
     384                 :            :     // get a term that witnesses this variable
     385                 :        211 :     Node ov = sm->getOriginalForm(v);
     386                 :        211 :     Node mvt = rs->getTermForRepresentative(ov);
     387                 :            :     // ensure that this term does not contain cex variables, in case CEQGI
     388                 :            :     // is combined with MBQI
     389                 :        211 :     if (mvt.isNull() || !TermUtil::getInstConstAttr(mvt).isNull())
     390                 :            :     {
     391         [ +  - ]:         36 :       Trace("mbqi") << "warning: failed to get term from value " << ov
     392                 :         18 :                     << ", use arbitrary term in query" << std::endl;
     393                 :         18 :       mvt = NodeManager::mkGroundTerm(ov.getType());
     394                 :            :     }
     395 [ -  + ][ -  + ]:        211 :     Assert(v.getType() == mvt.getType());
                 [ -  - ]
     396                 :        211 :     fvToInst.add(v, mvt);
     397                 :        211 :   }
     398                 :            : 
     399                 :            :   // now convert fresh variables into terms
     400         [ +  + ]:        693 :   for (Node& v : terms)
     401                 :            :   {
     402                 :        401 :     v = fvToInst.apply(v);
     403                 :            :   }
     404                 :            : 
     405                 :            :   // try to add instantiation
     406                 :        292 :   Instantiate* qinst = d_qim.getInstantiate();
     407         [ +  + ]:        292 :   if (!qinst->addInstantiation(q, terms, id))
     408                 :            :   {
     409                 :            :     // AlwaysAssert(false);
     410         [ +  - ]:         16 :     Trace("mbqi") << "...failed to add instantiation" << std::endl;
     411                 :         16 :     return false;
     412                 :            :   }
     413         [ +  - ]:        276 :   Trace("mbqi") << "...success, instantiated" << std::endl;
     414                 :        276 :   return true;
     415                 :        292 : }
     416                 :            : 
     417                 :       5492 : Node InstStrategyMbqi::convertToQuery(
     418                 :            :     Node t,
     419                 :            :     std::unordered_map<Node, Node>& cmap,
     420                 :            :     std::map<TypeNode, std::unordered_set<Node> >& freshVarType)
     421                 :            : {
     422                 :       5492 :   NodeManager* nm = nodeManager();
     423                 :       5492 :   SkolemManager* sm = nm->getSkolemManager();
     424                 :       5492 :   FirstOrderModel* fm = d_treg.getModel();
     425                 :       5492 :   std::unordered_map<Node, Node>::iterator it;
     426                 :       5492 :   std::map<Node, Node> modelValue;
     427                 :       5492 :   std::unordered_set<Node> processingChildren;
     428                 :       5492 :   std::vector<TNode> visit;
     429                 :       5492 :   visit.push_back(t);
     430                 :       5492 :   TNode cur;
     431                 :            :   do
     432                 :            :   {
     433                 :      67947 :     cur = visit.back();
     434                 :      67947 :     visit.pop_back();
     435                 :      67947 :     it = cmap.find(cur);
     436         [ +  - ]:     135894 :     Trace("mbqi-debug") << "convertToQuery: " << cur << " " << cur.getKind()
     437 [ -  + ][ -  - ]:      67947 :                         << " " << cur.getType() << std::endl;
     438         [ +  + ]:      67947 :     if (it != cmap.end())
     439                 :            :     {
     440                 :            :       // already computed
     441                 :      51885 :       continue;
     442                 :            :     }
     443         [ +  + ]:      58574 :     if (processingChildren.find(cur) == processingChildren.end())
     444                 :            :     {
     445                 :      42516 :       Kind ck = cur.getKind();
     446         [ +  + ]:      42516 :       if (ck == Kind::BOUND_VARIABLE)
     447                 :            :       {
     448                 :       1136 :         cmap[cur] = cur;
     449                 :            :       }
     450         [ +  + ]:      41368 :       else if (ck == Kind::CONST_SEQUENCE || ck == Kind::FUNCTION_ARRAY_CONST
     451 [ +  + ][ +  + ]:      82748 :                || cur.isVar())
                 [ +  + ]
     452                 :            :       {
     453                 :            :         // constant sequences and variables require two passes
     454         [ +  + ]:      15159 :         if (!cur.getType().isFirstClass())
     455                 :            :         {
     456                 :            :           // can be e.g. tester/constructor/selector
     457                 :        131 :           cmap[cur] = cur;
     458                 :            :         }
     459                 :            :         else
     460                 :            :         {
     461                 :      15028 :           std::map<Node, Node>::iterator itm = modelValue.find(cur);
     462         [ +  + ]:      15028 :           if (itm == modelValue.end())
     463                 :            :           {
     464                 :       7518 :             Node mval;
     465         [ +  + ]:       7518 :             if (ck == Kind::CONST_SEQUENCE)
     466                 :            :             {
     467                 :          8 :               mval = strings::utils::mkConcatForConstSequence(cur);
     468                 :            :             }
     469         [ +  + ]:       7510 :             else if (ck == Kind::FUNCTION_ARRAY_CONST)
     470                 :            :             {
     471                 :         14 :               mval = uf::FunctionConst::toLambda(cur);
     472                 :            :             }
     473                 :            :             else
     474                 :            :             {
     475                 :       7496 :               mval = fm->getValue(cur);
     476                 :            :             }
     477         [ +  - ]:       7518 :             Trace("mbqi-model") << "  M[" << cur << "] = " << mval << "\n";
     478                 :       7518 :             modelValue[cur] = mval;
     479         [ +  + ]:       7518 :             if (expr::hasSubterm(mval, cur))
     480                 :            :             {
     481                 :            :               // failed to evaluate in model, keep itself
     482                 :          4 :               cmap[cur] = cur;
     483                 :            :             }
     484                 :            :             else
     485                 :            :             {
     486                 :       7514 :               visit.push_back(cur);
     487                 :       7514 :               visit.push_back(mval);
     488                 :            :             }
     489                 :       7518 :           }
     490                 :            :           else
     491                 :            :           {
     492                 :       7510 :             Assert(cmap.find(itm->second) != cmap.end())
     493                 :          0 :                 << "Missing " << itm->second;
     494                 :       7510 :             cmap[cur] = cmap[itm->second];
     495                 :            :           }
     496                 :            :         }
     497                 :            :       }
     498         [ +  + ]:      26221 :       else if (d_nonClosedKinds.find(ck) != d_nonClosedKinds.end())
     499                 :            :       {
     500                 :            :         // if its a constant, we can continue, we will assume it is distinct
     501                 :            :         // from all others of its type
     502         [ +  + ]:        369 :         if (cur.isConst())
     503                 :            :         {
     504                 :            :           // return the fresh variable for this term
     505                 :        365 :           Node k = sm->mkPurifySkolem(cur);
     506                 :        365 :           freshVarType[cur.getType()].insert(k);
     507                 :        365 :           cmap[cur] = k;
     508                 :        365 :           continue;
     509                 :        365 :         }
     510                 :            :         // if this is a bad kind, fail immediately
     511                 :          8 :         return Node::null();
     512                 :            :       }
     513         [ +  + ]:      25852 :       else if (cur.getNumChildren() == 0)
     514                 :            :       {
     515                 :       9766 :         cmap[cur] = cur;
     516                 :            :       }
     517                 :            :       else
     518                 :            :       {
     519                 :      16086 :         processingChildren.insert(cur);
     520                 :      16086 :         visit.push_back(cur);
     521         [ +  + ]:      16086 :         if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
     522                 :            :         {
     523                 :       1949 :           visit.push_back(cur.getOperator());
     524                 :            :         }
     525                 :      16086 :         visit.insert(visit.end(), cur.begin(), cur.end());
     526                 :            :       }
     527                 :      42147 :       continue;
     528                 :      42147 :     }
     529                 :      16058 :     processingChildren.erase(cur);
     530                 :      16058 :     bool childChanged = false;
     531                 :      16058 :     std::vector<Node> children;
     532         [ +  + ]:      16058 :     if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
     533                 :            :     {
     534                 :       1949 :       children.push_back(cur.getOperator());
     535                 :            :     }
     536                 :      16058 :     children.insert(children.end(), cur.begin(), cur.end());
     537         [ +  + ]:      47387 :     for (Node& cn : children)
     538                 :            :     {
     539                 :      31329 :       it = cmap.find(cn);
     540 [ -  + ][ -  + ]:      31329 :       Assert(it != cmap.end());
                 [ -  - ]
     541 [ -  + ][ -  + ]:      31329 :       Assert(!it->second.isNull());
                 [ -  - ]
     542 [ +  + ][ +  + ]:      31329 :       childChanged = childChanged || cn != it->second;
     543                 :      31329 :       cn = it->second;
     544                 :            :     }
     545                 :      16058 :     Node ret = cur;
     546         [ +  + ]:      16058 :     if (childChanged)
     547                 :            :     {
     548                 :      12714 :       ret = rewrite(nm->mkNode(cur.getKind(), children));
     549                 :            :     }
     550                 :      16058 :     cmap[cur] = ret;
     551         [ +  + ]:      84001 :   } while (!visit.empty());
     552                 :            : 
     553 [ -  + ][ -  + ]:       5488 :   Assert(cmap.find(cur) != cmap.end());
                 [ -  - ]
     554                 :       5488 :   return cmap[cur];
     555                 :       5492 : }
     556                 :            : 
     557                 :        485 : Node InstStrategyMbqi::convertFromModel(
     558                 :            :     Node t,
     559                 :            :     std::unordered_map<Node, Node>& cmap,
     560                 :            :     const std::map<Node, Node>& mvToFreshVar)
     561                 :            : {
     562                 :        485 :   NodeManager* nm = nodeManager();
     563                 :        485 :   std::unordered_map<Node, Node>::iterator it;
     564                 :        485 :   std::map<Node, Node> modelValue;
     565                 :        485 :   std::unordered_set<Node> processingChildren;
     566                 :        485 :   std::vector<TNode> visit;
     567                 :        485 :   visit.push_back(t);
     568                 :        485 :   TNode cur;
     569                 :            :   do
     570                 :            :   {
     571                 :       2045 :     cur = visit.back();
     572                 :       2045 :     visit.pop_back();
     573                 :       2045 :     it = cmap.find(cur);
     574         [ +  - ]:       4090 :     Trace("mbqi-debug") << "convertFromModel: " << cur << " " << cur.getKind()
     575 [ -  + ][ -  - ]:       2045 :                         << " " << cur.getType() << std::endl;
     576         [ +  + ]:       2045 :     if (it != cmap.end())
     577                 :            :     {
     578                 :            :       // already computed
     579                 :       1511 :       continue;
     580                 :            :     }
     581         [ +  + ]:       1796 :     if (processingChildren.find(cur) == processingChildren.end())
     582                 :            :     {
     583                 :       1262 :       Kind ck = cur.getKind();
     584         [ +  + ]:       1262 :       if (ck == Kind::UNINTERPRETED_SORT_VALUE)
     585                 :            :       {
     586                 :            :         // converting from query, find the variable that it is equal to
     587                 :        158 :         std::map<Node, Node>::const_iterator itmv = mvToFreshVar.find(cur);
     588         [ +  + ]:        158 :         if (itmv != mvToFreshVar.end())
     589                 :            :         {
     590                 :        130 :           cmap[cur] = itmv->second;
     591                 :            :         }
     592                 :            :         else
     593                 :            :         {
     594                 :            :           // Just use the purification skolem if it does not exist. This
     595                 :            :           // can happen if our query involved parameteric types (e.g. functions,
     596                 :            :           // arrays) over uninterpreted sorts, where their models cannot be
     597                 :            :           // statically enforced to be in the finite domain.
     598                 :         28 :           SkolemManager* sm = nm->getSkolemManager();
     599                 :         28 :           cmap[cur] = sm->mkPurifySkolem(cur);
     600                 :            :         }
     601                 :        158 :         continue;
     602                 :        158 :       }
     603                 :            :       // must convert to concat of sequence units
     604                 :            :       // must convert function array constant to lambda
     605                 :       1104 :       Node cconv;
     606         [ -  + ]:       1104 :       if (ck == Kind::CONST_SEQUENCE)
     607                 :            :       {
     608                 :          0 :         cconv = strings::utils::mkConcatForConstSequence(cur);
     609                 :            :       }
     610         [ -  + ]:       1104 :       else if (ck == Kind::FUNCTION_ARRAY_CONST)
     611                 :            :       {
     612                 :          0 :         cconv = uf::FunctionConst::toLambda(cur);
     613                 :            :       }
     614                 :            :       // TODO (wishue #143): could convert RAN to witness term here
     615         [ -  + ]:       1104 :       if (!cconv.isNull())
     616                 :            :       {
     617                 :          0 :         Node cconvRet = convertFromModel(cconv, cmap, mvToFreshVar);
     618         [ -  - ]:          0 :         if (cconvRet.isNull())
     619                 :            :         {
     620                 :          0 :           return cconvRet;
     621                 :            :         }
     622                 :          0 :         cmap[cur] = cconvRet;
     623                 :          0 :         continue;
     624         [ -  - ]:          0 :       }
     625         [ +  + ]:       1104 :       else if (cur.getNumChildren() == 0)
     626                 :            :       {
     627                 :        570 :         cmap[cur] = cur;
     628                 :        570 :         continue;
     629                 :            :       }
     630                 :        534 :       processingChildren.insert(cur);
     631                 :        534 :       visit.push_back(cur);
     632         [ +  + ]:        534 :       if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
     633                 :            :       {
     634                 :         44 :         visit.push_back(cur.getOperator());
     635                 :            :       }
     636                 :        534 :       visit.insert(visit.end(), cur.begin(), cur.end());
     637                 :        534 :       continue;
     638         [ +  - ]:       1104 :     }
     639                 :        534 :     processingChildren.erase(cur);
     640                 :        534 :     bool childChanged = false;
     641                 :        534 :     std::vector<Node> children;
     642         [ +  + ]:        534 :     if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
     643                 :            :     {
     644                 :         44 :       children.push_back(cur.getOperator());
     645                 :            :     }
     646                 :        534 :     children.insert(children.end(), cur.begin(), cur.end());
     647         [ +  + ]:       1560 :     for (Node& cn : children)
     648                 :            :     {
     649                 :       1026 :       it = cmap.find(cn);
     650 [ -  + ][ -  + ]:       1026 :       Assert(it != cmap.end());
                 [ -  - ]
     651 [ -  + ][ -  + ]:       1026 :       Assert(!it->second.isNull());
                 [ -  - ]
     652 [ +  + ][ +  + ]:       1026 :       childChanged = childChanged || cn != it->second;
     653                 :       1026 :       cn = it->second;
     654                 :            :     }
     655                 :        534 :     Node ret = cur;
     656         [ +  + ]:        534 :     if (childChanged)
     657                 :            :     {
     658                 :         84 :       ret = rewrite(nm->mkNode(cur.getKind(), children));
     659                 :            :     }
     660                 :        534 :     cmap[cur] = ret;
     661         [ +  + ]:       2579 :   } while (!visit.empty());
     662                 :            : 
     663 [ -  + ][ -  + ]:        485 :   Assert(cmap.find(cur) != cmap.end());
                 [ -  - ]
     664                 :        485 :   return cmap[cur];
     665                 :        485 : }
     666                 :            : 
     667                 :        471 : Node InstStrategyMbqi::mkMbqiSkolem(const Node& t)
     668                 :            : {
     669                 :        471 :   SkolemManager* skm = nodeManager()->getSkolemManager();
     670                 :        471 :   return skm->mkInternalSkolemFunction(
     671                 :       1413 :       InternalSkolemId::MBQI_INPUT, t.getType(), {t});
     672                 :            : }
     673                 :            : 
     674                 :          0 : Result InstStrategyMbqi::checkWithSubsolverSimple(
     675                 :            :     Node query, const SubsolverSetupInfo& info)
     676                 :            : {
     677                 :          0 :   query = extendedRewrite(query);
     678                 :          0 :   if (!options().quantifiers.mbqiNestedCheck
     679                 :          0 :       && expr::hasSubtermKind(Kind::FORALL, query))
     680                 :            :   {
     681         [ -  - ]:          0 :     Trace("mbqi") << "*** SKIP " << query << std::endl;
     682                 :          0 :     return Result();
     683                 :            :   }
     684                 :            :   return checkWithSubsolver(query,
     685                 :            :                             info,
     686                 :          0 :                             options().quantifiers.mbqiCheckTimeout != 0,
     687                 :          0 :                             options().quantifiers.mbqiCheckTimeout);
     688                 :            : }
     689                 :            : 
     690                 :            : }  // namespace quantifiers
     691                 :            : }  // namespace theory
     692                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14