GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp Lines: 267 354 75.4 %
Date: 2021-08-17 Branches: 475 1293 36.7 %

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
6500
InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers(
68
    inst::TriggerDatabase& td,
69
    QuantifiersState& qs,
70
    QuantifiersInferenceManager& qim,
71
    QuantifiersRegistry& qr,
72
    TermRegistry& tr,
73
6500
    QuantRelevance* qrlv)
74
6500
    : InstStrategy(td, qs, qim, qr, tr), d_quant_rel(qrlv)
75
{
76
  //how to select trigger terms
77
6500
  d_tr_strategy = options::triggerSelMode();
78
  //whether to select new triggers during the search
79
6500
  if( options::incrementTriggers() ){
80
6500
    d_regenerate_frequency = 3;
81
6500
    d_regenerate = true;
82
  }else{
83
    d_regenerate_frequency = 1;
84
    d_regenerate = false;
85
  }
86
6500
}
87
88
24322
void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){
89
24322
  Trace("inst-alg-debug") << "reset auto-gen triggers" << std::endl;
90
  //reset triggers
91
72966
  for( unsigned r=0; r<2; r++ ){
92
48644
    std::map<Node, std::map<inst::Trigger*, bool> >& agts =
93
        d_auto_gen_trigger[r];
94
160950
    for (std::pair<const Node, std::map<inst::Trigger*, bool> >& agt : agts)
95
    {
96
185806
      for (std::map<inst::Trigger*, bool>::iterator it = agt.second.begin();
97
185806
           it != agt.second.end();
98
           ++it)
99
      {
100
73500
        it->first->resetInstantiationRound();
101
73500
        it->first->reset(Node::null());
102
      }
103
    }
104
  }
105
24322
  d_processed_trigger.clear();
106
24322
  Trace("inst-alg-debug") << "done reset auto-gen triggers" << std::endl;
107
24322
}
108
109
81326
InstStrategyStatus InstStrategyAutoGenTriggers::process(Node f,
110
                                                        Theory::Effort effort,
111
                                                        int e)
112
{
113
81326
  options::UserPatMode upMode = getInstUserPatMode();
114
81326
  if (hasUserPatterns(f) && upMode == options::UserPatMode::TRUST)
115
  {
116
28048
    return InstStrategyStatus::STATUS_UNKNOWN;
117
  }
118
159834
  int peffort = (hasUserPatterns(f) && upMode != options::UserPatMode::IGNORE
119
                 && upMode != options::UserPatMode::RESORT)
120
159834
                    ? 2
121
53278
                    : 1;
122
53278
  if (e < peffort)
123
  {
124
26639
    return InstStrategyStatus::STATUS_UNFINISHED;
125
  }
126
26639
  Trace("inst-alg") << "-> Auto-gen instantiate " << f << "..." << std::endl;
127
26639
  bool gen = false;
128
26639
  if (e == peffort)
129
  {
130
26639
    if (d_counter.find(f) == d_counter.end())
131
    {
132
10338
      d_counter[f] = 0;
133
10338
      gen = true;
134
    }else{
135
16301
      d_counter[f]++;
136
16301
      gen = d_regenerate && d_counter[f] % d_regenerate_frequency == 0;
137
    }
138
  }
139
  else
140
  {
141
    gen = true;
142
  }
143
26639
  if (gen)
144
  {
145
13052
    generateTriggers(f);
146
36442
    if (d_counter[f] == 0 && d_auto_gen_trigger[0][f].empty()
147
15013
        && d_auto_gen_trigger[1][f].empty() && f.getNumChildren() == 2)
148
    {
149
994
      Trace("trigger-warn") << "Could not find trigger for " << f << std::endl;
150
1988
      Output(options::OutputTag::TRIGGER)
151
994
          << "(no-trigger " << f << ")" << std::endl;
152
    }
153
  }
154
26639
  if (options::triggerActiveSelMode() != options::TriggerActiveSelMode::ALL)
155
  {
156
    int max_score = -1;
157
    Trigger* max_trigger = nullptr;
158
    std::map<Trigger*, bool>& agt = d_auto_gen_trigger[0][f];
159
    for (std::map<Trigger*, bool>::iterator it = agt.begin(); it != agt.end();
160
         ++it)
161
    {
162
      Trigger* t = it->first;
163
      int score = t->getActiveScore();
164
      if (options::triggerActiveSelMode() == options::TriggerActiveSelMode::MIN)
165
      {
166
        if (score >= 0 && (score < max_score || max_score < 0))
167
        {
168
          max_score = score;
169
          max_trigger = t;
170
        }
171
      }
172
      else
173
      {
174
        if (score > max_score)
175
        {
176
          max_score = score;
177
          max_trigger = t;
178
        }
179
      }
180
      agt[t] = false;
181
    }
182
    if (max_trigger != nullptr)
183
    {
184
      agt[max_trigger] = true;
185
    }
186
  }
187
188
26639
  bool hasInst = false;
189
79917
  for (unsigned r = 0; r < 2; r++)
190
  {
191
53278
    std::map<Trigger*, bool>& agt = d_auto_gen_trigger[r][f];
192
86662
    for (std::map<Trigger*, bool>::iterator it = agt.begin(); it != agt.end();
193
         ++it)
194
    {
195
33384
      Trigger* tr = it->first;
196
33384
      if (tr == nullptr || !it->second)
197
      {
198
        // trigger is null or currently disabled
199
208
        continue;
200
      }
201
33280
      if (d_processed_trigger[f].find(tr) != d_processed_trigger[f].end())
202
      {
203
        // trigger is already processed this round
204
        continue;
205
      }
206
33280
      d_processed_trigger[f][tr] = true;
207
33280
      Trace("process-trigger") << "  Process ";
208
33280
      tr->debugPrint("process-trigger");
209
33280
      Trace("process-trigger") << "..." << std::endl;
210
33280
      unsigned numInst = tr->addInstantiations();
211
33280
      hasInst = numInst > 0 || hasInst;
212
66560
      Trace("process-trigger")
213
33280
          << "  Done, numInst = " << numInst << "." << std::endl;
214
33280
      if (d_qstate.isInConflict())
215
      {
216
        break;
217
      }
218
    }
219
53278
    if (d_qstate.isInConflict() || (hasInst && options::multiTriggerPriority()))
220
    {
221
      break;
222
    }
223
  }
224
26639
  return InstStrategyStatus::STATUS_UNKNOWN;
225
}
226
227
13052
void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
228
13052
  Trace("auto-gen-trigger-debug") << "Generate triggers for " << f << ", #var=" << f[0].getNumChildren() << "..." << std::endl;
