GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/ceg_instantiator.cpp Lines: 815 890 91.6 %
Date: 2021-05-21 Branches: 1662 3360 49.5 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Piotr Trojanek, 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 counterexample-guided quantifier instantiation.
14
 */
15
16
#include "theory/quantifiers/cegqi/ceg_instantiator.h"
17
18
#include "theory/quantifiers/cegqi/ceg_arith_instantiator.h"
19
#include "theory/quantifiers/cegqi/ceg_bv_instantiator.h"
20
#include "theory/quantifiers/cegqi/ceg_dt_instantiator.h"
21
22
#include "expr/dtype.h"
23
#include "expr/dtype_cons.h"
24
#include "expr/node_algorithm.h"
25
#include "options/quantifiers_options.h"
26
#include "theory/arith/arith_msum.h"
27
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
28
#include "theory/quantifiers/first_order_model.h"
29
#include "theory/quantifiers/quantifiers_attributes.h"
30
#include "theory/quantifiers/quantifiers_state.h"
31
#include "theory/quantifiers/term_database.h"
32
#include "theory/quantifiers/term_util.h"
33
#include "theory/rewriter.h"
34
35
using namespace std;
36
using namespace cvc5::kind;
37
38
namespace cvc5 {
39
namespace theory {
40
namespace quantifiers {
41
42
357
CegTermType mkStrictCTT(CegTermType c)
43
{
44
357
  Assert(!isStrictCTT(c));
45
357
  if (c == CEG_TT_LOWER)
46
  {
47
232
    return CEG_TT_LOWER_STRICT;
48
  }
49
125
  else if (c == CEG_TT_UPPER)
50
  {
51
125
    return CEG_TT_UPPER_STRICT;
52
  }
53
  return c;
54
}
55
56
2164
CegTermType mkNegateCTT(CegTermType c)
57
{
58
2164
  if (c == CEG_TT_LOWER)
59
  {
60
415
    return CEG_TT_UPPER;
61
  }
62
1749
  else if (c == CEG_TT_UPPER)
63
  {
64
1749
    return CEG_TT_LOWER;
65
  }
66
  else if (c == CEG_TT_LOWER_STRICT)
67
  {
68
    return CEG_TT_UPPER_STRICT;
69
  }
70
  else if (c == CEG_TT_UPPER_STRICT)
71
  {
72
    return CEG_TT_LOWER_STRICT;
73
  }
74
  return c;
75
}
76
357
bool isStrictCTT(CegTermType c)
77
{
78
357
  return c == CEG_TT_LOWER_STRICT || c == CEG_TT_UPPER_STRICT;
79
}
80
bool isLowerBoundCTT(CegTermType c)
81
{
82
  return c == CEG_TT_LOWER || c == CEG_TT_LOWER_STRICT;
83
}
84
10142
bool isUpperBoundCTT(CegTermType c)
85
{
86
10142
  return c == CEG_TT_UPPER || c == CEG_TT_UPPER_STRICT;
87
}
88
89
std::ostream& operator<<(std::ostream& os, CegInstEffort e)
90
{
91
  switch (e)
92
  {
93
    case CEG_INST_EFFORT_NONE: os << "?"; break;
94
    case CEG_INST_EFFORT_STANDARD: os << "STANDARD"; break;
95
    case CEG_INST_EFFORT_STANDARD_MV: os << "STANDARD_MV"; break;
96
    case CEG_INST_EFFORT_FULL: os << "FULL"; break;
97
    default: Unreachable();
98
  }
99
  return os;
100
}
101
102
std::ostream& operator<<(std::ostream& os, CegInstPhase phase)
103
{
104
  switch (phase)
105
  {
106
    case CEG_INST_PHASE_NONE: os << "?"; break;
107
    case CEG_INST_PHASE_EQC: os << "eqc"; break;
108
    case CEG_INST_PHASE_EQUAL: os << "eq"; break;
109
    case CEG_INST_PHASE_ASSERTION: os << "as"; break;
110
    case CEG_INST_PHASE_MVALUE: os << "mv"; break;
111
    default: Unreachable();
112
  }
113
  return os;
114
}
115
std::ostream& operator<<(std::ostream& os, CegHandledStatus status)
116
{
117
  switch (status)
118
  {
119
    case CEG_UNHANDLED: os << "unhandled"; break;
120
    case CEG_PARTIALLY_HANDLED: os << "partially_handled"; break;
121
    case CEG_HANDLED: os << "handled"; break;
122
    case CEG_HANDLED_UNCONDITIONAL: os << "handled_unc"; break;
123
    default: Unreachable();
124
  }
125
  return os;
126
}
127
128
51
void TermProperties::composeProperty(TermProperties& p)
129
{
130
51
  if (p.d_coeff.isNull())
131
  {
132
    return;
133
  }
134
51
  if (d_coeff.isNull())
135
  {
136
29
    d_coeff = p.d_coeff;
137
  }
138
  else
139
  {
140
22
    d_coeff = NodeManager::currentNM()->mkNode(MULT, d_coeff, p.d_coeff);
141
22
    d_coeff = Rewriter::rewrite(d_coeff);
142
  }
143
}
144
145
// push the substitution pv_prop.getModifiedTerm(pv) -> n
146
18387
void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop)
147
{
148
18387
  d_vars.push_back(pv);
149
18387
  d_subs.push_back(n);
150
18387
  d_props.push_back(pv_prop);
151
18387
  if (pv_prop.isBasic())
152
  {
153
18218
    return;
154
  }
155
169
  d_non_basic.push_back(pv);
156
  // update theta value
157
338
  Node new_theta = getTheta();
158
169
  if (new_theta.isNull())
159
  {
160
127
    new_theta = pv_prop.d_coeff;
161
  }
162
  else
163
  {
164
42
    new_theta =
165
84
        NodeManager::currentNM()->mkNode(MULT, new_theta, pv_prop.d_coeff);
166
42
    new_theta = Rewriter::rewrite(new_theta);
167
  }
168
169
  d_theta.push_back(new_theta);
169
}
170
// pop the substitution pv_prop.getModifiedTerm(pv) -> n
171
3714
void SolvedForm::pop_back(Node pv, Node n, TermProperties& pv_prop)
172
{
173
3714
  d_vars.pop_back();
174
3714
  d_subs.pop_back();
175
3714
  d_props.pop_back();
176
3714
  if (pv_prop.isBasic())
177
  {
178
3674
    return;
179
  }
180
40
  d_non_basic.pop_back();
181
  // update theta value
182
40
  d_theta.pop_back();
183
}
184
185
1584
CegInstantiator::CegInstantiator(Node q,
186
                                 QuantifiersState& qs,
187
                                 TermRegistry& tr,
188
1584
                                 InstStrategyCegqi* parent)
189
    : d_quant(q),
190
      d_qstate(qs),
191
      d_treg(tr),
192
      d_parent(parent),
193
      d_is_nested_quant(false),
194
1584
      d_effort(CEG_INST_EFFORT_NONE)
195
{
196
1584
}
197
198
4752
CegInstantiator::~CegInstantiator() {
199
4506
  for (std::pair<Node, Instantiator*> inst : d_instantiator)
200
  {
201
2922
    delete inst.second;
202
  }
203
2290
  for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
204
  {
205
706
    delete instp.second;
206
  }
207
3168
}
208
209
1274524
void CegInstantiator::computeProgVars( Node n ){
210
1274524
  if( d_prog_var.find( n )==d_prog_var.end() ){
211
59079
    d_prog_var[n].clear();
212
59079
    if (n.getKind() == kind::WITNESS)
213
    {
214
612
      Assert(d_prog_var.find(n[0][0]) == d_prog_var.end());
215
612
      d_prog_var[n[0][0]].clear();
216
    }
217
59079
    if (d_vars_set.find(n) != d_vars_set.end())
218
    {
219
2609
      d_prog_var[n].insert(n);
220
    }
221
56470
    else if (!isEligibleForInstantiation(n))
222
    {
223
2924
      d_inelig.insert(n);
224
2924
      return;
225
    }
226
138969
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
227
82814
      computeProgVars( n[i] );
228
82814
      if( d_inelig.find( n[i] )!=d_inelig.end() ){
229
14394
        d_inelig.insert(n);
230
      }
231
      // all variables in child are contained in this
232
82814
      d_prog_var[n].insert(d_prog_var[n[i]].begin(), d_prog_var[n[i]].end());
233
    }
234
    // selectors applied to program variables are also variables
235
112310
    if (n.getKind() == APPLY_SELECTOR_TOTAL
236
112310
        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
237
    {
238
26
      d_prog_var[n].insert(n);
239
    }
240
56155
    if (n.getKind() == kind::WITNESS)
241
    {
242
612
      d_prog_var.erase(n[0][0]);
243
    }
244
  }
245
}
246
247
437210
bool CegInstantiator::isEligible( Node n ) {
248
  //compute d_subs_fv, which program variables are contained in n, and determines if eligible
249
437210
  computeProgVars( n );
250
437210
  return d_inelig.find( n )==d_inelig.end();
251
}
252
253
46611
CegHandledStatus CegInstantiator::isCbqiKind(Kind k)
254
{
255
117325
  if (quantifiers::TermUtil::isBoolConnective(k) || k == PLUS || k == GEQ
256
13011
      || k == EQUAL || k == MULT || k == NONLINEAR_MULT || k == DIVISION
257
7836
      || k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL
258
7723
      || k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == TO_INTEGER
259
54235
      || k == IS_INTEGER)
260
  {
261
38991
    return CEG_HANDLED;
262
  }
263
264
  // CBQI typically works for satisfaction-complete theories
265
7620
  TheoryId t = kindToTheoryId(k);
266
7620
  if (t == THEORY_BV || t == THEORY_FP || t == THEORY_DATATYPES
267
5020
      || t == THEORY_BOOL)
268
  {
269
2600
    return CEG_HANDLED;
270
  }
271
5020
  return CEG_UNHANDLED;
272
}
273
274
6641
CegHandledStatus CegInstantiator::isCbqiTerm(Node n)
275
{
276
6641
  CegHandledStatus ret = CEG_HANDLED;
277
13282
  std::unordered_set<TNode> visited;
278
13282
  std::vector<TNode> visit;
279
13282
  TNode cur;
280
6641
  visit.push_back(n);
281
85778
  do
282
  {
283
92419
    cur = visit.back();
284
92419
    visit.pop_back();
285
92419
    if (visited.find(cur) == visited.end())
286
    {
287
76845
      visited.insert(cur);
288
76845
      if (cur.getKind() != BOUND_VARIABLE && TermUtil::hasBoundVarAttr(cur))
289
      {
290
53567
        if (cur.getKind() == FORALL || cur.getKind() == WITNESS)
291
        {
292
6956
          visit.push_back(cur[1]);
293
        }
294
        else
295
        {
296
46611
          CegHandledStatus curr = isCbqiKind(cur.getKind());
297
46611
          if (curr < ret)
298
          {
299
5020
            ret = curr;
300
10040
            Trace("cegqi-debug2") << "Non-cbqi kind : " << cur.getKind()
301
5020
                                 << " in " << n << std::endl;
302
5020
            if (curr == CEG_UNHANDLED)
303
            {
304
5020
              return CEG_UNHANDLED;
305
            }
306
          }
307
130066
          for (const Node& nc : cur)
308
          {
309
88475
            visit.push_back(nc);
310
          }
311
        }
312
      }
313
    }
314
87399
  } while (!visit.empty());
315
1621
  return ret;
316
}
317
318
24885
CegHandledStatus CegInstantiator::isCbqiSort(TypeNode tn)
319
{
320
49770
  std::map<TypeNode, CegHandledStatus> visited;
321
49770
  return isCbqiSort(tn, visited);
322
}
323
324
29010
CegHandledStatus CegInstantiator::isCbqiSort(
325
    TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited)
326
{
327
29010
  std::map<TypeNode, CegHandledStatus>::iterator itv = visited.find(tn);
328
29010
  if (itv != visited.end())
329
  {
330
2370
    return itv->second;
331
  }
332
26640
  CegHandledStatus ret = CEG_UNHANDLED;
333
70696
  if (tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector()
334
41972
      || tn.isFloatingPoint())
335
  {
336
11321
    ret = CEG_HANDLED;
337
  }
338
15319
  else if (tn.isDatatype())
339
  {
340
    // recursive calls to this datatype are handlable
341
1951
    visited[tn] = CEG_HANDLED;
342
    // we initialize to handled, we remain handled as long as all subfields
343
    // of this datatype are not unhandled.
344
1951
    ret = CEG_HANDLED;
345
1951
    const DType& dt = tn.getDType();
346
3949
    for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
347
    {
348
      // get the constructor type
349
5296
      TypeNode consType;
350
3298
      if (dt.isParametric())
351
      {
352
        // if parametric, must instantiate the argument types
353
32
        consType = dt[i].getSpecializedConstructorType(tn);
354
      }
355
      else
356
      {
357
3266
        consType = dt[i].getConstructor().getType();
358
      }
359
6123
      for (const TypeNode& crange : consType)
360
      {
361
4125
        CegHandledStatus cret = isCbqiSort(crange, visited);
362
4125
        if (cret == CEG_UNHANDLED)
363
        {
364
2600
          Trace("cegqi-debug2")
365
1300
              << "Non-cbqi sort : " << tn << " due to " << crange << std::endl;
366
1300
          visited[tn] = CEG_UNHANDLED;
367
1300
          return CEG_UNHANDLED;
368
        }
369
2825
        else if (cret < ret)
370
        {
371
          ret = cret;
372
        }
373
      }
374
    }
375
  }
376
  // sets, arrays, functions and others are not supported
377
25340
  visited[tn] = ret;
378
25340
  return ret;
379
}
380
381
20007
CegHandledStatus CegInstantiator::isCbqiQuantPrefix(Node q)
382
{
383
20007
  CegHandledStatus hmin = CEG_HANDLED_UNCONDITIONAL;
384
31484
  for (const Node& v : q[0])
385
  {
386
36320
    TypeNode tn = v.getType();
387
24843
    CegHandledStatus handled = isCbqiSort(tn);
388
24843
    if (handled == CEG_UNHANDLED)
389
    {
390
13366
      return CEG_UNHANDLED;
391
    }
392
11477
    else if (handled < hmin)
393
    {
394
6922
      hmin = handled;
395
    }
396
  }
397
6641
  return hmin;
398
}
399
400
24738
CegHandledStatus CegInstantiator::isCbqiQuant(Node q)
401
{
402
24738
  Assert(q.getKind() == FORALL);
403
  // compute attributes
404
49476
  QAttributes qa;
405
24738
  QuantAttributes::computeQuantAttributes(q, qa);
406
24738
  if (qa.d_quant_elim)
407
  {
408
74
    return CEG_HANDLED;
409
  }
410
24664
  if (qa.d_sygus)
411
  {
412
334
    return CEG_UNHANDLED;
413
  }
414
24330
  Assert(!qa.d_quant_elim_partial);
415
  // if has an instantiation pattern, don't do it
416
24330
  if (q.getNumChildren() == 3)
417
  {
418
5019
    for (const Node& pat : q[2])
419
    {
420
4787
      if (pat.getKind() == INST_PATTERN)
421
      {
422
4323
        return CEG_UNHANDLED;
423
      }
424
    }
425
  }
426
20007
  CegHandledStatus ret = CEG_HANDLED;
427
  // if quantifier has a non-handled variable, then do not use cbqi
428
20007
  CegHandledStatus ncbqiv = CegInstantiator::isCbqiQuantPrefix(q);
429
40014
  Trace("cegqi-quant-debug") << "isCbqiQuantPrefix returned " << ncbqiv
430
20007
                            << std::endl;
431
20007
  if (ncbqiv == CEG_UNHANDLED)
432
  {
433
    // unhandled variable type
434
13366
    ret = CEG_UNHANDLED;
435
  }
436
  else
437
  {
438
6641
    CegHandledStatus cbqit = CegInstantiator::isCbqiTerm(q);
439
6641
    Trace("cegqi-quant-debug") << "isCbqiTerm returned " << cbqit << std::endl;
440
6641
    if (cbqit == CEG_UNHANDLED)
441
    {
442
5020
      if (ncbqiv == CEG_HANDLED_UNCONDITIONAL)
443
      {
444
        // all variables are fully handled, this implies this will be handlable
445
        // regardless of body (e.g. for EPR)
446
        //  so, try but not exclusively
447
        ret = CEG_PARTIALLY_HANDLED;
448
      }
449
      else
450
      {
451
        // cannot be handled
452
5020
        ret = CEG_UNHANDLED;
453
      }
454
    }
455
1621
    else if (cbqit == CEG_PARTIALLY_HANDLED)
456
    {
457
      ret = CEG_PARTIALLY_HANDLED;
458
    }
459
  }
460
20007
  if (ret == CEG_UNHANDLED && options::cegqiAll())
461
  {
462
    // try but not exclusively
463
17
    ret = CEG_PARTIALLY_HANDLED;
464
  }
465
20007
  return ret;
466
}
467
468
142834
bool CegInstantiator::hasVariable( Node n, Node pv ) {
469
142834
  computeProgVars( n );
470
142834
  return d_prog_var[n].find( pv )!=d_prog_var[n].end();
471
}
472
473
18451
void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
474
{
475
18451
  if( d_instantiator.find( v )==d_instantiator.end() ){
476
5844
    TypeNode tn = v.getType();
477
    Instantiator * vinst;
478
2922
    if( tn.isReal() ){
479
1575
      vinst = new ArithInstantiator(tn, d_parent->getVtsTermCache());
480
1347
    }else if( tn.isDatatype() ){
481
30
      vinst = new DtInstantiator(tn);
482
1317
    }else if( tn.isBitVector() ){
483
1098
      vinst = new BvInstantiator(tn, d_parent->getBvInverter());
484
219
    }else if( tn.isBoolean() ){
485
207
      vinst = new ModelValueInstantiator(tn);
486
    }else{
487
      //default
488
12
      vinst = new Instantiator(tn);
489
    }
490
2922
    d_instantiator[v] = vinst;
491
  }
492
18451
  d_curr_subs_proc[v].clear();
493
18451
  d_curr_index[v] = index;
494
18451
  d_curr_iphase[v] = CEG_INST_PHASE_NONE;
495
18451
}
496
497
3778
void CegInstantiator::deactivateInstantiationVariable(Node v)
498
{
499
3778
  d_curr_subs_proc.erase(v);
500
3778
  d_curr_index.erase(v);
501
3778
  d_curr_iphase.erase(v);
502
3778
}
503
504
30156
bool CegInstantiator::hasTriedInstantiation(Node v)
505
{
506
30156
  return !d_curr_subs_proc[v].empty();
507
}
508
509
4231
void CegInstantiator::registerTheoryIds(TypeNode tn,
510
                                        std::map<TypeNode, bool>& visited)
511
{
512
4231
  if (visited.find(tn) == visited.end())
513
  {
514
4193
    visited[tn] = true;
515
4193
    TheoryId tid = Theory::theoryOf(tn);
516
4193
    registerTheoryId(tid);
517
4193
    if (tn.isDatatype())
518
    {
519
40
      const DType& dt = tn.getDType();
520
112
      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
521
      {
522
148
        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
523
        {
524
76
          registerTheoryIds(dt[i].getArgType(j), visited);
525
        }
526
      }
527
    }
528
  }
529
4231
}
530
531
5777
void CegInstantiator::registerTheoryId(TheoryId tid)
532
{
533
5777
  if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
534
  {
535
    // setup any theory-specific preprocessors here
536
3223
    if (tid == THEORY_BV)
537
    {
538
706
      d_tipp[tid] = new BvInstantiatorPreprocess;
539
    }
540
3223
    d_tids.push_back(tid);
541
  }
542
5777
}
543
544
4155
void CegInstantiator::registerVariable(Node v)
545
{
546
4155
  Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
547
4155
  d_vars.push_back(v);
548
4155
  d_vars_set.insert(v);
549
8310
  TypeNode vtn = v.getType();
550
8310
  Trace("cegqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
551
4155
                           << v << std::endl;
552
  // collect relevant theories for this variable
553
8310
  std::map<TypeNode, bool> visited;
554
4155
  registerTheoryIds(vtn, visited);
555
4155
}
556
557
23487
bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
558
{
559
23487
  if( i==d_vars.size() ){
560
    //solved for all variables, now construct instantiation
561
    bool needsPostprocess =
562
5036
        sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty();
563
10072
    std::vector< Instantiator * > pp_inst;
564
10072
    std::map< Instantiator *, Node > pp_inst_to_var;
565
23423
    for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){
566
55161
      if (ita->second->needsPostProcessInstantiationForVariable(
567
36774
              this, sf, ita->first, d_effort))
568
      {
569
198
        needsPostprocess = true;
570
198
        pp_inst_to_var[ ita->second ] = ita->first;
571
      }
572
    }
573
5036
    if( needsPostprocess ){
574
      //must make copy so that backtracking reverts sf
575
2712
      SolvedForm sf_tmp = sf;
576
1356
      bool postProcessSuccess = true;
577
1518
      for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){
578
594
        if (!itp->first->postProcessInstantiationForVariable(
579
396
                this, sf_tmp, itp->second, d_effort))
580
        {
581
36
          postProcessSuccess = false;
582
36
          break;
583
        }
584
      }
585
1356
      if( postProcessSuccess ){
586
1320
        return doAddInstantiation(sf_tmp.d_vars, sf_tmp.d_subs);
587
      }else{
588
36
        return false;
589
      }
590
    }else{
591
3680
      return doAddInstantiation(sf.d_vars, sf.d_subs);
592
    }
593
  }else{
594
18451
    bool is_sv = false;
595
36902
    Node pv;
596
18451
    if( d_stack_vars.empty() ){
597
18421
      pv = d_vars[i];
598
    }else{
599
30
      pv = d_stack_vars.back();
600
30
      is_sv = true;
601
30
      d_stack_vars.pop_back();
602
    }
603
18451
    activateInstantiationVariable(pv, i);
604
605
    //get the instantiator object
606
18451
    Assert(d_instantiator.find(pv) != d_instantiator.end());
607
18451
    Instantiator* vinst = d_instantiator[pv];
608
18451
    Assert(vinst != NULL);
609
18451
    d_active_instantiators[pv] = vinst;
610
18451
    vinst->reset(this, sf, pv, d_effort);
611
    // if d_effort is full, we must choose at least one model value
612
18451
    if ((i + 1) < d_vars.size() || d_effort != CEG_INST_EFFORT_FULL)
613
    {
614
      // First, try to construct an instantiation term for pv based on
615
      // equality and theory-specific instantiation techniques.
616
17324
      if (constructInstantiation(sf, vinst, pv))
617
      {
618
9973
        return true;
619
      }
620
    }
621
    // If the above call fails, resort to using value in model. We do so if:
622
    // - we have yet to try an instantiation this round (or we are trying
623
    //   multiple instantiations, indicated by options::cegqiMultiInst),
624
    // - the instantiator uses model values at this effort or
625
    //   if we are solving for a subfield of a datatype (is_sv), and
626
    // - the instantiator allows model values.
627
25354
    if ((options::cegqiMultiInst() || !hasTriedInstantiation(pv))
628
14498
        && (vinst->useModelValue(this, sf, pv, d_effort) || is_sv)
629
22792
        && vinst->allowModelValue(this, sf, pv, d_effort))
630
    {
631
6972
      Node mv = getModelValue( pv );
632
6972
      TermProperties pv_prop_m;
633
5836
      Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
634
5836
      d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
635
5836
      CegInstEffort prev = d_effort;
636
5836
      if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
637
      {
638
        // update the effort level to indicate we have used a model value
639
1555
        d_effort = CEG_INST_EFFORT_STANDARD_MV;
640
      }
641
5836
      if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
642
      {
643
4700
        return true;
644
      }
645
1136
      d_effort = prev;
646
    }
647
648
3778
    Trace("cegqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl;
649
3778
    if (is_sv)
650
    {
651
      d_stack_vars.push_back( pv );
652
    }
653
3778
    d_active_instantiators.erase( pv );
654
3778
    deactivateInstantiationVariable(pv);
655
3778
    return false;
656
  }
657
}
658
659
17324
bool CegInstantiator::constructInstantiation(SolvedForm& sf,
660
                                             Instantiator* vinst,
661
                                             Node pv)
662
{
663
34648
  TypeNode pvtn = pv.getType();
664
34648
  TypeNode pvtnb = pvtn.getBaseType();
665
34648
  Node pvr = pv;
666
17324
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
667
17324
  if (ee->hasTerm(pv))
668
  {
669
12071
    pvr = ee->getRepresentative(pv);
670
  }
671
34648
  Trace("cegqi-inst-debug") << "[Find instantiation for " << pv
672
17324
                           << "], rep=" << pvr << ", instantiator is "
673
17324
                           << vinst->identify() << std::endl;
674
34648
  Node pv_value;
675
17324
  if (options::cegqiModel())
676
  {
677
17324
    pv_value = getModelValue(pv);
678
17324
    Trace("cegqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl;
679
  }
680
681
  //[1] easy case : pv is in the equivalence class as another term not
682
  // containing pv
683
17324
  if (vinst->hasProcessEqualTerm(this, sf, pv, d_effort))
684
  {
685
68
    Trace("cegqi-inst-debug")
686
34
        << "[1] try based on equivalence class." << std::endl;
687
34
    d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
688
34
    std::map<Node, std::vector<Node> >::iterator it_eqc = d_curr_eqc.find(pvr);
689
34
    if (it_eqc != d_curr_eqc.end())
690
    {
691
      // std::vector< Node > eq_candidates;
692
68
      Trace("cegqi-inst-debug2")
693
34
          << "...eqc has size " << it_eqc->second.size() << std::endl;
694
76
      for (const Node& n : it_eqc->second)
695
      {
696
53
        if (n != pv)
697
        {
698
56
          Trace("cegqi-inst-debug")
699
28
              << "...try based on equal term " << n << std::endl;
700
          // must be an eligible term
701
28
          if (isEligible(n))
702
          {
703
45
            Node ns;
704
            // coefficient of pv in the equality we solve (null is 1)
705
45
            TermProperties pv_prop;
706
28
            bool proc = false;
707
28
            if (!d_prog_var[n].empty())
708
            {
709
17
              ns = applySubstitution(pvtn, n, sf, pv_prop, false);
710
17
              if (!ns.isNull())
711
              {
712
17
                computeProgVars(ns);
713
                // substituted version must be new and cannot contain pv
714
17
                proc = d_prog_var[ns].find(pv) == d_prog_var[ns].end();
715
              }
716
            }
717
            else
718
            {
719
11
              ns = n;
720
11
              proc = true;
721
            }
722
28
            if (proc)
723
            {
724
11
              if (vinst->processEqualTerm(this, sf, pv, pv_prop, ns, d_effort))
725
              {
726
11
                return true;
727
              }
728
              else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
729
              {
730
                return false;
731
              }
732
              // Do not consider more than one equal term,
733
              // this helps non-monotonic strategies that may encounter
734
              // duplicate instantiations.
735
              break;
736
            }
737
          }
738
        }
739
      }
740
23
      if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
741
      {
742
15
        return true;
743
      }
744
8
      else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
745
      {
746
        return false;
747
      }
748
    }
749
    else
750
    {
751
      Trace("cegqi-inst-debug2") << "...eqc not found." << std::endl;
752
    }
753
  }
754
755
  //[2] : we can solve an equality for pv
756
  /// iterate over equivalence classes to find cases where we can solve for
757
  /// the variable
758
17298
  if (vinst->hasProcessEquality(this, sf, pv, d_effort))
759
  {
760
23030
    Trace("cegqi-inst-debug")
761
11515
        << "[2] try based on solving equalities." << std::endl;
762
11515
    d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
763
11515
    std::vector<Node>& cteqc = d_curr_type_eqc[pvtnb];
764
765
173380
    for (const Node& r : cteqc)
766
    {
767
166812
      std::map<Node, std::vector<Node> >::iterator it_reqc = d_curr_eqc.find(r);
768
328677
      std::vector<Node> lhs;
769
328677
      std::vector<bool> lhs_v;
770
328677
      std::vector<TermProperties> lhs_prop;
771
166812
      Assert(it_reqc != d_curr_eqc.end());
772
575623
      for (const Node& n : it_reqc->second)
773
      {
774
413758
        Trace("cegqi-inst-debug2") << "...look at term " << n << std::endl;
775
        // must be an eligible term
776
413758
        if (isEligible(n))
777
        {
778
511961
          Node ns;
779
511961
          TermProperties pv_prop;
780
258454
          if (!d_prog_var[n].empty())
781
          {
782
214149
            ns = applySubstitution(pvtn, n, sf, pv_prop);
783
214149
            if (!ns.isNull())
784
            {
785
214133
              computeProgVars(ns);
786
            }
787
          }
788
          else
789
          {
790
44305
            ns = n;
791
          }
792
258454
          if (!ns.isNull())
793
          {
794
258438
            bool hasVar = d_prog_var[ns].find(pv) != d_prog_var[ns].end();
795
516876
            Trace("cegqi-inst-debug2") << "... " << ns << " has var " << pv
796
258438
                                      << " : " << hasVar << std::endl;
797
511929
            std::vector<TermProperties> term_props;
798
511929
            std::vector<Node> terms;
799
258438
            term_props.push_back(pv_prop);
800
258438
            terms.push_back(ns);
801
513853
            for (unsigned j = 0, size = lhs.size(); j < size; j++)
802
            {
803
              // if this term or the another has pv in it, try to solve for it
804
260362
              if (hasVar || lhs_v[j])
805
              {
806
30532
                Trace("cegqi-inst-debug") << "......try based on equality "
807
15266
                                         << lhs[j] << " = " << ns << std::endl;
808
15266
                term_props.push_back(lhs_prop[j]);
809
15266
                terms.push_back(lhs[j]);
810
15266
                if (vinst->processEquality(
811
15266
                        this, sf, pv, term_props, terms, d_effort))
812
                {
813
4143
                  return true;
814
                }
815
11123
                else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
816
                {
817
804
                  return false;
818
                }
819
10319
                term_props.pop_back();
820
10319
                terms.pop_back();
821
              }
822
            }
823
253491
            lhs.push_back(ns);
824
253491
            lhs_v.push_back(hasVar);
825
253491
            lhs_prop.push_back(pv_prop);
826
          }
827
          else
828
          {
829
32
            Trace("cegqi-inst-debug2")
830
16
                << "... term " << n << " is ineligible after substitution."
831
16
                << std::endl;
832
          }
833
        }
834
        else
835
        {
836
310608
          Trace("cegqi-inst-debug2")
837
155304
              << "... term " << n << " is ineligible." << std::endl;
838
        }
839
      }
840
    }
841
  }
842
  //[3] directly look at assertions
843
12351
  if (!vinst->hasProcessAssertion(this, sf, pv, d_effort))
844
  {
845
2957
    return false;
846
  }
847
9394
  Trace("cegqi-inst-debug") << "[3] try based on assertions." << std::endl;
848
9394
  d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
849
18788
  std::unordered_set<Node> lits;
850
28182
  for (unsigned r = 0; r < 2; r++)
851
  {
852
18788
    TheoryId tid = r == 0 ? Theory::theoryOf(pvtn) : THEORY_UF;
853
18788
    Trace("cegqi-inst-debug2") << "  look at assertions of " << tid << std::endl;
854
    std::map<TheoryId, std::vector<Node> >::iterator ita =
855
18788
        d_curr_asserts.find(tid);
856
18788
    if (ita != d_curr_asserts.end())
857
    {
858
163491
      for (const Node& lit : ita->second)
859
      {
860
150694
        if (lits.find(lit) == lits.end())
861
        {
862
145478
          lits.insert(lit);
863
290956
          Node plit;
864
290956
          if (options::cegqiRepeatLit() || !isSolvedAssertion(lit))
865
          {
866
144269
            plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort);
867
          }
868
145478
          if (!plit.isNull())
869
          {
870
142931
            Trace("cegqi-inst-debug2") << "  look at " << lit;
871
142931
            if (plit != lit)
872
            {
873
2971
              Trace("cegqi-inst-debug2") << "...processed to : " << plit;
874
            }
875
142931
            Trace("cegqi-inst-debug2") << std::endl;
876
            // apply substitutions
877
285862
            Node slit = applySubstitutionToLiteral(plit, sf);
878
142931
            if (!slit.isNull())
879
            {
880
              // check if contains pv
881
142834
              if (hasVariable(slit, pv))
882
              {
883
21766
                Trace("cegqi-inst-debug")
884
10883
                    << "...try based on literal " << slit << "," << std::endl;
885
10883
                Trace("cegqi-inst-debug") << "...from " << lit << std::endl;
886
10883
                if (vinst->processAssertion(this, sf, pv, slit, lit, d_effort))
887
                {
888
                  return true;
889
                }
890
10883
                else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
891
                {
892
                  return false;
893
                }
894
              }
895
            }
896
          }
897
        }
898
      }
899
    }
900
  }
901
9394
  if (vinst->processAssertions(this, sf, pv, d_effort))
902
  {
903
5804
    return true;
904
  }
905
3590
  return false;
906
}
907
908
30
void CegInstantiator::pushStackVariable( Node v ) {
909
30
  d_stack_vars.push_back( v );
910
30
}
911
912
void CegInstantiator::popStackVariable() {
913
  Assert(!d_stack_vars.empty());
914
  d_stack_vars.pop_back();
915
}
916
917
18391
bool CegInstantiator::constructInstantiationInc(Node pv,
918
                                                Node n,
919
                                                TermProperties& pv_prop,
920
                                                SolvedForm& sf,
921
                                                bool revertOnSuccess)
922
{
923
36782
  Node cnode = pv_prop.getCacheNode();
924
18391
  if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
925
18387
    d_curr_subs_proc[pv][n][cnode] = true;
926
18387
    if( Trace.isOn("cegqi-inst-debug") ){
927
      for( unsigned j=0; j<sf.d_subs.size(); j++ ){
928
        Trace("cegqi-inst-debug") << " ";
929
      }
930
      Trace("cegqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv]
931
                         << ") ";
932
      Node mod_pv = pv_prop.getModifiedTerm( pv );
933
      Trace("cegqi-inst-debug") << mod_pv << " -> " << n << std::endl;
934
      Assert(n.getType().isSubtypeOf(pv.getType()));
935
    }
936
    //must ensure variables have been computed for n
937
18387
    computeProgVars( n );
938
18387
    Assert(d_inelig.find(n) == d_inelig.end());
939
940
    //substitute into previous substitutions, when applicable
941
36774
    std::vector< Node > a_var;
942
18387
    a_var.push_back( pv );
943
36774
    std::vector< Node > a_subs;
944
18387
    a_subs.push_back( n );
945
36774
    std::vector< TermProperties > a_prop;
946
18387
    a_prop.push_back( pv_prop );
947
36774
    std::vector< Node > a_non_basic;
948
18387
    if( !pv_prop.isBasic() ){
949
169
      a_non_basic.push_back( pv );
950
    }
951
18387
    bool success = true;
952
36774
    std::map< int, Node > prev_subs;
953
36774
    std::map< int, TermProperties > prev_prop;
954
36774
    std::map< int, Node > prev_sym_subs;
955
36774
    std::vector< Node > new_non_basic;
956
18387
    Trace("cegqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl;
957
241940
    for( unsigned j=0; j<sf.d_subs.size(); j++ ){
958
223553
      Trace("cegqi-inst-debug2") << "  Apply for " << sf.d_subs[j]  << std::endl;
959
223553
      Assert(d_prog_var.find(sf.d_subs[j]) != d_prog_var.end());
960
223553
      if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
961
10737
        prev_subs[j] = sf.d_subs[j];
962
21474
        TNode tv = pv;
963
21474
        TNode ts = n;
964
21474
        TermProperties a_pv_prop;
965
21474
        Node new_subs = applySubstitution( sf.d_vars[j].getType(), sf.d_subs[j], a_var, a_subs, a_prop, a_non_basic, a_pv_prop, true );
966
10737
        if( !new_subs.isNull() ){
967
10737
          sf.d_subs[j] = new_subs;
968
          // the substitution apply to this term resulted in a non-basic substitution relationship
969
10737
          if( !a_pv_prop.isBasic() ){
970
            // we are processing:
971
            //    sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n }
972
973
            // based on the above substitution, we have:
974
            //   x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n }
975
            // is equivalent to
976
            //   a_pv_prop.getModifiedTerm( x ) = new_subs
977
978
            // thus we must compose substitutions:
979
            //   a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs
980
981
51
            prev_prop[j] = sf.d_props[j];
982
51
            bool prev_basic = sf.d_props[j].isBasic();
983
984
            // now compose the property
985
51
            sf.d_props[j].composeProperty( a_pv_prop );
986
987
            // if previously was basic, becomes non-basic
988
51
            if( prev_basic && !sf.d_props[j].isBasic() ){
989
29
              Assert(std::find(sf.d_non_basic.begin(),
990
                               sf.d_non_basic.end(),
991
                               sf.d_vars[j])
992
                     == sf.d_non_basic.end());
993
29
              new_non_basic.push_back( sf.d_vars[j] );
994
29
              sf.d_non_basic.push_back( sf.d_vars[j] );
995
            }
996
          }
997
10737
          if( sf.d_subs[j]!=prev_subs[j] ){
998
10737
            computeProgVars( sf.d_subs[j] );
999
10737
            Assert(d_inelig.find(sf.d_subs[j]) == d_inelig.end());
1000
          }
1001
10737
          Trace("cegqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl;
1002
        }else{
1003
          Trace("cegqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl;
1004
          success = false;
1005
          break;
1006
        }
1007
      }else{
1008
212816
        Trace("cegqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl;
1009
      }
1010
    }
1011
18387
    if( success ){
1012
18387
      Trace("cegqi-inst-debug2") << "Adding to vectors..." << std::endl;
1013
18387
      sf.push_back( pv, n, pv_prop );
1014
18387
      Trace("cegqi-inst-debug2") << "Recurse..." << std::endl;
1015
18387
      unsigned i = d_curr_index[pv];
1016
18387
      success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
1017
18387
      if (!success || revertOnSuccess)
1018
      {
1019
3714
        Trace("cegqi-inst-debug2") << "Removing from vectors..." << std::endl;
1020
3714
        sf.pop_back( pv, n, pv_prop );
1021
      }
1022
    }
1023
18387
    if (success && !revertOnSuccess)
1024
    {
1025
14673
      return true;
1026
    }else{
1027
3714
      Trace("cegqi-inst-debug2") << "Revert substitutions..." << std::endl;
1028
      //revert substitution information
1029
5033
      for (std::map<int, Node>::iterator it = prev_subs.begin();
1030
5033
           it != prev_subs.end();
1031
           ++it)
1032
      {
1033
1319
        sf.d_subs[it->first] = it->second;
1034
      }
1035
3714
      for (std::map<int, TermProperties>::iterator it = prev_prop.begin();
1036
3714
           it != prev_prop.end();
1037
           ++it)
1038
      {
1039
        sf.d_props[it->first] = it->second;
1040
      }
1041
3714
      for( unsigned i=0; i<new_non_basic.size(); i++ ){
1042
        sf.d_non_basic.pop_back();
1043
      }
1044
3714
      return success;
1045
    }
1046
  }else{
1047
    //already tried this substitution
1048
4
    return false;
1049
  }
1050
}
1051
1052
5000
bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars,
1053
                                         std::vector<Node>& subs)
1054
{
1055
5000
  if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
1056
  {
1057
1320
    Trace("cegqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
1058
2640
    std::map< Node, Node > subs_map;
1059
15053
    for( unsigned i=0; i<subs.size(); i++ ){
1060
13733
      subs_map[vars[i]] = subs[i];
1061
    }
1062
1320
    subs.clear();
1063
9652
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1064
    {
1065
8332
      std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
1066
8332
      Assert(it != subs_map.end());
1067
16664
      Node n = it->second;
1068
16664
      Trace("cegqi-inst-debug") << "  " << d_input_vars[i] << " -> " << n
1069
8332
                               << std::endl;
1070
8332
      Assert(n.getType().isSubtypeOf(d_input_vars[i].getType()));
1071
8332
      subs.push_back( n );
1072
    }
1073
  }
1074
5000
  if (Trace.isOn("cegqi-inst"))
1075
  {
1076
    Trace("cegqi-inst") << "Ceg Instantiator produced : " << std::endl;
1077
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1078
    {
1079
      Node v = d_input_vars[i];
1080
      Trace("cegqi-inst") << i << " (" << d_curr_iphase[v] << ") : "
1081
                         << v << " -> " << subs[i] << std::endl;
1082
      Assert(subs[i].getType().isSubtypeOf(v.getType()));
1083
    }
1084
  }
1085
5000
  Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl;
1086
5000
  return d_parent->doAddInstantiation(subs);
1087
}
1088
1089
56496
bool CegInstantiator::isEligibleForInstantiation(Node n) const
1090
{
1091
56496
  if (n.getKind() != INST_CONSTANT && n.getKind() != SKOLEM)
1092
  {
1093
52950
    return true;
1094
  }
1095
3546
  if (n.getAttribute(VirtualTermSkolemAttribute()))
1096
  {
1097
    // virtual terms are allowed
1098
81
    return true;
1099
  }
1100
  // only legal if current quantified formula contains n
1101
3465
  return expr::hasSubterm(d_quant, n);
1102
}
1103
1104
368392
bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
1105
368392
  Assert(d_prog_var.find(n) != d_prog_var.end());
1106
368392
  if( !non_basic.empty() ){
1107
8973
    for (std::unordered_set<Node>::iterator it = d_prog_var[n].begin();
1108
8973
         it != d_prog_var[n].end();
1109
         ++it)
1110
    {
1111
6428
      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
1112
      {
1113
1583
        return false;
1114
      }
1115
    }
1116
  }
1117
366809
  return true;
1118
}
1119
1120
225461
Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop,
1121
                                         std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) {
1122
225461
  n = Rewriter::rewrite(n);
1123
225461
  computeProgVars( n );
1124
225461
  bool is_basic = canApplyBasicSubstitution( n, non_basic );
1125
225461
  if( Trace.isOn("sygus-si-apply-subs-debug") ){
1126
    Trace("sygus-si-apply-subs-debug") << "is_basic = " << is_basic << "  " << tn << std::endl;
1127
    for( unsigned i=0; i<subs.size(); i++ ){
1128
      Trace("sygus-si-apply-subs-debug") << "  " << vars[i] << " -> " << subs[i] << "   types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl;
1129
      Assert(subs[i].getType().isSubtypeOf(vars[i].getType()));
1130
    }
1131
  }
1132
225461
  Node nret;
1133
225461
  if( is_basic ){
1134
224533
    nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1135
  }else{
1136
928
    if( !tn.isInteger() ){
1137
      //can do basic substitution instead with divisions
1138
1126
      std::vector< Node > nvars;
1139
1126
      std::vector< Node > nsubs;
1140
4734
      for( unsigned i=0; i<vars.size(); i++ ){
1141
4171
        if( !prop[i].d_coeff.isNull() ){
1142
2013
          Assert(vars[i].getType().isInteger());
1143
2013
          Assert(prop[i].d_coeff.isConst());
1144
4026
          Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
1145
2013
          nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn );
1146
2013
          nn =  Rewriter::rewrite( nn );
1147
2013
          nsubs.push_back( nn );
1148
        }else{
1149
2158
          nsubs.push_back( subs[i] );
1150
        }
1151
      }
1152
563
      nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() );
1153
365
    }else if( try_coeff ){
1154
      //must convert to monomial representation
1155
730
      std::map< Node, Node > msum;
1156
365
      if (ArithMSum::getMonomialSum(n, msum))
1157
      {
1158
730
        std::map< Node, Node > msum_coeff;
1159
730
        std::map< Node, Node > msum_term;
1160
1676
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1161
          //check if in substitution
1162
1311
          std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first );
1163
1311
          if( its!=vars.end() ){
1164
671
            int index = its-vars.begin();
1165
671
            if( prop[index].d_coeff.isNull() ){
1166
              //apply substitution
1167
288
              msum_term[it->first] = subs[index];
1168
            }else{
1169
              //apply substitution, multiply to ensure no divisibility conflict
1170
383
              msum_term[it->first] = subs[index];
1171
              //relative coefficient
1172
383
              msum_coeff[it->first] = prop[index].d_coeff;
1173
383
              if( pv_prop.d_coeff.isNull() ){
1174
349
                pv_prop.d_coeff = prop[index].d_coeff;
1175
              }else{
1176
34
                pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff );
1177
              }
1178
            }
1179
          }else{
1180
640
            msum_term[it->first] = it->first;
1181
          }
1182
        }
1183
        //make sum with normalized coefficient
1184
365
        if( !pv_prop.d_coeff.isNull() ){
1185
349
          pv_prop.d_coeff = Rewriter::rewrite( pv_prop.d_coeff );
1186
349
          Trace("sygus-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl;
1187
698
          std::vector< Node > children;
1188
1628
          for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1189
2558
            Node c_coeff;
1190
1279
            if( !msum_coeff[it->first].isNull() ){
1191
383
              c_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkConst( pv_prop.d_coeff.getConst<Rational>() / msum_coeff[it->first].getConst<Rational>() ) );
1192
            }else{
1193
896
              c_coeff = pv_prop.d_coeff;
1194
            }
1195
1279
            if( !it->second.isNull() ){
1196
979
              c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
1197
            }
1198
1279
            Assert(!c_coeff.isNull());
1199
2558
            Node c;
1200
1279
            if( msum_term[it->first].isNull() ){
1201
57
              c = c_coeff;
1202
            }else{
1203
1222
              c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
1204
            }
1205
1279
            children.push_back( c );
1206
1279
            Trace("sygus-si-apply-subs-debug") << "Add child : " << c << std::endl;
1207
          }
1208
698
          Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children );
1209
349
          nretc = Rewriter::rewrite( nretc );
1210
          //ensure that nret does not contain vars
1211
349
          if (!expr::hasSubterm(nretc, vars))
1212
          {
1213
            //result is ( nret / pv_prop.d_coeff )
1214
349
            nret = nretc;
1215
          }else{
1216
            Trace("sygus-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl;
1217
          }
1218
        }else{
1219
          //implies that we have a monomial that has a free variable
1220
16
          Trace("sygus-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl;
1221
        }
1222
      }else{
1223
        Trace("sygus-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl;
1224
      }
1225
    }
1226
  }
