GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp Lines: 265 352 75.3 %
Date: 2021-05-22 Branches: 494 1337 36.9 %

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