GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/ceg_instantiator.cpp Lines: 816 891 91.6 %
Date: 2021-09-10 Branches: 1656 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
322
CegTermType mkStrictCTT(CegTermType c)
43
{
44
322
  Assert(!isStrictCTT(c));
45
322
  if (c == CEG_TT_LOWER)
46
  {
47
214
    return CEG_TT_LOWER_STRICT;
48
  }
49
108
  else if (c == CEG_TT_UPPER)
50
  {
51
108
    return CEG_TT_UPPER_STRICT;
52
  }
53
  return c;
54
}
55
56
3304
CegTermType mkNegateCTT(CegTermType c)
57
{
58
3304
  if (c == CEG_TT_LOWER)
59
  {
60
933
    return CEG_TT_UPPER;
61
  }
62
2371
  else if (c == CEG_TT_UPPER)
63
  {
64
2371
    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
322
bool isStrictCTT(CegTermType c)
77
{
78
322
  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
20563
bool isUpperBoundCTT(CegTermType c)
85
{
86
20563
  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
40
    d_coeff = p.d_coeff;
137
  }
138
  else
139
  {
140
6
    d_coeff = NodeManager::currentNM()->mkNode(MULT, d_coeff, p.d_coeff);
141
6
    d_coeff = Rewriter::rewrite(d_coeff);
142
  }
143
}
144
145
// push the substitution pv_prop.getModifiedTerm(pv) -> n
146
45381
void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop)
147
{
148
45381
  d_vars.push_back(pv);
149
45381
  d_subs.push_back(n);
150
45381
  d_props.push_back(pv_prop);
151
45381
  if (pv_prop.isBasic())
152
  {
153
45177
    return;
154
  }
155
204
  d_non_basic.push_back(pv);
156
  // update theta value
157
408
  Node new_theta = getTheta();
158
204
  if (new_theta.isNull())
159
  {
160
150
    new_theta = pv_prop.d_coeff;
161
  }
162
  else
163
  {
164
54
    new_theta =
165
108
        NodeManager::currentNM()->mkNode(MULT, new_theta, pv_prop.d_coeff);
166
54
    new_theta = Rewriter::rewrite(new_theta);
167
  }
168
204
  d_theta.push_back(new_theta);
169
}
170
// pop the substitution pv_prop.getModifiedTerm(pv) -> n
171
9444
void SolvedForm::pop_back(Node pv, Node n, TermProperties& pv_prop)
172
{
173
9444
  d_vars.pop_back();
174
9444
  d_subs.pop_back();
175
9444
  d_props.pop_back();
176
9444
  if (pv_prop.isBasic())
177
  {
178
9399
    return;
179
  }
180
45
  d_non_basic.pop_back();
181
  // update theta value
182
45
  d_theta.pop_back();
183
}
184
185
1623
CegInstantiator::CegInstantiator(Node q,
186
                                 QuantifiersState& qs,
187
                                 TermRegistry& tr,
188
1623
                                 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
1623
      d_effort(CEG_INST_EFFORT_NONE)
195
{
196
1623
}
197
198
4869
CegInstantiator::~CegInstantiator() {
199
4681
  for (std::pair<Node, Instantiator*> inst : d_instantiator)
200
  {
201
3058
    delete inst.second;
202
  }
203
2340
  for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
204
  {
205
717
    delete instp.second;
206
  }
207
3246
}
208
209
3334308
void CegInstantiator::computeProgVars( Node n ){
210
3334308
  if( d_prog_var.find( n )==d_prog_var.end() ){
211
58787
    d_prog_var[n].clear();
212
58787
    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
58787
    if (d_vars_set.find(n) != d_vars_set.end())
218
    {
219
2755
      d_prog_var[n].insert(n);
220
    }
221
56032
    else if (!isEligibleForInstantiation(n))
222
    {
223
2929
      d_inelig.insert(n);
224
2929
      return;
225
    }
226
135938
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
227
80080
      computeProgVars( n[i] );
228
80080
      if( d_inelig.find( n[i] )!=d_inelig.end() ){
229
11837
        d_inelig.insert(n);
230
      }
231
      // all variables in child are contained in this
232
80080
      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
111716
    if (n.getKind() == APPLY_SELECTOR_TOTAL
236
111716
        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
237
    {
238
42
      d_prog_var[n].insert(n);
239
    }
240
55858
    if (n.getKind() == kind::WITNESS)
241
    {
242
580
      d_prog_var.erase(n[0][0]);
243
    }
244
  }
245
}
246
247
955178
bool CegInstantiator::isEligible( Node n ) {
248
  //compute d_subs_fv, which program variables are contained in n, and determines if eligible
249
955178
  computeProgVars( n );
250
955178
  return d_inelig.find( n )==d_inelig.end();
251
}
252
253
50257
CegHandledStatus CegInstantiator::isCbqiKind(Kind k)
254
{
255
126351
  if (quantifiers::TermUtil::isBoolConnective(k) || k == PLUS || k == GEQ
256
14037
      || k == EQUAL || k == MULT || k == NONLINEAR_MULT || k == DIVISION
257
8635
      || k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL
258
8499
      || k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == TO_INTEGER
259
58655
      || k == IS_INTEGER)
260
  {
261
41863
    return CEG_HANDLED;
262
  }
263
264
  // CBQI typically works for satisfaction-complete theories
265
8394
  TheoryId t = kindToTheoryId(k);
266
8394
  if (t == THEORY_BV || t == THEORY_FP || t == THEORY_DATATYPES
267
5751
      || t == THEORY_BOOL)
268
  {
269
2643
    return CEG_HANDLED;
270
  }
271
5751
  return CEG_UNHANDLED;
272
}
273
274
7424
CegHandledStatus CegInstantiator::isCbqiTerm(Node n)
275
{
276
7424
  CegHandledStatus ret = CEG_HANDLED;
277
14848
  std::unordered_set<TNode> visited;
278
14848
  std::vector<TNode> visit;
279
14848
  TNode cur;
280
7424
  visit.push_back(n);
281
91430
  do
282
  {
283
98854
    cur = visit.back();
284
98854
    visit.pop_back();
285
98854
    if (visited.find(cur) == visited.end())
286
    {
287
81796
      visited.insert(cur);
288
81796
      if (cur.getKind() != BOUND_VARIABLE && TermUtil::hasBoundVarAttr(cur))
289
      {
290
57997
        if (cur.getKind() == FORALL || cur.getKind() == WITNESS)
291
        {
292
7740
          visit.push_back(cur[1]);
293
        }
294
        else
295
        {
296
50257
          CegHandledStatus curr = isCbqiKind(cur.getKind());
297
50257
          if (curr < ret)
298
          {
299
5751
            ret = curr;
300
11502
            Trace("cegqi-debug2") << "Non-cbqi kind : " << cur.getKind()
301
5751
                                 << " in " << n << std::endl;
302
5751
            if (curr == CEG_UNHANDLED)
303
            {
304
5751
              return CEG_UNHANDLED;
305
            }
306
          }
307
140155
          for (const Node& nc : cur)
308
          {
309
95649
            visit.push_back(nc);
310
          }
311
        }
312
      }
313
    }
314
93103
  } while (!visit.empty());
315
1673
  return ret;
316
}
317
318
24410
CegHandledStatus CegInstantiator::isCbqiSort(TypeNode tn)
319
{
320
48820
  std::map<TypeNode, CegHandledStatus> visited;
321
48820
  return isCbqiSort(tn, visited);
322
}
323
324
29281
CegHandledStatus CegInstantiator::isCbqiSort(
325
    TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited)
326
{
327
29281
  std::map<TypeNode, CegHandledStatus>::iterator itv = visited.find(tn);
328
29281
  if (itv != visited.end())
329
  {
330
2854
    return itv->second;
331
  }
332
26427
  CegHandledStatus ret = CEG_UNHANDLED;
333
68806
  if (tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector()
334
40176
      || tn.isFloatingPoint())
335
  {
336
12691
    ret = CEG_HANDLED;
337
  }
338
13736
  else if (tn.isDatatype())
339
  {
340
    // recursive calls to this datatype are handlable
341
2167
    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
2167
    ret = CEG_HANDLED;
345
2167
    const DType& dt = tn.getDType();
346
4538
    for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
347
    {
348
      // get the constructor type
349
6138
      TypeNode consType;
350
3767
      if (dt.isParametric())
351
      {
352
        // if parametric, must instantiate the argument types
353
36
        consType = dt[i].getSpecializedConstructorType(tn);
354
      }
355
      else
356
      {
357
3731
        consType = dt[i].getConstructor().getType();
358
      }
359
7242
      for (const TypeNode& crange : consType)
360
      {
361
4871
        CegHandledStatus cret = isCbqiSort(crange, visited);
362
4871
        if (cret == CEG_UNHANDLED)
363
        {
364
2792
          Trace("cegqi-debug2")
365
1396
              << "Non-cbqi sort : " << tn << " due to " << crange << std::endl;
366
1396
          visited[tn] = CEG_UNHANDLED;
367
1396
          return CEG_UNHANDLED;
368
        }
369
3475
        else if (cret < ret)
370
        {
371
          ret = cret;
372
        }
373
      }
374
    }
375
  }
376
  // sets, arrays, functions and others are not supported
377
25031
  visited[tn] = ret;
378
25031
  return ret;
379
}
380
381
18991
CegHandledStatus CegInstantiator::isCbqiQuantPrefix(Node q)
382
{
383
18991
  CegHandledStatus hmin = CEG_HANDLED_UNCONDITIONAL;
384
31792
  for (const Node& v : q[0])
385
  {
386
37169
    TypeNode tn = v.getType();
387
24368
    CegHandledStatus handled = isCbqiSort(tn);
388
24368
    if (handled == CEG_UNHANDLED)
389
    {
390
11567
      return CEG_UNHANDLED;
391
    }
392
12801
    else if (handled < hmin)
393
    {
394
7698
      hmin = handled;
395
    }
396
  }
397
7424
  return hmin;
398
}
399
400
23535
CegHandledStatus CegInstantiator::isCbqiQuant(Node q)
401
{
402
23535
  Assert(q.getKind() == FORALL);
403
  // compute attributes
404
47070
  QAttributes qa;
405
23535
  QuantAttributes::computeQuantAttributes(q, qa);
406
23535
  if (qa.d_quant_elim)
407
  {
408
74
    return CEG_HANDLED;
409
  }
410
23461
  if (qa.d_sygus)
411
  {
412
335
    return CEG_UNHANDLED;
413
  }
414
23126
  Assert(!qa.d_quant_elim_partial);
415
  // if has an instantiation pattern, don't do it
416
23126
  if (q.getNumChildren() == 3)
417
  {
418
5995
    for (const Node& pat : q[2])
419
    {
420
5234
      if (pat.getKind() == INST_PATTERN)
421
      {
422
4135
        return CEG_UNHANDLED;
423
      }
424
    }
425
  }
426
18991
  CegHandledStatus ret = CEG_HANDLED;
427
  // if quantifier has a non-handled variable, then do not use cbqi
428
18991
  CegHandledStatus ncbqiv = CegInstantiator::isCbqiQuantPrefix(q);
429
37982
  Trace("cegqi-quant-debug") << "isCbqiQuantPrefix returned " << ncbqiv
430
18991
                            << std::endl;
431
18991
  if (ncbqiv == CEG_UNHANDLED)
432
  {
433
    // unhandled variable type
434
11567
    ret = CEG_UNHANDLED;
435
  }
436
  else
437
  {
438
7424
    CegHandledStatus cbqit = CegInstantiator::isCbqiTerm(q);
439
7424
    Trace("cegqi-quant-debug") << "isCbqiTerm returned " << cbqit << std::endl;
440
7424
    if (cbqit == CEG_UNHANDLED)
441
    {
442
5751
      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
5751
        ret = CEG_UNHANDLED;
453
      }
454
    }
455
1673
    else if (cbqit == CEG_PARTIALLY_HANDLED)
456
    {
457
      ret = CEG_PARTIALLY_HANDLED;
458
    }
459
  }
460
18991
  if (ret == CEG_UNHANDLED && options::cegqiAll())
461
  {
462
    // try but not exclusively
463
17
    ret = CEG_PARTIALLY_HANDLED;
464
  }
465
18991
  return ret;
466
}
467
468
426094
bool CegInstantiator::hasVariable( Node n, Node pv ) {
469
426094
  computeProgVars( n );
470
426094
  return d_prog_var[n].find( pv )!=d_prog_var[n].end();
471
}
472
473
41369
void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
474
{
475
41369
  if( d_instantiator.find( v )==d_instantiator.end() ){
476
6116
    TypeNode tn = v.getType();
477
    Instantiator * vinst;
478
3058
    if( tn.isReal() ){
479
1687
      vinst = new ArithInstantiator(tn, d_parent->getVtsTermCache());
480
1371
    }else if( tn.isDatatype() ){
481
42
      vinst = new DtInstantiator(tn);
482
1329
    }else if( tn.isBitVector() ){
483
1110
      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
3058
    d_instantiator[v] = vinst;
491
  }
492
41369
  d_curr_subs_proc[v].clear();
493
41369
  d_curr_index[v] = index;
494
41369
  d_curr_iphase[v] = CEG_INST_PHASE_NONE;
495
41369
}
496
497
5432
void CegInstantiator::deactivateInstantiationVariable(Node v)
498
{
499
5432
  d_curr_subs_proc.erase(v);
500
5432
  d_curr_index.erase(v);
501
5432
  d_curr_iphase.erase(v);
502
5432
}
503
504
63633
bool CegInstantiator::hasTriedInstantiation(Node v)
505
{
506
63633
  return !d_curr_subs_proc[v].empty();
507
}
508
509
4499
void CegInstantiator::registerTheoryIds(TypeNode tn,
510
                                        std::map<TypeNode, bool>& visited)
511
{
512
4499
  if (visited.find(tn) == visited.end())
513
  {
514
4453
    visited[tn] = true;
515
4453
    TheoryId tid = Theory::theoryOf(tn);
516
4453
    registerTheoryId(tid);
517
4453
    if (tn.isDatatype())
518
    {
519
58
      const DType& dt = tn.getDType();
520
150
      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
521
      {
522
194
        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
523
        {
524
102
          registerTheoryIds(dt[i].getArgType(j), visited);
525
        }
526
      }
527
    }
528
  }
529
4499
}
530
531
6076
void CegInstantiator::registerTheoryId(TheoryId tid)
532
{
533
6076
  if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
534
  {
535
    // setup any theory-specific preprocessors here
536
3306
    if (tid == THEORY_BV)
537
    {
538
717
      d_tipp[tid] = new BvInstantiatorPreprocess;
539
    }
540
3306
    d_tids.push_back(tid);
541
  }
542
6076
}
543
544
4397
void CegInstantiator::registerVariable(Node v)
545
{
546
4397
  Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
547
4397
  d_vars.push_back(v);
548
4397
  d_vars_set.insert(v);
549
8794
  TypeNode vtn = v.getType();
550
8794
  Trace("cegqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
551
4397
                           << v << std::endl;
552
  // collect relevant theories for this variable
553
8794
  std::map<TypeNode, bool> visited;
554
4397
  registerTheoryIds(vtn, visited);
555
4397
}
556
557
51310
bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
558
{
559
51310
  if( i==d_vars.size() ){
560
    //solved for all variables, now construct instantiation
561
    bool needsPostprocess =
562
9941
        sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty();
563
19882
    std::vector< Instantiator * > pp_inst;
564
19882
    std::map< Instantiator *, Node > pp_inst_to_var;
565
62815
    for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){
566
158622
      if (ita->second->needsPostProcessInstantiationForVariable(
567
105748
              this, sf, ita->first, d_effort))
568
      {
569
244
        needsPostprocess = true;
570
244
        pp_inst_to_var[ ita->second ] = ita->first;
571
      }
572
    }
573
9941
    if( needsPostprocess ){
574
      //must make copy so that backtracking reverts sf
575
12526
      SolvedForm sf_tmp = sf;
576
6263
      bool postProcessSuccess = true;
577
6466
      for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){
578
732
        if (!itp->first->postProcessInstantiationForVariable(
579
488
                this, sf_tmp, itp->second, d_effort))
580
        {
581
41
          postProcessSuccess = false;
582
41
          break;
583
        }
584
      }
585
6263
      if( postProcessSuccess ){
586
6222
        return doAddInstantiation(sf_tmp.d_vars, sf_tmp.d_subs);
587
      }else{
588
41
        return false;
589
      }
590
    }else{
591
3678
      return doAddInstantiation(sf.d_vars, sf.d_subs);
592
    }
593
  }else{
594
41369
    bool is_sv = false;
595
82738
    Node pv;
596
41369
    if( d_stack_vars.empty() ){
597
41327
      pv = d_vars[i];
598
    }else{
599
42
      pv = d_stack_vars.back();
600
42
      is_sv = true;
601
42
      d_stack_vars.pop_back();
602
    }
603
41369
    activateInstantiationVariable(pv, i);
604
605
    //get the instantiator object
606
41369
    Assert(d_instantiator.find(pv) != d_instantiator.end());
607
41369
    Instantiator* vinst = d_instantiator[pv];
608
41369
    Assert(vinst != NULL);
609
41369
    d_active_instantiators[pv] = vinst;
610
41369
    vinst->reset(this, sf, pv, d_effort);
611
    // if d_effort is full, we must choose at least one model value
612
41369
    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
40018
      if (constructInstantiation(sf, vinst, pv))
617
      {
618
26006
        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
45029
    if ((options::cegqiMultiInst() || !hasTriedInstantiation(pv))
628
27768
        && (vinst->useModelValue(this, sf, pv, d_effort) || is_sv)
629
42046
        && vinst->allowModelValue(this, sf, pv, d_effort))
630
    {
631
12709
      Node mv = getModelValue( pv );
632
12709
      TermProperties pv_prop_m;
633
11320
      Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
634
11320
      d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
635
11320
      CegInstEffort prev = d_effort;
636
11320
      if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
637
      {
638
        // update the effort level to indicate we have used a model value
639
2020
        d_effort = CEG_INST_EFFORT_STANDARD_MV;
640
      }
641
11320
      if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
642
      {
643
9931
        return true;
644
      }
645
1389
      d_effort = prev;
646
    }
647
648
5432
    Trace("cegqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl;
649
5432
    if (is_sv)
650
    {
651
      d_stack_vars.push_back( pv );
652
    }
653
5432
    d_active_instantiators.erase( pv );
654
5432
    deactivateInstantiationVariable(pv);
655
5432
    return false;
656
  }
657
}
658
659
40018
bool CegInstantiator::constructInstantiation(SolvedForm& sf,
660
                                             Instantiator* vinst,
661
                                             Node pv)
662
{
663
80036
  TypeNode pvtn = pv.getType();
664
80036
  TypeNode pvtnb = pvtn.getBaseType();
665
80036
  Node pvr = pv;
666
40018
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
667
40018
  if (ee->hasTerm(pv))
668
  {
669
27686
    pvr = ee->getRepresentative(pv);
670
  }
671
80036
  Trace("cegqi-inst-debug") << "[Find instantiation for " << pv
672
40018
                           << "], rep=" << pvr << ", instantiator is "
673
40018
                           << vinst->identify() << std::endl;
674
80036
  Node pv_value;
675
40018
  if (options::cegqiModel())
676
  {
677
40018
    pv_value = getModelValue(pv);
678
40018
    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
40018
  if (vinst->hasProcessEqualTerm(this, sf, pv, d_effort))
684
  {
685
88
    Trace("cegqi-inst-debug")
686
44
        << "[1] try based on equivalence class." << std::endl;
687
44
    d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
688
44
    std::map<Node, std::vector<Node> >::iterator it_eqc = d_curr_eqc.find(pvr);
689
44
    if (it_eqc != d_curr_eqc.end())
690
    {
691
      // std::vector< Node > eq_candidates;
692
88
      Trace("cegqi-inst-debug2")
693
44
          << "...eqc has size " << it_eqc->second.size() << std::endl;
694
124
      for (const Node& n : it_eqc->second)
695
      {
696
91
        if (n != pv)
697
        {
698
114
          Trace("cegqi-inst-debug")
699
57
              << "...try based on equal term " << n << std::endl;
700
          // must be an eligible term
701
57
          if (isEligible(n))
702
          {
703
63
            Node ns;
704
            // coefficient of pv in the equality we solve (null is 1)
705
63
            TermProperties pv_prop;
706
37
            bool proc = false;
707
37
            if (!d_prog_var[n].empty())
708
            {
709
29
              ns = applySubstitution(pvtn, n, sf, pv_prop, false);
710
29
              if (!ns.isNull())
711
              {
712
29
                computeProgVars(ns);
713
                // substituted version must be new and cannot contain pv
714
29
                proc = d_prog_var[ns].find(pv) == d_prog_var[ns].end();
715
              }
716
            }
717
            else
718
            {
719
8
              ns = n;
720
8
              proc = true;
721
            }
722
37
            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
33
      if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
741
      {
742
25
        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
39982
  if (vinst->hasProcessEquality(this, sf, pv, d_effort))
759
  {
760
56634
    Trace("cegqi-inst-debug")
761
28317
        << "[2] try based on solving equalities." << std::endl;
762
28317
    d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
763
28317
    std::vector<Node>& cteqc = d_curr_type_eqc[pvtnb];
764
765
397654
    for (const Node& r : cteqc)
766
    {
767
382307
      std::map<Node, std::vector<Node> >::iterator it_reqc = d_curr_eqc.find(r);
768
751644
      std::vector<Node> lhs;
769
751644
      std::vector<bool> lhs_v;
770
751644
      std::vector<TermProperties> lhs_prop;
771
382307
      Assert(it_reqc != d_curr_eqc.end());
772
1287676
      for (const Node& n : it_reqc->second)
773
      {
774
918339
        Trace("cegqi-inst-debug2") << "...look at term " << n << std::endl;
775
        // must be an eligible term
776
918339
        if (isEligible(n))
777
        {
778
1481618
          Node ns;
779
1481618
          TermProperties pv_prop;
780
747294
          if (!d_prog_var[n].empty())
781
          {
782
668349
            ns = applySubstitution(pvtn, n, sf, pv_prop);
783
668349
            if (!ns.isNull())
784
            {
785
668331
              computeProgVars(ns);
786
            }
787
          }
788
          else
789
          {
790
78945
            ns = n;
791
          }
792
747294
          if (!ns.isNull())
793
          {
794
747276
            bool hasVar = d_prog_var[ns].find(pv) != d_prog_var[ns].end();
795
1494552
            Trace("cegqi-inst-debug2") << "... " << ns << " has var " << pv
796
747276
                                      << " : " << hasVar << std::endl;
797
1481582
            std::vector<TermProperties> term_props;
798
1481582
            std::vector<Node> terms;
799
747276
            term_props.push_back(pv_prop);
800
747276
            terms.push_back(ns);
801
1494982
            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
760676
              if (hasVar || lhs_v[j])
805
              {
806
110524
                Trace("cegqi-inst-debug") << "......try based on equality "
807
55262
                                         << lhs[j] << " = " << ns << std::endl;
808
55262
                term_props.push_back(lhs_prop[j]);
809
55262
                terms.push_back(lhs[j]);
810
55262
                if (vinst->processEquality(
811
55262
                        this, sf, pv, term_props, terms, d_effort))
812
                {
813
12194
                  return true;
814
                }
815
43068
                else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
816
                {
817
776
                  return false;
818
                }
819
42292
                term_props.pop_back();
820
42292
                terms.pop_back();
821
              }
822
            }
823
734306
            lhs.push_back(ns);
824
734306
            lhs_v.push_back(hasVar);
825
734306
            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
342090
          Trace("cegqi-inst-debug2")
837
171045
              << "... term " << n << " is ineligible." << std::endl;
838
        }
839
      }
840
    }
841
  }
842
  //[3] directly look at assertions
843
27012
  if (!vinst->hasProcessAssertion(this, sf, pv, d_effort))
844
  {
845
7224
    return false;
846
  }
847
19788
  Trace("cegqi-inst-debug") << "[3] try based on assertions." << std::endl;
848
19788
  d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
849
39576
  std::unordered_set<Node> lits;
850
59364
  for (unsigned r = 0; r < 2; r++)
851
  {
852
39576
    TheoryId tid = r == 0 ? Theory::theoryOf(pvtn) : THEORY_UF;
853
39576
    Trace("cegqi-inst-debug2") << "  look at assertions of " << tid << std::endl;
854
    std::map<TheoryId, std::vector<Node> >::iterator ita =
855
39576
        d_curr_asserts.find(tid);
856
39576
    if (ita != d_curr_asserts.end())
857
    {
858
474021
      for (const Node& lit : ita->second)
859
      {
860
449415
        if (lits.find(lit) == lits.end())
861
        {
862
443470
          lits.insert(lit);
863
886940
          Node plit;
864
443470
          if (options::cegqiRepeatLit() || !isSolvedAssertion(lit))
865
          {
866
437804
            plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort);
867
          }
868
443470
          if (!plit.isNull())
869
          {
870
426199
            Trace("cegqi-inst-debug2") << "  look at " << lit;
871
426199
            if (plit != lit)
872
            {
873
8793
              Trace("cegqi-inst-debug2") << "...processed to : " << plit;
874
            }
875
426199
            Trace("cegqi-inst-debug2") << std::endl;
876
            // apply substitutions
877
852398
            Node slit = applySubstitutionToLiteral(plit, sf);
878
426199
            if (!slit.isNull())
879
            {
880
              // check if contains pv
881
426094
              if (hasVariable(slit, pv))
882
              {
883
37280
                Trace("cegqi-inst-debug")
884
18640
                    << "...try based on literal " << slit << "," << std::endl;
885
18640
                Trace("cegqi-inst-debug") << "...from " << lit << std::endl;
886
18640
                if (vinst->processAssertion(this, sf, pv, slit, lit, d_effort))
887
                {
888
                  return true;
889
                }
890
18640
                else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
891
                {
892
                  return false;
893
                }
894
              }
895
            }
896
          }
897
        }
898
      }
899
    }
900
  }
901
19788
  if (vinst->processAssertions(this, sf, pv, d_effort))
902
  {
903
13776
    return true;
904
  }
905
6012
  return false;
906
}
907
908
42
void CegInstantiator::pushStackVariable( Node v ) {
909
42
  d_stack_vars.push_back( v );
910
42
}
911
912
void CegInstantiator::popStackVariable() {
913
  Assert(!d_stack_vars.empty());
914
  d_stack_vars.pop_back();
915
}
916
917
50170
bool CegInstantiator::constructInstantiationInc(Node pv,
918
                                                Node n,
919
                                                TermProperties& pv_prop,
920
                                                SolvedForm& sf,
921
                                                bool revertOnSuccess)
922
{
923
100340
  Node cnode = pv_prop.getCacheNode();
924
50170
  if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
925
45381
    d_curr_subs_proc[pv][n][cnode] = true;
926
45381
    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
45381
    computeProgVars( n );
938
45381
    Assert(d_inelig.find(n) == d_inelig.end());
939
940
    //substitute into previous substitutions, when applicable
941
90762
    std::vector< Node > a_var;
942
45381
    a_var.push_back( pv );
943
90762
    std::vector< Node > a_subs;
944
45381
    a_subs.push_back( n );
945
90762
    std::vector< TermProperties > a_prop;
946
45381
    a_prop.push_back( pv_prop );
947
90762
    std::vector< Node > a_non_basic;
948
45381
    if( !pv_prop.isBasic() ){
949
204
      a_non_basic.push_back( pv );
950
    }
951
45381
    bool success = true;
952
90762
    std::map< int, Node > prev_subs;
953
90762
    std::map< int, TermProperties > prev_prop;
954
90762
    std::map< int, Node > prev_sym_subs;
955
90762
    std::vector< Node > new_non_basic;
956
45381
    Trace("cegqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl;
957
838624
    for( unsigned j=0; j<sf.d_subs.size(); j++ ){
958
793243
      Trace("cegqi-inst-debug2") << "  Apply for " << sf.d_subs[j]  << std::endl;
959
793243
      Assert(d_prog_var.find(sf.d_subs[j]) != d_prog_var.end());
960
793243
      if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
961
31967
        prev_subs[j] = sf.d_subs[j];
962
63934
        TNode tv = pv;
963
63934
        TNode ts = n;
964
63934
        TermProperties a_pv_prop;
965
63934
        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
31967
        if( !new_subs.isNull() ){
967
31967
          sf.d_subs[j] = new_subs;
968
          // the substitution apply to this term resulted in a non-basic substitution relationship
969
31967
          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
40
              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
40
              new_non_basic.push_back( sf.d_vars[j] );
994
40
              sf.d_non_basic.push_back( sf.d_vars[j] );
995
            }
996
          }
997
31967
          if( sf.d_subs[j]!=prev_subs[j] ){
998
31965
            computeProgVars( sf.d_subs[j] );
999
31965
            Assert(d_inelig.find(sf.d_subs[j]) == d_inelig.end());
1000
          }
1001
31967
          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
761276
        Trace("cegqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl;
1009
      }
1010
    }
1011
45381
    if( success ){
1012
45381
      Trace("cegqi-inst-debug2") << "Adding to vectors..." << std::endl;
1013
45381
      sf.push_back( pv, n, pv_prop );
1014
45381
      Trace("cegqi-inst-debug2") << "Recurse..." << std::endl;
1015
45381
      unsigned i = d_curr_index[pv];
1016
45381
      success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
1017
45381
      if (!success || revertOnSuccess)
1018
      {
1019
9444
        Trace("cegqi-inst-debug2") << "Removing from vectors..." << std::endl;
1020
9444
        sf.pop_back( pv, n, pv_prop );
1021
      }
1022
    }
1023
45381
    if (success && !revertOnSuccess)
1024
    {
1025
35937
      return true;
1026
    }else{
1027
9444
      Trace("cegqi-inst-debug2") << "Revert substitutions..." << std::endl;
1028
      //revert substitution information
1029
12036
      for (std::map<int, Node>::iterator it = prev_subs.begin();
1030
12036
           it != prev_subs.end();
1031
           ++it)
1032
      {
1033
2592
        sf.d_subs[it->first] = it->second;
1034
      }
1035
9444
      for (std::map<int, TermProperties>::iterator it = prev_prop.begin();
1036
9444
           it != prev_prop.end();
1037
           ++it)
1038
      {
1039
        sf.d_props[it->first] = it->second;
1040
      }
1041
9444
      for( unsigned i=0; i<new_non_basic.size(); i++ ){
1042
        sf.d_non_basic.pop_back();
1043
      }
1044
9444
      return success;
1045
    }
1046
  }else{
1047
    //already tried this substitution
1048
4789
    return false;
1049
  }
1050
}
1051
1052
9900
bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars,
1053
                                         std::vector<Node>& subs)
1054
{
1055
9900
  if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
1056
  {
1057
6222
    Trace("cegqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
1058
12444
    std::map< Node, Node > subs_map;
1059
54427
    for( unsigned i=0; i<subs.size(); i++ ){
1060
48205
      subs_map[vars[i]] = subs[i];
1061
    }
1062
6222
    subs.clear();
1063
33470
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1064
    {
1065
27248
      std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
1066
27248
      Assert(it != subs_map.end());
1067
54496
      Node n = it->second;
1068
54496
      Trace("cegqi-inst-debug") << "  " << d_input_vars[i] << " -> " << n
1069
27248
                               << std::endl;
1070
27248
      Assert(n.getType().isSubtypeOf(d_input_vars[i].getType()));
1071
27248
      subs.push_back( n );
1072
    }
1073
  }
1074
9900
  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
9900
  Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl;
1086
9900
  return d_parent->doAddInstantiation(subs);
1087
}
1088
1089
56055
bool CegInstantiator::isEligibleForInstantiation(Node n) const
1090
{
1091
56055
  Kind nk = n.getKind();
1092
56055
  if (nk != INST_CONSTANT && nk != SKOLEM && nk != BOOLEAN_TERM_VARIABLE)
1093
  {
1094
52486
    return true;
1095
  }
1096
3569
  if (n.getAttribute(VirtualTermSkolemAttribute()))
1097
  {
1098
    // virtual terms are allowed
1099
79
    return true;
1100
  }
1101
  // only legal if current quantified formula contains n
1102
3490
  return expr::hasSubterm(d_quant, n);
1103
}
1104
1105
1127250
bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
1106
1127250
  Assert(d_prog_var.find(n) != d_prog_var.end());
1107
1127250
  if( !non_basic.empty() ){
1108
11096
    for (std::unordered_set<Node>::iterator it = d_prog_var[n].begin();
1109
11096
         it != d_prog_var[n].end();
1110
         ++it)
1111
    {
1112
7776
      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
1113
      {
1114
1899
        return false;
1115
      }
1116
    }
1117
  }
1118
1125351
  return true;
1119
}
1120
1121
701051
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
701051
  n = Rewriter::rewrite(n);
1124
701051
  computeProgVars( n );
1125
701051
  bool is_basic = canApplyBasicSubstitution( n, non_basic );
1126
701051
  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
701051
  Node nret;
1134
701051
  if( is_basic ){
1135
699963
    nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1136
  }else{
1137
1088
    if( !tn.isInteger() ){
1138
      //can do basic substitution instead with divisions
1139
1422
      std::vector< Node > nvars;
1140
1422
      std::vector< Node > nsubs;
1141
6208
      for( unsigned i=0; i<vars.size(); i++ ){
1142
5497
        if( !prop[i].d_coeff.isNull() ){
1143
2517
          Assert(vars[i].getType().isInteger());
1144
2517
          Assert(prop[i].d_coeff.isConst());
1145
5034
          Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
1146
2517
          nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn );
1147
2517
          nn =  Rewriter::rewrite( nn );
1148
2517
          nsubs.push_back( nn );
1149
        }else{
1150
2980
          nsubs.push_back( subs[i] );
1151
        }
1152
      }
1153
711
      nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() );
1154
377
    }else if( try_coeff ){
1155
      //must convert to monomial representation
1156
754
      std::map< Node, Node > msum;
1157
377
      if (ArithMSum::getMonomialSum(n, msum))
1158
      {
1159
754
        std::map< Node, Node > msum_coeff;
1160
754
        std::map< Node, Node > msum_term;
1161
1706
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1162
          //check if in substitution
1163
1329
          std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first );
1164
1329
          if( its!=vars.end() ){
1165
656
            int index = its-vars.begin();
1166
656
            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
368
              msum_term[it->first] = subs[index];
1172
              //relative coefficient
1173
368
              msum_coeff[it->first] = prop[index].d_coeff;
1174
368
              if( pv_prop.d_coeff.isNull() ){
1175
359
                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
673
            msum_term[it->first] = it->first;
1182
          }
1183
        }
1184
        //make sum with normalized coefficient
1185
377
        if( !pv_prop.d_coeff.isNull() ){
1186
359
          pv_prop.d_coeff = Rewriter::rewrite( pv_prop.d_coeff );
1187
359
          Trace("sygus-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl;
1188
718
          std::vector< Node > children;
1189
1652
          for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1190
2586
            Node c_coeff;
1191
1293
            if( !msum_coeff[it->first].isNull() ){
1192
368
              c_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkConst( pv_prop.d_coeff.getConst<Rational>() / msum_coeff[it->first].getConst<Rational>() ) );
1193
            }else{
1194
925
              c_coeff = pv_prop.d_coeff;
1195
            }
1196
1293
            if( !it->second.isNull() ){
1197
1008
              c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
1198
            }
1199
1293
            Assert(!c_coeff.isNull());
1200
2586
            Node c;
1201
1293
            if( msum_term[it->first].isNull() ){
1202
73
              c = c_coeff;
1203
            }else{
1204
1220
              c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
1205
            }
1206
1293
            children.push_back( c );
1207
1293
            Trace("sygus-si-apply-subs-debug") << "Add child : " << c << std::endl;
1208
          }
1209
718
          Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children );
1210
359
          nretc = Rewriter::rewrite( nretc );
1211
          //ensure that nret does not contain vars
1212
359
          if (!expr::hasSubterm(nretc, vars))
1213
          {
1214
            //result is ( nret / pv_prop.d_coeff )
1215
359
            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
701051
  if( n!=nret && !nret.isNull() ){
1229
348792
    nret = Rewriter::rewrite( nret );
1230
  }
1231
701051
  return nret;
1232
}
1233
1234
426199
Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs,
1235
                                                  std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) {
1236
426199
  computeProgVars( lit );
1237
426199
  bool is_basic = canApplyBasicSubstitution( lit, non_basic );
1238
426199
  Node lret;
1239
426199
  if( is_basic ){
1240
425388
   lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1241
  }else{
1242
1622
    Node atom = lit.getKind()==NOT ? lit[0] : lit;
1243
811
    bool pol = lit.getKind()!=NOT;
1244
    //arithmetic inequalities and disequalities
1245
811
    if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){
1246
706
      NodeManager* nm = NodeManager::currentNM();
1247
706
      Assert(atom.getKind() != GEQ || atom[1].isConst());
1248
1412
      Node atom_lhs;
1249
1412
      Node atom_rhs;
1250
706
      if( atom.getKind()==GEQ ){
1251
675
        atom_lhs = atom[0];
1252
675
        atom_rhs = atom[1];
1253
      }else{
1254
31
        atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]);
1255
31
        atom_lhs = Rewriter::rewrite( atom_lhs );
1256
31
        atom_rhs = nm->mkConst(Rational(0));
1257
      }
1258
      //must be an eligible term
1259
706
      if( isEligible( atom_lhs ) ){
1260
        //apply substitution to LHS of atom
1261
1412
        TermProperties atom_lhs_prop;
1262
706
        atom_lhs = applySubstitution(nm->realType(),
1263
                                     atom_lhs,
1264
                                     vars,
1265
                                     subs,
1266
                                     prop,
1267
                                     non_basic,
1268
                                     atom_lhs_prop);
1269
706
        if( !atom_lhs.isNull() ){
1270
706
          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
706
          lret = nm->mkNode(atom.getKind(), atom_lhs, atom_rhs);
1275
706
          if( !pol ){
1276
376
            lret = lret.negate();
1277
          }
1278
        }
1279
      }
1280
    }else{
1281
      // don't know how to apply substitution to literal
1282
    }
1283
  }
1284
426199
  if( lit!=lret && !lret.isNull() ){
1285
251362
    lret = Rewriter::rewrite( lret );
1286
  }
1287
426199
  return lret;
1288
}
1289
1290
4597
bool CegInstantiator::check() {
1291
4597
  processAssertions();
1292
6229
  for( unsigned r=0; r<2; r++ ){
1293
5929
    d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
1294
7561
    SolvedForm sf;
1295
5929
    d_stack_vars.clear();
1296
5929
    d_bound_var_index.clear();
1297
5929
    d_solved_asserts.clear();
1298
    //try to add an instantiation
1299
5929
    if (constructInstantiation(sf, 0))
1300
    {
1301
4297
      return true;
1302
    }
1303
  }
1304
300
  Trace("cegqi-engine") << "  WARNING : unable to find CEGQI single invocation instantiation." << std::endl;
1305
300
  return false;
1306
}
1307
1308
4597
void CegInstantiator::processAssertions() {
1309
9194
  Trace("cegqi-proc") << "--- Process assertions, #var = " << d_vars.size()
1310
4597
                     << std::endl;
1311
4597
  d_curr_asserts.clear();
1312
4597
  d_curr_eqc.clear();
1313
4597
  d_curr_type_eqc.clear();
1314
1315
  // must use master equality engine to avoid value instantiations
1316
4597
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
1317
1318
  //for each variable
1319
41821
  for( unsigned i=0; i<d_vars.size(); i++ ){
1320
74448
    Node pv = d_vars[i];
1321
74448
    TypeNode pvtn = pv.getType();
1322
37224
    Trace("cegqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
1323
    //collect information about eqc
1324
37224
    if( ee->hasTerm( pv ) ){
1325
50820
      Node pvr = ee->getRepresentative( pv );
1326
25410
      if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){
1327
13654
        Trace("cegqi-proc") << "Collect equivalence class " << pvr << std::endl;
1328
13654
        eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee );
1329
71762
        while( !eqc_i.isFinished() ){
1330
29054
          d_curr_eqc[pvr].push_back( *eqc_i );
1331
29054
          ++eqc_i;
1332
        }
1333
      }
1334
    }
1335
  }
1336
  //collect assertions for relevant theories
1337
4597
  const LogicInfo& logicInfo = d_qstate.getLogicInfo();
1338
14321
  for (TheoryId tid : d_tids)
1339
  {
1340
9724
    if (!logicInfo.isTheoryEnabled(tid))
1341
    {
1342
2075
      continue;
1343
    }
1344
15298
    Trace("cegqi-proc") << "Collect assertions from theory " << tid
1345
7649
                        << std::endl;
1346
7649
    d_curr_asserts[tid].clear();
1347
    // collect all assertions from theory
1348
367005
    for (context::CDList<Assertion>::const_iterator
1349
7649
             it = d_qstate.factsBegin(tid),
1350
7649
             itEnd = d_qstate.factsEnd(tid);
1351
374654
         it != itEnd;
1352
         ++it)
1353
    {
1354
734010
      Node lit = (*it).d_assertion;
1355
734010
      Node atom = lit.getKind() == NOT ? lit[0] : lit;
1356
734010
      if (d_is_nested_quant
1357
1092509
          || std::find(d_ce_atoms.begin(), d_ce_atoms.end(), atom)
1358
1092509
                 != d_ce_atoms.end())
1359
      {
1360
36076
        d_curr_asserts[tid].push_back(lit);
1361
36076
        Trace("cegqi-proc-debug") << "...add : " << lit << std::endl;
1362
      }
1363
      else
1364
      {
1365
661858
        Trace("cegqi-proc")
1366
330929
            << "...do not consider literal " << tid << " : " << lit
1367
330929
            << " since it is not part of CE body." << std::endl;
1368
      }
1369
    }
1370
  }
1371
  //collect equivalence classes that correspond to relevant theories
1372
4597
  Trace("cegqi-proc-debug") << "...collect typed equivalence classes" << std::endl;
1373
4597
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
1374
780183
  while( !eqcs_i.isFinished() ){
1375
775586
    Node r = *eqcs_i;
1376
775586
    TypeNode rtn = r.getType();
1377
387793
    TheoryId tid = Theory::theoryOf( rtn );
1378
    //if we care about the theory of this eqc
1379
387793
    if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){
1380
326851
      if( rtn.isInteger() || rtn.isReal() ){
1381
22662
        rtn = rtn.getBaseType();
1382
      }
1383
326851
      Trace("cegqi-proc-debug") << "...type eqc: " << r << std::endl;
1384
326851
      d_curr_type_eqc[rtn].push_back( r );
1385
326851
      if( d_curr_eqc.find( r )==d_curr_eqc.end() ){
1386
313197
        Trace("cegqi-proc") << "Collect equivalence class " << r << std::endl;
1387
313197
        Trace("cegqi-proc-debug") << "  ";
1388
313197
        eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
1389
1061225
        while( !eqc_i.isFinished() ){
1390
374014
          Trace("cegqi-proc-debug") << *eqc_i << " ";
1391
374014
          d_curr_eqc[r].push_back( *eqc_i );
1392
374014
          ++eqc_i;
1393
        }
1394
313197
        Trace("cegqi-proc-debug") << std::endl;
1395
      }
1396
    }
1397
387793
    ++eqcs_i;
1398
  }
1399
1400
  //remove unecessary assertions
1401
12246
  for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
1402
15298
    std::vector< Node > akeep;
1403
43725
    for( unsigned i=0; i<it->second.size(); i++ ){
1404
72152
      Node n = it->second[i];
1405
      //must be an eligible term
1406
36076
      if( isEligible( n ) ){
1407
        //must contain at least one variable
1408
30578
        if( !d_prog_var[n].empty() ){
1409
28860
          Trace("cegqi-proc") << "...literal[" << it->first << "] : " << n << std::endl;
1410
28860
          akeep.push_back( n );
1411
        }else{
1412
1718
          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
7649
    it->second.clear();
1419
7649
    it->second.insert( it->second.end(), akeep.begin(), akeep.end() );
1420
  }
1421
1422
  //remove duplicate terms from eqc
1423
331448
  for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
1424
653702
    std::vector< Node > new_eqc;
1425
729919
    for( unsigned i=0; i<it->second.size(); i++ ){
1426
403068
      if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){
1427
403068
        new_eqc.push_back( it->second[i] );
1428
      }
1429
    }
1430
326851
    it->second.clear();
1431
326851
    it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() );
1432
  }
1433
4597
}
1434
1435
116238
Node CegInstantiator::getModelValue( Node n ) {
1436
116238
  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
445748
bool CegInstantiator::isSolvedAssertion(Node n) const
1460
{
1461
445748
  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
24180
void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
1477
24180
  if( n.getKind()==FORALL ){
1478
164
    d_is_nested_quant = true;
1479
24016
  }else if( visited.find( n )==visited.end() ){
1480
22190
    visited[n] = true;
1481
22190
    if( TermUtil::isBoolConnectiveTerm( n ) ){
1482
33756
      for( unsigned i=0; i<n.getNumChildren(); i++ ){
1483
22454
        collectCeAtoms( n[i], visited );
1484
      }
1485
    }else{
1486
10888
      if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
1487
10888
        Trace("cegqi-ce-atoms") << "CE atoms : " << n << std::endl;
1488
10888
        d_ce_atoms.push_back( n );
1489
      }
1490
    }
1491
  }
1492
24180
}
1493
1494
1623
void CegInstantiator::registerCounterexampleLemma(Node lem,
1495
                                                  std::vector<Node>& ceVars,
1496
                                                  std::vector<Node>& auxLems)
