GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/ceg_instantiator.cpp Lines: 822 899 91.4 %
Date: 2021-11-05 Branches: 1656 3362 49.3 %

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 "expr/dtype.h"
19
#include "expr/dtype_cons.h"
20
#include "expr/node_algorithm.h"
21
#include "options/quantifiers_options.h"
22
#include "theory/arith/arith_msum.h"
23
#include "theory/quantifiers/cegqi/ceg_arith_instantiator.h"
24
#include "theory/quantifiers/cegqi/ceg_bv_instantiator.h"
25
#include "theory/quantifiers/cegqi/ceg_dt_instantiator.h"
26
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
27
#include "theory/quantifiers/first_order_model.h"
28
#include "theory/quantifiers/quantifiers_attributes.h"
29
#include "theory/quantifiers/quantifiers_state.h"
30
#include "theory/quantifiers/term_database.h"
31
#include "theory/quantifiers/term_util.h"
32
#include "theory/rewriter.h"
33
#include "util/rational.h"
34
35
using namespace std;
36
using namespace cvc5::kind;
37
38
namespace cvc5 {
39
namespace theory {
40
namespace quantifiers {
41
42
366
CegTermType mkStrictCTT(CegTermType c)
43
{
44
366
  Assert(!isStrictCTT(c));
45
366
  if (c == CEG_TT_LOWER)
46
  {
47
219
    return CEG_TT_LOWER_STRICT;
48
  }
49
147
  else if (c == CEG_TT_UPPER)
50
  {
51
147
    return CEG_TT_UPPER_STRICT;
52
  }
53
  return c;
54
}
55
56
3797
CegTermType mkNegateCTT(CegTermType c)
57
{
58
3797
  if (c == CEG_TT_LOWER)
59
  {
60
1031
    return CEG_TT_UPPER;
61
  }
62
2766
  else if (c == CEG_TT_UPPER)
63
  {
64
2766
    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
366
bool isStrictCTT(CegTermType c)
77
{
78
366
  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
18741
bool isUpperBoundCTT(CegTermType c)
85
{
86
18741
  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
47
void TermProperties::composeProperty(TermProperties& p)
129
{
130
47
  if (p.d_coeff.isNull())
131
  {
132
    return;
133
  }
134
47
  if (d_coeff.isNull())
135
  {
136
41
    d_coeff = p.d_coeff;
137
  }
138
  else
139
  {
140
6
    NodeManager* nm = NodeManager::currentNM();
141
12
    d_coeff = nm->mkConst(Rational(d_coeff.getConst<Rational>()
142
6
                                   * p.d_coeff.getConst<Rational>()));
143
  }
144
}
145
146
// push the substitution pv_prop.getModifiedTerm(pv) -> n
147
41244
void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop)
148
{
149
41244
  d_vars.push_back(pv);
150
41244
  d_subs.push_back(n);
151
41244
  d_props.push_back(pv_prop);
152
41244
  if (pv_prop.isBasic())
153
  {
154
41032
    return;
155
  }
156
212
  d_non_basic.push_back(pv);
157
  // update theta value
158
424
  Node new_theta = getTheta();
159
212
  if (new_theta.isNull())
160
  {
161
158
    new_theta = pv_prop.d_coeff;
162
  }
163
  else
164
  {
165
54
    Assert(new_theta.getKind() == CONST_RATIONAL);
166
54
    Assert(pv_prop.d_coeff.getKind() == CONST_RATIONAL);
167
54
    NodeManager* nm = NodeManager::currentNM();
168
54
    new_theta = nm->mkConst(Rational(new_theta.getConst<Rational>()
169
                                     * pv_prop.d_coeff.getConst<Rational>()));
170
  }
171
212
  d_theta.push_back(new_theta);
172
}
173
// pop the substitution pv_prop.getModifiedTerm(pv) -> n
174
4388
void SolvedForm::pop_back(Node pv, Node n, TermProperties& pv_prop)
175
{
176
4388
  d_vars.pop_back();
177
4388
  d_subs.pop_back();
178
4388
  d_props.pop_back();
179
4388
  if (pv_prop.isBasic())
180
  {
181
4343
    return;
182
  }
183
45
  d_non_basic.pop_back();
184
  // update theta value
185
45
  d_theta.pop_back();
186
}
187
188
1931
CegInstantiator::CegInstantiator(Env& env,
189
                                 Node q,
190
                                 QuantifiersState& qs,
191
                                 TermRegistry& tr,
192
1931
                                 InstStrategyCegqi* parent)
193
    : EnvObj(env),
194
      d_quant(q),
195
      d_qstate(qs),
196
      d_treg(tr),
197
      d_parent(parent),
198
      d_is_nested_quant(false),
199
1931
      d_effort(CEG_INST_EFFORT_NONE)
200
{
201
1931
}
202
203
5793
CegInstantiator::~CegInstantiator() {
204
5461
  for (std::pair<Node, Instantiator*> inst : d_instantiator)
205
  {
206
3530
    delete inst.second;
207
  }
208
2669
  for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
209
  {
210
738
    delete instp.second;
211
  }
212
3862
}
213
214
3386659
void CegInstantiator::computeProgVars( Node n ){
215
3386659
  if( d_prog_var.find( n )==d_prog_var.end() ){
216
64480
    d_prog_var[n].clear();
217
64480
    if (n.getKind() == kind::WITNESS)
218
    {
219
544
      Assert(d_prog_var.find(n[0][0]) == d_prog_var.end());
220
544
      d_prog_var[n[0][0]].clear();
221
    }
222
64480
    if (d_vars_set.find(n) != d_vars_set.end())
223
    {
224
3197
      d_prog_var[n].insert(n);
225
    }
226
61283
    else if (!isEligibleForInstantiation(n))
227
    {
228
3078
      d_inelig.insert(n);
229
3078
      return;
230
    }
231
148488
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
232
87086
      computeProgVars( n[i] );
233
87086
      if( d_inelig.find( n[i] )!=d_inelig.end() ){
234
12443
        d_inelig.insert(n);
235
      }
236
      // all variables in child are contained in this
237
87086
      d_prog_var[n].insert(d_prog_var[n[i]].begin(), d_prog_var[n[i]].end());
238
    }
239
    // selectors applied to program variables are also variables
240
122804
    if (n.getKind() == APPLY_SELECTOR_TOTAL
241
122804
        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
242
    {
243
60
      d_prog_var[n].insert(n);
244
    }
245
61402
    if (n.getKind() == kind::WITNESS)
246
    {
247
544
      d_prog_var.erase(n[0][0]);
248
    }
249
  }
250
}
251
252
948656
bool CegInstantiator::isEligible( Node n ) {
253
  //compute d_subs_fv, which program variables are contained in n, and determines if eligible
254
948656
  computeProgVars( n );
255
948656
  return d_inelig.find( n )==d_inelig.end();
256
}
257
258
56096
CegHandledStatus CegInstantiator::isCbqiKind(Kind k)
259
{
260
141303
  if (quantifiers::TermUtil::isBoolConnective(k) || k == PLUS || k == GEQ
261
15078
      || k == EQUAL || k == MULT || k == NONLINEAR_MULT || k == DIVISION
262
9239
      || k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL
263
9103
      || k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == TO_INTEGER
264
65098
      || k == IS_INTEGER)
265
  {
266
47098
    return CEG_HANDLED;
267
  }
268
269
  // CBQI typically works for satisfaction-complete theories
270
8998
  TheoryId t = kindToTheoryId(k);
271
8998
  if (t == THEORY_BV || t == THEORY_FP || t == THEORY_DATATYPES
272
5825
      || t == THEORY_BOOL)
273
  {
274
3173
    return CEG_HANDLED;
275
  }
276
5825
  return CEG_UNHANDLED;
277
}
278
279
7856
CegHandledStatus CegInstantiator::isCbqiTerm(Node n)
280
{
281
7856
  CegHandledStatus ret = CEG_HANDLED;
282
15712
  std::unordered_set<TNode> visited;
283
15712
  std::vector<TNode> visit;
284
15712
  TNode cur;
285
7856
  visit.push_back(n);
286
103126
  do
287
  {
288
110982
    cur = visit.back();
289
110982
    visit.pop_back();
290
110982
    if (visited.find(cur) == visited.end())
291
    {
292
90729
      visited.insert(cur);
293
90729
      if (cur.getKind() != BOUND_VARIABLE && TermUtil::hasBoundVarAttr(cur))
294
      {
295
64286
        if (cur.getKind() == FORALL || cur.getKind() == WITNESS)
296
        {
297
8190
          visit.push_back(cur[1]);
298
        }
299
        else
300
        {
301
56096
          CegHandledStatus curr = isCbqiKind(cur.getKind());
302
56096
          if (curr < ret)
303
          {
304
5825
            ret = curr;
305
11650
            Trace("cegqi-debug2") << "Non-cbqi kind : " << cur.getKind()
306
5825
                                 << " in " << n << std::endl;
307
5825
            if (curr == CEG_UNHANDLED)
308
            {
309
5825
              return CEG_UNHANDLED;
310
            }
311
          }
312
157386
          for (const Node& nc : cur)
313
          {
314
107115
            visit.push_back(nc);
315
          }
316
        }
317
      }
318
    }
319
105157
  } while (!visit.empty());
320
2031
  return ret;
321
}
322
323
25893
CegHandledStatus CegInstantiator::isCbqiSort(TypeNode tn)
324
{
325
51786
  std::map<TypeNode, CegHandledStatus> visited;
326
51786
  return isCbqiSort(tn, visited);
327
}
328
329
31073
CegHandledStatus CegInstantiator::isCbqiSort(
330
    TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited)
331
{
332
31073
  std::map<TypeNode, CegHandledStatus>::iterator itv = visited.find(tn);
333
31073
  if (itv != visited.end())
334
  {
335
3011
    return itv->second;
336
  }
337
28062
  CegHandledStatus ret = CEG_UNHANDLED;
338
72625
  if (tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector()
339
42266
      || tn.isFloatingPoint())
340
  {
341
13871
    ret = CEG_HANDLED;
342
  }
343
14191
  else if (tn.isDatatype())
344
  {
345
    // recursive calls to this datatype are handlable
346
2317
    visited[tn] = CEG_HANDLED;
347
    // we initialize to handled, we remain handled as long as all subfields
348
    // of this datatype are not unhandled.
349
2317
    ret = CEG_HANDLED;
350
2317
    const DType& dt = tn.getDType();
351
4799
    for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
352
    {
353
      // get the constructor type
354
6486
      TypeNode consType;
355
4004
      if (dt.isParametric())
356
      {
357
        // if parametric, must instantiate the argument types
358
36
        consType = dt[i].getSpecializedConstructorType(tn);
359
      }
360
      else
361
      {
362
3968
        consType = dt[i].getConstructor().getType();
363
      }
364
7662
      for (const TypeNode& crange : consType)
365
      {
366
5180
        CegHandledStatus cret = isCbqiSort(crange, visited);
367
5180
        if (cret == CEG_UNHANDLED)
368
        {
369
3044
          Trace("cegqi-debug2")
370
1522
              << "Non-cbqi sort : " << tn << " due to " << crange << std::endl;
371
1522
          visited[tn] = CEG_UNHANDLED;
372
1522
          return CEG_UNHANDLED;
373
        }
374
3658
        else if (cret < ret)
375
        {
376
          ret = cret;
377
        }
378
      }
379
    }
380
  }
381
  // sets, arrays, functions and others are not supported
382
26540
  visited[tn] = ret;
383
26540
  return ret;
384
}
385
386
19728
CegHandledStatus CegInstantiator::isCbqiQuantPrefix(Node q)
387
{
388
19728
  CegHandledStatus hmin = CEG_HANDLED_UNCONDITIONAL;
389
33692
  for (const Node& v : q[0])
390
  {
391
39800
    TypeNode tn = v.getType();
392
25836
    CegHandledStatus handled = isCbqiSort(tn);
393
25836
    if (handled == CEG_UNHANDLED)
394
    {
395
11872
      return CEG_UNHANDLED;
396
    }
397
13964
    else if (handled < hmin)
398
    {
399
8175
      hmin = handled;
400
    }
401
  }
402
7856
  return hmin;
403
}
404
405
24527
CegHandledStatus CegInstantiator::isCbqiQuant(Node q)
406
{
407
24527
  Assert(q.getKind() == FORALL);
408
  // compute attributes
409
49054
  QAttributes qa;
410
24527
  QuantAttributes::computeQuantAttributes(q, qa);
411
24527
  if (qa.d_quant_elim)
412
  {
413
96
    return CEG_HANDLED;
414
  }
415
24431
  if (qa.d_sygus)
416
  {
417
548
    return CEG_UNHANDLED;
418
  }
419
23883
  Assert(!qa.d_quant_elim_partial);
420
  // if has an instantiation pattern, don't do it
421
23883
  if (q.getNumChildren() == 3)
422
  {
423
6131
    for (const Node& pat : q[2])
424
    {
425
5314
      if (pat.getKind() == INST_PATTERN)
426
      {
427
4155
        return CEG_UNHANDLED;
428
      }
429
    }
430
  }
431
19728
  CegHandledStatus ret = CEG_HANDLED;
432
  // if quantifier has a non-handled variable, then do not use cbqi
433
19728
  CegHandledStatus ncbqiv = CegInstantiator::isCbqiQuantPrefix(q);
434
39456
  Trace("cegqi-quant-debug") << "isCbqiQuantPrefix returned " << ncbqiv
435
19728
                            << std::endl;
436
19728
  if (ncbqiv == CEG_UNHANDLED)
437
  {
438
    // unhandled variable type
439
11872
    ret = CEG_UNHANDLED;
440
  }
441
  else
442
  {
443
7856
    CegHandledStatus cbqit = CegInstantiator::isCbqiTerm(q);
444
7856
    Trace("cegqi-quant-debug") << "isCbqiTerm returned " << cbqit << std::endl;
445
7856
    if (cbqit == CEG_UNHANDLED)
446
    {
447
5825
      if (ncbqiv == CEG_HANDLED_UNCONDITIONAL)
448
      {
449
        // all variables are fully handled, this implies this will be handlable
450
        // regardless of body (e.g. for EPR)
451
        //  so, try but not exclusively
452
        ret = CEG_PARTIALLY_HANDLED;
453
      }
454
      else
455
      {
456
        // cannot be handled
457
5825
        ret = CEG_UNHANDLED;
458
      }
459
    }
460
2031
    else if (cbqit == CEG_PARTIALLY_HANDLED)
461
    {
462
      ret = CEG_PARTIALLY_HANDLED;
463
    }
464
  }
465
19728
  if (ret == CEG_UNHANDLED && options::cegqiAll())
466
  {
467
    // try but not exclusively
468
17
    ret = CEG_PARTIALLY_HANDLED;
469
  }
470
19728
  return ret;
471
}
472
473
436140
bool CegInstantiator::hasVariable( Node n, Node pv ) {
474
436140
  computeProgVars( n );
475
436140
  return d_prog_var[n].find( pv )!=d_prog_var[n].end();
476
}
477
478
41348
void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
479
{
480
41348
  if( d_instantiator.find( v )==d_instantiator.end() ){
481
7060
    TypeNode tn = v.getType();
482
    Instantiator * vinst;
483
3530
    if( tn.isReal() ){
484
2021
      vinst = new ArithInstantiator(d_env, tn, d_parent->getVtsTermCache());
485
1509
    }else if( tn.isDatatype() ){
486
54
      vinst = new DtInstantiator(d_env, tn);
487
1455
    }else if( tn.isBitVector() ){
488
1224
      vinst = new BvInstantiator(d_env, tn, d_parent->getBvInverter());
489
231
    }else if( tn.isBoolean() ){
490
219
      vinst = new ModelValueInstantiator(d_env, tn);
491
    }else{
492
      //default
493
12
      vinst = new Instantiator(d_env, tn);
494
    }
495
3530
    d_instantiator[v] = vinst;
496
  }
497
41348
  d_curr_subs_proc[v].clear();
498
41348
  d_curr_index[v] = index;
499
41348
  d_curr_iphase[v] = CEG_INST_PHASE_NONE;
500
41348
}
501
502
4492
void CegInstantiator::deactivateInstantiationVariable(Node v)
503
{
504
4492
  d_curr_subs_proc.erase(v);
505
4492
  d_curr_index.erase(v);
506
4492
  d_curr_iphase.erase(v);
507
4492
}
508
509
66392
bool CegInstantiator::hasTriedInstantiation(Node v)
510
{
511
66392
  return !d_curr_subs_proc[v].empty();
512
}
513
514
5431
void CegInstantiator::registerTheoryIds(TypeNode tn,
515
                                        std::map<TypeNode, bool>& visited)
516
{
517
5431
  if (visited.find(tn) == visited.end())
518
  {
519
5377
    visited[tn] = true;
520
5377
    TheoryId tid = Theory::theoryOf(tn);
521
5377
    registerTheoryId(tid);
522
5377
    if (tn.isDatatype())
523
    {
524
66
      const DType& dt = tn.getDType();
525
170
      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
526
      {
527
222
        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
528
        {
529
118
          registerTheoryIds(dt[i].getArgType(j), visited);
530
        }
531
      }
532
    }
533
  }
534
5431
}
535
536
7308
void CegInstantiator::registerTheoryId(TheoryId tid)
537
{
538
7308
  if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
539
  {
540
    // setup any theory-specific preprocessors here
541
3935
    if (tid == THEORY_BV)
542
    {
543
738
      d_tipp[tid] = new BvInstantiatorPreprocess;
544
    }
545
3935
    d_tids.push_back(tid);
546
  }
547
7308
}
548
549
5313
void CegInstantiator::registerVariable(Node v)
550
{
551
5313
  Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
552
5313
  d_vars.push_back(v);
553
5313
  d_vars_set.insert(v);
554
10626
  TypeNode vtn = v.getType();
555
10626
  Trace("cegqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
556
5313
                           << v << std::endl;
557
  // collect relevant theories for this variable
558
10626
  std::map<TypeNode, bool> visited;
559
5313
  registerTheoryIds(vtn, visited);
560
5313
}
561
562
47363
bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
563
{
564
47363
  if( i==d_vars.size() ){
565
    //solved for all variables, now construct instantiation
566
    bool needsPostprocess =
567
6015
        sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty();
568
12030
    std::vector< Instantiator * > pp_inst;
569
12030
    std::map< Instantiator *, Node > pp_inst_to_var;
570
47259
    for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){
571
123732
      if (ita->second->needsPostProcessInstantiationForVariable(
572
82488
              this, sf, ita->first, d_effort))
573
      {
574
253
        needsPostprocess = true;
575
253
        pp_inst_to_var[ ita->second ] = ita->first;
576
      }
577
    }
578
6015
    if( needsPostprocess ){
579
      //must make copy so that backtracking reverts sf
580
4426
      SolvedForm sf_tmp = sf;
581
2213
      bool postProcessSuccess = true;
582
2425
      for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){
583
759
        if (!itp->first->postProcessInstantiationForVariable(
584
506
                this, sf_tmp, itp->second, d_effort))
585
        {
586
41
          postProcessSuccess = false;
587
41
          break;
588
        }
589
      }
590
2213
      if( postProcessSuccess ){
591
2172
        return doAddInstantiation(sf_tmp.d_vars, sf_tmp.d_subs);
592
      }else{
593
41
        return false;
594
      }
595
    }else{
596
3802
      return doAddInstantiation(sf.d_vars, sf.d_subs);
597
    }
598
  }else{
599
41348
    bool is_sv = false;
600
82696
    Node pv;
601
41348
    if( d_stack_vars.empty() ){
602
41288
      pv = d_vars[i];
603
    }else{
604
60
      pv = d_stack_vars.back();
605
60
      is_sv = true;
606
60
      d_stack_vars.pop_back();
607
    }
608
41348
    activateInstantiationVariable(pv, i);
609
610
    //get the instantiator object
611
41348
    Assert(d_instantiator.find(pv) != d_instantiator.end());
612
41348
    Instantiator* vinst = d_instantiator[pv];
613
41348
    Assert(vinst != NULL);
614
41348
    d_active_instantiators[pv] = vinst;
615
41348
    vinst->reset(this, sf, pv, d_effort);
616
    // if d_effort is full, we must choose at least one model value
617
41348
    if ((i + 1) < d_vars.size() || d_effort != CEG_INST_EFFORT_FULL)
618
    {
619
      // First, try to construct an instantiation term for pv based on
620
      // equality and theory-specific instantiation techniques.
621
40035
      if (constructInstantiation(sf, vinst, pv))
622
      {
623
26595
        return true;
624
      }
625
    }
626
    // If the above call fails, resort to using value in model. We do so if:
627
    // - we have yet to try an instantiation this round (or we are trying
628
    //   multiple instantiations, indicated by options::cegqiMultiInst),
629
    // - the instantiator uses model values at this effort or
630
    //   if we are solving for a subfield of a datatype (is_sv), and
631
    // - the instantiator allows model values.
632
44219
    if ((options().quantifiers.cegqiMultiInst || !hasTriedInstantiation(pv))
633
26536
        && (vinst->useModelValue(this, sf, pv, d_effort) || is_sv)
634
41125
        && vinst->allowModelValue(this, sf, pv, d_effort))
635
    {
636
12977
      Node mv = getModelValue( pv );
637
12977
      TermProperties pv_prop_m;
638
11619
      Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
639
11619
      d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
640
11619
      CegInstEffort prev = d_effort;
641
11619
      if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
642
      {
643
        // update the effort level to indicate we have used a model value
644
2114
        d_effort = CEG_INST_EFFORT_STANDARD_MV;
645
      }
646
11619
      if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
647
      {
648
10261
        return true;
649
      }
650
1358
      d_effort = prev;
651
    }
652
653
4492
    Trace("cegqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl;
654
4492
    if (is_sv)
655
    {
656
      d_stack_vars.push_back( pv );
657
    }
658
4492
    d_active_instantiators.erase( pv );
659
4492
    deactivateInstantiationVariable(pv);
660
4492
    return false;
661
  }
662
}
663
664
40035
bool CegInstantiator::constructInstantiation(SolvedForm& sf,
665
                                             Instantiator* vinst,
666
                                             Node pv)
667
{
668
80070
  TypeNode pvtn = pv.getType();
669
80070
  TypeNode pvtnb = pvtn.getBaseType();
670
80070
  Node pvr = pv;
671
40035
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
672
40035
  if (ee->hasTerm(pv))
673
  {
674
27646
    pvr = ee->getRepresentative(pv);
675
  }
676
80070
  Trace("cegqi-inst-debug") << "[Find instantiation for " << pv
677
40035
                           << "], rep=" << pvr << ", instantiator is "
678
40035
                           << vinst->identify() << std::endl;
679
80070
  Node pv_value;
680
40035
  if (options().quantifiers.cegqiModel)
681
  {
682
40035
    pv_value = getModelValue(pv);
683
40035
    Trace("cegqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl;
684
  }
685
686
  //[1] easy case : pv is in the equivalence class as another term not
687
  // containing pv
688
40035
  if (vinst->hasProcessEqualTerm(this, sf, pv, d_effort))
689
  {
690
116
    Trace("cegqi-inst-debug")
691
58
        << "[1] try based on equivalence class." << std::endl;
692
58
    d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
693
58
    std::map<Node, std::vector<Node> >::iterator it_eqc = d_curr_eqc.find(pvr);
694
58
    if (it_eqc != d_curr_eqc.end())
695
    {
696
      // std::vector< Node > eq_candidates;
697
116
      Trace("cegqi-inst-debug2")
698
58
          << "...eqc has size " << it_eqc->second.size() << std::endl;
699
164
      for (const Node& n : it_eqc->second)
700
      {
701
120
        if (n != pv)
702
        {
703
148
          Trace("cegqi-inst-debug")
704
74
              << "...try based on equal term " << n << std::endl;
705
          // must be an eligible term
706
74
          if (isEligible(n))
707
          {
708
94
            Node ns;
709
            // coefficient of pv in the equality we solve (null is 1)
710
94
            TermProperties pv_prop;
711
54
            bool proc = false;
712
54
            if (!d_prog_var[n].empty())
713
            {
714
46
              ns = applySubstitution(pvtn, n, sf, pv_prop, false);
715
46
              if (!ns.isNull())
716
              {
717
46
                computeProgVars(ns);
718
                // substituted version must be new and cannot contain pv
719
46
                proc = d_prog_var[ns].find(pv) == d_prog_var[ns].end();
720
              }
721
            }
722
            else
723
            {
724
8
              ns = n;
725
8
              proc = true;
726
            }
727
54
            if (proc)
728
            {
729
14
              if (vinst->processEqualTerm(this, sf, pv, pv_prop, ns, d_effort))
730
              {
731
14
                return true;
732
              }
733
              else if (!options().quantifiers.cegqiMultiInst
734
                       && hasTriedInstantiation(pv))
735
              {
736
                return false;
737
              }
738
              // Do not consider more than one equal term,
739
              // this helps non-monotonic strategies that may encounter
740
              // duplicate instantiations.
741
              break;
742
            }
743
          }
744
        }
745
      }
746
44
      if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
747
      {
748
34
        return true;
749
      }
750
20
      else if (!options().quantifiers.cegqiMultiInst
751
20
               && hasTriedInstantiation(pv))
752
      {
753
        return false;
754
      }
755
    }
756
    else
757
    {
758
      Trace("cegqi-inst-debug2") << "...eqc not found." << std::endl;
759
    }
760
  }
761
762
  //[2] : we can solve an equality for pv
763
  /// iterate over equivalence classes to find cases where we can solve for
764
  /// the variable
765
39987
  if (vinst->hasProcessEquality(this, sf, pv, d_effort))
766
  {
767
55892
    Trace("cegqi-inst-debug")
768
27946
        << "[2] try based on solving equalities." << std::endl;
769
27946
    d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
770
27946
    std::vector<Node>& cteqc = d_curr_type_eqc[pvtnb];
771
772
387952
    for (const Node& r : cteqc)
773
    {
774
373230
      std::map<Node, std::vector<Node> >::iterator it_reqc = d_curr_eqc.find(r);
775
733236
      std::vector<Node> lhs;
776
733236
      std::vector<bool> lhs_v;
777
733236
      std::vector<TermProperties> lhs_prop;
778
373230
      Assert(it_reqc != d_curr_eqc.end());
779
1270464
      for (const Node& n : it_reqc->second)
780
      {
781
910458
        Trace("cegqi-inst-debug2") << "...look at term " << n << std::endl;
782
        // must be an eligible term
783
910458
        if (isEligible(n))
784
        {
785
1474676
          Node ns;
786
1474676
          TermProperties pv_prop;
787
743950
          if (!d_prog_var[n].empty())
788
          {
789
686235
            ns = applySubstitution(pvtn, n, sf, pv_prop);
790
686235
            if (!ns.isNull())
791
            {
792
686217
              computeProgVars(ns);
793
            }
794
          }
795
          else
796
          {
797
57715
            ns = n;
798
          }
799
743950
          if (!ns.isNull())
800
          {
801
743932
            bool hasVar = d_prog_var[ns].find(pv) != d_prog_var[ns].end();
802
1487864
            Trace("cegqi-inst-debug2") << "... " << ns << " has var " << pv
803
743932
                                      << " : " << hasVar << std::endl;
804
1474640
            std::vector<TermProperties> term_props;
805
1474640
            std::vector<Node> terms;
806
743932
            term_props.push_back(pv_prop);
807
743932
            terms.push_back(ns);
808
1536079
            for (unsigned j = 0, size = lhs.size(); j < size; j++)
809
            {
810
              // if this term or the another has pv in it, try to solve for it
811
805371
              if (hasVar || lhs_v[j])
812
              {
813
92246
                Trace("cegqi-inst-debug") << "......try based on equality "
814
46123
                                         << lhs[j] << " = " << ns << std::endl;
815
46123
                term_props.push_back(lhs_prop[j]);
816
46123
                terms.push_back(lhs[j]);
817
46123
                if (vinst->processEquality(
818
46123
                        this, sf, pv, term_props, terms, d_effort))
819
                {
820
12442
                  return true;
821
                }
822
67362
                else if (!options().quantifiers.cegqiMultiInst
823
67362
                         && hasTriedInstantiation(pv))
824
                {
825
782
                  return false;
826
                }
827
32899
                term_props.pop_back();
828
32899
                terms.pop_back();
829
              }
830
            }
831
730708
            lhs.push_back(ns);
832
730708
            lhs_v.push_back(hasVar);
833
730708
            lhs_prop.push_back(pv_prop);
834
          }
835
          else
836
          {
837
36
            Trace("cegqi-inst-debug2")
838
18
                << "... term " << n << " is ineligible after substitution."
839
18
                << std::endl;
840
          }
841
        }
842
        else
843
        {
844
333016
          Trace("cegqi-inst-debug2")
845
166508
              << "... term " << n << " is ineligible." << std::endl;
846
        }
847
      }
848
    }
849
  }
850
  //[3] directly look at assertions
851
26763
  if (!vinst->hasProcessAssertion(this, sf, pv, d_effort))
852
  {
853
7196
    return false;
854
  }
855
19567
  Trace("cegqi-inst-debug") << "[3] try based on assertions." << std::endl;
856
19567
  d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
857
39134
  std::unordered_set<Node> lits;
858
58701
  for (unsigned r = 0; r < 2; r++)
859
  {
860
39134
    TheoryId tid = r == 0 ? Theory::theoryOf(pvtn) : THEORY_UF;
861
39134
    Trace("cegqi-inst-debug2") << "  look at assertions of " << tid << std::endl;
862
    std::map<TheoryId, std::vector<Node> >::iterator ita =
863
39134
        d_curr_asserts.find(tid);
864
39134
    if (ita != d_curr_asserts.end())
865
    {
866
486491
      for (const Node& lit : ita->second)
867
      {
868
462331
        if (lits.find(lit) == lits.end())
869
        {
870
453486
          lits.insert(lit);
871
906972
          Node plit;
872
453486
          if (options().quantifiers.cegqiRepeatLit || !isSolvedAssertion(lit))
873
          {
874
447862
            plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort);
875
          }
876
453486
          if (!plit.isNull())
877
          {
878
436257
            Trace("cegqi-inst-debug2") << "  look at " << lit;
879
436257
            if (plit != lit)
880
            {
881
9229
              Trace("cegqi-inst-debug2") << "...processed to : " << plit;
882
            }
883
436257
            Trace("cegqi-inst-debug2") << std::endl;
884
            // apply substitutions
885
872514
            Node slit = applySubstitutionToLiteral(plit, sf);
886
436257
            if (!slit.isNull())
887
            {
888
              // check if contains pv
889
436140
              if (hasVariable(slit, pv))
890
              {
891
36280
                Trace("cegqi-inst-debug")
892
18140
                    << "...try based on literal " << slit << "," << std::endl;
893
18140
                Trace("cegqi-inst-debug") << "...from " << lit << std::endl;
894
18140
                if (vinst->processAssertion(this, sf, pv, slit, lit, d_effort))
895
                {
896
                  return true;
897
                }
898
36280
                else if (!options().quantifiers.cegqiMultiInst
899
36280
                         && hasTriedInstantiation(pv))
900
                {
901
                  return false;
902
                }
903
              }
904
            }
905
          }
906
        }
907
      }
908
    }
909
  }
910
19567
  if (vinst->processAssertions(this, sf, pv, d_effort))
911
  {
912
14105
    return true;
913
  }
914
5462
  return false;
915
}
916
917
60
void CegInstantiator::pushStackVariable( Node v ) {
918
60
  d_stack_vars.push_back( v );
919
60
}
920
921
void CegInstantiator::popStackVariable() {
922
  Assert(!d_stack_vars.empty());
923
  d_stack_vars.pop_back();
924
}
925
926
41244
bool CegInstantiator::constructInstantiationInc(Node pv,
927
                                                Node n,
928
                                                TermProperties& pv_prop,
929
                                                SolvedForm& sf,
930
                                                bool revertOnSuccess)
931
{
932
82488
  Node cnode = pv_prop.getCacheNode();
933
41244
  if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
934
41244
    d_curr_subs_proc[pv][n][cnode] = true;
935
41244
    if( Trace.isOn("cegqi-inst-debug") ){
936
      for( unsigned j=0; j<sf.d_subs.size(); j++ ){
937
        Trace("cegqi-inst-debug") << " ";
938
      }
939
      Trace("cegqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv]
940
                         << ") ";
941
      Node mod_pv = pv_prop.getModifiedTerm( pv );
942
      Trace("cegqi-inst-debug") << mod_pv << " -> " << n << std::endl;
943
      Assert(n.getType().isSubtypeOf(pv.getType()));
944
    }
945
    //must ensure variables have been computed for n
946
41244
    computeProgVars( n );
947
41244
    Assert(d_inelig.find(n) == d_inelig.end());
948
949
    //substitute into previous substitutions, when applicable
950
82488
    std::vector< Node > a_var;
951
41244
    a_var.push_back( pv );
952
82488
    std::vector< Node > a_subs;
953
41244
    a_subs.push_back( n );
954
82488
    std::vector< TermProperties > a_prop;
955
41244
    a_prop.push_back( pv_prop );
956
82488
    std::vector< Node > a_non_basic;
957
41244
    if( !pv_prop.isBasic() ){
958
212
      a_non_basic.push_back( pv );
959
    }
960
41244
    bool success = true;
961
82488
    std::map< int, Node > prev_subs;
962
82488
    std::map< int, TermProperties > prev_prop;
963
82488
    std::map< int, Node > prev_sym_subs;
964
82488
    std::vector< Node > new_non_basic;
965
41244
    Trace("cegqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl;
966
835506
    for( unsigned j=0; j<sf.d_subs.size(); j++ ){
967
794262
      Trace("cegqi-inst-debug2") << "  Apply for " << sf.d_subs[j]  << std::endl;
968
794262
      Assert(d_prog_var.find(sf.d_subs[j]) != d_prog_var.end());
969
794262
      if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
970
31978
        prev_subs[j] = sf.d_subs[j];
971
63956
        TNode tv = pv;
972
63956
        TNode ts = n;
973
63956
        TermProperties a_pv_prop;
974
63956
        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 );
975
31978
        if( !new_subs.isNull() ){
976
31978
          sf.d_subs[j] = new_subs;
977
          // the substitution apply to this term resulted in a non-basic substitution relationship
978
31978
          if( !a_pv_prop.isBasic() ){
979
            // we are processing:
980
            //    sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n }
981
982
            // based on the above substitution, we have:
983
            //   x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n }
984
            // is equivalent to
985
            //   a_pv_prop.getModifiedTerm( x ) = new_subs
986
987
            // thus we must compose substitutions:
988
            //   a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs
989
990
47
            prev_prop[j] = sf.d_props[j];
991
47
            bool prev_basic = sf.d_props[j].isBasic();
992
993
            // now compose the property
994
47
            sf.d_props[j].composeProperty( a_pv_prop );
995
996
            // if previously was basic, becomes non-basic
997
47
            if( prev_basic && !sf.d_props[j].isBasic() ){
998
41
              Assert(std::find(sf.d_non_basic.begin(),
999
                               sf.d_non_basic.end(),
1000
                               sf.d_vars[j])
1001
                     == sf.d_non_basic.end());
1002
41
              new_non_basic.push_back( sf.d_vars[j] );
1003
41
              sf.d_non_basic.push_back( sf.d_vars[j] );
1004
            }
1005
          }
1006
31978
          if( sf.d_subs[j]!=prev_subs[j] ){
1007
31974
            computeProgVars( sf.d_subs[j] );
1008
31974
            Assert(d_inelig.find(sf.d_subs[j]) == d_inelig.end());
1009
          }
1010
31978
          Trace("cegqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl;
1011
        }else{
1012
          Trace("cegqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl;
1013
          success = false;
1014
          break;
1015
        }
1016
      }else{
1017
762284
        Trace("cegqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl;
1018
      }
1019
    }
1020
41244
    if( success ){
1021
41244
      Trace("cegqi-inst-debug2") << "Adding to vectors..." << std::endl;
1022
41244
      sf.push_back( pv, n, pv_prop );
1023
41244
      Trace("cegqi-inst-debug2") << "Recurse..." << std::endl;
1024
41244
      unsigned i = d_curr_index[pv];
1025
41244
      success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
1026
41244
      if (!success || revertOnSuccess)
1027
      {
1028
4388
        Trace("cegqi-inst-debug2") << "Removing from vectors..." << std::endl;
1029
4388
        sf.pop_back( pv, n, pv_prop );
1030
      }
1031
    }
1032
41244
    if (success && !revertOnSuccess)
1033
    {
1034
36856
      return true;
1035
    }else{
1036
4388
      Trace("cegqi-inst-debug2") << "Revert substitutions..." << std::endl;
1037
      //revert substitution information
1038
6249
      for (std::map<int, Node>::iterator it = prev_subs.begin();
1039
6249
           it != prev_subs.end();
1040
           ++it)
1041
      {
1042
1861
        sf.d_subs[it->first] = it->second;
1043
      }
1044
4388
      for (std::map<int, TermProperties>::iterator it = prev_prop.begin();
1045
4388
           it != prev_prop.end();
1046
           ++it)
1047
      {
1048
        sf.d_props[it->first] = it->second;
1049
      }
1050
4388
      for( unsigned i=0; i<new_non_basic.size(); i++ ){
1051
        sf.d_non_basic.pop_back();
1052
      }
1053
4388
      return success;
1054
    }
1055
  }else{
1056
    //already tried this substitution
1057
    return false;
1058
  }
1059
}
1060
1061
5974
bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars,
1062
                                         std::vector<Node>& subs)
1063
{
1064
5974
  if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
1065
  {
1066
2172
    Trace("cegqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
1067
4344
    std::map< Node, Node > subs_map;
1068
38647
    for( unsigned i=0; i<subs.size(); i++ ){
1069
36475
      subs_map[vars[i]] = subs[i];
1070
    }
1071
2172
    subs.clear();
1072
25838
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1073
    {
1074
23666
      std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
1075
23666
      Assert(it != subs_map.end());
1076
47332
      Node n = it->second;
1077
47332
      Trace("cegqi-inst-debug") << "  " << d_input_vars[i] << " -> " << n
1078
23666
                               << std::endl;
1079
23666
      Assert(n.getType().isComparableTo(d_input_vars[i].getType()));
1080
23666
      subs.push_back( n );
1081
    }
1082
  }
1083
5974
  if (Trace.isOn("cegqi-inst"))
1084
  {
1085
    Trace("cegqi-inst") << "Ceg Instantiator produced : " << std::endl;
1086
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1087
    {
1088
      Node v = d_input_vars[i];
1089
      Trace("cegqi-inst") << i << " (" << d_curr_iphase[v] << ") : "
1090
                         << v << " -> " << subs[i] << std::endl;
1091
      Assert(subs[i].getType().isComparableTo(v.getType()));
1092
    }
1093
  }
1094
5974
  Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl;
1095
5974
  return d_parent->doAddInstantiation(subs);
1096
}
1097
1098
61334
bool CegInstantiator::isEligibleForInstantiation(Node n) const
1099
{
1100
61334
  Kind nk = n.getKind();
1101
61334
  if (nk != INST_CONSTANT && nk != SKOLEM && nk != BOOLEAN_TERM_VARIABLE)
1102
  {
1103
57402
    return true;
1104
  }
1105
3932
  if (n.getAttribute(VirtualTermSkolemAttribute()))
1106
  {
1107
    // virtual terms are allowed
1108
89
    return true;
1109
  }
1110
  // only legal if current quantified formula contains n
1111
3843
  return expr::hasSubterm(d_quant, n);
1112
}
1113
1114
1155296
bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
1115
1155296
  Assert(d_prog_var.find(n) != d_prog_var.end());
1116
1155296
  if( !non_basic.empty() ){
1117
11275
    for (std::unordered_set<Node>::iterator it = d_prog_var[n].begin();
1118
11275
         it != d_prog_var[n].end();
1119
         ++it)
1120
    {
1121
7967
      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
1122
      {
1123
2081
        return false;
1124
      }
1125
    }
1126
  }
1127
1153215
  return true;
1128
}
1129
1130
719039
Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop,
1131
                                         std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) {
1132
719039
  n = rewrite(n);
1133
719039
  computeProgVars( n );
1134
719039
  bool is_basic = canApplyBasicSubstitution( n, non_basic );
1135
719039
  if( Trace.isOn("sygus-si-apply-subs-debug") ){
1136
    Trace("sygus-si-apply-subs-debug") << "is_basic = " << is_basic << "  " << tn << std::endl;
1137
    for( unsigned i=0; i<subs.size(); i++ ){
1138
      Trace("sygus-si-apply-subs-debug") << "  " << vars[i] << " -> " << subs[i] << "   types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl;
1139
      Assert(subs[i].getType().isSubtypeOf(vars[i].getType()));
1140
    }
1141
  }
1142
719039
  Node nret;
1143
719039
  if( is_basic ){
1144
717855
    nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1145
  }else{
1146
1184
    if( !tn.isInteger() ){
1147
      //can do basic substitution instead with divisions
1148
1572
      std::vector< Node > nvars;
1149
1572
      std::vector< Node > nsubs;
1150
6736
      for( unsigned i=0; i<vars.size(); i++ ){
1151
5950
        if( !prop[i].d_coeff.isNull() ){
1152
2662
          Assert(vars[i].getType().isInteger());
1153
2662
          Assert(prop[i].d_coeff.isConst());
1154
5324
          Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
1155
2662
          nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn );
1156
2662
          nn = rewrite(nn);
1157
2662
          nsubs.push_back( nn );
1158
        }else{
1159
3288
          nsubs.push_back( subs[i] );
1160
        }
1161
      }
1162
786
      nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() );
1163
398
    }else if( try_coeff ){
1164
      //must convert to monomial representation
1165
796
      std::map< Node, Node > msum;
1166
398
      if (ArithMSum::getMonomialSum(n, msum))
1167
      {
1168
796
        std::map< Node, Node > msum_coeff;
1169
796
        std::map< Node, Node > msum_term;
1170
1767
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1171
          //check if in substitution
1172
1369
          std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first );
1173
1369
          if( its!=vars.end() ){
1174
677
            int index = its-vars.begin();
1175
677
            if( prop[index].d_coeff.isNull() ){
1176
              //apply substitution
1177
288
              msum_term[it->first] = subs[index];
1178
            }else{
1179
              //apply substitution, multiply to ensure no divisibility conflict
1180
389
              msum_term[it->first] = subs[index];
1181
              //relative coefficient
1182
389
              msum_coeff[it->first] = prop[index].d_coeff;
1183
389
              if( pv_prop.d_coeff.isNull() ){
1184
380
                pv_prop.d_coeff = prop[index].d_coeff;
1185
              }else{
1186
9
                pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff );
1187
              }
1188
            }
1189
          }else{
1190
692
            msum_term[it->first] = it->first;
1191
          }
1192
        }
1193
        //make sum with normalized coefficient
1194
398
        if( !pv_prop.d_coeff.isNull() ){
1195
380
          pv_prop.d_coeff = rewrite(pv_prop.d_coeff);
1196
380
          Trace("sygus-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl;
1197
760
          std::vector< Node > children;
1198
1713
          for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1199
2666
            Node c_coeff;
1200
1333
            if( !msum_coeff[it->first].isNull() ){
1201
778
              c_coeff = rewrite(NodeManager::currentNM()->mkConst(
1202
389
                  pv_prop.d_coeff.getConst<Rational>()
1203
1167
                  / msum_coeff[it->first].getConst<Rational>()));
1204
            }else{
1205
944
              c_coeff = pv_prop.d_coeff;
1206
            }
1207
1333
            if( !it->second.isNull() ){
1208
1030
              c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
1209
            }
1210
1333
            Assert(!c_coeff.isNull());
1211
2666
            Node c;
1212
1333
            if( msum_term[it->first].isNull() ){
1213
74
              c = c_coeff;
1214
            }else{
1215
1259
              c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
1216
            }
1217
1333
            children.push_back( c );
1218
1333
            Trace("sygus-si-apply-subs-debug") << "Add child : " << c << std::endl;
1219
          }
1220
760
          Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children );
1221
380
          nretc = rewrite(nretc);
1222
          //ensure that nret does not contain vars
1223
380
          if (!expr::hasSubterm(nretc, vars))
1224
          {
1225
            //result is ( nret / pv_prop.d_coeff )
1226
380
            nret = nretc;
1227
          }else{
1228
            Trace("sygus-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl;
1229
          }
1230
        }else{
1231
          //implies that we have a monomial that has a free variable
1232
18
          Trace("sygus-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl;
1233
        }
1234
      }else{
1235
        Trace("sygus-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl;
1236
      }
1237
    }
1238
  }
1239
719039
  if( n!=nret && !nret.isNull() ){
1240
359778
    nret = rewrite(nret);
1241
  }
1242
719039
  return nret;
1243
}
1244
1245
436257
Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs,
1246
                                                  std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) {
1247
436257
  computeProgVars( lit );
1248
436257
  bool is_basic = canApplyBasicSubstitution( lit, non_basic );
1249
436257
  Node lret;
1250
436257
  if( is_basic ){
1251
435360
   lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1252
  }else{
1253
1794
    Node atom = lit.getKind()==NOT ? lit[0] : lit;
1254
897
    bool pol = lit.getKind()!=NOT;
1255
    //arithmetic inequalities and disequalities
1256
897
    if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){
1257
780
      NodeManager* nm = NodeManager::currentNM();
1258
780
      Assert(atom.getKind() != GEQ || atom[1].isConst());
1259
1560
      Node atom_lhs;
1260
1560
      Node atom_rhs;
1261
780
      if( atom.getKind()==GEQ ){
1262
718
        atom_lhs = atom[0];
1263
718
        atom_rhs = atom[1];
1264
      }else{
1265
62
        atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]);
1266
62
        atom_lhs = rewrite(atom_lhs);
1267
62
        atom_rhs = nm->mkConst(Rational(0));
1268
      }
1269
      //must be an eligible term
1270
780
      if( isEligible( atom_lhs ) ){
1271
        //apply substitution to LHS of atom
1272
1560
        TermProperties atom_lhs_prop;
1273
780
        atom_lhs = applySubstitution(nm->realType(),
1274
                                     atom_lhs,
1275
                                     vars,
1276
                                     subs,
1277
                                     prop,
1278
                                     non_basic,
1279
                                     atom_lhs_prop);
1280
780
        if( !atom_lhs.isNull() ){
1281
780
          if( !atom_lhs_prop.d_coeff.isNull() ){
1282
            atom_rhs = nm->mkNode(MULT, atom_lhs_prop.d_coeff, atom_rhs);
1283
            atom_rhs = rewrite(atom_rhs);
1284
          }
1285
780
          lret = nm->mkNode(atom.getKind(), atom_lhs, atom_rhs);
1286
780
          if( !pol ){
1287
423
            lret = lret.negate();
1288
          }
1289
        }
1290
      }
1291
    }else{
1292
      // don't know how to apply substitution to literal
1293
    }
1294
  }
