GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/ceg_instantiator.cpp Lines: 816 891 91.6 %
Date: 2021-08-16 Branches: 1655 3332 49.7 %

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
338
CegTermType mkStrictCTT(CegTermType c)
43
{
44
338
  Assert(!isStrictCTT(c));
45
338
  if (c == CEG_TT_LOWER)
46
  {
47
226
    return CEG_TT_LOWER_STRICT;
48
  }
49
112
  else if (c == CEG_TT_UPPER)
50
  {
51
112
    return CEG_TT_UPPER_STRICT;
52
  }
53
  return c;
54
}
55
56
3106
CegTermType mkNegateCTT(CegTermType c)
57
{
58
3106
  if (c == CEG_TT_LOWER)
59
  {
60
880
    return CEG_TT_UPPER;
61
  }
62
2226
  else if (c == CEG_TT_UPPER)
63
  {
64
2226
    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
338
bool isStrictCTT(CegTermType c)
77
{
78
338
  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
16972
bool isUpperBoundCTT(CegTermType c)
85
{
86
16972
  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
46
void TermProperties::composeProperty(TermProperties& p)
129
{
130
46
  if (p.d_coeff.isNull())
131
  {
132
    return;
133
  }
134
46
  if (d_coeff.isNull())
135
  {
136
30
    d_coeff = p.d_coeff;
137
  }
138
  else
139
  {
140
16
    d_coeff = NodeManager::currentNM()->mkNode(MULT, d_coeff, p.d_coeff);
141
16
    d_coeff = Rewriter::rewrite(d_coeff);
142
  }
143
}
144
145
// push the substitution pv_prop.getModifiedTerm(pv) -> n
146
40937
void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop)
147
{
148
40937
  d_vars.push_back(pv);
149
40937
  d_subs.push_back(n);
150
40937
  d_props.push_back(pv_prop);
151
40937
  if (pv_prop.isBasic())
152
  {
153
40728
    return;
154
  }
155
209
  d_non_basic.push_back(pv);
156
  // update theta value
157
418
  Node new_theta = getTheta();
158
209
  if (new_theta.isNull())
159
  {
160
140
    new_theta = pv_prop.d_coeff;
161
  }
162
  else
163
  {
164
69
    new_theta =
165
138
        NodeManager::currentNM()->mkNode(MULT, new_theta, pv_prop.d_coeff);
166
69
    new_theta = Rewriter::rewrite(new_theta);
167
  }
168
209
  d_theta.push_back(new_theta);
169
}
170
// pop the substitution pv_prop.getModifiedTerm(pv) -> n
171
4406
void SolvedForm::pop_back(Node pv, Node n, TermProperties& pv_prop)
172
{
173
4406
  d_vars.pop_back();
174
4406
  d_subs.pop_back();
175
4406
  d_props.pop_back();
176
4406
  if (pv_prop.isBasic())
177
  {
178
4361
    return;
179
  }
180
45
  d_non_basic.pop_back();
181
  // update theta value
182
45
  d_theta.pop_back();
183
}
184
185
1611
CegInstantiator::CegInstantiator(Node q,
186
                                 QuantifiersState& qs,
187
                                 TermRegistry& tr,
188
1611
                                 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
1611
      d_effort(CEG_INST_EFFORT_NONE)
195
{
196
1611
}
197
198
4833
CegInstantiator::~CegInstantiator() {
199
4626
  for (std::pair<Node, Instantiator*> inst : d_instantiator)
200
  {
201
3015
    delete inst.second;
202
  }
203
2328
  for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
204
  {
205
717
    delete instp.second;
206
  }
207
3222
}
208
209
3319769
void CegInstantiator::computeProgVars( Node n ){
210
3319769
  if( d_prog_var.find( n )==d_prog_var.end() ){
211
57369
    d_prog_var[n].clear();
212
57369
    if (n.getKind() == kind::WITNESS)
213
    {
214
580
      Assert(d_prog_var.find(n[0][0]) == d_prog_var.end());
215
580
      d_prog_var[n[0][0]].clear();
216
    }
217
57369
    if (d_vars_set.find(n) != d_vars_set.end())
218
    {
219
2714
      d_prog_var[n].insert(n);
220
    }
221
54655
    else if (!isEligibleForInstantiation(n))
222
    {
223
2838
      d_inelig.insert(n);
224
2838
      return;
225
    }
226
132684
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
227
78153
      computeProgVars( n[i] );
228
78153
      if( d_inelig.find( n[i] )!=d_inelig.end() ){
229
11755
        d_inelig.insert(n);
230
      }
231
      // all variables in child are contained in this
232
78153
      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
109062
    if (n.getKind() == APPLY_SELECTOR_TOTAL
236
109062
        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
237
    {
238
32
      d_prog_var[n].insert(n);
239
    }
240
54531
    if (n.getKind() == kind::WITNESS)
241
    {
242
580
      d_prog_var.erase(n[0][0]);
243
    }
244
  }
245
}
246
247
930189
bool CegInstantiator::isEligible( Node n ) {
248
  //compute d_subs_fv, which program variables are contained in n, and determines if eligible
249
930189
  computeProgVars( n );
250
930189
  return d_inelig.find( n )==d_inelig.end();
251
}
252
253
48471
CegHandledStatus CegInstantiator::isCbqiKind(Kind k)
254
{
255
121902
  if (quantifiers::TermUtil::isBoolConnective(k) || k == PLUS || k == GEQ
256
13675
      || k == EQUAL || k == MULT || k == NONLINEAR_MULT || k == DIVISION
257
8395
      || k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL
258
8264
      || k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == TO_INTEGER
259
56636
      || k == IS_INTEGER)
260
  {
261
40310
    return CEG_HANDLED;
262
  }
263
264
  // CBQI typically works for satisfaction-complete theories
265
8161
  TheoryId t = kindToTheoryId(k);
266
8161
  if (t == THEORY_BV || t == THEORY_FP || t == THEORY_DATATYPES
267
5551
      || t == THEORY_BOOL)
268
  {
269
2610
    return CEG_HANDLED;
270
  }
271
5551
  return CEG_UNHANDLED;
272
}
273
274
7194
CegHandledStatus CegInstantiator::isCbqiTerm(Node n)
275
{
276
7194
  CegHandledStatus ret = CEG_HANDLED;
277
14388
  std::unordered_set<TNode> visited;
278
14388
  std::vector<TNode> visit;
279
14388
  TNode cur;
280
7194
  visit.push_back(n);
281
88413
  do
282
  {
283
95607
    cur = visit.back();
284
95607
    visit.pop_back();
285
95607
    if (visited.find(cur) == visited.end())
286
    {
287
79205
      visited.insert(cur);
288
79205
      if (cur.getKind() != BOUND_VARIABLE && TermUtil::hasBoundVarAttr(cur))
289
      {
290
55984
        if (cur.getKind() == FORALL || cur.getKind() == WITNESS)
291
        {
292
7513
          visit.push_back(cur[1]);
293
        }
294
        else
295
        {
296
48471
          CegHandledStatus curr = isCbqiKind(cur.getKind());
297
48471
          if (curr < ret)
298
          {
299
5551
            ret = curr;
300
11102
            Trace("cegqi-debug2") << "Non-cbqi kind : " << cur.getKind()
301
5551
                                 << " in " << n << std::endl;
302
5551
            if (curr == CEG_UNHANDLED)
303
            {
304
5551
              return CEG_UNHANDLED;
305
            }
306
          }
307
135176
          for (const Node& nc : cur)
308
          {
309
92256
            visit.push_back(nc);
310
          }
311
        }
312
      }
313
    }
314
90056
  } while (!visit.empty());
315
1643
  return ret;
316
}
317
318
23658
CegHandledStatus CegInstantiator::isCbqiSort(TypeNode tn)
319
{
320
47316
  std::map<TypeNode, CegHandledStatus> visited;
321
47316
  return isCbqiSort(tn, visited);
322
}
323
324
28484
CegHandledStatus CegInstantiator::isCbqiSort(
325
    TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited)
326
{
327
28484
  std::map<TypeNode, CegHandledStatus>::iterator itv = visited.find(tn);
328
28484
  if (itv != visited.end())
329
  {
330
2837
    return itv->second;
331
  }
332
25647
  CegHandledStatus ret = CEG_UNHANDLED;
333
67128
  if (tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector()
334
39273
      || tn.isFloatingPoint())
335
  {
336
12034
    ret = CEG_HANDLED;
337
  }
338
13613
  else if (tn.isDatatype())
339
  {
340
    // recursive calls to this datatype are handlable
341
2139
    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
2139
    ret = CEG_HANDLED;
345
2139
    const DType& dt = tn.getDType();
346
4500
    for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
347
    {
348
      // get the constructor type
349
6101
      TypeNode consType;
350
3740
      if (dt.isParametric())
351
      {
352
        // if parametric, must instantiate the argument types
353
32
        consType = dt[i].getSpecializedConstructorType(tn);
354
      }
355
      else
356
      {
357
3708
        consType = dt[i].getConstructor().getType();
358
      }
359
7187
      for (const TypeNode& crange : consType)
360
      {
361
4826
        CegHandledStatus cret = isCbqiSort(crange, visited);
362
4826
        if (cret == CEG_UNHANDLED)
363
        {
364
2758
          Trace("cegqi-debug2")
365
1379
              << "Non-cbqi sort : " << tn << " due to " << crange << std::endl;
366
1379
          visited[tn] = CEG_UNHANDLED;
367
1379
          return CEG_UNHANDLED;
368
        }
369
3447
        else if (cret < ret)
370
        {
371
          ret = cret;
372
        }
373
      }
374
    }
375
  }
376
  // sets, arrays, functions and others are not supported
377
24268
  visited[tn] = ret;
378
24268
  return ret;
379
}
380
381
18666
CegHandledStatus CegInstantiator::isCbqiQuantPrefix(Node q)
382
{
383
18666
  CegHandledStatus hmin = CEG_HANDLED_UNCONDITIONAL;
384
30810
  for (const Node& v : q[0])
385
  {
386
35760
    TypeNode tn = v.getType();
387
23616
    CegHandledStatus handled = isCbqiSort(tn);
388
23616
    if (handled == CEG_UNHANDLED)
389
    {
390
11472
      return CEG_UNHANDLED;
391
    }
392
12144
    else if (handled < hmin)
393
    {
394
7439
      hmin = handled;
395
    }
396
  }
397
7194
  return hmin;
398
}
399
400
23413
CegHandledStatus CegInstantiator::isCbqiQuant(Node q)
401
{
402
23413
  Assert(q.getKind() == FORALL);
403
  // compute attributes
404
46826
  QAttributes qa;
405
23413
  QuantAttributes::computeQuantAttributes(q, qa);
406
23413
  if (qa.d_quant_elim)
407
  {
408
74
    return CEG_HANDLED;
409
  }
410
23339
  if (qa.d_sygus)
411
  {
412
336
    return CEG_UNHANDLED;
413
  }
414
23003
  Assert(!qa.d_quant_elim_partial);
415
  // if has an instantiation pattern, don't do it
416
23003
  if (q.getNumChildren() == 3)
417
  {
418
6037
    for (const Node& pat : q[2])
419
    {
420
5303
      if (pat.getKind() == INST_PATTERN)
421
      {
422
4337
        return CEG_UNHANDLED;
423
      }
424
    }
425
  }
426
18666
  CegHandledStatus ret = CEG_HANDLED;
427
  // if quantifier has a non-handled variable, then do not use cbqi
428
18666
  CegHandledStatus ncbqiv = CegInstantiator::isCbqiQuantPrefix(q);
429
37332
  Trace("cegqi-quant-debug") << "isCbqiQuantPrefix returned " << ncbqiv
430
18666
                            << std::endl;
431
18666
  if (ncbqiv == CEG_UNHANDLED)
432
  {
433
    // unhandled variable type
434
11472
    ret = CEG_UNHANDLED;
435
  }
436
  else
437
  {
438
7194
    CegHandledStatus cbqit = CegInstantiator::isCbqiTerm(q);
439
7194
    Trace("cegqi-quant-debug") << "isCbqiTerm returned " << cbqit << std::endl;
440
7194
    if (cbqit == CEG_UNHANDLED)
441
    {
442
5551
      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
5551
        ret = CEG_UNHANDLED;
453
      }
454
    }
455
1643
    else if (cbqit == CEG_PARTIALLY_HANDLED)
456
    {
457
      ret = CEG_PARTIALLY_HANDLED;
458
    }
459
  }
460
18666
  if (ret == CEG_UNHANDLED && options::cegqiAll())
461
  {
462
    // try but not exclusively
463
17
    ret = CEG_PARTIALLY_HANDLED;
464
  }
465
18666
  return ret;
466
}
467
468
427453
bool CegInstantiator::hasVariable( Node n, Node pv ) {
469
427453
  computeProgVars( n );
470
427453
  return d_prog_var[n].find( pv )!=d_prog_var[n].end();
471
}
472
473
41001
void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
474
{
475
41001
  if( d_instantiator.find( v )==d_instantiator.end() ){
476
6030
    TypeNode tn = v.getType();
477
    Instantiator * vinst;
478
3015
    if( tn.isReal() ){
479
1646
      vinst = new ArithInstantiator(tn, d_parent->getVtsTermCache());
480
1369
    }else if( tn.isDatatype() ){
481
36
      vinst = new DtInstantiator(tn);
482
1333
    }else if( tn.isBitVector() ){
483
1110
      vinst = new BvInstantiator(tn, d_parent->getBvInverter());
484
223
    }else if( tn.isBoolean() ){
485
211
      vinst = new ModelValueInstantiator(tn);
486
    }else{
487
      //default
488
12
      vinst = new Instantiator(tn);
489
    }
490
3015
    d_instantiator[v] = vinst;
491
  }
492
41001
  d_curr_subs_proc[v].clear();
493
41001
  d_curr_index[v] = index;
494
41001
  d_curr_iphase[v] = CEG_INST_PHASE_NONE;
495
41001
}
496
497
4470
void CegInstantiator::deactivateInstantiationVariable(Node v)
498
{
499
4470
  d_curr_subs_proc.erase(v);
500
4470
  d_curr_index.erase(v);
501
4470
  d_curr_iphase.erase(v);
502
4470
}
503
504
64629
bool CegInstantiator::hasTriedInstantiation(Node v)
505
{
506
64629
  return !d_curr_subs_proc[v].empty();
507
}
508
509
4466
void CegInstantiator::registerTheoryIds(TypeNode tn,
510
                                        std::map<TypeNode, bool>& visited)
511
{
512
4466
  if (visited.find(tn) == visited.end())
513
  {
514
4428
    visited[tn] = true;
515
4428
    TheoryId tid = Theory::theoryOf(tn);
516
4428
    registerTheoryId(tid);
517
4428
    if (tn.isDatatype())
518
    {
519
46
      const DType& dt = tn.getDType();
520
126
      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
521
      {
522
162
        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
523
        {
524
82
          registerTheoryIds(dt[i].getArgType(j), visited);
525
        }
526
      }
527
    }
528
  }
529
4466
}
530
531
6039
void CegInstantiator::registerTheoryId(TheoryId tid)
532
{
533
6039
  if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
534
  {
535
    // setup any theory-specific preprocessors here
536
3285
    if (tid == THEORY_BV)
537
    {
538
717
      d_tipp[tid] = new BvInstantiatorPreprocess;
539
    }
540
3285
    d_tids.push_back(tid);
541
  }
542
6039
}
543
544
4384
void CegInstantiator::registerVariable(Node v)
545
{
546
4384
  Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
547
4384
  d_vars.push_back(v);
548
4384
  d_vars_set.insert(v);
549
8768
  TypeNode vtn = v.getType();
550
8768
  Trace("cegqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
551
4384
                           << v << std::endl;
552
  // collect relevant theories for this variable
553
8768
  std::map<TypeNode, bool> visited;
554
4384
  registerTheoryIds(vtn, visited);
555
4384
}
556
557
46836
bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
558
{
559
46836
  if( i==d_vars.size() ){
560
    //solved for all variables, now construct instantiation
561
    bool needsPostprocess =
562
5835
        sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty();
563
11670
    std::vector< Instantiator * > pp_inst;
564
11670
    std::map< Instantiator *, Node > pp_inst_to_var;
565
46772
    for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){
566
122811
      if (ita->second->needsPostProcessInstantiationForVariable(
567
81874
              this, sf, ita->first, d_effort))
568
      {
569
239
        needsPostprocess = true;
570
239
        pp_inst_to_var[ ita->second ] = ita->first;
571
      }
572
    }
573
5835
    if( needsPostprocess ){
574
      //must make copy so that backtracking reverts sf
575
3948
      SolvedForm sf_tmp = sf;
576
1974
      bool postProcessSuccess = true;
577
2172
      for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){
578
717
        if (!itp->first->postProcessInstantiationForVariable(
579
478
                this, sf_tmp, itp->second, d_effort))
580
        {
581
41
          postProcessSuccess = false;
582
41
          break;
583
        }
584
      }
585
1974
      if( postProcessSuccess ){
586
1933
        return doAddInstantiation(sf_tmp.d_vars, sf_tmp.d_subs);
587
      }else{
588
41
        return false;
589
      }
590
    }else{
591
3861
      return doAddInstantiation(sf.d_vars, sf.d_subs);
592
    }
593
  }else{
594
41001
    bool is_sv = false;
595
82002
    Node pv;
596
41001
    if( d_stack_vars.empty() ){
597
40963
      pv = d_vars[i];
598
    }else{
599
38
      pv = d_stack_vars.back();
600
38
      is_sv = true;
601
38
      d_stack_vars.pop_back();
602
    }
603
41001
    activateInstantiationVariable(pv, i);
604
605
    //get the instantiator object
606
41001
    Assert(d_instantiator.find(pv) != d_instantiator.end());
607
41001
    Instantiator* vinst = d_instantiator[pv];
608
41001
    Assert(vinst != NULL);
609
41001
    d_active_instantiators[pv] = vinst;
610
41001
    vinst->reset(this, sf, pv, d_effort);
611
    // if d_effort is full, we must choose at least one model value
612
41001
    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
39681
      if (constructInstantiation(sf, vinst, pv))
617
      {
618
26475
        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
43498
    if ((options::cegqiMultiInst() || !hasTriedInstantiation(pv))
628
26114
        && (vinst->useModelValue(this, sf, pv, d_effort) || is_sv)
629
40456
        && vinst->allowModelValue(this, sf, pv, d_effort))
630
    {
631
12752
      Node mv = getModelValue( pv );
632
12752
      TermProperties pv_prop_m;
633
11404
      Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
634
11404
      d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
635
11404
      CegInstEffort prev = d_effort;
636
11404
      if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
637
      {
638
        // update the effort level to indicate we have used a model value
639
2037
        d_effort = CEG_INST_EFFORT_STANDARD_MV;
640
      }
641
11404
      if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
642
      {
643
10056
        return true;
644
      }
645
1348
      d_effort = prev;
646
    }
647
648
4470
    Trace("cegqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl;
649
4470
    if (is_sv)
650
    {
651
      d_stack_vars.push_back( pv );
652
    }
653
4470
    d_active_instantiators.erase( pv );
654
4470
    deactivateInstantiationVariable(pv);
655
4470
    return false;
656
  }
657
}
658
659
39681
bool CegInstantiator::constructInstantiation(SolvedForm& sf,
660
                                             Instantiator* vinst,
661
                                             Node pv)
662
{
663
79362
  TypeNode pvtn = pv.getType();
664
79362
  TypeNode pvtnb = pvtn.getBaseType();
665
79362
  Node pvr = pv;
666
39681
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
667
39681
  if (ee->hasTerm(pv))
668
  {
669
27014
    pvr = ee->getRepresentative(pv);
670
  }
671
79362
  Trace("cegqi-inst-debug") << "[Find instantiation for " << pv
672
39681
                           << "], rep=" << pvr << ", instantiator is "
673
39681
                           << vinst->identify() << std::endl;
674
79362
  Node pv_value;
675
39681
  if (options::cegqiModel())
676
  {
677
39681
    pv_value = getModelValue(pv);
678
39681
    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
39681
  if (vinst->hasProcessEqualTerm(this, sf, pv, d_effort))
684
  {
685
80
    Trace("cegqi-inst-debug")
686
40
        << "[1] try based on equivalence class." << std::endl;
687
40
    d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
688
40
    std::map<Node, std::vector<Node> >::iterator it_eqc = d_curr_eqc.find(pvr);
689
40
    if (it_eqc != d_curr_eqc.end())
690
    {
691
      // std::vector< Node > eq_candidates;
692
80
      Trace("cegqi-inst-debug2")
693
40
          << "...eqc has size " << it_eqc->second.size() << std::endl;
694
110
      for (const Node& n : it_eqc->second)
695
      {
696
79
        if (n != pv)
697
        {
698
96
          Trace("cegqi-inst-debug")
699
48
              << "...try based on equal term " << n << std::endl;
700
          // must be an eligible term
701
48
          if (isEligible(n))
702
          {
703
47
            Node ns;
704
            // coefficient of pv in the equality we solve (null is 1)
705
47
            TermProperties pv_prop;
706
28
            bool proc = false;
707
28
            if (!d_prog_var[n].empty())
708
            {
709
19
              ns = applySubstitution(pvtn, n, sf, pv_prop, false);
710
19
              if (!ns.isNull())
711
              {
712
19
                computeProgVars(ns);
713
                // substituted version must be new and cannot contain pv
714
19
                proc = d_prog_var[ns].find(pv) == d_prog_var[ns].end();
715
              }
716
            }
717
            else
718
            {
719
9
              ns = n;
720
9
              proc = true;
721
            }
722
28
            if (proc)
723
            {
724
9
              if (vinst->processEqualTerm(this, sf, pv, pv_prop, ns, d_effort))
725
              {
726
9
                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
31
      if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
741
      {
742
23
        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
39649
  if (vinst->hasProcessEquality(this, sf, pv, d_effort))
759
  {
760
55598
    Trace("cegqi-inst-debug")
761
27799
        << "[2] try based on solving equalities." << std::endl;
762
27799
    d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
763
27799
    std::vector<Node>& cteqc = d_curr_type_eqc[pvtnb];
764
765
377136
    for (const Node& r : cteqc)
766
    {
767
362488
      std::map<Node, std::vector<Node> >::iterator it_reqc = d_curr_eqc.find(r);
768
711825
      std::vector<Node> lhs;
769
711825
      std::vector<bool> lhs_v;
770
711825
      std::vector<TermProperties> lhs_prop;
771
362488
      Assert(it_reqc != d_curr_eqc.end());
772
1243687
      for (const Node& n : it_reqc->second)
773
      {
774
894350
        Trace("cegqi-inst-debug2") << "...look at term " << n << std::endl;
775
        // must be an eligible term
776
894350
        if (isEligible(n))
777
        {
778
1448081
          Node ns;
779
1448081
          TermProperties pv_prop;
780
730616
          if (!d_prog_var[n].empty())
781
          {
782
675056
            ns = applySubstitution(pvtn, n, sf, pv_prop);
783
675056
            if (!ns.isNull())
784
            {
785
675038
              computeProgVars(ns);
786
            }
787
          }
788
          else
789
          {
790
55560
            ns = n;
791
          }
792
730616
          if (!ns.isNull())
793
          {
794
730598
            bool hasVar = d_prog_var[ns].find(pv) != d_prog_var[ns].end();
795
1461196
            Trace("cegqi-inst-debug2") << "... " << ns << " has var " << pv
796
730598
                                      << " : " << hasVar << std::endl;
797
1448045
            std::vector<TermProperties> term_props;
798
1448045
            std::vector<Node> terms;
799
730598
            term_props.push_back(pv_prop);
800
730598
            terms.push_back(ns);
801
1466739
            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
749292
              if (hasVar || lhs_v[j])
805
              {
806
92530
                Trace("cegqi-inst-debug") << "......try based on equality "
807
46265
                                         << lhs[j] << " = " << ns << std::endl;
808
46265
                term_props.push_back(lhs_prop[j]);
809
46265
                terms.push_back(lhs[j]);
810
46265
                if (vinst->processEquality(
811
46265
                        this, sf, pv, term_props, terms, d_effort))
812
                {
813
12387
                  return true;
814
                }
815
33878
                else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
816
                {
817
764
                  return false;
818
                }
819
33114
                term_props.pop_back();
820
33114
                terms.pop_back();
821
              }
822
            }
823
717447
            lhs.push_back(ns);
824
717447
            lhs_v.push_back(hasVar);
825
717447
            lhs_prop.push_back(pv_prop);
826
          }
827
          else
828
          {
829
36
            Trace("cegqi-inst-debug2")
830
18
                << "... term " << n << " is ineligible after substitution."
831
18
                << std::endl;
832
          }
833
        }
834
        else
835
        {
836
327468
          Trace("cegqi-inst-debug2")
837
163734
              << "... term " << n << " is ineligible." << std::endl;
838
        }
839
      }
840
    }
841
  }
842
  //[3] directly look at assertions
843
26498
  if (!vinst->hasProcessAssertion(this, sf, pv, d_effort))
844
  {
845
7320
    return false;
846
  }
847
19178
  Trace("cegqi-inst-debug") << "[3] try based on assertions." << std::endl;
848
19178
  d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
849
38356
  std::unordered_set<Node> lits;
850
57534
  for (unsigned r = 0; r < 2; r++)
851
  {
852
38356
    TheoryId tid = r == 0 ? Theory::theoryOf(pvtn) : THEORY_UF;
853
38356
    Trace("cegqi-inst-debug2") << "  look at assertions of " << tid << std::endl;
854
    std::map<TheoryId, std::vector<Node> >::iterator ita =
855
38356
        d_curr_asserts.find(tid);
856
38356
    if (ita != d_curr_asserts.end())
857
    {
858
473393
      for (const Node& lit : ita->second)
859
      {
860
450350
        if (lits.find(lit) == lits.end())
861
        {
862
445213
          lits.insert(lit);
863
890426
          Node plit;
864
445213
          if (options::cegqiRepeatLit() || !isSolvedAssertion(lit))
865
          {
866
439565
            plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort);
867
          }
868
445213
          if (!plit.isNull())
869
          {
870
427561
            Trace("cegqi-inst-debug2") << "  look at " << lit;
871
427561
            if (plit != lit)
872
            {
873
8810
              Trace("cegqi-inst-debug2") << "...processed to : " << plit;
874
            }
875
427561
            Trace("cegqi-inst-debug2") << std::endl;
876
            // apply substitutions
877
855122
            Node slit = applySubstitutionToLiteral(plit, sf);
878
427561
            if (!slit.isNull())
879
            {
880
              // check if contains pv
881
427453
              if (hasVariable(slit, pv))
882
              {
883
33106
                Trace("cegqi-inst-debug")
884
16553
                    << "...try based on literal " << slit << "," << std::endl;
885
16553
                Trace("cegqi-inst-debug") << "...from " << lit << std::endl;
886
16553
                if (vinst->processAssertion(this, sf, pv, slit, lit, d_effort))
887
                {
888
                  return true;
889
                }
890
16553
                else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
891
                {
892
                  return false;
893
                }
894
              }
895
            }
896
          }
897
        }
898
      }
899
    }
900
  }
901
19178
  if (vinst->processAssertions(this, sf, pv, d_effort))
902
  {
903
14056
    return true;
904
  }
905
5122
  return false;
906
}
907
908
38
void CegInstantiator::pushStackVariable( Node v ) {
909
38
  d_stack_vars.push_back( v );
910
38
}
911
912
void CegInstantiator::popStackVariable() {
913
  Assert(!d_stack_vars.empty());
914
  d_stack_vars.pop_back();
915
}
916
917
40941
bool CegInstantiator::constructInstantiationInc(Node pv,
918
                                                Node n,
919
                                                TermProperties& pv_prop,
920
                                                SolvedForm& sf,
921
                                                bool revertOnSuccess)
922
{
923
81882
  Node cnode = pv_prop.getCacheNode();
924
40941
  if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
925
40937
    d_curr_subs_proc[pv][n][cnode] = true;
926
40937
    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
40937
    computeProgVars( n );
938
40937
    Assert(d_inelig.find(n) == d_inelig.end());
939
940
    //substitute into previous substitutions, when applicable
941
81874
    std::vector< Node > a_var;
942
40937
    a_var.push_back( pv );
943
81874
    std::vector< Node > a_subs;
944
40937
    a_subs.push_back( n );
945
81874
    std::vector< TermProperties > a_prop;
946
40937
    a_prop.push_back( pv_prop );
947
81874
    std::vector< Node > a_non_basic;
948
40937
    if( !pv_prop.isBasic() ){
949
209
      a_non_basic.push_back( pv );
950
    }
951
40937
    bool success = true;
952
81874
    std::map< int, Node > prev_subs;
953
81874
    std::map< int, TermProperties > prev_prop;
954
81874
    std::map< int, Node > prev_sym_subs;
955
81874
    std::vector< Node > new_non_basic;
956
40937
    Trace("cegqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl;
957
845101
    for( unsigned j=0; j<sf.d_subs.size(); j++ ){
958
804164
      Trace("cegqi-inst-debug2") << "  Apply for " << sf.d_subs[j]  << std::endl;
959
804164
      Assert(d_prog_var.find(sf.d_subs[j]) != d_prog_var.end());
960
804164
      if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
961
32284
        prev_subs[j] = sf.d_subs[j];
962
64568
        TNode tv = pv;
963
64568
        TNode ts = n;
964
64568
        TermProperties a_pv_prop;
965
64568
        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
32284
        if( !new_subs.isNull() ){
967
32284
          sf.d_subs[j] = new_subs;
968
          // the substitution apply to this term resulted in a non-basic substitution relationship
969
32284
          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
46
            prev_prop[j] = sf.d_props[j];
982
46
            bool prev_basic = sf.d_props[j].isBasic();
983
984
            // now compose the property
985
46
            sf.d_props[j].composeProperty( a_pv_prop );
986
987
            // if previously was basic, becomes non-basic
988
46
            if( prev_basic && !sf.d_props[j].isBasic() ){
989
30
              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
30
              new_non_basic.push_back( sf.d_vars[j] );
994
30
              sf.d_non_basic.push_back( sf.d_vars[j] );
995
            }
996
          }
997
32284
          if( sf.d_subs[j]!=prev_subs[j] ){
998
32284
            computeProgVars( sf.d_subs[j] );
999
32284
            Assert(d_inelig.find(sf.d_subs[j]) == d_inelig.end());
1000
          }
1001
32284
          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
771880
        Trace("cegqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl;
1009
      }
1010
    }
1011
40937
    if( success ){
1012
40937
      Trace("cegqi-inst-debug2") << "Adding to vectors..." << std::endl;
1013
40937
      sf.push_back( pv, n, pv_prop );
1014
40937
      Trace("cegqi-inst-debug2") << "Recurse..." << std::endl;
1015
40937
      unsigned i = d_curr_index[pv];
1016
40937
      success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
1017
40937
      if (!success || revertOnSuccess)
1018
      {
1019
4406
        Trace("cegqi-inst-debug2") << "Removing from vectors..." << std::endl;
1020
4406
        sf.pop_back( pv, n, pv_prop );
1021
      }
1022
    }
1023
40937
    if (success && !revertOnSuccess)
1024
    {
1025
36531
      return true;
1026
    }else{
1027
4406
      Trace("cegqi-inst-debug2") << "Revert substitutions..." << std::endl;
1028
      //revert substitution information
1029
6208
      for (std::map<int, Node>::iterator it = prev_subs.begin();
1030
6208
           it != prev_subs.end();
1031
           ++it)
1032
      {
1033
1802
        sf.d_subs[it->first] = it->second;
1034
      }
1035
4406
      for (std::map<int, TermProperties>::iterator it = prev_prop.begin();
1036
4406
           it != prev_prop.end();
1037
           ++it)
1038
      {
1039
        sf.d_props[it->first] = it->second;
1040
      }
1041
4406
      for( unsigned i=0; i<new_non_basic.size(); i++ ){
1042
        sf.d_non_basic.pop_back();
1043
      }
1044
4406
      return success;
1045
    }
1046
  }else{
1047
    //already tried this substitution
1048
4
    return false;
1049
  }
1050
}
1051
1052
5794
bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars,
1053
                                         std::vector<Node>& subs)
1054
{
1055
5794
  if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
1056
  {
1057
1933
    Trace("cegqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
1058
3866
    std::map< Node, Node > subs_map;
1059
38012
    for( unsigned i=0; i<subs.size(); i++ ){
1060
36079
      subs_map[vars[i]] = subs[i];
1061
    }
1062
1933
    subs.clear();
1063
25371
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1064
    {
1065
23438
      std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
1066
23438
      Assert(it != subs_map.end());
1067
46876
      Node n = it->second;
1068
46876
      Trace("cegqi-inst-debug") << "  " << d_input_vars[i] << " -> " << n
1069
23438
                               << std::endl;
1070
23438
      Assert(n.getType().isSubtypeOf(d_input_vars[i].getType()));
1071
23438
      subs.push_back( n );
1072
    }
1073
  }
1074
5794
  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
5794
  Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl;
1086
5794
  return d_parent->doAddInstantiation(subs);
1087
}
1088
1089
54678
bool CegInstantiator::isEligibleForInstantiation(Node n) const
1090
{
1091
54678
  Kind nk = n.getKind();
1092
54678
  if (nk != INST_CONSTANT && nk != SKOLEM && nk != BOOLEAN_TERM_VARIABLE)
1093
  {
1094
51232
    return true;
1095
  }
1096
3446
  if (n.getAttribute(VirtualTermSkolemAttribute()))
1097
  {
1098
    // virtual terms are allowed
1099
81
    return true;
1100
  }
1101
  // only legal if current quantified formula contains n
1102
3365
  return expr::hasSubterm(d_quant, n);
1103
}
1104
1105
1135696
bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
1106
1135696
  Assert(d_prog_var.find(n) != d_prog_var.end());
1107
1135696
  if( !non_basic.empty() ){
1108
11683
    for (std::unordered_set<Node>::iterator it = d_prog_var[n].begin();
1109
11683
         it != d_prog_var[n].end();
1110
         ++it)
1111
    {
1112
8221
      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
1113
      {
1114
2017
        return false;
1115
      }
1116
    }
1117
  }
1118
1133679
  return true;
1119
}
1120
1121
708135
Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop,
1122
                                         std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) {
1123
708135
  n = Rewriter::rewrite(n);
1124
708135
  computeProgVars( n );
1125
708135
  bool is_basic = canApplyBasicSubstitution( n, non_basic );
1126
708135
  if( Trace.isOn("sygus-si-apply-subs-debug") ){
1127
    Trace("sygus-si-apply-subs-debug") << "is_basic = " << is_basic << "  " << tn << std::endl;
1128
    for( unsigned i=0; i<subs.size(); i++ ){
1129
      Trace("sygus-si-apply-subs-debug") << "  " << vars[i] << " -> " << subs[i] << "   types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl;
1130
      Assert(subs[i].getType().isSubtypeOf(vars[i].getType()));
1131
    }
1132
  }
1133
708135
  Node nret;
1134
708135
  if( is_basic ){
1135
707002
    nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1136
  }else{
1137
1133
    if( !tn.isInteger() ){
1138
      //can do basic substitution instead with divisions
1139
1562
      std::vector< Node > nvars;
1140
1562
      std::vector< Node > nsubs;
1141
6632
      for( unsigned i=0; i<vars.size(); i++ ){
1142
5851
        if( !prop[i].d_coeff.isNull() ){
1143
2677
          Assert(vars[i].getType().isInteger());
1144
2677
          Assert(prop[i].d_coeff.isConst());
1145
5354
          Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
1146
2677
          nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn );
1147
2677
          nn =  Rewriter::rewrite( nn );
1148
2677
          nsubs.push_back( nn );
1149
        }else{
1150
3174
          nsubs.push_back( subs[i] );
1151
        }
1152
      }
1153
781
      nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() );
1154
352
    }else if( try_coeff ){
1155
      //must convert to monomial representation
1156
704
      std::map< Node, Node > msum;
1157
352
      if (ArithMSum::getMonomialSum(n, msum))
1158
      {
1159
704
        std::map< Node, Node > msum_coeff;
1160
704
        std::map< Node, Node > msum_term;
1161
1648
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1162
          //check if in substitution
1163
1296
          std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first );
1164
1296
          if( its!=vars.end() ){
1165
631
            int index = its-vars.begin();
1166
631
            if( prop[index].d_coeff.isNull() ){
1167
              //apply substitution
1168
288
              msum_term[it->first] = subs[index];
1169
            }else{
1170
              //apply substitution, multiply to ensure no divisibility conflict
1171
343
              msum_term[it->first] = subs[index];
1172
              //relative coefficient
1173
343
              msum_coeff[it->first] = prop[index].d_coeff;
1174
343
              if( pv_prop.d_coeff.isNull() ){
1175
334
                pv_prop.d_coeff = prop[index].d_coeff;
1176
              }else{
1177
9
                pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff );
1178
              }
1179
            }
1180
          }else{
1181
665
            msum_term[it->first] = it->first;
1182
          }
1183
        }
1184
        //make sum with normalized coefficient
1185
352
        if( !pv_prop.d_coeff.isNull() ){
1186
334
          pv_prop.d_coeff = Rewriter::rewrite( pv_prop.d_coeff );
1187
334
          Trace("sygus-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl;
1188
668
          std::vector< Node > children;
1189
1594
          for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1190
2520
            Node c_coeff;
1191
1260
            if( !msum_coeff[it->first].isNull() ){
1192
343
              c_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkConst( pv_prop.d_coeff.getConst<Rational>() / msum_coeff[it->first].getConst<Rational>() ) );
1193
            }else{
1194
917
              c_coeff = pv_prop.d_coeff;
1195
            }
1196
1260
            if( !it->second.isNull() ){
1197
976
              c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
1198
            }
1199
1260
            Assert(!c_coeff.isNull());
1200
2520
            Node c;
1201
1260
            if( msum_term[it->first].isNull() ){
1202
62
              c = c_coeff;
1203
            }else{
1204
1198
              c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
1205
            }
1206
1260
            children.push_back( c );
1207
1260
            Trace("sygus-si-apply-subs-debug") << "Add child : " << c << std::endl;
1208
          }
1209
668
          Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children );
1210
334
          nretc = Rewriter::rewrite( nretc );
1211
          //ensure that nret does not contain vars
1212
334
          if (!expr::hasSubterm(nretc, vars))
1213
          {
1214
            //result is ( nret / pv_prop.d_coeff )
1215
334
            nret = nretc;
1216
          }else{
1217
            Trace("sygus-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl;
1218
          }
1219
        }else{
1220
          //implies that we have a monomial that has a free variable
1221
18
          Trace("sygus-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl;
1222
        }
1223
      }else{
1224
        Trace("sygus-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl;
1225
      }
1226
    }
1227
  }
1228
708135
  if( n!=nret && !nret.isNull() ){
1229
347080
    nret = Rewriter::rewrite( nret );
1230
  }
1231
708135
  return nret;
1232
}
1233
1234
427561
Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs,
1235
                                                  std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) {
1236
427561
  computeProgVars( lit );
1237
427561
  bool is_basic = canApplyBasicSubstitution( lit, non_basic );
1238
427561
  Node lret;
1239
427561
  if( is_basic ){
1240
426677
   lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1241
  }else{
1242
1768
    Node atom = lit.getKind()==NOT ? lit[0] : lit;
1243
884
    bool pol = lit.getKind()!=NOT;
1244
    //arithmetic inequalities and disequalities
1245
884
    if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){
1246
776
      NodeManager* nm = NodeManager::currentNM();
1247
776
      Assert(atom.getKind() != GEQ || atom[1].isConst());
1248
1552
      Node atom_lhs;
1249
1552
      Node atom_rhs;
1250
776
      if( atom.getKind()==GEQ ){
1251
746
        atom_lhs = atom[0];
1252
746
        atom_rhs = atom[1];
1253
      }else{
1254
30
        atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]);
1255
30
        atom_lhs = Rewriter::rewrite( atom_lhs );
1256
30
        atom_rhs = nm->mkConst(Rational(0));
1257
      }
1258
      //must be an eligible term
1259
776
      if( isEligible( atom_lhs ) ){
1260
        //apply substitution to LHS of atom
1261
1552
        TermProperties atom_lhs_prop;
1262
776
        atom_lhs = applySubstitution(nm->realType(),
1263
                                     atom_lhs,
1264
                                     vars,
1265
                                     subs,
1266
                                     prop,
1267
                                     non_basic,
1268
                                     atom_lhs_prop);
1269
776
        if( !atom_lhs.isNull() ){
1270
776
          if( !atom_lhs_prop.d_coeff.isNull() ){
1271
            atom_rhs = nm->mkNode(MULT, atom_lhs_prop.d_coeff, atom_rhs);
1272
            atom_rhs = Rewriter::rewrite(atom_rhs);
1273
          }
1274
776
          lret = nm->mkNode(atom.getKind(), atom_lhs, atom_rhs);
1275
776
          if( !pol ){
1276
421
            lret = lret.negate();
1277
          }
1278
        }
1279
      }
1280
    }else{
1281
      // don't know how to apply substitution to literal
1282
    }
1283
  }
1284
427561
  if( lit!=lret && !lret.isNull() ){
1285
250554
    lret = Rewriter::rewrite( lret );
1286
  }
1287
427561
  return lret;
1288
}
1289
1290
4579
bool CegInstantiator::check() {
1291
4579
  processAssertions();
1292
6191
  for( unsigned r=0; r<2; r++ ){
1293
5899
    d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
1294
7511
    SolvedForm sf;
1295
5899
    d_stack_vars.clear();
1296
5899
    d_bound_var_index.clear();
1297
5899
    d_solved_asserts.clear();
1298
    //try to add an instantiation
1299
5899
    if (constructInstantiation(sf, 0))
1300
    {
1301
4287
      return true;
1302
    }
1303
  }
1304
292
  Trace("cegqi-engine") << "  WARNING : unable to find CEGQI single invocation instantiation." << std::endl;
1305
292
  return false;
1306
}
1307
1308
4579
void CegInstantiator::processAssertions() {
1309
9158
  Trace("cegqi-proc") << "--- Process assertions, #var = " << d_vars.size()
1310
4579
                     << std::endl;
1311
4579
  d_curr_asserts.clear();
1312
4579
  d_curr_eqc.clear();
1313
4579
  d_curr_type_eqc.clear();
1314
1315
  // must use master equality engine to avoid value instantiations
1316
4579
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
1317
1318
  //for each variable
1319
42360
  for( unsigned i=0; i<d_vars.size(); i++ ){
1320
75562
    Node pv = d_vars[i];
1321
75562
    TypeNode pvtn = pv.getType();
1322
37781
    Trace("cegqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
1323
    //collect information about eqc
1324
37781
    if( ee->hasTerm( pv ) ){
1325
51258
      Node pvr = ee->getRepresentative( pv );
1326
25629
      if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){
1327
13687
        Trace("cegqi-proc") << "Collect equivalence class " << pvr << std::endl;
1328
13687
        eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee );
1329
71813
        while( !eqc_i.isFinished() ){
1330
29063
          d_curr_eqc[pvr].push_back( *eqc_i );
1331
29063
          ++eqc_i;
1332
        }
1333
      }
1334
    }
1335
  }
1336
  //collect assertions for relevant theories
1337
4579
  const LogicInfo& logicInfo = d_qstate.getLogicInfo();
1338
14284
  for (TheoryId tid : d_tids)
1339
  {
1340
9705
    if (!logicInfo.isTheoryEnabled(tid))
1341
    {
1342
2098
      continue;
1343
    }
1344
15214
    Trace("cegqi-proc") << "Collect assertions from theory " << tid
1345
7607
                        << std::endl;
1346
7607
    d_curr_asserts[tid].clear();
1347
    // collect all assertions from theory
1348
357183
    for (context::CDList<Assertion>::const_iterator
1349
7607
             it = d_qstate.factsBegin(tid),
1350
7607
             itEnd = d_qstate.factsEnd(tid);
1351
364790
         it != itEnd;
1352
         ++it)
1353
    {
1354
714366
      Node lit = (*it).d_assertion;
1355
714366
      Node atom = lit.getKind() == NOT ? lit[0] : lit;
1356
714366
      if (d_is_nested_quant
1357
1063043
          || std::find(d_ce_atoms.begin(), d_ce_atoms.end(), atom)
1358
1063043
                 != d_ce_atoms.end())
1359
      {
1360
35015
        d_curr_asserts[tid].push_back(lit);
1361
35015
        Trace("cegqi-proc-debug") << "...add : " << lit << std::endl;
1362
      }
1363
      else
1364
      {
1365
644336
        Trace("cegqi-proc")
1366
322168
            << "...do not consider literal " << tid << " : " << lit
1367
322168
            << " since it is not part of CE body." << std::endl;
1368
      }
1369
    }
1370
  }
1371
  //collect equivalence classes that correspond to relevant theories
1372
4579
  Trace("cegqi-proc-debug") << "...collect typed equivalence classes" << std::endl;
1373
4579
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
1374
778037
  while( !eqcs_i.isFinished() ){
1375
773458
    Node r = *eqcs_i;
1376
773458
    TypeNode rtn = r.getType();
1377
386729
    TheoryId tid = Theory::theoryOf( rtn );
1378
    //if we care about the theory of this eqc
1379
386729
    if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){
1380
326197
      if( rtn.isInteger() || rtn.isReal() ){
1381
22044
        rtn = rtn.getBaseType();
1382
      }
1383
326197
      Trace("cegqi-proc-debug") << "...type eqc: " << r << std::endl;
1384
326197
      d_curr_type_eqc[rtn].push_back( r );
1385
326197
      if( d_curr_eqc.find( r )==d_curr_eqc.end() ){
1386
312510
        Trace("cegqi-proc") << "Collect equivalence class " << r << std::endl;
1387
312510
        Trace("cegqi-proc-debug") << "  ";
1388
312510
        eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
1389
1058454
        while( !eqc_i.isFinished() ){
1390
372972
          Trace("cegqi-proc-debug") << *eqc_i << " ";
1391
372972
          d_curr_eqc[r].push_back( *eqc_i );
1392
372972
          ++eqc_i;
1393
        }
1394
312510
        Trace("cegqi-proc-debug") << std::endl;
1395
      }
1396
    }
1397
386729
    ++eqcs_i;
1398
  }
1399
1400
  //remove unecessary assertions
1401
12186
  for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
1402
15214
    std::vector< Node > akeep;
1403
42622
    for( unsigned i=0; i<it->second.size(); i++ ){
1404
70030
      Node n = it->second[i];
1405
      //must be an eligible term
1406
35015
      if( isEligible( n ) ){
1407
        //must contain at least one variable
1408
29517
        if( !d_prog_var[n].empty() ){
1409
28832
          Trace("cegqi-proc") << "...literal[" << it->first << "] : " << n << std::endl;
1410
28832
          akeep.push_back( n );
1411
        }else{
1412
685
          Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl;
1413
        }
1414
      }else{
1415
5498
        Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl;
1416
      }
1417
    }
1418
7607
    it->second.clear();
1419
7607
    it->second.insert( it->second.end(), akeep.begin(), akeep.end() );
1420
  }