229
230
  // first, generate the set of pattern terms
231
13052
  if (!generatePatternTerms(f))
232
  {
233
192
    Trace("auto-gen-trigger-debug")
234
96
        << "...failed to generate pattern terms" << std::endl;
235
96
    return;
236
  }
237
238
  // then, group them to make triggers
239
12956
  unsigned rmin = d_patTerms[0][f].empty() ? 1 : 0;
240
12956
  unsigned rmax = options::multiTriggerWhenSingle() ? 1 : rmin;
241
25912
  for (unsigned r = rmin; r <= rmax; r++)
242
  {
243
21333
    std::vector<Node> patTerms;
244
12956
    std::vector<Node>& ptc = d_patTerms[r][f];
245
32917
    for (const Node& p : ptc)
246
    {
247
19961
      if (r == 1 || d_single_trigger_gen.find(p) == d_single_trigger_gen.end())
248
      {
249
16823
        patTerms.push_back(p);
250
      }
251
    }
252
12956
    if (patTerms.empty())
253
    {
254
3541
      continue;
255
    }
256
9415
    Trace("auto-gen-trigger") << "Generate trigger for " << f << std::endl;
257
    // sort terms based on relevance
258
9415
    if (options::relevantTriggers())
259
    {
260
319
      Assert(d_quant_rel);
261
638
      sortQuantifiersForSymbol sqfs;
262
319
      sqfs.d_quant_rel = d_quant_rel;
263
936
      for (const Node& p : patTerms)
264
      {
265
617
        Assert(d_pat_to_mpat.find(p) != d_pat_to_mpat.end());
266
617
        Assert(d_pat_to_mpat[p].hasOperator());
267
617
        sqfs.d_op_map[p] = d_pat_to_mpat[p].getOperator();
268
      }
269
      // sort based on # occurrences (this will cause Trigger to select rarer
270
      // symbols)
271
319
      std::sort(patTerms.begin(), patTerms.end(), sqfs);
272
319
      if (Debug.isOn("relevant-trigger"))
273
      {
274
        Debug("relevant-trigger") << "Terms based on relevance: " << std::endl;
275
        for (const Node& p : patTerms)
276
        {
277
          Debug("relevant-trigger")
278
              << "   " << p << " from " << d_pat_to_mpat[p] << " (";
279
          Debug("relevant-trigger") << d_quant_rel->getNumQuantifiersForSymbol(
280
                                           d_pat_to_mpat[p].getOperator())
281
                                    << ")" << std::endl;
282
        }
283
      }
284
    }
285
    // now, generate the trigger...
286
9415
    Trigger* tr = NULL;
287
9415
    if (d_is_single_trigger[patTerms[0]])
288
    {
289
25131
      tr = d_td.mkTrigger(f,
290
8377
                          patTerms[0],
291
                          false,
292
                          TriggerDatabase::TR_RETURN_NULL,
293
8377
                          d_num_trigger_vars[f]);
294
8377
      d_single_trigger_gen[patTerms[0]] = true;
295
    }
296
    else
297
    {
298
      // only generate multi trigger if option set, or if no single triggers
299
      // exist
300
1038
      if (!d_patTerms[0][f].empty())
301
      {
302
        if (options::multiTriggerWhenSingle())
303
        {
304
          Trace("multi-trigger-debug")
305
              << "Resort to choosing multi-triggers..." << std::endl;
306
        }
307
        else
308
        {
309
          return;
310
        }
311
      }
312
      // if we are re-generating triggers, shuffle based on some method
313
1038
      if (d_made_multi_trigger[f])
314
      {
315
71
        std::shuffle(patTerms.begin(),
316
                     patTerms.end(),
317
                     Random::getRandom());  // shuffle randomly
318
      }
319
      else
320
      {
321
967
        d_made_multi_trigger[f] = true;
322
      }
323
      // will possibly want to get an old trigger
324
2076
      tr = d_td.mkTrigger(f,
325
                          patTerms,
326
                          false,
327
                          TriggerDatabase::TR_GET_OLD,
328
1038
                          d_num_trigger_vars[f]);
329
    }
330
9415
    if (tr == nullptr)
331
    {
332
      // did not generate a trigger
333
      continue;
334
    }
335
9415
    addTrigger(tr, f);
336
9415
    if (tr->isMultiTrigger())
337
    {
338
      // only add a single multi-trigger
339
1038
      continue;
340
    }
341
    // if we are generating additional triggers...
342
8377
    size_t index = 0;
343
8377
    if (index < patTerms.size())
344
    {
345
      // check if similar patterns exist, and if so, add them additionally
346
8377
      unsigned nqfs_curr = 0;
347
8377
      if (options::relevantTriggers())
348
      {
349
250
        nqfs_curr =
350
500
            d_quant_rel->getNumQuantifiersForSymbol(patTerms[0].getOperator());
351
      }
352
8377
      index++;
353
8377
      bool success = true;
354
15249
      while (success && index < patTerms.size()
355
15249
             && d_is_single_trigger[patTerms[index]])
356
      {
357
3436
        success = false;
358
6872
        if (!options::relevantTriggers()
359
6892
            || d_quant_rel->getNumQuantifiersForSymbol(
360
3446
                   patTerms[index].getOperator())
361
10
                   <= nqfs_curr)
362
        {
363
3436
          d_single_trigger_gen[patTerms[index]] = true;
364
13744
          Trigger* tr2 = d_td.mkTrigger(f,
365
3436
                                        patTerms[index],
366
                                        false,
367
                                        TriggerDatabase::TR_RETURN_NULL,
368
6872
                                        d_num_trigger_vars[f]);
369
3436
          addTrigger(tr2, f);
370
3436
          success = true;
371
        }
372
3436
        index++;
373
      }
374
    }
375
  }
