LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers/fmf - model_engine.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 150 210 71.4 %
Date: 2026-03-17 10:40:45 Functions: 13 15 86.7 %
Branches: 90 201 44.8 %

           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                 :            :  * Implementation of model engine class.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/quantifiers/fmf/model_engine.h"
      14                 :            : 
      15                 :            : #include "options/quantifiers_options.h"
      16                 :            : #include "theory/quantifiers/first_order_model.h"
      17                 :            : #include "theory/quantifiers/fmf/full_model_check.h"
      18                 :            : #include "theory/quantifiers/instantiate.h"
      19                 :            : #include "theory/quantifiers/quant_rep_bound_ext.h"
      20                 :            : #include "theory/quantifiers/quantifiers_attributes.h"
      21                 :            : #include "theory/quantifiers/term_database.h"
      22                 :            : #include "theory/rep_set_iterator.h"
      23                 :            : 
      24                 :            : using namespace cvc5::internal::kind;
      25                 :            : using namespace cvc5::context;
      26                 :            : 
      27                 :            : namespace cvc5::internal {
      28                 :            : namespace theory {
      29                 :            : namespace quantifiers {
      30                 :            : 
      31                 :            : //Model Engine constructor
      32                 :      32084 : ModelEngine::ModelEngine(Env& env,
      33                 :            :                          QuantifiersState& qs,
      34                 :            :                          QuantifiersInferenceManager& qim,
      35                 :            :                          QuantifiersRegistry& qr,
      36                 :            :                          TermRegistry& tr,
      37                 :      32084 :                          QModelBuilder* builder)
      38                 :            :     : QuantifiersModule(env, qs, qim, qr, tr),
      39                 :      32084 :       d_incomplete_check(true),
      40                 :      32084 :       d_addedLemmas(0),
      41                 :      32084 :       d_triedLemmas(0),
      42                 :      32084 :       d_totalLemmas(0),
      43                 :      32084 :       d_builder(builder)
      44                 :            : {
      45                 :            : 
      46                 :      32084 : }
      47                 :            : 
      48                 :      63610 : ModelEngine::~ModelEngine() {
      49                 :            : 
      50                 :      63610 : }
      51                 :            : 
      52                 :          0 : std::string ModelEngine::identify() const { return "fmf-inst"; }
      53                 :            : 
      54                 :      80728 : bool ModelEngine::needsCheck( Theory::Effort e ) {
      55                 :      80728 :   return e==Theory::EFFORT_LAST_CALL;
      56                 :            : }
      57                 :            : 
      58                 :       9734 : QuantifiersModule::QEffort ModelEngine::needsModel(CVC5_UNUSED Theory::Effort e)
      59                 :            : {
      60         [ -  + ]:       9734 :   if (options().quantifiers.mbqiInterleave)
      61                 :            :   {
      62                 :          0 :     return QEFFORT_STANDARD;
      63                 :            :   }
      64                 :            :   else
      65                 :            :   {
      66                 :       9734 :     return QEFFORT_MODEL;
      67                 :            :   }
      68                 :            : }
      69                 :            : 
      70                 :      36296 : void ModelEngine::reset_round(CVC5_UNUSED Theory::Effort e)
      71                 :            : {
      72                 :      36296 :   d_incomplete_check = true;
      73                 :      36296 : }
      74                 :      28143 : void ModelEngine::check(CVC5_UNUSED Theory::Effort e, QEffort quant_e)
      75                 :            : {
      76                 :      28143 :   bool doCheck = false;
      77         [ -  + ]:      28143 :   if (options().quantifiers.mbqiInterleave)
      78                 :            :   {
      79 [ -  - ][ -  - ]:          0 :     doCheck = quant_e == QEFFORT_STANDARD && d_qim.hasPendingLemma();
      80                 :            :   }
      81         [ +  - ]:      28143 :   if( !doCheck ){
      82                 :      28143 :     doCheck = quant_e == QEFFORT_MODEL;
      83                 :            :   }
      84         [ +  + ]:      28143 :   if( doCheck ){
      85 [ -  + ][ -  + ]:       6703 :     Assert(!d_qstate.isInConflict());
                 [ -  - ]
      86                 :       6703 :     int addedLemmas = 0;
      87                 :            : 
      88                 :            :     //the following will test that the model satisfies all asserted universal quantifiers by
      89                 :            :     // (model-based) exhaustive instantiation.
      90                 :       6703 :     beginCallDebug();
      91         [ +  - ]:       6703 :     Trace("model-engine-debug") << "Check model..." << std::endl;
      92                 :       6703 :     d_incomplete_check = false;
      93                 :            :     // print debug
      94         [ -  + ]:       6703 :     if (TraceIsOn("fmf-model-complete"))
      95                 :            :     {
      96         [ -  - ]:          0 :       Trace("fmf-model-complete") << std::endl;
      97                 :          0 :       debugPrint("fmf-model-complete");
      98                 :            :     }
      99                 :            :     // successfully built an acceptable model, now check it
     100                 :       6703 :     addedLemmas += checkModel();
     101                 :            : 
     102                 :       6703 :     endCallDebug();
     103                 :            : 
     104         [ +  + ]:       6703 :     if( addedLemmas==0 ){
     105         [ +  - ]:      10164 :       Trace("model-engine-debug")
     106                 :          0 :           << "No lemmas added, incomplete = "
     107 [ -  - ][ -  - ]:       5082 :           << (d_incomplete_check || !d_incompleteQuants.empty()) << std::endl;
     108                 :            :       // cvc5 will answer SAT or unknown
     109         [ -  + ]:       5082 :       if( TraceIsOn("fmf-consistent") ){
     110         [ -  - ]:          0 :         Trace("fmf-consistent") << std::endl;
     111                 :          0 :         debugPrint("fmf-consistent");
     112                 :            :       }
     113                 :            :     }
     114                 :            :   }
     115                 :      28143 : }
     116                 :            : 
     117                 :       2870 : bool ModelEngine::checkComplete(IncompleteId& incId)
     118                 :            : {
     119         [ -  + ]:       2870 :   if (d_incomplete_check)
     120                 :            :   {
     121                 :          0 :     incId = IncompleteId::QUANTIFIERS_FMF;
     122                 :          0 :     return false;
     123                 :            :   }
     124                 :       2870 :   return true;
     125                 :            : }
     126                 :            : 
     127                 :       1978 : bool ModelEngine::checkCompleteFor( Node q ) {
     128                 :       1978 :   return d_incompleteQuants.find(q) == d_incompleteQuants.end();
     129                 :            : }
     130                 :            : 
     131                 :      26039 : void ModelEngine::registerQuantifier( Node f ){
     132         [ -  + ]:      26039 :   if( TraceIsOn("fmf-warn") ){
     133                 :          0 :     bool canHandle = true;
     134         [ -  - ]:          0 :     for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
     135                 :          0 :       TypeNode tn = f[0][i].getType();
     136         [ -  - ]:          0 :       if (!tn.isUninterpretedSort())
     137                 :            :       {
     138         [ -  - ]:          0 :         if (!d_env.isFiniteType(tn))
     139                 :            :         {
     140         [ -  - ]:          0 :           if( tn.isInteger() ){
     141         [ -  - ]:          0 :             if (!options().quantifiers.fmfBound)
     142                 :            :             {
     143                 :          0 :               canHandle = false;
     144                 :            :             }
     145                 :            :           }else{
     146                 :          0 :             canHandle = false;
     147                 :            :           }
     148                 :            :         }
     149                 :            :       }
     150                 :          0 :     }
     151         [ -  - ]:          0 :     if( !canHandle ){
     152         [ -  - ]:          0 :       Trace("fmf-warn") << "Warning : Model Engine : may not be able to answer SAT because of formula : " << f << std::endl;
     153                 :            :     }
     154                 :            :   }
     155                 :      26039 : }
     156                 :            : 
     157                 :       6703 : int ModelEngine::checkModel(){
     158                 :       6703 :   FirstOrderModel* fm = d_treg.getModel();
     159                 :            : 
     160                 :            :   //for debugging, setup
     161                 :       6703 :   for (std::map<TypeNode, std::vector<Node> >::iterator it =
     162                 :       6703 :            fm->getRepSetPtr()->d_type_reps.begin();
     163         [ +  + ]:      33187 :        it != fm->getRepSetPtr()->d_type_reps.end();
     164                 :      26484 :        ++it)
     165                 :            :   {
     166         [ +  + ]:      26484 :     if (it->first.isUninterpretedSort())
     167                 :            :     {
     168         [ +  - ]:       6248 :       Trace("model-engine") << "Cardinality( " << it->first << " )"
     169                 :       3124 :                             << " = " << it->second.size() << std::endl;
     170         [ +  - ]:       3124 :       Trace("model-engine-debug") << "        Reps : ";
     171         [ +  + ]:      11342 :       for( size_t i=0; i<it->second.size(); i++ ){
     172         [ +  - ]:       8218 :         Trace("model-engine-debug") << it->second[i] << "  ";
     173                 :            :       }
     174         [ +  - ]:       3124 :       Trace("model-engine-debug") << std::endl;
     175         [ +  - ]:       3124 :       Trace("model-engine-debug") << "   Term reps : ";
     176         [ +  + ]:      11342 :       for( size_t i=0; i<it->second.size(); i++ ){
     177                 :      16436 :         Node r = fm->getInternalRepresentative(it->second[i], Node::null(), 0);
     178         [ -  + ]:       8218 :         if (r.isNull())
     179                 :            :         {
     180                 :            :           // there was an invalid equivalence class
     181                 :          0 :           d_incomplete_check = true;
     182                 :            :         }
     183         [ +  - ]:       8218 :         Trace("model-engine-debug") << r << " ";
     184                 :       8218 :       }
     185         [ +  - ]:       3124 :       Trace("model-engine-debug") << std::endl;
     186                 :       3124 :       Node mbt = fm->getModelBasisTerm(it->first);
     187         [ +  - ]:       3124 :       Trace("model-engine-debug") << "  Basis term : " << mbt << std::endl;
     188                 :       3124 :     }
     189                 :            :   }
     190                 :            : 
     191                 :       6703 :   d_triedLemmas = 0;
     192                 :       6703 :   d_addedLemmas = 0;
     193                 :       6703 :   d_totalLemmas = 0;
     194                 :            :   //for statistics
     195         [ -  + ]:       6703 :   if( TraceIsOn("model-engine") ){
     196         [ -  - ]:          0 :     for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
     197                 :          0 :       Node f = fm->getAssertedQuantifier( i );
     198                 :          0 :       if (fm->isQuantifierActive(f) && shouldProcess(f))
     199                 :            :       {
     200                 :          0 :         int totalInst = 1;
     201         [ -  - ]:          0 :         for( unsigned j=0; j<f[0].getNumChildren(); j++ ){
     202                 :          0 :           TypeNode tn = f[0][j].getType();
     203         [ -  - ]:          0 :           if (fm->getRepSet()->hasType(tn))
     204                 :            :           {
     205                 :          0 :             totalInst =
     206                 :          0 :                 totalInst * (int)fm->getRepSet()->getNumRepresentatives(tn);
     207                 :            :           }
     208                 :          0 :         }
     209                 :          0 :         d_totalLemmas += totalInst;
     210                 :            :       }
     211                 :          0 :     }
     212                 :            :   }
     213                 :            : 
     214         [ +  - ]:       6703 :   Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
     215                 :            :   // FMC uses two sub-effort levels
     216                 :       6703 :   options::FmfMbqiMode mode = options().quantifiers.fmfMbqiMode;
     217                 :       6703 :   int e_max = mode == options::FmfMbqiMode::FMC
     218         [ +  + ]:       6703 :                   ? 2
     219                 :       1013 :                   : (mode == options::FmfMbqiMode::TRUST ? 0 : 1);
     220         [ +  + ]:      16749 :   for( int e=0; e<e_max; e++) {
     221                 :      11667 :     d_incompleteQuants.clear();
     222         [ +  + ]:      38794 :     for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
     223                 :      27127 :       Node q = fm->getAssertedQuantifier( i, true );
     224         [ +  - ]:      27127 :       Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << q << ", effort = " << e << "..." << std::endl;
     225                 :            :       //determine if we should check this quantifier
     226         [ +  + ]:      27127 :       if (!fm->isQuantifierActive(q))
     227                 :            :       {
     228         [ +  - ]:        176 :         Trace("fmf-exh-inst") << "-> Inactive : " << q << std::endl;
     229                 :        176 :         continue;
     230                 :            :       }
     231         [ +  + ]:      26951 :       if (!shouldProcess(q))
     232                 :            :       {
     233         [ +  - ]:      12802 :         Trace("fmf-exh-inst") << "-> Not processed : " << q << std::endl;
     234                 :      12802 :         d_incompleteQuants.insert(q);
     235                 :      12802 :         continue;
     236                 :            :       }
     237                 :      14149 :       exhaustiveInstantiate(q, e);
     238         [ -  + ]:      14149 :       if (d_qstate.isInConflict())
     239                 :            :       {
     240                 :          0 :         break;
     241                 :            :       }
     242    [ +  + ][ - ]:      27127 :     }
     243         [ +  + ]:      11667 :     if( d_addedLemmas>0 ){
     244                 :       1621 :       break;
     245                 :            :     }else{
     246 [ -  + ][ -  + ]:      10046 :       Assert(!d_qstate.isInConflict());
                 [ -  - ]
     247                 :            :     }
     248                 :            :   }
     249                 :            : 
     250                 :            :   //print debug information
     251         [ -  + ]:       6703 :   if (d_qstate.isInConflict())
     252                 :            :   {
     253         [ -  - ]:          0 :     Trace("model-engine") << "Conflict, added lemmas = ";
     254                 :            :   }else{
     255         [ +  - ]:       6703 :     Trace("model-engine") << "Added Lemmas = ";
     256                 :            :   } 
     257         [ +  - ]:       6703 :   Trace("model-engine") << d_addedLemmas << " / " << d_triedLemmas << " / ";
     258         [ +  - ]:       6703 :   Trace("model-engine") << d_totalLemmas << std::endl;
     259                 :       6703 :   return d_addedLemmas;
     260                 :            : }
     261                 :            : 
     262                 :      14149 : void ModelEngine::exhaustiveInstantiate(Node q, int effort)
     263                 :            : {
     264                 :            :   //first check if the builder can do the exhaustive instantiation
     265                 :      14149 :   unsigned prev_alem = d_builder->getNumAddedLemmas();
     266                 :      14149 :   unsigned prev_tlem = d_builder->getNumTriedLemmas();
     267                 :      14149 :   FirstOrderModel* fm = d_treg.getModel();
     268                 :      14149 :   int retEi = d_builder->doExhaustiveInstantiation(fm, q, effort);
     269         [ +  + ]:      14149 :   if( retEi!=0 ){
     270         [ -  + ]:      13979 :     if( retEi<0 ){
     271         [ -  - ]:          0 :       Trace("fmf-exh-inst") << "-> Builder determined complete instantiation was impossible." << std::endl;
     272                 :          0 :       d_incompleteQuants.insert(q);
     273                 :            :     }else{
     274         [ +  - ]:      13979 :       Trace("fmf-exh-inst") << "-> Builder determined instantiation(s)." << std::endl;
     275                 :            :     }
     276                 :      13979 :     d_triedLemmas += d_builder->getNumTriedLemmas() - prev_tlem;
     277                 :      13979 :     d_addedLemmas += d_builder->getNumAddedLemmas() - prev_alem;
     278                 :            :   }else{
     279         [ -  + ]:        170 :     if( TraceIsOn("fmf-exh-inst-debug") ){
     280         [ -  - ]:          0 :       Trace("fmf-exh-inst-debug") << "   Instantiation Constants: ";
     281         [ -  - ]:          0 :       for (size_t i = 0, nchild = q[0].getNumChildren(); i < nchild; i++)
     282                 :            :       {
     283         [ -  - ]:          0 :         Trace("fmf-exh-inst-debug")
     284                 :          0 :             << d_qreg.getInstantiationConstant(q, i) << " ";
     285                 :            :       }
     286         [ -  - ]:          0 :       Trace("fmf-exh-inst-debug") << std::endl;
     287                 :            :     }
     288                 :        170 :     QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference();
     289                 :            :     //create a rep set iterator and iterate over the (relevant) domain of the quantifier
     290                 :        170 :     QRepBoundExt qrbe(d_env, qbi, d_qstate, d_treg, q);
     291                 :        170 :     RepSetIterator riter(fm->getRepSet(), &qrbe);
     292         [ +  - ]:        170 :     if (riter.setQuantifier(q))
     293                 :            :     {
     294         [ +  - ]:        170 :       Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
     295         [ +  + ]:        170 :       if( !riter.isIncomplete() ){
     296                 :         72 :         int triedLemmas = 0;
     297                 :         72 :         int addedLemmas = 0;
     298                 :         72 :         Instantiate* inst = d_qim.getInstantiate();
     299                 :         72 :         while (
     300                 :        278 :             !riter.isFinished()
     301 [ +  + ][ +  + ]:        278 :             && (addedLemmas == 0 || !options().quantifiers.fmfOneInstPerRound))
         [ +  - ][ +  + ]
     302                 :            :         {
     303                 :            :           // instantiation was not shown to be true, construct the term vector
     304                 :        206 :           std::vector<Node> terms;
     305                 :        206 :           riter.getCurrentTerms(terms);
     306         [ +  - ]:        412 :           Trace("fmf-model-eval")
     307                 :        206 :               << "* Add instantiation " << terms << std::endl;
     308                 :        206 :           triedLemmas++;
     309                 :            :           //add as instantiation
     310                 :        206 :           inst->processInstantiationRep(q, terms);
     311                 :        206 :           if (inst->addInstantiation(q,
     312                 :            :                                      terms,
     313                 :            :                                      InferenceId::QUANTIFIERS_INST_FMF_EXH,
     314         [ +  + ]:        412 :                                      Node::null()))
     315                 :            :           {
     316                 :        172 :             addedLemmas++;
     317         [ -  + ]:        172 :             if (d_qstate.isInConflict())
     318                 :            :             {
     319                 :          0 :               break;
     320                 :            :             }
     321                 :            :           }else{
     322         [ +  - ]:         68 :             Trace("fmf-model-eval")
     323                 :         34 :                 << "* Failed Add instantiation " << terms << std::endl;
     324                 :            :           }
     325                 :        206 :           riter.increment();
     326         [ +  - ]:        206 :         }
     327                 :         72 :         d_addedLemmas += addedLemmas;
     328                 :         72 :         d_triedLemmas += triedLemmas;
     329                 :            :       }
     330                 :            :     }
     331                 :            :     else
     332                 :            :     {
     333         [ -  - ]:          0 :       Trace("fmf-exh-inst") << "...exhaustive instantiation did set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
     334                 :            :     }
     335                 :            :     //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
     336         [ +  + ]:        170 :     if (riter.isIncomplete())
     337                 :            :     {
     338                 :        106 :       d_incompleteQuants.insert(q);
     339                 :            :     }
     340                 :        170 :   }
     341                 :      14149 : }
     342                 :            : 
     343                 :          0 : void ModelEngine::debugPrint( const char* c ){
     344         [ -  - ]:          0 :   if (TraceIsOn(c))
     345                 :            :   {
     346         [ -  - ]:          0 :     Trace(c) << "Quantifiers: " << std::endl;
     347                 :          0 :     FirstOrderModel* m = d_treg.getModel();
     348         [ -  - ]:          0 :     for (size_t i = 0, nquant = m->getNumAssertedQuantifiers(); i < nquant; i++)
     349                 :            :     {
     350                 :          0 :       Node q = m->getAssertedQuantifier(i);
     351         [ -  - ]:          0 :       if (d_qreg.hasOwnership(q, this))
     352                 :            :       {
     353         [ -  - ]:          0 :         Trace(c) << "   ";
     354         [ -  - ]:          0 :         if (!m->isQuantifierActive(q))
     355                 :            :         {
     356         [ -  - ]:          0 :           Trace(c) << "*Inactive* ";
     357                 :            :         }
     358                 :            :         else
     359                 :            :         {
     360         [ -  - ]:          0 :           Trace(c) << "           ";
     361                 :            :         }
     362         [ -  - ]:          0 :         Trace(c) << q << std::endl;
     363                 :            :       }
     364                 :          0 :     }
     365                 :            :   }
     366                 :          0 : }
     367                 :            : 
     368                 :      26951 : bool ModelEngine::shouldProcess(Node q)
     369                 :            : {
     370         [ +  + ]:      26951 :   if (!d_qreg.hasOwnership(q, this))
     371                 :            :   {
     372                 :            :     // if we don't have ownership, another module has taken responsibility
     373                 :            :     // for processing q.
     374                 :       7881 :     return false;
     375                 :            :   }
     376                 :            :   // if finite model finding or fmf bound is on, we process everything
     377 [ +  + ][ +  + ]:      19070 :   if (options().quantifiers.finiteModelFind || options().quantifiers.fmfBound)
                 [ +  + ]
     378                 :            :   {
     379                 :      11824 :     return true;
     380                 :            :   }
     381                 :            :   // otherwise, we are only using model-based instantiation for internally
     382                 :            :   // generated bounded quantified formulas
     383                 :       7246 :   QuantAttributes& qattr = d_qreg.getQuantAttributes();
     384                 :       7246 :   return qattr.isQuantBounded(q);
     385                 :            : }
     386                 :            : 
     387                 :            : }  // namespace quantifiers
     388                 :            : }  // namespace theory
     389                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14