1227
225461
  if( n!=nret && !nret.isNull() ){
1228
110245
    nret = Rewriter::rewrite( nret );
1229
  }
1230
225461
  return nret;
1231
}
1232
1233
142931
Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs,
1234
                                                  std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) {
1235
142931
  computeProgVars( lit );
1236
142931
  bool is_basic = canApplyBasicSubstitution( lit, non_basic );
1237
142931
  Node lret;
1238
142931
  if( is_basic ){
1239
142276
   lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1240
  }else{
1241
1310
    Node atom = lit.getKind()==NOT ? lit[0] : lit;
1242
655
    bool pol = lit.getKind()!=NOT;
1243
    //arithmetic inequalities and disequalities
1244
655
    if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){
1245
558
      NodeManager* nm = NodeManager::currentNM();
1246
558
      Assert(atom.getKind() != GEQ || atom[1].isConst());
1247
1116
      Node atom_lhs;
1248
1116
      Node atom_rhs;
1249
558
      if( atom.getKind()==GEQ ){
1250
531
        atom_lhs = atom[0];
1251
531
        atom_rhs = atom[1];
1252
      }else{
1253
27
        atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]);
1254
27
        atom_lhs = Rewriter::rewrite( atom_lhs );
1255
27
        atom_rhs = nm->mkConst(Rational(0));
1256
      }
