GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp Lines: 276 364 75.8 %
Date: 2021-11-07 Branches: 500 1335 37.5 %

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