GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp Lines: 268 356 75.3 %
Date: 2021-09-10 Branches: 482 1309 36.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Morgan Deters, Mathias Preiner
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * Implementation of e matching instantiation strategies.
14
 */
15
16
#include "theory/quantifiers/ematching/inst_strategy_e_matching.h"
17
18
#include "options/base_options.h"
19
#include "options/outputc.h"
20
#include "theory/quantifiers/ematching/pattern_term_selector.h"
21
#include "theory/quantifiers/ematching/trigger_database.h"
22
#include "theory/quantifiers/quant_relevance.h"
23
#include "theory/quantifiers/quantifiers_inference_manager.h"
24
#include "theory/quantifiers/quantifiers_registry.h"
25
#include "theory/quantifiers/quantifiers_state.h"
26
#include "util/random.h"
27
28
using namespace cvc5::kind;
29
using namespace cvc5::theory::quantifiers::inst;
30
31
namespace cvc5 {
32
namespace theory {
33
namespace quantifiers {
34
35
//priority levels :
36
//1 : user patterns (when user-pat!={resort,ignore}), auto-gen patterns (for non-user pattern quantifiers, or when user-pat={resort,ignore})
37
//2 : user patterns (when user-pat=resort), auto gen patterns (for user pattern quantifiers when user-pat=use)
38
39
// user-pat=interleave alternates between use and resort
40
41
6296
struct sortQuantifiersForSymbol {
42
  QuantRelevance* d_quant_rel;
43
  std::map< Node, Node > d_op_map;
44
596
  bool operator() (Node i, Node j) {
45
596
    size_t nqfsi = d_quant_rel->getNumQuantifiersForSymbol(d_op_map[i]);
46
596
    size_t nqfsj = d_quant_rel->getNumQuantifiersForSymbol(d_op_map[j]);
47
596
    if( nqfsi<nqfsj ){
48
      return true;
49
596
    }else if( nqfsi>nqfsj ){
50
      return false;
51
    }
52
596
    return false;
53
  }
54
};
55
56
struct sortTriggers {
57
5279
  bool operator() (Node i, Node j) {
58
5279
    int32_t wi = TriggerTermInfo::getTriggerWeight(i);
59
5279
    int32_t wj = TriggerTermInfo::getTriggerWeight(j);
60
5279
    if( wi==wj ){
61
4369
      return i<j;
62
    }
63
910
    return wi < wj;
64
  }
65
};
66
67
6560
InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers(
68
    inst::TriggerDatabase& td,
69
    QuantifiersState& qs,
70
    QuantifiersInferenceManager& qim,
71
    QuantifiersRegistry& qr,
72
    TermRegistry& tr,
73
6560
    QuantRelevance* qrlv)
74
6560
    : InstStrategy(td, qs, qim, qr, tr), d_quant_rel(qrlv)
75
{
76
  //how to select trigger terms
77
6560
  d_tr_strategy = options::triggerSelMode();
78
  //whether to select new triggers during the search
79
6560
  if( options::incrementTriggers() ){
80
6560
    d_regenerate_frequency = 3;
81
6560
    d_regenerate = true;
82
  }else{
83
    d_regenerate_frequency = 1;
84
    d_regenerate = false;
85
  }
86
6560
}
87
88
23880
void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){
89
23880
  Trace("inst-alg-debug") << "reset auto-gen triggers" << std::endl;
90
  //reset triggers
91
71640
  for( unsigned r=0; r<2; r++ ){
92
47760
    std::map<Node, std::map<inst::Trigger*, bool> >& agts =
93
        d_auto_gen_trigger[r];
94
166900
    for (std::pair<const Node, std::map<inst::Trigger*, bool> >& agt : agts)
95
    {
96
195470
      for (std::map<inst::Trigger*, bool>::iterator it = agt.second.begin();
97
195470
           it != agt.second.end();
98
           ++it)
99
      {
100
76330
        it->first->resetInstantiationRound();
101
76330
        it->first->reset(Node::null());
102
      }
103
    }
104
  }
105
23880
  d_processed_trigger.clear();
106
23880
  Trace("inst-alg-debug") << "done reset auto-gen triggers" << std::endl;
107
23880
}
108
109
83862
InstStrategyStatus InstStrategyAutoGenTriggers::process(Node f,
110
                                                        Theory::Effort effort,
111
                                                        int e)
112
{
113
83862
  options::UserPatMode upMode = getInstUserPatMode();
114
  // we don't auto-generate triggers if the mode is trust or strict
115
251586
  if (hasUserPatterns(f)
116
278494
      && (upMode == options::UserPatMode::TRUST
117
          || upMode == options::UserPatMode::STRICT))
118
  {
119
26908
    return InstStrategyStatus::STATUS_UNKNOWN;
120
  }
121
170862
  int peffort = (hasUserPatterns(f) && upMode != options::UserPatMode::IGNORE
122
                 && upMode != options::UserPatMode::RESORT)
123
170862
                    ? 2
124
56954
                    : 1;
125
56954
  if (e < peffort)
126
  {
127
28477
    return InstStrategyStatus::STATUS_UNFINISHED;
128
  }
129
28477
  Trace("inst-alg") << "-> Auto-gen instantiate " << f << "..." << std::endl;
130
28477
  bool gen = false;
131
28477
  if (e == peffort)
132
  {
133
28477
    if (d_counter.find(f) == d_counter.end())
134
    {
135
10646
      d_counter[f] = 0;
136
10646
      gen = true;
137
    }else{
138
17831
      d_counter[f]++;
139
17831
      gen = d_regenerate && d_counter[f] % d_regenerate_frequency == 0;
140
    }
141
  }
142
  else
143
  {
144
    gen = true;
145
  }
146
28477
  if (gen)
147
  {
148
13727
    generateTriggers(f);
149
38100
    if (d_counter[f] == 0 && d_auto_gen_trigger[0][f].empty()
150
29465
        && d_auto_gen_trigger[1][f].empty() && !QuantAttributes::hasPattern(f))
151
    {
152
998
      Trace("trigger-warn") << "Could not find trigger for " << f << std::endl;
153
1996
      Output(options::OutputTag::TRIGGER)
154
998
          << "(no-trigger " << f << ")" << std::endl;
155
    }
156
  }
157
28477
  if (options::triggerActiveSelMode() != options::TriggerActiveSelMode::ALL)
158
  {
159
    int max_score = -1;
160
    Trigger* max_trigger = nullptr;
161
    std::map<Trigger*, bool>& agt = d_auto_gen_trigger[0][f];
162
    for (std::map<Trigger*, bool>::iterator it = agt.begin(); it != agt.end();
163
         ++it)
164
    {
165
      Trigger* t = it->first;
166
      int score = t->getActiveScore();
167
      if (options::triggerActiveSelMode() == options::TriggerActiveSelMode::MIN)
168
      {
169
        if (score >= 0 && (score < max_score || max_score < 0))
170
        {
171
          max_score = score;
172
          max_trigger = t;
173
        }
174
      }
175
      else
176
      {
177
        if (score > max_score)
178
        {
179
          max_score = score;
180
          max_trigger = t;
181
        }
182
      }
183
      agt[t] = false;
184
    }
185
    if (max_trigger != nullptr)
186
    {
187
      agt[max_trigger] = true;
188
    }
189
  }
190
191
28477
  bool hasInst = false;
192
85431
  for (unsigned r = 0; r < 2; r++)
193
  {
194
56954
    std::map<Trigger*, bool>& agt = d_auto_gen_trigger[r][f];
195
92150
    for (std::map<Trigger*, bool>::iterator it = agt.begin(); it != agt.end();
196
         ++it)
197
    {
198
35196
      Trigger* tr = it->first;
199
35196
      if (tr == nullptr || !it->second)
200
      {
201
        // trigger is null or currently disabled
202
364
        continue;
203
      }
204
35014
      if (d_processed_trigger[f].find(tr) != d_processed_trigger[f].end())
205
      {
206
        // trigger is already processed this round
207
        continue;
208
      }
209
35014
      d_processed_trigger[f][tr] = true;
210
35014
      Trace("process-trigger") << "  Process ";
211
35014
      tr->debugPrint("process-trigger");
212
35014
      Trace("process-trigger") << "..." << std::endl;
213
35014
      unsigned numInst = tr->addInstantiations();
214
35014
      hasInst = numInst > 0 || hasInst;
215
70028
      Trace("process-trigger")
216
35014
          << "  Done, numInst = " << numInst << "." << std::endl;
217
35014
      if (d_qstate.isInConflict())
218
      {
219
        break;
220
      }
221
    }
222
56954
    if (d_qstate.isInConflict() || (hasInst && options::multiTriggerPriority()))
223
    {
224
      break;
225
    }
226
  }
227
28477
  return InstStrategyStatus::STATUS_UNKNOWN;
228
}
229
230
13727
void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
231
13727
  Trace("auto-gen-trigger-debug") << "Generate triggers for " << f << ", #var=" << f[0].getNumChildren() << "..." << std::endl;
232
233
  // first, generate the set of pattern terms
234
13727
  if (!generatePatternTerms(f))
235
  {
236
200
    Trace("auto-gen-trigger-debug")
237
100
        << "...failed to generate pattern terms" << std::endl;
238
100
    return;
239
  }
240
241
  // then, group them to make triggers
242
13627
  unsigned rmin = d_patTerms[0][f].empty() ? 1 : 0;
243
13627
  unsigned rmax = options::multiTriggerWhenSingle() ? 1 : rmin;
244
27254
  for (unsigned r = rmin; r <= rmax; r++)
245
  {
246
22262
    std::vector<Node> patTerms;
247
13627
    std::vector<Node>& ptc = d_patTerms[r][f];
248
34669
    for (const Node& p : ptc)
249
    {
250
21042
      if (r == 1 || d_single_trigger_gen.find(p) == d_single_trigger_gen.end())
251
      {
252
17658
        patTerms.push_back(p);
253
      }
254
    }
255
13627
    if (patTerms.empty())
256
    {
257
3843
      continue;
258
    }
259
9784
    Trace("auto-gen-trigger") << "Generate trigger for " << f << std::endl;
260
    // sort terms based on relevance
261
9784
    if (options::relevantTriggers())
262
    {
263
319
      Assert(d_quant_rel);
264
638
      sortQuantifiersForSymbol sqfs;
265
319
      sqfs.d_quant_rel = d_quant_rel;
266
936
      for (const Node& p : patTerms)
267
      {
268
617
        Assert(d_pat_to_mpat.find(p) != d_pat_to_mpat.end());
269
617
        Assert(d_pat_to_mpat[p].hasOperator());
270
617
        sqfs.d_op_map[p] = d_pat_to_mpat[p].getOperator();
271
      }
272
      // sort based on # occurrences (this will cause Trigger to select rarer
273
      // symbols)
274
319
      std::sort(patTerms.begin(), patTerms.end(), sqfs);
275
319
      if (Debug.isOn("relevant-trigger"))
276
      {
277
        Debug("relevant-trigger") << "Terms based on relevance: " << std::endl;
278
        for (const Node& p : patTerms)
279
        {
280
          Debug("relevant-trigger")
281
              << "   " << p << " from " << d_pat_to_mpat[p] << " (";
282
          Debug("relevant-trigger") << d_quant_rel->getNumQuantifiersForSymbol(
283
                                           d_pat_to_mpat[p].getOperator())
284
                                    << ")" << std::endl;
285
        }
286
      }
287
    }
288
    // now, generate the trigger...
289
9784
    Trigger* tr = NULL;
290
9784
    if (d_is_single_trigger[patTerms[0]])
291
    {
292
25905
      tr = d_td.mkTrigger(f,
293
8635
                          patTerms[0],
294
                          false,
295
                          TriggerDatabase::TR_RETURN_NULL,
296
8635
                          d_num_trigger_vars[f]);
297
8635
      d_single_trigger_gen[patTerms[0]] = true;
298
    }
299
    else
300
    {
301
      // only generate multi trigger if option set, or if no single triggers
302
      // exist
303
1149
      if (!d_patTerms[0][f].empty())
304
      {
305
        if (options::multiTriggerWhenSingle())
306
        {
307
          Trace("multi-trigger-debug")
308
              << "Resort to choosing multi-triggers..." << std::endl;
309
        }
310
        else
311
        {
312
          return;
313
        }
314
      }
315
      // if we are re-generating triggers, shuffle based on some method
316
1149
      if (d_made_multi_trigger[f])
317
      {
318
136
        std::shuffle(patTerms.begin(),
319
                     patTerms.end(),
320
                     Random::getRandom());  // shuffle randomly
321
      }
322
      else
323
      {
324
1013
        d_made_multi_trigger[f] = true;
325
      }
326
      // will possibly want to get an old trigger
327
2298
      tr = d_td.mkTrigger(f,
328
                          patTerms,
329
                          false,
330
                          TriggerDatabase::TR_GET_OLD,
331
1149
                          d_num_trigger_vars[f]);
332
    }
333
9784
    if (tr == nullptr)
334
    {
335
      // did not generate a trigger
336
      continue;
337
    }
338
9784
    addTrigger(tr, f);
339
9784
    if (tr->isMultiTrigger())
340
    {
341
      // only add a single multi-trigger
342
1149
      continue;
343
    }
344
    // if we are generating additional triggers...
345
8635
    size_t index = 0;
346
8635
    if (index < patTerms.size())
347
    {
348
      // check if similar patterns exist, and if so, add them additionally
349
8635
      unsigned nqfs_curr = 0;
350
8635
      if (options::relevantTriggers())
351
      {
352
250
        nqfs_curr =
353
500
            d_quant_rel->getNumQuantifiersForSymbol(patTerms[0].getOperator());
354
      }
355
8635
      index++;
356
8635
      bool success = true;
357
15605
      while (success && index < patTerms.size()
358
15605
             && d_is_single_trigger[patTerms[index]])
359
      {
360
3485
        success = false;
361
6970
        if (!options::relevantTriggers()
362
6990
            || d_quant_rel->getNumQuantifiersForSymbol(
363
3495
                   patTerms[index].getOperator())
364
10
                   <= nqfs_curr)
365
        {
366
3485
          d_single_trigger_gen[patTerms[index]] = true;
367
13940
          Trigger* tr2 = d_td.mkTrigger(f,
368
3485
                                        patTerms[index],
369
                                        false,
370
                                        TriggerDatabase::TR_RETURN_NULL,
371
6970
                                        d_num_trigger_vars[f]);
372
3485
          addTrigger(tr2, f);
373
3485
          success = true;
374
        }
375
3485
        index++;
376
      }
377
    }
378
  }
379
}
380
381
13727
bool InstStrategyAutoGenTriggers::generatePatternTerms(Node f)
382
{
383
13727
  if (d_patTerms[0].find(f) != d_patTerms[0].end())
384
  {
385
    // already generated
386
3081
    return true;
387
  }
388
  // determine all possible pattern terms based on trigger term selection
389
  // strategy d_tr_strategy
390
10646
  d_patTerms[0][f].clear();
391
10646
  d_patTerms[1][f].clear();
392
10646
  bool ntrivTriggers = options::relationalTriggers();
393
21292
  std::vector<Node> patTermsF;
394
21292
  std::map<Node, inst::TriggerTermInfo> tinfo;
395
10646
  NodeManager* nm = NodeManager::currentNM();
396
  // well-defined function: can assume LHS is only pattern
397
10646
  if (options::quantFunWellDefined())
398
  {
399
    Node hd = QuantAttributes::getFunDefHead(f);
400
    if (!hd.isNull())
401
    {
402
      hd = d_qreg.substituteBoundVariablesToInstConstants(hd, f);
403
      patTermsF.push_back(hd);
404
      tinfo[hd].init(f, hd);
405
    }
406
  }
407
  // otherwise, use algorithm for collecting pattern terms
408
10646
  if (patTermsF.empty())
409
  {
410
21292
    Node bd = d_qreg.getInstConstantBody(f);
411
21292
    PatternTermSelector pts(f, d_tr_strategy, d_user_no_gen[f], true);
412
10646
    pts.collect(bd, patTermsF, tinfo);
413
10646
    if (ntrivTriggers)
414
    {
415
      sortTriggers st;
416
1174
      std::sort(patTermsF.begin(), patTermsF.end(), st);
417
    }
418
10646
    if (Trace.isOn("auto-gen-trigger-debug"))
419
    {
420
      Trace("auto-gen-trigger-debug")
421
          << "Collected pat terms for " << bd
422
          << ", no-patterns : " << d_user_no_gen[f].size() << std::endl;
423
      for (const Node& p : patTermsF)
424
      {
425
        Assert(tinfo.find(p) != tinfo.end());
426
        Trace("auto-gen-trigger-debug") << "   " << p << std::endl;
427
        Trace("auto-gen-trigger-debug2")
428
            << "     info = [" << tinfo[p].d_reqPol << ", "
429
            << tinfo[p].d_reqPolEq << ", " << tinfo[p].d_fv.size() << "]"
430
            << std::endl;
431
      }
432
      Trace("auto-gen-trigger-debug") << std::endl;
433
    }
434
  }
435
  // sort into single/multi triggers, calculate which terms should not be
436
  // considered
437
21292
  std::map<Node, bool> vcMap;
438
21292
  std::map<Node, bool> rmPatTermsF;
439
10646
  int32_t last_weight = -1;
440
48446
  for (const Node& p : patTermsF)
441
  {
442
37800
    Assert(p.getKind() != NOT);
443
37800
    bool newVar = false;
444
37800
    inst::TriggerTermInfo& tip = tinfo[p];
445
132446
    for (const Node& v : tip.d_fv)
446
    {
447
94646
      if (vcMap.find(v) == vcMap.end())
448
      {
449
27482
        vcMap[v] = true;
450
27482
        newVar = true;
451
      }
452
    }
453
37800
    int32_t curr_w = TriggerTermInfo::getTriggerWeight(p);
454
    // triggers whose value is maximum (2) are considered expendable.
455
37800
    if (ntrivTriggers && !newVar && last_weight != -1 && curr_w > last_weight
456
472
        && curr_w >= 2)
457
    {
458
944
      Trace("auto-gen-trigger-debug")
459
472
          << "...exclude expendible non-trivial trigger : " << p << std::endl;
460
472
      rmPatTermsF[p] = true;
461
    }
462
    else
463
    {
464
37328
      last_weight = curr_w;
465
    }
466
  }
467
10646
  d_num_trigger_vars[f] = vcMap.size();
468
21292
  if (d_num_trigger_vars[f] > 0
469
21292
      && d_num_trigger_vars[f] < f[0].getNumChildren())
470
  {
471
200
    Trace("auto-gen-trigger-partial")
472
100
        << "Quantified formula : " << f << std::endl;
473
200
    Trace("auto-gen-trigger-partial")
474
100
        << "...does not contain all variables in triggers!!!" << std::endl;
475
    // Invoke partial trigger strategy: partition variables of quantified
476
    // formula into (X,Y) where X are contained in a trigger and Y are not.
477
    // We then force a split of the quantified formula so that it becomes:
478
    //   forall X. forall Y. P( X, Y )
479
    // and hence is treatable by E-matching. We only do this for "standard"
480
    // quantified formulas (those with only two children), since this
481
    // technique should not be used for e.g. quantifiers marked for
482
    // quantifier elimination.
483
100
    QAttributes qa;
484
100
    QuantAttributes::computeQuantAttributes(f, qa);
485
100
    if (options::partialTriggers() && qa.isStandard())
486
    {
487
      std::vector<Node> vcs[2];
488
      for (size_t i = 0, nchild = f[0].getNumChildren(); i < nchild; i++)
489
      {
490
        Node ic = d_qreg.getInstantiationConstant(f, i);
491
        vcs[vcMap.find(ic) == vcMap.end() ? 0 : 1].push_back(f[0][i]);
492
      }
493
      for (size_t i = 0; i < 2; i++)
494
      {
495
        d_vc_partition[i][f] = nm->mkNode(BOUND_VAR_LIST, vcs[i]);
496
      }
497
    }
498
    else
499
    {
500
100
      return false;
501
    }
502
  }
503
48097
  for (const Node& patf : patTermsF)
504
  {
505
74630
    Node pat = patf;
506
37551
    if (rmPatTermsF.find(pat) != rmPatTermsF.end())
507
    {
508
472
      continue;
509
    }
510
74158
    Trace("auto-gen-trigger-debug")
511
37079
        << "...processing pattern " << pat << std::endl;
512
74158
    Node mpat = pat;
513
    // process the pattern: if it has a required polarity, consider it
514
37079
    Assert(tinfo.find(pat) != tinfo.end());
515
37079
    int rpol = tinfo[pat].d_reqPol;
516
74158
    Node rpoleq = tinfo[pat].d_reqPolEq;
517
37079
    size_t num_fv = tinfo[pat].d_fv.size();
518
74158
    Trace("auto-gen-trigger-debug")
519
37079
        << "...required polarity for " << pat << " is " << rpol
520
37079
        << ", eq=" << rpoleq << std::endl;
521
37079
    if (rpol != 0)
522
    {
523
8786
      Assert(rpol == 1 || rpol == -1);
524
8786
      if (TriggerTermInfo::isRelationalTrigger(pat))
525
      {
526
33
        pat = rpol == -1 ? pat.negate() : pat;
527
      }
528
      else
529
      {
530
8753
        Assert(TriggerTermInfo::isAtomicTrigger(pat));
531
8753
        if (pat.getType().isBoolean() && rpoleq.isNull())
532
        {
533
6548
          if (options::literalMatchMode() == options::LiteralMatchMode::USE)
534
          {
535
6548
            pat = pat.eqNode(nm->mkConst(rpol == -1)).negate();
536
          }
537
          else if (options::literalMatchMode()
538
                   != options::LiteralMatchMode::NONE)
539
          {
540
            pat = pat.eqNode(nm->mkConst(rpol == 1));
541
          }
542
        }
543
        else
544
        {
545
2205
          Assert(!rpoleq.isNull());
546
2205
          if (rpol == -1)
547
          {
548
802
            if (options::literalMatchMode() != options::LiteralMatchMode::NONE)
549
            {
550
              // all equivalence classes except rpoleq
551
802
              pat = pat.eqNode(rpoleq).negate();
552
            }
553
          }
554
1403
          else if (rpol == 1)
555
          {
556
1403
            if (options::literalMatchMode() == options::LiteralMatchMode::AGG)
557
            {
558
              // only equivalence class rpoleq
559
              pat = pat.eqNode(rpoleq);
560
            }
561
          }
562
        }
563
      }
564
8786
      Trace("auto-gen-trigger-debug") << "...got : " << pat << std::endl;
565
    }
566
    else
567
    {
568
28293
      if (TriggerTermInfo::isRelationalTrigger(pat))
569
      {
570
        // consider both polarities
571
19
        addPatternToPool(f, pat.negate(), num_fv, mpat);
572
      }
573
    }
574
37079
    addPatternToPool(f, pat, num_fv, mpat);
575
  }
576
  // tinfo not used below this point
577
10546
  d_made_multi_trigger[f] = false;
578
10546
  if (Trace.isOn("auto-gen-trigger"))
579
  {
580
    Trace("auto-gen-trigger")
581
        << "Single trigger pool for " << f << " : " << std::endl;
582
    std::vector<Node>& spats = d_patTerms[0][f];
583
    for (size_t i = 0, psize = spats.size(); i < psize; i++)
584
    {
585
      Trace("auto-gen-trigger") << "   " << spats[i] << std::endl;
586
    }
587
    std::vector<Node>& mpats = d_patTerms[0][f];
588
    if (!mpats.empty())
589
    {
590
      Trace("auto-gen-trigger")
591
          << "Multi-trigger term pool for " << f << " : " << std::endl;
592
      for (size_t i = 0, psize = mpats.size(); i < psize; i++)
593
      {
594
        Trace("auto-gen-trigger") << "   " << mpats[i] << std::endl;
595
      }
596
    }
597
  }
598
10546
  return true;
599
}
600
601
37098
void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat ) {
602
37098
  d_pat_to_mpat[pat] = mpat;
603
37098
  unsigned num_vars = options::partialTriggers() ? d_num_trigger_vars[q] : q[0].getNumChildren();
604
37098
  if (num_fv == num_vars)
605
  {
606
12120
    d_patTerms[0][q].push_back( pat );
607
12120
    d_is_single_trigger[ pat ] = true;
608
  }else{
609
24978
    d_patTerms[1][q].push_back( pat );
610
24978
    d_is_single_trigger[ pat ] = false;
611
  }
612
37098
}
613
614
615
13269
void InstStrategyAutoGenTriggers::addTrigger( inst::Trigger * tr, Node q ) {
616
13269
  if (tr == nullptr)
617
  {
618
    return;
619
  }
620
13269
  if (d_num_trigger_vars[q] < q[0].getNumChildren())
621
  {
622
    NodeManager* nm = NodeManager::currentNM();
623
    // partial trigger : generate implication to mark user pattern
624
    Node pat =
625
        d_qreg.substituteInstConstantsToBoundVariables(tr->getInstPattern(), q);
626
    Node ipl = nm->mkNode(INST_PATTERN_LIST, pat);
627
    Node qq = nm->mkNode(FORALL,
628
                         d_vc_partition[1][q],
629
                         nm->mkNode(FORALL, d_vc_partition[0][q], q[1]),
630
                         ipl);
631
    Trace("auto-gen-trigger-partial")
632
        << "Make partially specified user pattern: " << std::endl;
633
    Trace("auto-gen-trigger-partial") << "  " << qq << std::endl;
634
    Node lem = nm->mkNode(OR, q.negate(), qq);
635
    d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_PARTIAL_TRIGGER_REDUCE);
636
    return;
637
  }