1257
      //must be an eligible term
1258
558
      if( isEligible( atom_lhs ) ){
1259
        //apply substitution to LHS of atom
1260
1116
        TermProperties atom_lhs_prop;
1261
558
        atom_lhs = applySubstitution(nm->realType(),
1262
                                     atom_lhs,
1263
                                     vars,
1264
                                     subs,
1265
                                     prop,
1266
                                     non_basic,
1267
                                     atom_lhs_prop);
1268
558
        if( !atom_lhs.isNull() ){
1269
558
          if( !atom_lhs_prop.d_coeff.isNull() ){
1270
            atom_rhs = nm->mkNode(MULT, atom_lhs_prop.d_coeff, atom_rhs);
1271
            atom_rhs = Rewriter::rewrite(atom_rhs);
1272
          }
1273
558
          lret = nm->mkNode(atom.getKind(), atom_lhs, atom_rhs);
1274
558
          if( !pol ){
1275
316
            lret = lret.negate();
1276
          }
1277
        }
1278
      }
1279
    }else{
1280
      // don't know how to apply substitution to literal
1281
    }
1282
  }
1283
142931
  if( lit!=lret && !lret.isNull() ){
1284
81735
    lret = Rewriter::rewrite( lret );
1285
  }
1286
142931
  return lret;