376
}
377
378
13052
bool InstStrategyAutoGenTriggers::generatePatternTerms(Node f)
379
{
380
13052
  if (d_patTerms[0].find(f) != d_patTerms[0].end())
381
  {
382
    // already generated
383
2714
    return true;
384
  }
385
  // determine all possible pattern terms based on trigger term selection
386
  // strategy d_tr_strategy
387
10338
  d_patTerms[0][f].clear();
388
10338
  d_patTerms[1][f].clear();
389
10338
  bool ntrivTriggers = options::relationalTriggers();
390
20676
  std::vector<Node> patTermsF;
391
20676
  std::map<Node, inst::TriggerTermInfo> tinfo;
392
10338
  NodeManager* nm = NodeManager::currentNM();
393
  // well-defined function: can assume LHS is only pattern
394
10338
  if (options::quantFunWellDefined())
395
  {
396
    Node hd = QuantAttributes::getFunDefHead(f);
397
    if (!hd.isNull())
398
    {
399
      hd = d_qreg.substituteBoundVariablesToInstConstants(hd, f);
400
      patTermsF.push_back(hd);
401
      tinfo[hd].init(f, hd);
402
    }
403
  }
404
  // otherwise, use algorithm for collecting pattern terms
405
10338
  if (patTermsF.empty())
406
  {
407
20676
    Node bd = d_qreg.getInstConstantBody(f);
408
20676
    PatternTermSelector pts(f, d_tr_strategy, d_user_no_gen[f], true);
409
10338
    pts.collect(bd, patTermsF, tinfo);
410
10338
    if (ntrivTriggers)
411
    {
412
      sortTriggers st;
413
1174
      std::sort(patTermsF.begin(), patTermsF.end(), st);
414
    }
415
10338
    if (Trace.isOn("auto-gen-trigger-debug"))
416
    {
417
      Trace("auto-gen-trigger-debug")
418
          << "Collected pat terms for " << bd
419
          << ", no-patterns : " << d_user_no_gen[f].size() << std::endl;
420
      for (const Node& p : patTermsF)
421
      {
422
        Assert(tinfo.find(p) != tinfo.end());
423
        Trace("auto-gen-trigger-debug") << "   " << p << std::endl;
424
        Trace("auto-gen-trigger-debug2")
425
            << "     info = [" << tinfo[p].d_reqPol << ", "
426
            << tinfo[p].d_reqPolEq << ", " << tinfo[p].d_fv.size() << "]"
427
            << std::endl;
428
      }
429
      Trace("auto-gen-trigger-debug") << std::endl;
430
    }
431
  }
432
  // sort into single/multi triggers, calculate which terms should not be
433
  // considered
434
20676
  std::map<Node, bool> vcMap;
435
20676
  std::map<Node, bool> rmPatTermsF;
436
10338
  int32_t last_weight = -1;
437
47367
  for (const Node& p : patTermsF)
438
  {
439
37029
    Assert(p.getKind() != NOT);
440
37029
    bool newVar = false;
441
37029
    inst::TriggerTermInfo& tip = tinfo[p];
442
130189
    for (const Node& v : tip.d_fv)
443
    {
444
93160
      if (vcMap.find(v) == vcMap.end())
445
      {
446
26734
        vcMap[v] = true;
447
26734
        newVar = true;
448
      }
449
    }
450
37029
    int32_t curr_w = TriggerTermInfo::getTriggerWeight(p);
451
    // triggers whose value is maximum (2) are considered expendable.
452
37029
    if (ntrivTriggers && !newVar && last_weight != -1 && curr_w > last_weight
453
472
        && curr_w >= 2)
454
    {
455
944
      Trace("auto-gen-trigger-debug")
456
472
          << "...exclude expendible non-trivial trigger : " << p << std::endl;
457
472
      rmPatTermsF[p] = true;
458
    }
459
    else
460
    {
461
36557
      last_weight = curr_w;
462
    }
463
  }
464
10338
  d_num_trigger_vars[f] = vcMap.size();
465
20676
  if (d_num_trigger_vars[f] > 0
466
20676
      && d_num_trigger_vars[f] < f[0].getNumChildren())
467
  {
468
192
    Trace("auto-gen-trigger-partial")
469
96
        << "Quantified formula : " << f << std::endl;
470
192
    Trace("auto-gen-trigger-partial")
471
96
        << "...does not contain all variables in triggers!!!" << std::endl;
472
    // Invoke partial trigger strategy: partition variables of quantified
473
    // formula into (X,Y) where X are contained in a trigger and Y are not.
474
    // We then force a split of the quantified formula so that it becomes:
475
    //   forall X. forall Y. P( X, Y )
476
    // and hence is treatable by E-matching. We only do this for "standard"
477
    // quantified formulas (those with only two children), since this
478
    // technique should not be used for e.g. quantifiers marked for
479
    // quantifier elimination.
480
96
    QAttributes qa;
481
96
    QuantAttributes::computeQuantAttributes(f, qa);
482
96
    if (options::partialTriggers() && qa.isStandard())
483
    {
484
      std::vector<Node> vcs[2];
485
      for (size_t i = 0, nchild = f[0].getNumChildren(); i < nchild; i++)
486
      {
487
        Node ic = d_qreg.getInstantiationConstant(f, i);
488
        vcs[vcMap.find(ic) == vcMap.end() ? 0 : 1].push_back(f[0][i]);
489
      }
490
      for (size_t i = 0; i < 2; i++)
491
      {
492
        d_vc_partition[i][f] = nm->mkNode(BOUND_VAR_LIST, vcs[i]);
493
      }
494
    }
495
    else
496
    {
497
96
      return false;
498
    }
499
  }
500
47026
  for (const Node& patf : patTermsF)
501
  {
502
73096
    Node pat = patf;
503
36784
    if (rmPatTermsF.find(pat) != rmPatTermsF.end())
504
    {
505
472
      continue;
506
    }
507
72624
    Trace("auto-gen-trigger-debug")
508
36312
        << "...processing pattern " << pat << std::endl;
509
72624
    Node mpat = pat;
510
    // process the pattern: if it has a required polarity, consider it
511
36312
    Assert(tinfo.find(pat) != tinfo.end());
512
36312
    int rpol = tinfo[pat].d_reqPol;
513
72624
    Node rpoleq = tinfo[pat].d_reqPolEq;
514
36312
    size_t num_fv = tinfo[pat].d_fv.size();
515
72624
    Trace("auto-gen-trigger-debug")
516
36312
        << "...required polarity for " << pat << " is " << rpol
517
36312
        << ", eq=" << rpoleq << std::endl;
518
36312
    if (rpol != 0)
519
    {
520
8740
      Assert(rpol == 1 || rpol == -1);
521
8740
      if (TriggerTermInfo::isRelationalTrigger(pat))
522
      {
523
33
        pat = rpol == -1 ? pat.negate() : pat;
524
      }
525
      else
526
      {
527
8707
        Assert(TriggerTermInfo::isAtomicTrigger(pat));
528
8707
        if (pat.getType().isBoolean() && rpoleq.isNull())
529
        {
530
6551
          if (options::literalMatchMode() == options::LiteralMatchMode::USE)
531
          {
532
6551
            pat = pat.eqNode(nm->mkConst(rpol == -1)).negate();
533
          }
534
          else if (options::literalMatchMode()
535
                   != options::LiteralMatchMode::NONE)
536
          {
537
            pat = pat.eqNode(nm->mkConst(rpol == 1));
538
          }
539
        }
540
        else
541
        {
542
2156
          Assert(!rpoleq.isNull());
543
2156
          if (rpol == -1)
544
          {
545
829
            if (options::literalMatchMode() != options::LiteralMatchMode::NONE)
546
            {
547
              // all equivalence classes except rpoleq
548
829
              pat = pat.eqNode(rpoleq).negate();
549
            }
550
          }
551
1327
          else if (rpol == 1)
552
          {
553
1327
            if (options::literalMatchMode() == options::LiteralMatchMode::AGG)
554
            {
555
              // only equivalence class rpoleq
556
              pat = pat.eqNode(rpoleq);
557
            }
558
          }
559
        }
560
      }
561
8740
      Trace("auto-gen-trigger-debug") << "...got : " << pat << std::endl;
562
    }
563
    else
564
    {
565
27572
      if (TriggerTermInfo::isRelationalTrigger(pat))
566
      {
567
        // consider both polarities
568
19
        addPatternToPool(f, pat.negate(), num_fv, mpat);
569
      }
570
    }
571
36312
    addPatternToPool(f, pat, num_fv, mpat);
572
  }
573
  // tinfo not used below this point
574
10242
  d_made_multi_trigger[f] = false;
575
10242
  if (Trace.isOn("auto-gen-trigger"))
576
  {
577
    Trace("auto-gen-trigger")
578
        << "Single trigger pool for " << f << " : " << std::endl;
579
    std::vector<Node>& spats = d_patTerms[0][f];
580
    for (size_t i = 0, psize = spats.size(); i < psize; i++)
581
    {
582
      Trace("auto-gen-trigger") << "   " << spats[i] << std::endl;
583
    }
584
    std::vector<Node>& mpats = d_patTerms[0][f];
585
    if (!mpats.empty())
586
    {
587
      Trace("auto-gen-trigger")
588
          << "Multi-trigger term pool for " << f << " : " << std::endl;
589
      for (size_t i = 0, psize = mpats.size(); i < psize; i++)
590
      {
591
        Trace("auto-gen-trigger") << "   " << mpats[i] << std::endl;
592
      }
593
    }
594
  }
595
10242
  return true;
596
}
597
598
36331
void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat ) {
599
36331
  d_pat_to_mpat[pat] = mpat;
600
36331
  unsigned num_vars = options::partialTriggers() ? d_num_trigger_vars[q] : q[0].getNumChildren();
601
36331
  if (num_fv == num_vars)
602
  {
603
11813
    d_patTerms[0][q].push_back( pat );
604
11813
    d_is_single_trigger[ pat ] = true;
605
  }else{
606
24518
    d_patTerms[1][q].push_back( pat );
607
24518
    d_is_single_trigger[ pat ] = false;
608
  }
609
36331
}
610
611
612
12851
void InstStrategyAutoGenTriggers::addTrigger( inst::Trigger * tr, Node q ) {
613
12851
  if (tr == nullptr)
614
  {
615
    return;
616
  }
617
12851
  if (d_num_trigger_vars[q] < q[0].getNumChildren())
618
  {
619
    NodeManager* nm = NodeManager::currentNM();
620
    // partial trigger : generate implication to mark user pattern
621
    Node pat =
622
        d_qreg.substituteInstConstantsToBoundVariables(tr->getInstPattern(), q);
623
    Node ipl = nm->mkNode(INST_PATTERN_LIST, pat);
624
    Node qq = nm->mkNode(FORALL,
625
                         d_vc_partition[1][q],
626
                         nm->mkNode(FORALL, d_vc_partition[0][q], q[1]),
627
                         ipl);
628
    Trace("auto-gen-trigger-partial")
629
        << "Make partially specified user pattern: " << std::endl;
630
    Trace("auto-gen-trigger-partial") << "  " << qq << std::endl;
631
    Node lem = nm->mkNode(OR, q.negate(), qq);
632
    d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_PARTIAL_TRIGGER_REDUCE);
633
    return;
634
  }