1295
436257
  if( lit!=lret && !lret.isNull() ){
1296
256694
    lret = rewrite(lret);
1297
  }
1298
436257
  return lret;
1299
}
1300
1301
4806
bool CegInstantiator::check() {
1302
4806
  processAssertions();
1303
6419
  for( unsigned r=0; r<2; r++ ){
1304
6119
    d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
1305
7732
    SolvedForm sf;
1306
6119
    d_stack_vars.clear();
1307
6119
    d_bound_var_index.clear();
1308
6119
    d_solved_asserts.clear();
1309
    //try to add an instantiation
1310
6119
    if (constructInstantiation(sf, 0))
1311
    {
1312
4506
      return true;
1313
    }
1314
  }
1315
300
  Trace("cegqi-engine") << "  WARNING : unable to find CEGQI single invocation instantiation." << std::endl;
1316
300
  return false;
1317
}
1318
1319
4806
void CegInstantiator::processAssertions() {
1320
9612
  Trace("cegqi-proc") << "--- Process assertions, #var = " << d_vars.size()
1321
4806
                     << std::endl;
1322
4806
  d_curr_asserts.clear();
1323
4806
  d_curr_eqc.clear();
1324
4806
  d_curr_type_eqc.clear();
1325
1326
  // must use master equality engine to avoid value instantiations
1327
4806
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
1328
1329
  //for each variable
1330
42919
  for( unsigned i=0; i<d_vars.size(); i++ ){
1331
76226
    Node pv = d_vars[i];
1332
76226
    TypeNode pvtn = pv.getType();
1333
38113
    Trace("cegqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
1334
    //collect information about eqc
1335
38113
    if( ee->hasTerm( pv ) ){
1336
52484
      Node pvr = ee->getRepresentative( pv );
1337
26242
      if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){
1338
14511
        Trace("cegqi-proc") << "Collect equivalence class " << pvr << std::endl;
1339
14511
        eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee );
1340
74925
        while( !eqc_i.isFinished() ){
1341
30207
          d_curr_eqc[pvr].push_back( *eqc_i );
1342
30207
          ++eqc_i;
1343
        }
1344
      }
1345
    }
1346
  }