1287
}
1288
1289
3973
bool CegInstantiator::check() {
1290
3973
  processAssertions();
1291
5391
  for( unsigned r=0; r<2; r++ ){
1292
5100
    d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
1293
6518
    SolvedForm sf;
1294
5100
    d_stack_vars.clear();
1295
5100
    d_bound_var_index.clear();
1296
5100
    d_solved_asserts.clear();
1297
    //try to add an instantiation
1298
5100
    if (constructInstantiation(sf, 0))
1299
    {
1300
3682
      return true;
1301
    }
1302
  }
1303
291
  Trace("cegqi-engine") << "  WARNING : unable to find CEGQI single invocation instantiation." << std::endl;
1304
291
  return false;
1305
}
1306
1307
3973
void CegInstantiator::processAssertions() {
1308
7946
  Trace("cegqi-proc") << "--- Process assertions, #var = " << d_vars.size()
1309
3973
                     << std::endl;
1310
3973
  d_curr_asserts.clear();
1311
3973
  d_curr_eqc.clear();
1312
3973
  d_curr_type_eqc.clear();
1313
1314
  // must use master equality engine to avoid value instantiations
1315
3973
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
1316
1317
  //for each variable
1318
20000
  for( unsigned i=0; i<d_vars.size(); i++ ){
1319
32054
    Node pv = d_vars[i];
1320
32054
    TypeNode pvtn = pv.getType();
1321
16027
    Trace("cegqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
1322
    //collect information about eqc
1323
16027
    if( ee->hasTerm( pv ) ){
1324
22328
      Node pvr = ee->getRepresentative( pv );
1325
11164
      if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){
1326
7353
        Trace("cegqi-proc") << "Collect equivalence class " << pvr << std::endl;
1327
7353
        eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee );
1328
36265
        while( !eqc_i.isFinished() ){
1329
14456
          d_curr_eqc[pvr].push_back( *eqc_i );
1330
14456
          ++eqc_i;
1331
        }
1332
      }
1333
    }
1334
  }