1421
1422
  //remove duplicate terms from eqc
1423
330776
  for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
1424
652394
    std::vector< Node > new_eqc;
1425
728232
    for( unsigned i=0; i<it->second.size(); i++ ){
1426
402035
      if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){
1427
402035
        new_eqc.push_back( it->second[i] );
1428
      }
1429
    }
1430
326197
    it->second.clear();
1431
326197
    it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() );
1432
  }
1433
4579
}
1434
1435
109895
Node CegInstantiator::getModelValue( Node n ) {
1436
109895
  return d_treg.getModel()->getValue(n);
1437
}
1438
1439
1215
Node CegInstantiator::getBoundVariable(TypeNode tn)
1440
{
1441
1215
  unsigned index = 0;
1442
  std::unordered_map<TypeNode, unsigned>::iterator itb =
1443
1215
      d_bound_var_index.find(tn);
1444
1215
  if (itb != d_bound_var_index.end())
1445
  {
1446
136
    index = itb->second;
1447
  }
1448
1215
  d_bound_var_index[tn] = index + 1;
1449
2203
  while (index >= d_bound_var[tn].size())
1450
  {
1451
988
    std::stringstream ss;
1452
494
    ss << "x" << index;
1453
988
    Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn);
1454
494
    d_bound_var[tn].push_back(x);
1455
  }