638
  unsigned tindex;
639
13269
  if (tr->isMultiTrigger())
640
  {
641
    // disable all other multi triggers
642
1149
    std::map<Trigger*, bool>& agt = d_auto_gen_trigger[1][q];
643
1318
    for (std::map<Trigger*, bool>::iterator it = agt.begin(); it != agt.end();
644
         ++it)
645
    {
646
169
      agt[it->first] = false;
647
    }
648
1149
    tindex = 1;
649
  }
650
  else
651
  {
652
12120
    tindex = 0;
653
  }
654
  // making it during an instantiation round, so must reset
655
13269
  std::map<Trigger*, bool>& agt = d_auto_gen_trigger[tindex][q];
656
13269
  if (agt.find(tr) == agt.end())
657
  {
658
13174
    tr->resetInstantiationRound();
659
13174
    tr->reset(Node::null());
660
  }
661
13269
  agt[tr] = true;
662
}
663
664
140816
bool InstStrategyAutoGenTriggers::hasUserPatterns( Node q ) {
665
140816
  if (q.getNumChildren() != 3)
666
  {
667
111920
    return false;
668
  }
669
28896
  std::map<Node, bool>::iterator it = d_hasUserPatterns.find(q);
670
28896
  if (it != d_hasUserPatterns.end())
671
  {
672
25483
    return it->second;
673
  }
674
3413
  bool hasPat = false;
675
3861
  for (const Node& ip : q[2])
676
  {
677
3735
    if (ip.getKind() == INST_PATTERN)
678
    {
679
3287
      hasPat = true;
680
3287
      break;
681
    }
682
  }
683
3413
  d_hasUserPatterns[q] = hasPat;
684
3413
  return hasPat;
685
}
686
687
8
void InstStrategyAutoGenTriggers::addUserNoPattern( Node q, Node pat ) {
688
8
  Assert(pat.getKind() == INST_NO_PATTERN && pat.getNumChildren() == 1);
689
8
  std::vector<Node>& ung = d_user_no_gen[q];
690
8
  if (std::find(ung.begin(), ung.end(), pat[0]) == ung.end())
691
  {
692
8
    Trace("user-pat") << "Add user no-pattern: " << pat[0] << " for " << q << std::endl;
693
8
    ung.push_back(pat[0]);
694
  }
695
8
}
696
697
}  // namespace quantifiers
698
}  // namespace theory
699
29502
}  // namespace cvc5