1335
  //collect assertions for relevant theories
1336
3973
  const LogicInfo& logicInfo = d_qstate.getLogicInfo();
1337
12078
  for (TheoryId tid : d_tids)
1338
  {
1339
8105
    if (!logicInfo.isTheoryEnabled(tid))
1340
    {
1341
1657
      continue;
1342
    }
1343
12896
    Trace("cegqi-proc") << "Collect assertions from theory " << tid
1344
6448
                        << std::endl;
1345
6448
    d_curr_asserts[tid].clear();
1346
    // collect all assertions from theory
1347
300184
    for (context::CDList<Assertion>::const_iterator
1348
6448
             it = d_qstate.factsBegin(tid),
1349
6448
             itEnd = d_qstate.factsEnd(tid);
1350
306632
         it != itEnd;
1351
         ++it)
1352
    {
1353
600368
      Node lit = (*it).d_assertion;
1354
600368
      Node atom = lit.getKind() == NOT ? lit[0] : lit;
1355
600368
      if (d_is_nested_quant
1356
888918
          || std::find(d_ce_atoms.begin(), d_ce_atoms.end(), atom)
1357
888918
                 != d_ce_atoms.end())
1358
      {
1359
22866
        d_curr_asserts[tid].push_back(lit);
1360
22866
        Trace("cegqi-proc-debug") << "...add : " << lit << std::endl;
1361
      }
1362
      else
1363
      {
1364
554636
        Trace("cegqi-proc")
1365
277318
            << "...do not consider literal " << tid << " : " << lit
1366
277318
            << " since it is not part of CE body." << std::endl;
1367
      }
1368
    }
1369
  }
