LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/quantifiers/ematching - trigger.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 108 128 84.4 %
Date: 2026-08-10 10:35:18 Functions: 10 12 83.3 %
Branches: 54 96 56.2 %

           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 trigger class.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include "theory/quantifiers/ematching/trigger.h"
      14                 :            : 
      15                 :            : #include "expr/skolem_manager.h"
      16                 :            : #include "options/base_options.h"
      17                 :            : #include "options/quantifiers_options.h"
      18                 :            : #include "smt/env.h"
      19                 :            : #include "theory/quantifiers/ematching/candidate_generator.h"
      20                 :            : #include "theory/quantifiers/ematching/inst_match_generator.h"
      21                 :            : #include "theory/quantifiers/ematching/inst_match_generator_multi.h"
      22                 :            : #include "theory/quantifiers/ematching/inst_match_generator_multi_linear.h"
      23                 :            : #include "theory/quantifiers/ematching/inst_match_generator_simple.h"
      24                 :            : #include "theory/quantifiers/ematching/pattern_term_selector.h"
      25                 :            : #include "theory/quantifiers/ematching/trigger_trie.h"
      26                 :            : #include "theory/quantifiers/inst_match.h"
      27                 :            : #include "theory/quantifiers/instantiate.h"
      28                 :            : #include "theory/quantifiers/quantifiers_attributes.h"
      29                 :            : #include "theory/quantifiers/quantifiers_inference_manager.h"
      30                 :            : #include "theory/quantifiers/quantifiers_registry.h"
      31                 :            : #include "theory/quantifiers/quantifiers_state.h"
      32                 :            : #include "theory/quantifiers/term_util.h"
      33                 :            : #include "theory/valuation.h"
      34                 :            : 
      35                 :            : using namespace cvc5::internal::kind;
      36                 :            : 
      37                 :            : namespace cvc5::internal {
      38                 :            : namespace theory {
      39                 :            : namespace quantifiers {
      40                 :            : namespace inst {
      41                 :            : 
      42                 :            : /** trigger class constructor */
      43                 :      37370 : Trigger::Trigger(Env& env,
      44                 :            :                  QuantifiersState& qs,
      45                 :            :                  QuantifiersInferenceManager& qim,
      46                 :            :                  QuantifiersRegistry& qr,
      47                 :            :                  TermRegistry& tr,
      48                 :            :                  Node q,
      49                 :            :                  std::vector<Node>& nodes,
      50                 :      37370 :                  bool isUser)
      51                 :            :     : EnvObj(env),
      52                 :      37370 :       d_qstate(qs),
      53                 :      37370 :       d_qim(qim),
      54                 :      37370 :       d_qreg(qr),
      55                 :      37370 :       d_treg(tr),
      56                 :      37370 :       d_quant(q),
      57                 :      74740 :       d_instMatch(env, qs, tr, q)
      58                 :            : {
      59                 :            :   // set evaluator mode to "no entail"
      60                 :      37370 :   d_instMatch.setEvaluatorMode(ieval::TermEvaluatorMode::NO_ENTAIL);
      61                 :            :   // We must ensure that the ground subterms of the trigger have been
      62                 :            :   // preprocessed.
      63                 :      37370 :   Valuation& val = d_qstate.getValuation();
      64         [ +  + ]:      78113 :   for (const Node& n : nodes)
      65                 :            :   {
      66                 :      40743 :     Node np = ensureGroundTermPreprocessed(val, n, d_groundTerms);
      67                 :      40743 :     d_nodes.push_back(np);
      68                 :      40743 :   }
      69         [ -  + ]:      37370 :   if (TraceIsOn("trigger"))
      70                 :            :   {
      71                 :          0 :     QuantAttributes& qa = d_qreg.getQuantAttributes();
      72                 :          0 :     Trace("trigger") << "Trigger for " << qa.quantToString(q) << ": "
      73                 :          0 :                      << std::endl;
      74         [ -  - ]:          0 :     for (const Node& n : d_nodes)
      75                 :            :     {
      76         [ -  - ]:          0 :       Trace("trigger") << "   " << n << std::endl;
      77                 :            :     }
      78                 :            :   }
      79                 :      37370 :   std::vector<Node> extNodes;
      80         [ +  + ]:      78113 :   for (const Node& nt : d_nodes)
      81                 :            :   {
      82                 :            :     // note we must display the original form, so we go back to bound vars
      83                 :      81486 :     Node ns = d_qreg.substituteInstConstantsToBoundVariables(nt, q);
      84                 :      40743 :     extNodes.push_back(ns);
      85                 :      40743 :   }
      86                 :      37370 :   d_trNode = nodeManager()->mkNode(Kind::SEXPR, extNodes);
      87         [ -  + ]:      37370 :   if (isOutputOn(OutputTag::TRIGGER))
      88                 :            :   {
      89         [ -  - ]:          0 :     output(OutputTag::TRIGGER) << (isUser ? "(user-trigger " : "(trigger ");
      90                 :          0 :     QuantAttributes& qa = d_qreg.getQuantAttributes();
      91                 :          0 :     output(OutputTag::TRIGGER) << qa.quantToString(q) << " " << d_trNode;
      92                 :            :   }
      93                 :      37370 :   QuantifiersStatistics& stats = qs.getStats();
      94         [ +  + ]:      37370 :   if (d_nodes.size() == 1)
      95                 :            :   {
      96         [ +  + ]:      34641 :     if (TriggerTermInfo::isSimpleTrigger(d_nodes[0]))
      97                 :            :     {
      98                 :      17432 :       d_mg = new InstMatchGeneratorSimple(env, this, q, d_nodes[0]);
      99                 :      17432 :       ++(stats.d_simple_triggers);
     100                 :      17432 :       output(OutputTag::TRIGGER) << " :simple";
     101                 :            :     }
     102                 :            :     else
     103                 :            :     {
     104                 :      17209 :       d_mg = InstMatchGenerator::mkInstMatchGenerator(env, this, q, d_nodes[0]);
     105                 :      17209 :       ++(stats.d_triggers);
     106                 :            :     }
     107                 :            :   }
     108                 :            :   else
     109                 :            :   {
     110         [ -  + ]:       2729 :     if (options().quantifiers.multiTriggerCache)
     111                 :            :     {
     112                 :          0 :       d_mg = new InstMatchGeneratorMulti(env, this, q, d_nodes);
     113                 :          0 :       output(OutputTag::TRIGGER) << " :multi-cache";
     114                 :            :     }
     115                 :            :     else
     116                 :            :     {
     117                 :       2729 :       d_mg =
     118                 :       2729 :           InstMatchGenerator::mkInstMatchGeneratorMulti(env, this, q, d_nodes);
     119                 :       2729 :       output(OutputTag::TRIGGER) << " :multi";
     120                 :            :     }
     121         [ -  + ]:       2729 :     if (TraceIsOn("multi-trigger"))
     122                 :            :     {
     123         [ -  - ]:          0 :       Trace("multi-trigger") << "Trigger for " << q << ": " << std::endl;
     124         [ -  - ]:          0 :       for (const Node& nc : d_nodes)
     125                 :            :       {
     126         [ -  - ]:          0 :         Trace("multi-trigger") << "   " << nc << std::endl;
     127                 :            :       }
     128                 :            :     }
     129                 :       2729 :     ++(stats.d_multi_triggers);
     130                 :            :   }
     131         [ -  + ]:      37370 :   if (isOutputOn(OutputTag::TRIGGER))
     132                 :            :   {
     133                 :          0 :     output(OutputTag::TRIGGER) << ")" << std::endl;
     134                 :            :   }
     135                 :            : 
     136         [ +  - ]:      37370 :   Trace("trigger-debug") << "Finished making trigger." << std::endl;
     137                 :      37370 : }
     138                 :            : 
     139         [ +  - ]:      74448 : Trigger::~Trigger() { delete d_mg; }
     140                 :            : 
     141                 :     325295 : void Trigger::resetInstantiationRound() { d_mg->resetInstantiationRound(); }
     142                 :            : 
     143                 :     325295 : void Trigger::reset(Node eqc) { d_mg->reset(eqc); }
     144                 :            : 
     145                 :      30943 : bool Trigger::isMultiTrigger() const { return d_nodes.size() > 1; }
     146                 :            : 
     147                 :          0 : Node Trigger::getInstPattern() const
     148                 :            : {
     149                 :          0 :   return nodeManager()->mkNode(Kind::INST_PATTERN, d_nodes);
     150                 :            : }
     151                 :            : 
     152                 :     108149 : uint64_t Trigger::addInstantiations()
     153                 :            : {
     154                 :     108149 :   uint64_t gtAddedLemmas = 0;
     155         [ +  + ]:     108149 :   if (!d_groundTerms.empty())
     156                 :            :   {
     157                 :            :     // for each ground term t that does not exist in the equality engine, we
     158                 :            :     // add a purification lemma of the form (k = t).
     159                 :       8083 :     eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
     160         [ +  + ]:      16480 :     for (const Node& gt : d_groundTerms)
     161                 :            :     {
     162                 :       8397 :       if (!ee->hasTerm(gt) && !gt.getType().isBoolean())
     163                 :            :       {
     164                 :       1009 :         Node k = SkolemManager::mkPurifySkolem(gt);
     165                 :       1009 :         Node eq = k.eqNode(gt);
     166         [ +  - ]:       2018 :         Trace("trigger-gt-lemma")
     167                 :       1009 :             << "Trigger: ground term purify lemma: " << eq << std::endl;
     168                 :       1009 :         d_qim.addPendingLemma(eq, InferenceId::QUANTIFIERS_GT_PURIFY);
     169                 :       1009 :         gtAddedLemmas++;
     170                 :       1009 :       }
     171                 :            :     }
     172                 :            :   }
     173                 :     108149 :   uint64_t addedLemmas = d_mg->addInstantiations(d_instMatch);
     174         [ -  + ]:     108149 :   if (TraceIsOn("inst-trigger"))
     175                 :            :   {
     176         [ -  - ]:          0 :     if (addedLemmas > 0)
     177                 :            :     {
     178         [ -  - ]:          0 :       Trace("inst-trigger") << "Added " << addedLemmas
     179                 :          0 :                             << " lemmas, trigger was " << d_nodes << std::endl;
     180                 :            :     }
     181                 :            :   }
     182                 :     108149 :   return gtAddedLemmas + addedLemmas;
     183                 :            : }
     184                 :            : 
     185                 :     144486 : bool Trigger::sendInstantiation(std::vector<Node>& m)
     186                 :            : {
     187                 :     144486 :   InferenceId id = d_mg->getInferenceId();
     188                 :     144486 :   return d_qim.getInstantiate()->addInstantiation(d_quant, m, id, d_trNode);
     189                 :            : }
     190                 :            : 
     191                 :          0 : int Trigger::getActiveScore() { return d_mg->getActiveScore(); }
     192                 :            : 
     193                 :      40743 : Node Trigger::ensureGroundTermPreprocessed(Valuation& val,
     194                 :            :                                            Node n,
     195                 :            :                                            std::vector<Node>& gts)
     196                 :            : {
     197                 :      40743 :   NodeManager* nm = n.getNodeManager();
     198                 :      40743 :   std::unordered_map<TNode, Node> visited;
     199                 :      40743 :   std::unordered_map<TNode, Node>::iterator it;
     200                 :      40743 :   std::vector<TNode> visit;
     201                 :      40743 :   TNode cur;
     202                 :      40743 :   visit.push_back(n);
     203                 :            :   do
     204                 :            :   {
     205                 :     329923 :     cur = visit.back();
     206                 :     329923 :     visit.pop_back();
     207                 :     329923 :     it = visited.find(cur);
     208         [ +  + ]:     329923 :     if (it == visited.end())
     209                 :            :     {
     210 [ +  + ][ +  + ]:     224677 :       if (cur.getNumChildren() == 0 || cur.getKind() == Kind::BOUND_VAR_LIST)
                 [ +  + ]
     211                 :            :       {
     212                 :     120811 :         visited[cur] = cur;
     213                 :            :       }
     214         [ +  + ]:     103866 :       else if (!TermUtil::hasInstConstAttr(cur))
     215                 :            :       {
     216                 :            :         // cur has no INST_CONSTANT, thus is ground.
     217                 :       3366 :         Node vcur = val.getPreprocessedTerm(cur);
     218                 :       3366 :         gts.push_back(vcur);
     219                 :       3366 :         visited[cur] = vcur;
     220                 :       3366 :       }
     221                 :            :       else
     222                 :            :       {
     223                 :     100500 :         visited[cur] = Node::null();
     224                 :     100500 :         visit.push_back(cur);
     225                 :     100500 :         visit.insert(visit.end(), cur.begin(), cur.end());
     226                 :            :       }
     227                 :            :     }
     228         [ +  + ]:     105246 :     else if (it->second.isNull())
     229                 :            :     {
     230                 :     100500 :       Node ret = cur;
     231                 :     100500 :       bool childChanged = false;
     232                 :     100500 :       std::vector<Node> children;
     233         [ +  + ]:     100500 :       if (cur.getMetaKind() == metakind::PARAMETERIZED)
     234                 :            :       {
     235                 :      82978 :         children.push_back(cur.getOperator());
     236                 :            :       }
     237         [ +  + ]:     289180 :       for (const Node& cn : cur)
     238                 :            :       {
     239                 :     188680 :         it = visited.find(cn);
     240 [ -  + ][ -  + ]:     188680 :         Assert(it != visited.end());
                 [ -  - ]
     241 [ -  + ][ -  + ]:     188680 :         Assert(!it->second.isNull());
                 [ -  - ]
     242 [ +  + ][ +  + ]:     188680 :         childChanged = childChanged || cn != it->second;
     243                 :     188680 :         children.push_back(it->second);
     244                 :     188680 :       }
     245         [ +  + ]:     100500 :       if (childChanged)
     246                 :            :       {
     247                 :        221 :         ret = nm->mkNode(cur.getKind(), children);
     248                 :            :       }
     249                 :     100500 :       visited[cur] = ret;
     250                 :     100500 :     }
     251         [ +  + ]:     329923 :   } while (!visit.empty());
     252 [ -  + ][ -  + ]:      40743 :   Assert(visited.find(n) != visited.end());
                 [ -  - ]
     253 [ -  + ][ -  + ]:      40743 :   Assert(!visited.find(n)->second.isNull());
                 [ -  - ]
     254                 :      81486 :   return visited[n];
     255                 :      40743 : }
     256                 :            : 
     257                 :      80454 : void Trigger::debugPrint(CVC5_UNUSED const char* c) const
     258                 :            : {
     259         [ +  - ]:      80454 :   Trace(c) << "TRIGGER( " << d_nodes << " )" << std::endl;
     260                 :      80454 : }
     261                 :            : 
     262                 :            : }  // namespace inst
     263                 :            : }  // namespace quantifiers
     264                 :            : }  // namespace theory
     265                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14