1497
{
1498
1623
  Trace("cegqi-reg") << "Register counterexample lemma..." << std::endl;
1499
1623
  d_input_vars.clear();
1500
1623
  d_input_vars.insert(d_input_vars.end(), ceVars.begin(), ceVars.end());
1501
1502
  //Assert( d_vars.empty() );
1503
1623
  d_vars.clear();
1504
1623
  registerTheoryId(THEORY_UF);
1505
4789
  for (const Node& cv : ceVars)
1506
  {
1507
3166
    Trace("cegqi-reg") << "  register input variable : " << cv << std::endl;
1508
3166
    registerVariable(cv);
1509
  }
1510
1511
  // preprocess with all relevant instantiator preprocessors
1512
3246
  Trace("cegqi-debug") << "Preprocess based on theory-specific methods..."
1513
1623
                      << std::endl;
1514
3246
  std::vector<Node> pvars;
1515
1623
  pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
1516
2333
  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
3246
  Trace("cegqi-debug") << "Register variables from theory-specific methods "
1522
3246
                      << d_input_vars.size() << " " << pvars.size() << " ..."
1523
1623
                      << std::endl;
1524
1831
  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
3246
  std::unordered_set<Node> ceSyms;
1533
1623
  expr::getSymbols(lem, ceSyms);
1534
3246
  std::unordered_set<Node> qSyms;
1535
1623
  expr::getSymbols(d_quant, qSyms);
1536
  // all variables that are in counterexample lemma but not in quantified
1537
  // formula
1538
10485
  for (const Node& ces : ceSyms)
1539
  {
1540
8862
    if (qSyms.find(ces) != qSyms.end())
1541
    {
1542
      // a free symbol of the quantified formula.
1543
10718
      continue;
1544
    }
1545
5983
    if (std::find(d_vars.begin(), d_vars.end(), ces) != d_vars.end())
1546
    {
1547
      // already processed variable
1548
3130
      continue;
1549
    }
1550
    // must avoid selector symbols, and function skolems introduced by
1551
    // theory preprocessing
1552
3876
    TypeNode ct = ces.getType();
1553
2853
    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
1830
      continue;
1558
    }
1559
2046
    Trace("cegqi-reg") << "  register theory preprocess variable : " << ces
1560
1023
                       << std::endl;
1561
    // register the variable, which was introduced by TheoryEngine's preprocess
1562
    // method, e.g. an ITE skolem.
1563
1023
    registerVariable(ces);
1564
  }