1456
1215
  return d_bound_var[tn][index];
1457
}
1458
1459
447491
bool CegInstantiator::isSolvedAssertion(Node n) const
1460
{
1461
447491
  return d_solved_asserts.find(n) != d_solved_asserts.end();
1462
}
1463
1464
4556
void CegInstantiator::markSolved(Node n, bool solved)
1465
{
1466
4556
  if (solved)
1467
  {
1468
2278
    d_solved_asserts.insert(n);
1469
  }
1470
2278
  else if (isSolvedAssertion(n))
1471
  {
1472
2278
    d_solved_asserts.erase(n);
1473
  }
1474
4556
}
1475
1476
23800
void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
1477
23800
  if( n.getKind()==FORALL ){
1478
167
    d_is_nested_quant = true;
1479
23633
  }else if( visited.find( n )==visited.end() ){
1480
21826
    visited[n] = true;
1481
21826
    if( TermUtil::isBoolConnectiveTerm( n ) ){
1482
33210
      for( unsigned i=0; i<n.getNumChildren(); i++ ){
1483
22086
        collectCeAtoms( n[i], visited );
1484
      }
1485
    }else{
1486
10702
      if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
1487
10702
        Trace("cegqi-ce-atoms") << "CE atoms : " << n << std::endl;
1488
10702
        d_ce_atoms.push_back( n );
1489
      }
1490
    }