1347
  //collect assertions for relevant theories
1348
4806
  const LogicInfo& logicInfo = d_qstate.getLogicInfo();
1349
14968
  for (TheoryId tid : d_tids)
1350
  {
1351
10162
    if (!logicInfo.isTheoryEnabled(tid))
1352
    {
1353
2077
      continue;
1354
    }
1355
16170
    Trace("cegqi-proc") << "Collect assertions from theory " << tid
1356
8085
                        << std::endl;
1357
8085
    d_curr_asserts[tid].clear();
1358
    // collect all assertions from theory
1359
358477
    for (context::CDList<Assertion>::const_iterator
1360
8085
             it = d_qstate.factsBegin(tid),
1361
8085
             itEnd = d_qstate.factsEnd(tid);
1362
366562
         it != itEnd;
1363
         ++it)
1364
    {
1365
716954
      Node lit = (*it).d_assertion;
1366
716954
      Node atom = lit.getKind() == NOT ? lit[0] : lit;
1367
716954
      if (d_is_nested_quant
1368
1065231
          || std::find(d_ce_atoms.begin(), d_ce_atoms.end(), atom)
1369
1065231
                 != d_ce_atoms.end())
1370
      {
1371
37344
        d_curr_asserts[tid].push_back(lit);
1372
37344
        Trace("cegqi-proc-debug") << "...add : " << lit << std::endl;
1373
      }
1374
      else
1375
      {
1376
642266
        Trace("cegqi-proc")
1377
321133
            << "...do not consider literal " << tid << " : " << lit
1378
321133
            << " since it is not part of CE body." << std::endl;
1379
      }
1380
    }
1381
  }