635
  unsigned tindex;
636
12851
  if (tr->isMultiTrigger())
637
  {
638
    // disable all other multi triggers
639
1038
    std::map<Trigger*, bool>& agt = d_auto_gen_trigger[1][q];
640
1123
    for (std::map<Trigger*, bool>::iterator it = agt.begin(); it != agt.end();
641
         ++it)
642
    {
643
85
      agt[it->first] = false;
644
    }
645
1038
    tindex = 1;
646
  }
647
  else
648
  {
649
11813
    tindex = 0;
650
  }
651
  // making it during an instantiation round, so must reset
652
12851
  std::map<Trigger*, bool>& agt = d_auto_gen_trigger[tindex][q];
653
12851
  if (agt.find(tr) == agt.end())
654
  {
655
12812
    tr->resetInstantiationRound();
656
12812
    tr->reset(Node::null());
657
  }
658
12851
  agt[tr] = true;
659
}
660
661
134604
bool InstStrategyAutoGenTriggers::hasUserPatterns( Node q ) {
662
134604
  if (q.getNumChildren() != 3)
663
  {
664
104336
    return false;
665
  }
666
30268
  std::map<Node, bool>::iterator it = d_hasUserPatterns.find(q);
667
30268
  if (it != d_hasUserPatterns.end())
668
  {
669
26673
    return it->second;
670
  }
671
3595
  bool hasPat = false;
672
3945
  for (const Node& ip : q[2])
673
  {
674
3811
    if (ip.getKind() == INST_PATTERN)
675
    {
676
3461
      hasPat = true;
677
3461
      break;
678
    }
679
  }
680
3595
  d_hasUserPatterns[q] = hasPat;
681
3595
  return hasPat;
682
}
683
684
8
void InstStrategyAutoGenTriggers::addUserNoPattern( Node q, Node pat ) {
685
8
  Assert(pat.getKind() == INST_NO_PATTERN && pat.getNumChildren() == 1);
686
8
  std::vector<Node>& ung = d_user_no_gen[q];
687
8
  if (std::find(ung.begin(), ung.end(), pat[0]) == ung.end())
688
  {
689
8
    Trace("user-pat") << "Add user no-pattern: " << pat[0] << " for " << q << std::endl;
690
8
    ung.push_back(pat[0]);
691
  }
692
8
}
693
694
}  // namespace quantifiers
695
}  // namespace theory
696
29337
}  // namespace cvc5