1370
  //collect equivalence classes that correspond to relevant theories
1371
3973
  Trace("cegqi-proc-debug") << "...collect typed equivalence classes" << std::endl;
1372
3973
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
1373
773957
  while( !eqcs_i.isFinished() ){
1374
769984
    Node r = *eqcs_i;
1375
769984
    TypeNode rtn = r.getType();
1376
384992
    TheoryId tid = Theory::theoryOf( rtn );
1377
    //if we care about the theory of this eqc
1378
384992
    if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){
1379
306568
      if( rtn.isInteger() || rtn.isReal() ){
1380
15532
        rtn = rtn.getBaseType();
1381
      }
1382
306568
      Trace("cegqi-proc-debug") << "...type eqc: " << r << std::endl;
1383
306568
      d_curr_type_eqc[rtn].push_back( r );
1384
306568
      if( d_curr_eqc.find( r )==d_curr_eqc.end() ){
1385
299215
        Trace("cegqi-proc") << "Collect equivalence class " << r << std::endl;
1386
299215
        Trace("cegqi-proc-debug") << "  ";
1387
299215
        eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
1388
985085
        while( !eqc_i.isFinished() ){
1389
342935
          Trace("cegqi-proc-debug") << *eqc_i << " ";
1390
342935
          d_curr_eqc[r].push_back( *eqc_i );
1391
342935
          ++eqc_i;
1392
        }
1393
299215
        Trace("cegqi-proc-debug") << std::endl;
1394
      }
1395
    }