1382
  //collect equivalence classes that correspond to relevant theories
1383
4806
  Trace("cegqi-proc-debug") << "...collect typed equivalence classes" << std::endl;
1384
4806
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
1385
786642
  while( !eqcs_i.isFinished() ){
1386
781836
    Node r = *eqcs_i;
1387
781836
    TypeNode rtn = r.getType();
1388
390918
    TheoryId tid = Theory::theoryOf( rtn );
1389
    //if we care about the theory of this eqc
1390
390918
    if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){
1391
330593
      if( rtn.isInteger() || rtn.isReal() ){
1392
22845
        rtn = rtn.getBaseType();
1393
      }
1394
330593
      Trace("cegqi-proc-debug") << "...type eqc: " << r << std::endl;
1395
330593
      d_curr_type_eqc[rtn].push_back( r );
1396
330593
      if( d_curr_eqc.find( r )==d_curr_eqc.end() ){
1397
316082
        Trace("cegqi-proc") << "Collect equivalence class " << r << std::endl;
1398
316082
        Trace("cegqi-proc-debug") << "  ";
1399
316082
        eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
1400
1070882
        while( !eqc_i.isFinished() ){
1401
377400
          Trace("cegqi-proc-debug") << *eqc_i << " ";
1402
377400
          d_curr_eqc[r].push_back( *eqc_i );
1403
377400
          ++eqc_i;
1404
        }
1405
316082
        Trace("cegqi-proc-debug") << std::endl;
1406
      }
1407
    }