1491
  }
1492
23800
}
1493
1494
1611
void CegInstantiator::registerCounterexampleLemma(Node lem,
1495
                                                  std::vector<Node>& ceVars,
1496
                                                  std::vector<Node>& auxLems)
1497
{
1498
1611
  Trace("cegqi-reg") << "Register counterexample lemma..." << std::endl;
1499
1611
  d_input_vars.clear();
1500
1611
  d_input_vars.insert(d_input_vars.end(), ceVars.begin(), ceVars.end());
1501
1502
  //Assert( d_vars.empty() );
1503
1611
  d_vars.clear();
1504
1611
  registerTheoryId(THEORY_UF);
1505
4761
  for (const Node& cv : ceVars)
1506
  {
1507
3150
    Trace("cegqi-reg") << "  register input variable : " << cv << std::endl;
1508
3150
    registerVariable(cv);
1509
  }
1510
1511
  // preprocess with all relevant instantiator preprocessors
1512
3222
  Trace("cegqi-debug") << "Preprocess based on theory-specific methods..."
1513
1611
                      << std::endl;
1514
3222
  std::vector<Node> pvars;
1515
1611
  pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
1516
2321
  for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp)
1517
  {
1518
710
    p.second->registerCounterexampleLemma(lem, pvars, auxLems);
1519
  }