1396
384992
    ++eqcs_i;
1397
  }
1398
1399
  //remove unecessary assertions
1400
10421
  for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
1401
12896
    std::vector< Node > akeep;
1402
29314
    for( unsigned i=0; i<it->second.size(); i++ ){
1403
45732
      Node n = it->second[i];
1404
      //must be an eligible term
1405
22866
      if( isEligible( n ) ){
1406
        //must contain at least one variable
1407
17693
        if( !d_prog_var[n].empty() ){
1408
14915
          Trace("cegqi-proc") << "...literal[" << it->first << "] : " << n << std::endl;
1409
14915
          akeep.push_back( n );
1410
        }else{
1411
2778
          Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl;
1412
        }
1413
      }else{
1414
5173
        Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl;
1415
      }
1416
    }
1417
6448
    it->second.clear();
1418
6448
    it->second.insert( it->second.end(), akeep.begin(), akeep.end() );
1419
  }
1420
1421
  //remove duplicate terms from eqc
1422
310541
  for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
1423
613136
    std::vector< Node > new_eqc;
1424
663959
    for( unsigned i=0; i<it->second.size(); i++ ){
1425
357391
      if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){
1426
357391
        new_eqc.push_back( it->second[i] );
1427
      }
1428
    }
1429
306568
    it->second.clear();
1430
306568
    it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() );
1431
  }
1432
3973
}
1433
1434
51477
Node CegInstantiator::getModelValue( Node n ) {
1435
51477
  return d_treg.getModel()->getValue(n);
1436
}
1437
1438
1230
Node CegInstantiator::getBoundVariable(TypeNode tn)
1439
{
1440
1230
  unsigned index = 0;
1441
  std::unordered_map<TypeNode, unsigned>::iterator itb =
1442
1230
      d_bound_var_index.find(tn);
1443
1230
  if (itb != d_bound_var_index.end())
1444
  {
1445
182
    index = itb->second;
1446
  }
1447
1230
  d_bound_var_index[tn] = index + 1;
1448
2250
  while (index >= d_bound_var[tn].size())
1449
  {
1450
1020
    std::stringstream ss;
1451
510
    ss << "x" << index;
1452
1020
    Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn);
1453
510
    d_bound_var[tn].push_back(x);
1454
  }