1408
390918
    ++eqcs_i;
1409
  }
1410
1411
  //remove unecessary assertions
1412
12891
  for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
1413
16170
    std::vector< Node > akeep;
1414
45429
    for( unsigned i=0; i<it->second.size(); i++ ){
1415
74688
      Node n = it->second[i];
1416
      //must be an eligible term
1417
37344
      if( isEligible( n ) ){
1418
        //must contain at least one variable
1419
31255
        if( !d_prog_var[n].empty() ){
1420
30223
          Trace("cegqi-proc") << "...literal[" << it->first << "] : " << n << std::endl;
1421
30223
          akeep.push_back( n );
1422
        }else{
1423
1032
          Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl;
1424
        }
1425
      }else{
1426
6089
        Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl;
1427
      }
1428
    }
1429
8085
    it->second.clear();
1430
8085
    it->second.insert( it->second.end(), akeep.begin(), akeep.end() );
1431
  }
1432
1433
  //remove duplicate terms from eqc
1434
335399
  for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
1435
661186
    std::vector< Node > new_eqc;
1436
738200
    for( unsigned i=0; i<it->second.size(); i++ ){
1437
407607
      if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){
1438
407607
        new_eqc.push_back( it->second[i] );
1439
      }
1440
    }
1441
330593
    it->second.clear();
