GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp Lines: 267 357 74.8 %
Date: 2021-09-29 Branches: 479 1309 36.6 %

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