1520
  // must register variables generated by preprocessors
1521
3222
  Trace("cegqi-debug") << "Register variables from theory-specific methods "
1522
3222
                      << d_input_vars.size() << " " << pvars.size() << " ..."
1523
1611
                      << std::endl;
1524
1819
  for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i)
1525
  {
1526
416
    Trace("cegqi-reg") << "  register inst preprocess variable : " << pvars[i]
1527
208
                       << std::endl;
1528
208
    registerVariable(pvars[i]);
1529
  }
1530
1531
  // register variables that were introduced during TheoryEngine preprocessing
1532
3222
  std::unordered_set<Node> ceSyms;
1533
1611
  expr::getSymbols(lem, ceSyms);
1534
3222
  std::unordered_set<Node> qSyms;
1535
1611
  expr::getSymbols(d_quant, qSyms);
1536
  // all variables that are in counterexample lemma but not in quantified
1537
  // formula
1538
10361
  for (const Node& ces : ceSyms)
1539
  {
1540
8750
    if (qSyms.find(ces) != qSyms.end())
1541
    {
1542
      // a free symbol of the quantified formula.
1543
10503
      continue;
1544
    }
1545
5971
    if (std::find(d_vars.begin(), d_vars.end(), ces) != d_vars.end())
1546
    {
1547
      // already processed variable
1548
3114
      continue;
1549
    }
1550
    // must avoid selector symbols, and function skolems introduced by
1551
    // theory preprocessing
1552
3883
    TypeNode ct = ces.getType();
1553
2857
    if (ct.isBoolean() || ct.isFunctionLike())
1554
    {
1555
      // Boolean variables, including the counterexample literal, don't matter
1556
      // since they are always assigned a model value.
1557
1831
      continue;
1558
    }
1559
2052
    Trace("cegqi-reg") << "  register theory preprocess variable : " << ces
1560
1026
                       << std::endl;
1561
    // register the variable, which was introduced by TheoryEngine's preprocess
1562
    // method, e.g. an ITE skolem.
1563
1026
    registerVariable(ces);
1564
  }