1442
330593
    it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() );
1443
  }
1444
4806
}
1445
1446
113032
Node CegInstantiator::getModelValue( Node n ) {
1447
113032
  return d_treg.getModel()->getValue(n);
1448
}
1449
1450
1162
Node CegInstantiator::getBoundVariable(TypeNode tn)
1451
{
1452
1162
  unsigned index = 0;
1453
  std::unordered_map<TypeNode, unsigned>::iterator itb =
1454
1162
      d_bound_var_index.find(tn);
1455
1162
  if (itb != d_bound_var_index.end())
1456
  {
1457
91
    index = itb->second;
1458
  }
1459
1162
  d_bound_var_index[tn] = index + 1;
1460
2144
  while (index >= d_bound_var[tn].size())
1461
  {
1462
982
    std::stringstream ss;
1463
491
    ss << "x" << index;
1464
982
    Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn);
1465
491
    d_bound_var[tn].push_back(x);
1466
  }
1467
1162
  return d_bound_var[tn][index];
1468
}
1469
1470
455754
bool CegInstantiator::isSolvedAssertion(Node n) const
1471
{
1472
455754
  return d_solved_asserts.find(n) != d_solved_asserts.end();
1473
}
1474
1475
4536
void CegInstantiator::markSolved(Node n, bool solved)
1476
{
1477
4536
  if (solved)
1478
  {
1479
2268
    d_solved_asserts.insert(n);
1480
  }
1481
2268
  else if (isSolvedAssertion(n))
1482
  {
1483
2268
    d_solved_asserts.erase(n);
1484
  }
1485
4536
}
1486
1487
28633
void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
1488
28633
  if( n.getKind()==FORALL ){
1489
174
    d_is_nested_quant = true;
1490
28459
  }else if( visited.find( n )==visited.end() ){
1491
26435
    visited[n] = true;
1492
26435
    if( TermUtil::isBoolConnectiveTerm( n ) ){
1493
40204
      for( unsigned i=0; i<n.getNumChildren(); i++ ){
1494
26563
        collectCeAtoms( n[i], visited );
1495
      }
1496
    }else{
1497
12794
      if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
1498
12794
        Trace("cegqi-ce-atoms") << "CE atoms : " << n << std::endl;
1499
12794
        d_ce_atoms.push_back( n );
1500
      }
1501
    }