1455
1230
  return d_bound_var[tn][index];
1456
}
1457
1458
147065
bool CegInstantiator::isSolvedAssertion(Node n) const
1459
{
1460
147065
  return d_solved_asserts.find(n) != d_solved_asserts.end();
1461
}
1462
1463
3174
void CegInstantiator::markSolved(Node n, bool solved)
1464
{
1465
3174
  if (solved)
1466
  {
1467
1587
    d_solved_asserts.insert(n);
1468
  }
1469
1587
  else if (isSolvedAssertion(n))
1470
  {
1471
1587
    d_solved_asserts.erase(n);
1472
  }
1473
3174
}
1474
1475
22228
void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
1476
22228
  if( n.getKind()==FORALL ){
1477
147
    d_is_nested_quant = true;
1478
22081
  }else if( visited.find( n )==visited.end() ){
1479
20656
    visited[n] = true;
1480
20656
    if( TermUtil::isBoolConnectiveTerm( n ) ){
1481
31089
      for( unsigned i=0; i<n.getNumChildren(); i++ ){
1482
20541
        collectCeAtoms( n[i], visited );
1483
      }
1484
    }else{
1485
10108
      if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
1486
10108
        Trace("cegqi-ce-atoms") << "CE atoms : " << n << std::endl;
1487
10108
        d_ce_atoms.push_back( n );
1488
      }
1489
    }
1490
  }
1491
22228
}
1492
1493
1584
void CegInstantiator::registerCounterexampleLemma(Node lem,
1494
                                                  std::vector<Node>& ceVars,
1495
                                                  std::vector<Node>& auxLems)
1496
{
1497
1584
  Trace("cegqi-reg") << "Register counterexample lemma..." << std::endl;
1498
1584
  d_input_vars.clear();
1499
1584
  d_input_vars.insert(d_input_vars.end(), ceVars.begin(), ceVars.end());
1500
1501
  //Assert( d_vars.empty() );
1502
1584
  d_vars.clear();
1503
1584
  registerTheoryId(THEORY_UF);
1504
4633
  for (const Node& cv : ceVars)
1505
  {
1506
3049
    Trace("cegqi-reg") << "  register input variable : " << cv << std::endl;
1507
3049
    registerVariable(cv);
1508
  }
1509
1510
  // preprocess with all relevant instantiator preprocessors
1511
3168
  Trace("cegqi-debug") << "Preprocess based on theory-specific methods..."
1512
1584
                      << std::endl;
1513
3168
  std::vector<Node> pvars;
1514
1584
  pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
1515
2284
  for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp)
1516
  {
1517
700
    p.second->registerCounterexampleLemma(lem, pvars, auxLems);
1518
  }
1519
  // must register variables generated by preprocessors
1520
3168
  Trace("cegqi-debug") << "Register variables from theory-specific methods "
1521
3168
                      << d_input_vars.size() << " " << pvars.size() << " ..."
1522
1584
                      << std::endl;
1523
1792
  for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i)
1524
  {
1525
416
    Trace("cegqi-reg") << "  register inst preprocess variable : " << pvars[i]
1526
208
                       << std::endl;
1527
208
    registerVariable(pvars[i]);
1528
  }
1529
1530
  // register variables that were introduced during TheoryEngine preprocessing
1531
3168
  std::unordered_set<Node> ceSyms;
1532
1584
  expr::getSymbols(lem, ceSyms);
1533
3168
  std::unordered_set<Node> qSyms;
1534
1584
  expr::getSymbols(d_quant, qSyms);
1535
  // all variables that are in counterexample lemma but not in quantified
1536
  // formula
1537
10098
  for (const Node& ces : ceSyms)
1538
  {
1539
8514
    if (qSyms.find(ces) != qSyms.end())
1540
    {
1541
      // a free symbol of the quantified formula.
1542
10423
      continue;
1543
    }
1544
5707
    if (std::find(d_vars.begin(), d_vars.end(), ces) != d_vars.end())
1545
    {
1546
      // already processed variable
1547
3013
      continue;
1548
    }
1549
    // must avoid selector symbols, and function skolems introduced by
1550
    // theory preprocessing
1551
3592
    TypeNode ct = ces.getType();
1552
2694
    if (ct.isBoolean() || ct.isFunctionLike())
1553
    {
1554
      // Boolean variables, including the counterexample literal, don't matter
1555
      // since they are always assigned a model value.
1556
1796
      continue;
1557
    }
1558
1796
    Trace("cegqi-reg") << "  register theory preprocess variable : " << ces
1559
898
                       << std::endl;
1560
    // register the variable, which was introduced by TheoryEngine's preprocess
1561
    // method, e.g. an ITE skolem.
1562
898
    registerVariable(ces);
1563
  }
1564
1565
  // determine variable order: must do Reals before Ints
1566
1584
  Trace("cegqi-debug") << "Determine variable order..." << std::endl;
1567
1584
  if (!d_vars.empty())
1568
  {
1569
3168
    std::map<Node, unsigned> voo;
1570
1584
    bool doSort = false;
1571
3168
    std::vector<Node> vars;
1572
3168
    std::map<TypeNode, std::vector<Node> > tvars;
1573
5739
    for (unsigned i = 0, size = d_vars.size(); i < size; i++)
1574
    {
1575
4155
      voo[d_vars[i]] = i;
1576
4155
      d_var_order_index.push_back(0);
1577
8310
      TypeNode tn = d_vars[i].getType();
1578
4155
      if (tn.isInteger())
1579
      {
1580
2022
        doSort = true;
1581
2022
        tvars[tn].push_back(d_vars[i]);
1582
      }
1583
      else
1584
      {
1585
2133
        vars.push_back(d_vars[i]);
1586
      }
1587
    }
1588
1584
    if (doSort)
1589
    {
1590
535
      Trace("cegqi-debug") << "Sort variables based on ordering." << std::endl;
1591
1070
      for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
1592
      {
1593
535
        vars.insert(vars.end(), vs.second.begin(), vs.second.end());
1594
      }
1595
1596
535
      Trace("cegqi-debug") << "Consider variables in this order : " << std::endl;
1597
2760
      for (unsigned i = 0; i < vars.size(); i++)
1598
      {
1599
2225
        d_var_order_index[voo[vars[i]]] = i;
1600
4450
        Trace("cegqi-debug") << "  " << vars[i] << " : " << vars[i].getType()
1601
2225
                            << ", index was : " << voo[vars[i]] << std::endl;
1602
2225
        d_vars[i] = vars[i];
1603
      }
1604
535
      Trace("cegqi-debug") << std::endl;
1605
    }
1606
    else
1607
    {
1608
1049
      d_var_order_index.clear();
1609
    }
1610
  }
1611
1612
  // collect atoms from all lemmas: we will only solve for literals coming from
1613
  // the original body
1614
1584
  d_is_nested_quant = false;
1615
3168
  std::map< Node, bool > visited;
1616
1584
  collectCeAtoms(lem, visited);
1617
1687
  for (const Node& alem : auxLems)
1618
  {
1619
103
    collectCeAtoms(alem, visited);
1620
  }
1621
1584
}
1622
1623
2922
Instantiator::Instantiator(TypeNode tn) : d_type(tn)
1624
{
1625
2922
  d_closed_enum_type = tn.isClosedEnumerable();
1626
2922
}
1627
1628
11
bool Instantiator::processEqualTerm(CegInstantiator* ci,
1629
                                    SolvedForm& sf,
1630
                                    Node pv,
1631
                                    TermProperties& pv_prop,
1632
                                    Node n,
1633
                                    CegInstEffort effort)
1634
{
1635
11
  pv_prop.d_type = CEG_TT_EQUAL;
1636
11
  return ci->constructInstantiationInc(pv, n, pv_prop, sf);
1637
}
1638
1639
}  // namespace quantifiers
1640
}  // namespace theory
1641
173213
}  // namespace cvc5