1565
1566
  // determine variable order: must do Reals before Ints
1567
1611
  Trace("cegqi-debug") << "Determine variable order..." << std::endl;
1568
1611
  if (!d_vars.empty())
1569
  {
1570
3222
    std::map<Node, unsigned> voo;
1571
1611
    bool doSort = false;
1572
3222
    std::vector<Node> vars;
1573
3222
    std::map<TypeNode, std::vector<Node> > tvars;
1574
5995
    for (unsigned i = 0, size = d_vars.size(); i < size; i++)
1575
    {
1576
4384
      voo[d_vars[i]] = i;
1577
4384
      d_var_order_index.push_back(0);
1578
8768
      TypeNode tn = d_vars[i].getType();
1579
4384
      if (tn.isInteger())
1580
      {
1581
2150
        doSort = true;
1582
2150
        tvars[tn].push_back(d_vars[i]);
1583
      }
1584
      else
1585
      {
1586
2234
        vars.push_back(d_vars[i]);
1587
      }
1588
    }
1589
1611
    if (doSort)
1590
    {
1591
527
      Trace("cegqi-debug") << "Sort variables based on ordering." << std::endl;
1592
1054
      for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
1593
      {
1594
527
        vars.insert(vars.end(), vs.second.begin(), vs.second.end());
1595
      }
1596
1597
527
      Trace("cegqi-debug") << "Consider variables in this order : " << std::endl;
1598
2930
      for (unsigned i = 0; i < vars.size(); i++)
1599
      {
1600
2403
        d_var_order_index[voo[vars[i]]] = i;
1601
4806
        Trace("cegqi-debug") << "  " << vars[i] << " : " << vars[i].getType()
1602
2403
                            << ", index was : " << voo[vars[i]] << std::endl;
1603
2403
        d_vars[i] = vars[i];
1604
      }
1605
527
      Trace("cegqi-debug") << std::endl;
1606
    }
1607
    else
1608
    {
1609
1084
      d_var_order_index.clear();
1610
    }
1611
  }
1612
1613
  // collect atoms from all lemmas: we will only solve for literals coming from
1614
  // the original body
1615
1611
  d_is_nested_quant = false;
1616
3222
  std::map< Node, bool > visited;
1617
1611
  collectCeAtoms(lem, visited);
1618
1714
  for (const Node& alem : auxLems)
1619
  {
1620
103
    collectCeAtoms(alem, visited);
1621
  }
1622
1611
}
1623
1624
3015
Instantiator::Instantiator(TypeNode tn) : d_type(tn)
1625
{
1626
3015
  d_closed_enum_type = tn.isClosedEnumerable();
1627
3015
}
1628
1629
9
bool Instantiator::processEqualTerm(CegInstantiator* ci,
1630
                                    SolvedForm& sf,
1631
                                    Node pv,
1632
                                    TermProperties& pv_prop,
1633
                                    Node n,
1634
                                    CegInstEffort effort)
1635
{
1636
9
  pv_prop.d_type = CEG_TT_EQUAL;
1637
9
  return ci->constructInstantiationInc(pv, n, pv_prop, sf);
1638
}
1639
1640
}  // namespace quantifiers
1641
}  // namespace theory
1642
29340
}  // namespace cvc5