1565
1566
  // determine variable order: must do Reals before Ints
1567
1623
  Trace("cegqi-debug") << "Determine variable order..." << std::endl;
1568
1623
  if (!d_vars.empty())
1569
  {
1570
3246
    std::map<Node, unsigned> voo;
1571
1623
    bool doSort = false;
1572
3246
    std::vector<Node> vars;
1573
3246
    std::map<TypeNode, std::vector<Node> > tvars;
1574
6020
    for (unsigned i = 0, size = d_vars.size(); i < size; i++)
1575
    {
1576
4397
      voo[d_vars[i]] = i;
1577
4397
      d_var_order_index.push_back(0);
1578
8794
      TypeNode tn = d_vars[i].getType();
1579
4397
      if (tn.isInteger())
1580
      {
1581
2169
        doSort = true;
1582
2169
        tvars[tn].push_back(d_vars[i]);
1583
      }
1584
      else
1585
      {
1586
2228
        vars.push_back(d_vars[i]);
1587
      }
1588
    }
1589
1623
    if (doSort)
1590
    {
1591
544
      Trace("cegqi-debug") << "Sort variables based on ordering." << std::endl;
1592
1088
      for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
1593
      {
1594
544
        vars.insert(vars.end(), vs.second.begin(), vs.second.end());
1595
      }
1596
1597
544
      Trace("cegqi-debug") << "Consider variables in this order : " << std::endl;
1598
2964
      for (unsigned i = 0; i < vars.size(); i++)
1599
      {
1600
2420
        d_var_order_index[voo[vars[i]]] = i;
1601
4840
        Trace("cegqi-debug") << "  " << vars[i] << " : " << vars[i].getType()
1602
2420
                            << ", index was : " << voo[vars[i]] << std::endl;
1603
2420
        d_vars[i] = vars[i];
1604
      }
1605
544
      Trace("cegqi-debug") << std::endl;
1606
    }
1607
    else
1608
    {
1609
1079
      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
1623
  d_is_nested_quant = false;
1616
3246
  std::map< Node, bool > visited;
1617
1623
  collectCeAtoms(lem, visited);
1618
1726
  for (const Node& alem : auxLems)
1619
  {
1620
103
    collectCeAtoms(alem, visited);
1621
  }
1622
1623
}
1623
1624
3058
Instantiator::Instantiator(TypeNode tn) : d_type(tn)
1625
{
1626
3058
  d_closed_enum_type = tn.isClosedEnumerable();
1627
3058
}
1628
1629
11
bool Instantiator::processEqualTerm(CegInstantiator* ci,
1630
                                    SolvedForm& sf,
1631
                                    Node pv,
1632
                                    TermProperties& pv_prop,
1633
                                    Node n,
1634
                                    CegInstEffort effort)
1635
{
1636
11
  pv_prop.d_type = CEG_TT_EQUAL;
1637
11
  return ci->constructInstantiationInc(pv, n, pv_prop, sf);
1638
}
1639
1640
}  // namespace quantifiers
1641
}  // namespace theory
1642
29502
}  // namespace cvc5