1502
  }
1503
28633
}
1504
1505
1931
void CegInstantiator::registerCounterexampleLemma(Node lem,
1506
                                                  std::vector<Node>& ceVars,
1507
                                                  std::vector<Node>& auxLems)
1508
{
1509
1931
  Trace("cegqi-reg") << "Register counterexample lemma..." << std::endl;
1510
1931
  d_input_vars.clear();
1511
1931
  d_input_vars.insert(d_input_vars.end(), ceVars.begin(), ceVars.end());
1512
1513
  //Assert( d_vars.empty() );
1514
1931
  d_vars.clear();
1515
1931
  registerTheoryId(THEORY_UF);
1516
5901
  for (const Node& cv : ceVars)
1517
  {
1518
3970
    Trace("cegqi-reg") << "  register input variable : " << cv << std::endl;
1519
3970
    registerVariable(cv);
1520
  }
1521
1522
  // preprocess with all relevant instantiator preprocessors
1523
3862
  Trace("cegqi-debug") << "Preprocess based on theory-specific methods..."
1524
1931
                      << std::endl;
1525
3862
  std::vector<Node> pvars;
1526
1931
  pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
1527
2662
  for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp)
1528
  {
1529
731
    p.second->registerCounterexampleLemma(lem, pvars, auxLems);
1530
  }
1531
  // must register variables generated by preprocessors
1532
3862
  Trace("cegqi-debug") << "Register variables from theory-specific methods "
1533
3862
                      << d_input_vars.size() << " " << pvars.size() << " ..."
1534
1931
                      << std::endl;
1535
2211
  for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i)
1536
  {
1537
560
    Trace("cegqi-reg") << "  register inst preprocess variable : " << pvars[i]
1538
280
                       << std::endl;
1539
280
    registerVariable(pvars[i]);
1540
  }
1541
1542
  // register variables that were introduced during TheoryEngine preprocessing
1543
3862
  std::unordered_set<Node> ceSyms;
1544
1931
  expr::getSymbols(lem, ceSyms);
1545
3862
  std::unordered_set<Node> qSyms;
1546
1931
  expr::getSymbols(d_quant, qSyms);
1547
  // all variables that are in counterexample lemma but not in quantified
1548
  // formula
1549
12171
  for (const Node& ces : ceSyms)
1550
  {
1551
10240
    if (qSyms.find(ces) != qSyms.end())
1552
    {
1553
      // a free symbol of the quantified formula.
1554
12277
      continue;
1555
    }
1556
7140
    if (std::find(d_vars.begin(), d_vars.end(), ces) != d_vars.end())
1557
    {
1558
      // already processed variable
1559
3924
      continue;
1560
    }
1561
    // must avoid selector symbols, and function skolems introduced by
1562
    // theory preprocessing
1563
4279
    TypeNode ct = ces.getType();
1564
3216
    if (ct.isBoolean() || ct.isFunctionLike())
1565
    {
1566
      // Boolean variables, including the counterexample literal, don't matter
1567
      // since they are always assigned a model value.
1568
2153
      continue;
1569
    }
1570
2126
    Trace("cegqi-reg") << "  register theory preprocess variable : " << ces
1571
1063
                       << std::endl;
1572
    // register the variable, which was introduced by TheoryEngine's preprocess
1573
    // method, e.g. an ITE skolem.
1574
1063
    registerVariable(ces);
1575
  }
1576
1577
  // determine variable order: must do Reals before Ints
1578
1931
  Trace("cegqi-debug") << "Determine variable order..." << std::endl;
1579
1931
  if (!d_vars.empty())
1580
  {
1581
3862
    std::map<Node, unsigned> voo;
1582
1931
    bool doSort = false;
1583
3862
    std::vector<Node> vars;
1584
3862
    std::map<TypeNode, std::vector<Node> > tvars;
1585
7244
    for (unsigned i = 0, size = d_vars.size(); i < size; i++)
1586
    {
1587
5313
      voo[d_vars[i]] = i;
1588
5313
      d_var_order_index.push_back(0);
1589
10626
      TypeNode tn = d_vars[i].getType();
1590
5313
      if (tn.isInteger())
1591
      {
1592
2910
        doSort = true;
1593
2910
        tvars[tn].push_back(d_vars[i]);
1594
      }
1595
      else
1596
      {
1597
2403
        vars.push_back(d_vars[i]);
1598
      }
1599
    }
1600
1931
    if (doSort)
1601
    {
1602
814
      Trace("cegqi-debug") << "Sort variables based on ordering." << std::endl;
1603
1628
      for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
1604
      {
1605
814
        vars.insert(vars.end(), vs.second.begin(), vs.second.end());
1606
      }
1607
1608
814
      Trace("cegqi-debug") << "Consider variables in this order : " << std::endl;
1609
4023
      for (unsigned i = 0; i < vars.size(); i++)
1610
      {
1611
3209
        d_var_order_index[voo[vars[i]]] = i;
1612
6418
        Trace("cegqi-debug") << "  " << vars[i] << " : " << vars[i].getType()
1613
3209
                            << ", index was : " << voo[vars[i]] << std::endl;
1614
3209
        d_vars[i] = vars[i];
1615
      }
1616
814
      Trace("cegqi-debug") << std::endl;
1617
    }
1618
    else
1619
    {
1620
1117
      d_var_order_index.clear();
1621
    }
1622
  }
1623
1624
  // collect atoms from all lemmas: we will only solve for literals coming from
1625
  // the original body
1626
1931
  d_is_nested_quant = false;
1627
3862
  std::map< Node, bool > visited;
1628
1931
  collectCeAtoms(lem, visited);
1629
2070
  for (const Node& alem : auxLems)
1630
  {
1631
139
    collectCeAtoms(alem, visited);
1632
  }
1633
1931
}
1634
1635
3530
Instantiator::Instantiator(Env& env, TypeNode tn) : EnvObj(env), d_type(tn)
1636
{
1637
3530
  d_closed_enum_type = tn.isClosedEnumerable();
1638
3530
}
1639
1640
14
bool Instantiator::processEqualTerm(CegInstantiator* ci,
1641
                                    SolvedForm& sf,
1642
                                    Node pv,
1643
                                    TermProperties& pv_prop,
1644
                                    Node n,
1645
                                    CegInstEffort effort)
1646
{
1647
14
  pv_prop.d_type = CEG_TT_EQUAL;
1648
14
  return ci->constructInstantiationInc(pv, n, pv_prop, sf);
1649
}
1650
1651
}  // namespace quantifiers
1652
}  // namespace theory
1653
31125
}  // namespace cvc5