GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/ceg_instantiator.cpp Lines: 816 895 91.2 %
Date: 2021-09-29 Branches: 1645 3362 48.9 %

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
94
CegTermType mkStrictCTT(CegTermType c)
43
{
44
94
  Assert(!isStrictCTT(c));
45
94
  if (c == CEG_TT_LOWER)
46
  {
47
61
    return CEG_TT_LOWER_STRICT;
48
  }
49
33
  else if (c == CEG_TT_UPPER)
50
  {
51
33
    return CEG_TT_UPPER_STRICT;
52
  }
53
  return c;
54
}
55
56
1922
CegTermType mkNegateCTT(CegTermType c)
57
{
58
1922
  if (c == CEG_TT_LOWER)
59
  {
60
569
    return CEG_TT_UPPER;
61
  }
62
1353
  else if (c == CEG_TT_UPPER)
63
  {
64
1353
    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
94
bool isStrictCTT(CegTermType c)
77
{
78
94
  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
10946
bool isUpperBoundCTT(CegTermType c)
85
{
86
10946
  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
13
void TermProperties::composeProperty(TermProperties& p)
129
{
130
13
  if (p.d_coeff.isNull())
131
  {
132
    return;
133
  }
134
13
  if (d_coeff.isNull())
135
  {
136
7
    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
24101
void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop)
148
{
149
24101
  d_vars.push_back(pv);
150
24101
  d_subs.push_back(n);
151
24101
  d_props.push_back(pv_prop);
152
24101
  if (pv_prop.isBasic())
153
  {
154
24027
    return;
155
  }
156
74
  d_non_basic.push_back(pv);
157
  // update theta value
158
148
  Node new_theta = getTheta();
159
74
  if (new_theta.isNull())
160
  {
161
51
    new_theta = pv_prop.d_coeff;
162
  }
163
  else
164
  {
165
23
    Assert(new_theta.getKind() == CONST_RATIONAL);
166
23
    Assert(pv_prop.d_coeff.getKind() == CONST_RATIONAL);
167
23
    NodeManager* nm = NodeManager::currentNM();
168
23
    new_theta = nm->mkConst(Rational(new_theta.getConst<Rational>()
169
                                     * pv_prop.d_coeff.getConst<Rational>()));
170
  }
171
74
  d_theta.push_back(new_theta);
172
}
173
// pop the substitution pv_prop.getModifiedTerm(pv) -> n
174
4086
void SolvedForm::pop_back(Node pv, Node n, TermProperties& pv_prop)
175
{
176
4086
  d_vars.pop_back();
177
4086
  d_subs.pop_back();
178
4086
  d_props.pop_back();
179
4086
  if (pv_prop.isBasic())
180
  {
181
4077
    return;
182
  }
183
9
  d_non_basic.pop_back();
184
  // update theta value
185
9
  d_theta.pop_back();
186
}
187
188
1125
CegInstantiator::CegInstantiator(Env& env,
189
                                 Node q,
190
                                 QuantifiersState& qs,
191
                                 TermRegistry& tr,
192
1125
                                 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
1125
      d_effort(CEG_INST_EFFORT_NONE)
200
{
201
1125
}
202
203
3375
CegInstantiator::~CegInstantiator() {
204
3110
  for (std::pair<Node, Instantiator*> inst : d_instantiator)
205
  {
206
1985
    delete inst.second;
207
  }
208
1771
  for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
209
  {
210
646
    delete instp.second;
211
  }
212
2250
}
213
214
1910070
void CegInstantiator::computeProgVars( Node n ){
215
1910070
  if( d_prog_var.find( n )==d_prog_var.end() ){
216
31218
    d_prog_var[n].clear();
217
31218
    if (n.getKind() == kind::WITNESS)
218
    {
219
490
      Assert(d_prog_var.find(n[0][0]) == d_prog_var.end());
220
490
      d_prog_var[n[0][0]].clear();
221
    }
222
31218
    if (d_vars_set.find(n) != d_vars_set.end())
223
    {
224
1808
      d_prog_var[n].insert(n);
225
    }
226
29410
    else if (!isEligibleForInstantiation(n))
227
    {
228
1107
      d_inelig.insert(n);
229
1107
      return;
230
    }
231
72749
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
232
42638
      computeProgVars( n[i] );
233
42638
      if( d_inelig.find( n[i] )!=d_inelig.end() ){
234
3421
        d_inelig.insert(n);
235
      }
236
      // all variables in child are contained in this
237
42638
      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
60222
    if (n.getKind() == APPLY_SELECTOR_TOTAL
241
60222
        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
242
    {
243
24
      d_prog_var[n].insert(n);
244
    }
245
30111
    if (n.getKind() == kind::WITNESS)
246
    {
247
490
      d_prog_var.erase(n[0][0]);
248
    }
249
  }
250
}
251
252
538659
bool CegInstantiator::isEligible( Node n ) {
253
  //compute d_subs_fv, which program variables are contained in n, and determines if eligible
254
538659
  computeProgVars( n );
255
538659
  return d_inelig.find( n )==d_inelig.end();
256
}
257
258
22397
CegHandledStatus CegInstantiator::isCbqiKind(Kind k)
259
{
260
55966
  if (quantifiers::TermUtil::isBoolConnective(k) || k == PLUS || k == GEQ
261
6258
      || k == EQUAL || k == MULT || k == NONLINEAR_MULT || k == DIVISION
262
4576
      || k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL
263
4532
      || k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == TO_INTEGER
264
26892
      || k == IS_INTEGER)
265
  {
266
17903
    return CEG_HANDLED;
267
  }
268
269
  // CBQI typically works for satisfaction-complete theories
270
4494
  TheoryId t = kindToTheoryId(k);
271
4494
  if (t == THEORY_BV || t == THEORY_FP || t == THEORY_DATATYPES
272
2076
      || t == THEORY_BOOL)
273
  {
274
2418
    return CEG_HANDLED;
275
  }
276
2076
  return CEG_UNHANDLED;
277
}
278
279
3253
CegHandledStatus CegInstantiator::isCbqiTerm(Node n)
280
{
281
3253
  CegHandledStatus ret = CEG_HANDLED;
282
6506
  std::unordered_set<TNode> visited;
283
6506
  std::vector<TNode> visit;
284
6506
  TNode cur;
285
3253
  visit.push_back(n);
286
41846
  do
287
  {
288
45099
    cur = visit.back();
289
45099
    visit.pop_back();
290
45099
    if (visited.find(cur) == visited.end())
291
    {
292
35783
      visited.insert(cur);
293
35783
      if (cur.getKind() != BOUND_VARIABLE && TermUtil::hasBoundVarAttr(cur))
294
      {
295
25733
        if (cur.getKind() == FORALL || cur.getKind() == WITNESS)
296
        {
297
3336
          visit.push_back(cur[1]);
298
        }
299
        else
300
        {
301
22397
          CegHandledStatus curr = isCbqiKind(cur.getKind());
302
22397
          if (curr < ret)
303
          {
304
2076
            ret = curr;
305
4152
            Trace("cegqi-debug2") << "Non-cbqi kind : " << cur.getKind()
306
2076
                                 << " in " << n << std::endl;
307
2076
            if (curr == CEG_UNHANDLED)
308
            {
309
2076
              return CEG_UNHANDLED;
310
            }
311
          }
312
63509
          for (const Node& nc : cur)
313
          {
314
43188
            visit.push_back(nc);
315
          }
316
        }
317
      }
318
    }
319
43023
  } while (!visit.empty());
320
1177
  return ret;
321
}
322
323
9953
CegHandledStatus CegInstantiator::isCbqiSort(TypeNode tn)
324
{
325
19906
  std::map<TypeNode, CegHandledStatus> visited;
326
19906
  return isCbqiSort(tn, visited);
327
}
328
329
12348
CegHandledStatus CegInstantiator::isCbqiSort(
330
    TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited)
331
{
332
12348
  std::map<TypeNode, CegHandledStatus>::iterator itv = visited.find(tn);
333
12348
  if (itv != visited.end())
334
  {
335
1524
    return itv->second;
336
  }
337
10824
  CegHandledStatus ret = CEG_UNHANDLED;
338
28204
  if (tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector()
339
16029
      || tn.isFloatingPoint())
340
  {
341
5623
    ret = CEG_HANDLED;
342
  }
343
5201
  else if (tn.isDatatype())
344
  {
345
    // recursive calls to this datatype are handlable
346
1004
    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
1004
    ret = CEG_HANDLED;
350
1004
    const DType& dt = tn.getDType();
351
2302
    for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
352
    {
353
      // get the constructor type
354
3067
      TypeNode consType;
355
1769
      if (dt.isParametric())
356
      {
357
        // if parametric, must instantiate the argument types
358
9
        consType = dt[i].getSpecializedConstructorType(tn);
359
      }
360
      else
361
      {
362
1760
        consType = dt[i].getConstructor().getType();
363
      }
364
3693
      for (const TypeNode& crange : consType)
365
      {
366
2395
        CegHandledStatus cret = isCbqiSort(crange, visited);
367
2395
        if (cret == CEG_UNHANDLED)
368
        {
369
942
          Trace("cegqi-debug2")
370
471
              << "Non-cbqi sort : " << tn << " due to " << crange << std::endl;
371
471
          visited[tn] = CEG_UNHANDLED;
372
471
          return CEG_UNHANDLED;
373
        }
374
1924
        else if (cret < ret)
375
        {
376
          ret = cret;
377
        }
378
      }
379
    }
380
  }
381
  // sets, arrays, functions and others are not supported
382
10353
  visited[tn] = ret;
383
10353
  return ret;
384
}
385
386
7448
CegHandledStatus CegInstantiator::isCbqiQuantPrefix(Node q)
387
{
388
7448
  CegHandledStatus hmin = CEG_HANDLED_UNCONDITIONAL;
389
13164
  for (const Node& v : q[0])
390
  {
391
15627
    TypeNode tn = v.getType();
392
9911
    CegHandledStatus handled = isCbqiSort(tn);
393
9911
    if (handled == CEG_UNHANDLED)
394
    {
395
4195
      return CEG_UNHANDLED;
396
    }
397
5716
    else if (handled < hmin)
398
    {
399
3352
      hmin = handled;
400
    }
401
  }
402
3253
  return hmin;
403
}
404
405
9151
CegHandledStatus CegInstantiator::isCbqiQuant(Node q)
406
{
407
9151
  Assert(q.getKind() == FORALL);
408
  // compute attributes
409
18302
  QAttributes qa;
410
9151
  QuantAttributes::computeQuantAttributes(q, qa);
411
9151
  if (qa.d_quant_elim)
412
  {
413
65
    return CEG_HANDLED;
414
  }
415
9086
  if (qa.d_sygus)
416
  {
417
331
    return CEG_UNHANDLED;
418
  }
419
8755
  Assert(!qa.d_quant_elim_partial);
420
  // if has an instantiation pattern, don't do it
421
8755
  if (q.getNumChildren() == 3)
422
  {
423
2397
    for (const Node& pat : q[2])
424
    {
425
1910
      if (pat.getKind() == INST_PATTERN)
426
      {
427
1307
        return CEG_UNHANDLED;
428
      }
429
    }
430
  }
431
7448
  CegHandledStatus ret = CEG_HANDLED;
432
  // if quantifier has a non-handled variable, then do not use cbqi
433
7448
  CegHandledStatus ncbqiv = CegInstantiator::isCbqiQuantPrefix(q);
434
14896
  Trace("cegqi-quant-debug") << "isCbqiQuantPrefix returned " << ncbqiv
435
7448
                            << std::endl;
436
7448
  if (ncbqiv == CEG_UNHANDLED)
437
  {
438
    // unhandled variable type
439
4195
    ret = CEG_UNHANDLED;
440
  }
441
  else
442
  {
443
3253
    CegHandledStatus cbqit = CegInstantiator::isCbqiTerm(q);
444
3253
    Trace("cegqi-quant-debug") << "isCbqiTerm returned " << cbqit << std::endl;
445
3253
    if (cbqit == CEG_UNHANDLED)
446
    {
447
2076
      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
2076
        ret = CEG_UNHANDLED;
458
      }
459
    }
460
1177
    else if (cbqit == CEG_PARTIALLY_HANDLED)
461
    {
462
      ret = CEG_PARTIALLY_HANDLED;
463
    }
464
  }
465
7448
  if (ret == CEG_UNHANDLED && options::cegqiAll())
466
  {
467
    // try but not exclusively
468
14
    ret = CEG_PARTIALLY_HANDLED;
469
  }
470
7448
  return ret;
471
}
472
473
246287
bool CegInstantiator::hasVariable( Node n, Node pv ) {
474
246287
  computeProgVars( n );
475
246287
  return d_prog_var[n].find( pv )!=d_prog_var[n].end();
476
}
477
478
22128
void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
479
{
480
22128
  if( d_instantiator.find( v )==d_instantiator.end() ){
481
3970
    TypeNode tn = v.getType();
482
    Instantiator * vinst;
483
1985
    if( tn.isReal() ){
484
886
      vinst = new ArithInstantiator(d_env, tn, d_parent->getVtsTermCache());
485
1099
    }else if( tn.isDatatype() ){
486
21
      vinst = new DtInstantiator(d_env, tn);
487
1078
    }else if( tn.isBitVector() ){
488
947
      vinst = new BvInstantiator(d_env, tn, d_parent->getBvInverter());
489
131
    }else if( tn.isBoolean() ){
490
128
      vinst = new ModelValueInstantiator(d_env, tn);
491
    }else{
492
      //default
493
3
      vinst = new Instantiator(d_env, tn);
494
    }
495
1985
    d_instantiator[v] = vinst;
496
  }
497
22128
  d_curr_subs_proc[v].clear();
498
22128
  d_curr_index[v] = index;
499
22128
  d_curr_iphase[v] = CEG_INST_PHASE_NONE;
500
22128
}
501
502
2113
void CegInstantiator::deactivateInstantiationVariable(Node v)
503
{
504
2113
  d_curr_subs_proc.erase(v);
505
2113
  d_curr_index.erase(v);
506
2113
  d_curr_iphase.erase(v);
507
2113
}
508
509
34569
bool CegInstantiator::hasTriedInstantiation(Node v)
510
{
511
34569
  return !d_curr_subs_proc[v].empty();
512
}
513
514
2947
void CegInstantiator::registerTheoryIds(TypeNode tn,
515
                                        std::map<TypeNode, bool>& visited)
516
{
517
2947
  if (visited.find(tn) == visited.end())
518
  {
519
2919
    visited[tn] = true;
520
2919
    TheoryId tid = Theory::theoryOf(tn);
521
2919
    registerTheoryId(tid);
522
2919
    if (tn.isDatatype())
523
    {
524
31
      const DType& dt = tn.getDType();
525
75
      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
526
      {
527
101
        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
528
        {
529
57
          registerTheoryIds(dt[i].getArgType(j), visited);
530
        }
531
      }
532
    }
533
  }
534
2947
}
535
536
4044
void CegInstantiator::registerTheoryId(TheoryId tid)
537
{
538
4044
  if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
539
  {
540
    // setup any theory-specific preprocessors here
541
2281
    if (tid == THEORY_BV)
542
    {
543
646
      d_tipp[tid] = new BvInstantiatorPreprocess;
544
    }
545
2281
    d_tids.push_back(tid);
546
  }
547
4044
}
548
549
2890
void CegInstantiator::registerVariable(Node v)
550
{
551
2890
  Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
552
2890
  d_vars.push_back(v);
553
2890
  d_vars_set.insert(v);
554
5780
  TypeNode vtn = v.getType();
555
5780
  Trace("cegqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
556
2890
                           << v << std::endl;
557
  // collect relevant theories for this variable
558
5780
  std::map<TypeNode, bool> visited;
559
2890
  registerTheoryIds(vtn, visited);
560
2890
}
561
562
27765
bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
563
{
564
27765
  if( i==d_vars.size() ){
565
    //solved for all variables, now construct instantiation
566
    bool needsPostprocess =
567
5637
        sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty();
568
11274
    std::vector< Instantiator * > pp_inst;
569
11274
    std::map< Instantiator *, Node > pp_inst_to_var;
570
33424
    for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){
571
83361
      if (ita->second->needsPostProcessInstantiationForVariable(
572
55574
              this, sf, ita->first, d_effort))
573
      {
574
81
        needsPostprocess = true;
575
81
        pp_inst_to_var[ ita->second ] = ita->first;
576
      }
577
    }
578
5637
    if( needsPostprocess ){
579
      //must make copy so that backtracking reverts sf
580
6016
      SolvedForm sf_tmp = sf;
581
3008
      bool postProcessSuccess = true;
582
3080
      for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){
583
243
        if (!itp->first->postProcessInstantiationForVariable(
584
162
                this, sf_tmp, itp->second, d_effort))
585
        {
586
9
          postProcessSuccess = false;
587
9
          break;
588
        }
589
      }
590
3008
      if( postProcessSuccess ){
591
2999
        return doAddInstantiation(sf_tmp.d_vars, sf_tmp.d_subs);
592
      }else{
593
9
        return false;
594
      }
595
    }else{
596
2629
      return doAddInstantiation(sf.d_vars, sf.d_subs);
597
    }
598
  }else{
599
22128
    bool is_sv = false;
600
44256
    Node pv;
601
22128
    if( d_stack_vars.empty() ){
602
22104
      pv = d_vars[i];
603
    }else{
604
24
      pv = d_stack_vars.back();
605
24
      is_sv = true;
606
24
      d_stack_vars.pop_back();
607
    }
608
22128
    activateInstantiationVariable(pv, i);
609
610
    //get the instantiator object
611
22128
    Assert(d_instantiator.find(pv) != d_instantiator.end());
612
22128
    Instantiator* vinst = d_instantiator[pv];
613
22128
    Assert(vinst != NULL);
614
22128
    d_active_instantiators[pv] = vinst;
615
22128
    vinst->reset(this, sf, pv, d_effort);
616
    // if d_effort is full, we must choose at least one model value
617
22128
    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
21232
      if (constructInstantiation(sf, vinst, pv))
622
      {
623
14781
        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
21632
    if ((options::cegqiMultiInst() || !hasTriedInstantiation(pv))
633
13364
        && (vinst->useModelValue(this, sf, pv, d_effort) || is_sv)
634
20306
        && vinst->allowModelValue(this, sf, pv, d_effort))
635
    {
636
5990
      Node mv = getModelValue( pv );
637
5990
      TermProperties pv_prop_m;
638
5612
      Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
639
5612
      d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
640
5612
      CegInstEffort prev = d_effort;
641
5612
      if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
642
      {
643
        // update the effort level to indicate we have used a model value
644
897
        d_effort = CEG_INST_EFFORT_STANDARD_MV;
645
      }
646
5612
      if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
647
      {
648
5234
        return true;
649
      }
650
378
      d_effort = prev;
651
    }
652
653
2113
    Trace("cegqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl;
654
2113
    if (is_sv)
655
    {
656
      d_stack_vars.push_back( pv );
657
    }
658
2113
    d_active_instantiators.erase( pv );
659
2113
    deactivateInstantiationVariable(pv);
660
2113
    return false;
661
  }
662
}
663
664
21232
bool CegInstantiator::constructInstantiation(SolvedForm& sf,
665
                                             Instantiator* vinst,
666
                                             Node pv)
667
{
668
42464
  TypeNode pvtn = pv.getType();
669
42464
  TypeNode pvtnb = pvtn.getBaseType();
670
42464
  Node pvr = pv;
671
21232
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
672
21232
  if (ee->hasTerm(pv))
673
  {
674
14987
    pvr = ee->getRepresentative(pv);
675
  }
676
42464
  Trace("cegqi-inst-debug") << "[Find instantiation for " << pv
677
21232
                           << "], rep=" << pvr << ", instantiator is "
678
21232
                           << vinst->identify() << std::endl;
679
42464
  Node pv_value;
680
21232
  if (options::cegqiModel())
681
  {
682
21232
    pv_value = getModelValue(pv);
683
21232
    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
21232
  if (vinst->hasProcessEqualTerm(this, sf, pv, d_effort))
689
  {
690
46
    Trace("cegqi-inst-debug")
691
23
        << "[1] try based on equivalence class." << std::endl;
692
23
    d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
693
23
    std::map<Node, std::vector<Node> >::iterator it_eqc = d_curr_eqc.find(pvr);
694
23
    if (it_eqc != d_curr_eqc.end())
695
    {
696
      // std::vector< Node > eq_candidates;
697
46
      Trace("cegqi-inst-debug2")
698
23
          << "...eqc has size " << it_eqc->second.size() << std::endl;
699
64
      for (const Node& n : it_eqc->second)
700
      {
701
46
        if (n != pv)
702
        {
703
54
          Trace("cegqi-inst-debug")
704
27
              << "...try based on equal term " << n << std::endl;
705
          // must be an eligible term
706
27
          if (isEligible(n))
707
          {
708
39
            Node ns;
709
            // coefficient of pv in the equality we solve (null is 1)
710
39
            TermProperties pv_prop;
711
22
            bool proc = false;
712
22
            if (!d_prog_var[n].empty())
713
            {
714
20
              ns = applySubstitution(pvtn, n, sf, pv_prop, false);
715
20
              if (!ns.isNull())
716
              {
717
20
                computeProgVars(ns);
718
                // substituted version must be new and cannot contain pv
719
20
                proc = d_prog_var[ns].find(pv) == d_prog_var[ns].end();
720
              }
721
            }
722
            else
723
            {
724
2
              ns = n;
725
2
              proc = true;
726
            }
727
22
            if (proc)
728
            {
729
5
              if (vinst->processEqualTerm(this, sf, pv, pv_prop, ns, d_effort))
730
              {
731
5
                return true;
732
              }
733
              else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
734
              {
735
                return false;
736
              }
737
              // Do not consider more than one equal term,
738
              // this helps non-monotonic strategies that may encounter
739
              // duplicate instantiations.
740
              break;
741
            }
742
          }
743
        }
744
      }
745
18
      if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
746
      {
747
13
        return true;
748
      }
749
5
      else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
750
      {
751
        return false;
752
      }
753
    }
754
    else
755
    {
756
      Trace("cegqi-inst-debug2") << "...eqc not found." << std::endl;
757
    }
758
  }
759
760
  //[2] : we can solve an equality for pv
761
  /// iterate over equivalence classes to find cases where we can solve for
762
  /// the variable
763
21214
  if (vinst->hasProcessEquality(this, sf, pv, d_effort))
764
  {
765
30238
    Trace("cegqi-inst-debug")
766
15119
        << "[2] try based on solving equalities." << std::endl;
767
15119
    d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
768
15119
    std::vector<Node>& cteqc = d_curr_type_eqc[pvtnb];
769
770
219956
    for (const Node& r : cteqc)
771
    {
772
211801
      std::map<Node, std::vector<Node> >::iterator it_reqc = d_curr_eqc.find(r);
773
416638
      std::vector<Node> lhs;
774
416638
      std::vector<bool> lhs_v;
775
416638
      std::vector<TermProperties> lhs_prop;
776
211801
      Assert(it_reqc != d_curr_eqc.end());
777
724069
      for (const Node& n : it_reqc->second)
778
      {
779
519232
        Trace("cegqi-inst-debug2") << "...look at term " << n << std::endl;
780
        // must be an eligible term
781
519232
        if (isEligible(n))
782
        {
783
845756
          Node ns;
784
845756
          TermProperties pv_prop;
785
426360
          if (!d_prog_var[n].empty())
786
          {
787
387154
            ns = applySubstitution(pvtn, n, sf, pv_prop);
788
387154
            if (!ns.isNull())
789
            {
790
387154
              computeProgVars(ns);
791
            }
792
          }
793
          else
794
          {
795
39206
            ns = n;
796
          }
797
426360
          if (!ns.isNull())
798
          {
799
426360
            bool hasVar = d_prog_var[ns].find(pv) != d_prog_var[ns].end();
800
852720
            Trace("cegqi-inst-debug2") << "... " << ns << " has var " << pv
801
426360
                                      << " : " << hasVar << std::endl;
802
845756
            std::vector<TermProperties> term_props;
803
845756
            std::vector<Node> terms;
804
426360
            term_props.push_back(pv_prop);
805
426360
            terms.push_back(ns);
806
881883
            for (unsigned j = 0, size = lhs.size(); j < size; j++)
807
            {
808
              // if this term or the another has pv in it, try to solve for it
809
462487
              if (hasVar || lhs_v[j])
810
              {
811
59824
                Trace("cegqi-inst-debug") << "......try based on equality "
812
29912
                                         << lhs[j] << " = " << ns << std::endl;
813
29912
                term_props.push_back(lhs_prop[j]);
814
29912
                terms.push_back(lhs[j]);
815
29912
                if (vinst->processEquality(
816
29912
                        this, sf, pv, term_props, terms, d_effort))
817
                {
818
6720
                  return true;
819
                }
820
23192
                else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
821
                {
822
244
                  return false;
823
                }
824
22948
                term_props.pop_back();
825
22948
                terms.pop_back();
826
              }
827
            }
828
419396
            lhs.push_back(ns);
829
419396
            lhs_v.push_back(hasVar);
830
419396
            lhs_prop.push_back(pv_prop);
831
          }
832
          else
833
          {
834
            Trace("cegqi-inst-debug2")
835
                << "... term " << n << " is ineligible after substitution."
836
                << std::endl;
837
          }
838
        }
839
        else
840
        {
841
185744
          Trace("cegqi-inst-debug2")
842
92872
              << "... term " << n << " is ineligible." << std::endl;
843
        }
844
      }
845
    }
846
  }
847
  //[3] directly look at assertions
848
14250
  if (!vinst->hasProcessAssertion(this, sf, pv, d_effort))
849
  {
850
3502
    return false;
851
  }
852
10748
  Trace("cegqi-inst-debug") << "[3] try based on assertions." << std::endl;
853
10748
  d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
854
21496
  std::unordered_set<Node> lits;
855
32244
  for (unsigned r = 0; r < 2; r++)
856
  {
857
21496
    TheoryId tid = r == 0 ? Theory::theoryOf(pvtn) : THEORY_UF;
858
21496
    Trace("cegqi-inst-debug2") << "  look at assertions of " << tid << std::endl;
859
    std::map<TheoryId, std::vector<Node> >::iterator ita =
860
21496
        d_curr_asserts.find(tid);
861
21496
    if (ita != d_curr_asserts.end())
862
    {
863
266240
      for (const Node& lit : ita->second)
864
      {
865
252323
        if (lits.find(lit) == lits.end())
866
        {
867
247883
          lits.insert(lit);
868
495766
          Node plit;
869
247883
          if (options::cegqiRepeatLit() || !isSolvedAssertion(lit))
870
          {
871
246887
            plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort);
872
          }
873
247883
          if (!plit.isNull())
874
          {
875
246318
            Trace("cegqi-inst-debug2") << "  look at " << lit;
876
246318
            if (plit != lit)
877
            {
878
2843
              Trace("cegqi-inst-debug2") << "...processed to : " << plit;
879
            }
880
246318
            Trace("cegqi-inst-debug2") << std::endl;
881
            // apply substitutions
882
492636
            Node slit = applySubstitutionToLiteral(plit, sf);
883
246318
            if (!slit.isNull())
884
            {
885
              // check if contains pv
886
246287
              if (hasVariable(slit, pv))
887
              {
888
19948
                Trace("cegqi-inst-debug")
889
9974
                    << "...try based on literal " << slit << "," << std::endl;
890
9974
                Trace("cegqi-inst-debug") << "...from " << lit << std::endl;
891
9974
                if (vinst->processAssertion(this, sf, pv, slit, lit, d_effort))
892
                {
893
                  return true;
894
                }
895
9974
                else if (!options::cegqiMultiInst() && hasTriedInstantiation(pv))
896
                {
897
                  return false;
898
                }
899
              }
900
            }
901
          }
902
        }
903
      }
904
    }
905
  }
906
10748
  if (vinst->processAssertions(this, sf, pv, d_effort))
907
  {
908
8043
    return true;
909
  }
910
2705
  return false;
911
}
912
913
24
void CegInstantiator::pushStackVariable( Node v ) {
914
24
  d_stack_vars.push_back( v );
915
24
}
916
917
void CegInstantiator::popStackVariable() {
918
  Assert(!d_stack_vars.empty());
919
  d_stack_vars.pop_back();
920
}
921
922
26193
bool CegInstantiator::constructInstantiationInc(Node pv,
923
                                                Node n,
924
                                                TermProperties& pv_prop,
925
                                                SolvedForm& sf,
926
                                                bool revertOnSuccess)
927
{
928
52386
  Node cnode = pv_prop.getCacheNode();
929
26193
  if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
930
24101
    d_curr_subs_proc[pv][n][cnode] = true;
931
24101
    if( Trace.isOn("cegqi-inst-debug") ){
932
      for( unsigned j=0; j<sf.d_subs.size(); j++ ){
933
        Trace("cegqi-inst-debug") << " ";
934
      }
935
      Trace("cegqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv]
936
                         << ") ";
937
      Node mod_pv = pv_prop.getModifiedTerm( pv );
938
      Trace("cegqi-inst-debug") << mod_pv << " -> " << n << std::endl;
939
      Assert(n.getType().isSubtypeOf(pv.getType()));
940
    }
941
    //must ensure variables have been computed for n
942
24101
    computeProgVars( n );
943
24101
    Assert(d_inelig.find(n) == d_inelig.end());
944
945
    //substitute into previous substitutions, when applicable
946
48202
    std::vector< Node > a_var;
947
24101
    a_var.push_back( pv );
948
48202
    std::vector< Node > a_subs;
949
24101
    a_subs.push_back( n );
950
48202
    std::vector< TermProperties > a_prop;
951
24101
    a_prop.push_back( pv_prop );
952
48202
    std::vector< Node > a_non_basic;
953
24101
    if( !pv_prop.isBasic() ){
954
74
      a_non_basic.push_back( pv );
955
    }
956
24101
    bool success = true;
957
48202
    std::map< int, Node > prev_subs;
958
48202
    std::map< int, TermProperties > prev_prop;
959
48202
    std::map< int, Node > prev_sym_subs;
960
48202
    std::vector< Node > new_non_basic;
961
24101
    Trace("cegqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl;
962
443189
    for( unsigned j=0; j<sf.d_subs.size(); j++ ){
963
419088
      Trace("cegqi-inst-debug2") << "  Apply for " << sf.d_subs[j]  << std::endl;
964
419088
      Assert(d_prog_var.find(sf.d_subs[j]) != d_prog_var.end());
965
419088
      if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
966
18668
        prev_subs[j] = sf.d_subs[j];
967
37336
        TNode tv = pv;
968
37336
        TNode ts = n;
969
37336
        TermProperties a_pv_prop;
970
37336
        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 );
971
18668
        if( !new_subs.isNull() ){
972
18668
          sf.d_subs[j] = new_subs;
973
          // the substitution apply to this term resulted in a non-basic substitution relationship
974
18668
          if( !a_pv_prop.isBasic() ){
975
            // we are processing:
976
            //    sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n }
977
978
            // based on the above substitution, we have:
979
            //   x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n }
980
            // is equivalent to
981
            //   a_pv_prop.getModifiedTerm( x ) = new_subs
982
983
            // thus we must compose substitutions:
984
            //   a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs
985
986
13
            prev_prop[j] = sf.d_props[j];
987
13
            bool prev_basic = sf.d_props[j].isBasic();
988
989
            // now compose the property
990
13
            sf.d_props[j].composeProperty( a_pv_prop );
991
992
            // if previously was basic, becomes non-basic
993
13
            if( prev_basic && !sf.d_props[j].isBasic() ){
994
7
              Assert(std::find(sf.d_non_basic.begin(),
995
                               sf.d_non_basic.end(),
996
                               sf.d_vars[j])
997
                     == sf.d_non_basic.end());
998
7
              new_non_basic.push_back( sf.d_vars[j] );
999
7
              sf.d_non_basic.push_back( sf.d_vars[j] );
1000
            }
1001
          }
1002
18668
          if( sf.d_subs[j]!=prev_subs[j] ){
1003
18666
            computeProgVars( sf.d_subs[j] );
1004
18666
            Assert(d_inelig.find(sf.d_subs[j]) == d_inelig.end());
1005
          }
1006
18668
          Trace("cegqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl;
1007
        }else{
1008
          Trace("cegqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl;
1009
          success = false;
1010
          break;
1011
        }
1012
      }else{
1013
400420
        Trace("cegqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl;
1014
      }
1015
    }
1016
24101
    if( success ){
1017
24101
      Trace("cegqi-inst-debug2") << "Adding to vectors..." << std::endl;
1018
24101
      sf.push_back( pv, n, pv_prop );
1019
24101
      Trace("cegqi-inst-debug2") << "Recurse..." << std::endl;
1020
24101
      unsigned i = d_curr_index[pv];
1021
24101
      success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
1022
24101
      if (!success || revertOnSuccess)
1023
      {
1024
4086
        Trace("cegqi-inst-debug2") << "Removing from vectors..." << std::endl;
1025
4086
        sf.pop_back( pv, n, pv_prop );
1026
      }
1027
    }
1028
24101
    if (success && !revertOnSuccess)
1029
    {
1030
20015
      return true;
1031
    }else{
1032
4086
      Trace("cegqi-inst-debug2") << "Revert substitutions..." << std::endl;
1033
      //revert substitution information
1034
4808
      for (std::map<int, Node>::iterator it = prev_subs.begin();
1035
4808
           it != prev_subs.end();
1036
           ++it)
1037
      {
1038
722
        sf.d_subs[it->first] = it->second;
1039
      }
1040
4086
      for (std::map<int, TermProperties>::iterator it = prev_prop.begin();
1041
4086
           it != prev_prop.end();
1042
           ++it)
1043
      {
1044
        sf.d_props[it->first] = it->second;
1045
      }
1046
4086
      for( unsigned i=0; i<new_non_basic.size(); i++ ){
1047
        sf.d_non_basic.pop_back();
1048
      }
1049
4086
      return success;
1050
    }
1051
  }else{
1052
    //already tried this substitution
1053
2092
    return false;
1054
  }
1055
}
1056
1057
5628
bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars,
1058
                                         std::vector<Node>& subs)
1059
{
1060
5628
  if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
1061
  {
1062
2999
    Trace("cegqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
1063
5998
    std::map< Node, Node > subs_map;
1064
27466
    for( unsigned i=0; i<subs.size(); i++ ){
1065
24467
      subs_map[vars[i]] = subs[i];
1066
    }
1067
2999
    subs.clear();
1068
16970
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1069
    {
1070
13971
      std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
1071
13971
      Assert(it != subs_map.end());
1072
27942
      Node n = it->second;
1073
27942
      Trace("cegqi-inst-debug") << "  " << d_input_vars[i] << " -> " << n
1074
13971
                               << std::endl;
1075
13971
      Assert(n.getType().isSubtypeOf(d_input_vars[i].getType()));
1076
13971
      subs.push_back( n );
1077
    }
1078
  }
1079
5628
  if (Trace.isOn("cegqi-inst"))
1080
  {
1081
    Trace("cegqi-inst") << "Ceg Instantiator produced : " << std::endl;
1082
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1083
    {
1084
      Node v = d_input_vars[i];
1085
      Trace("cegqi-inst") << i << " (" << d_curr_iphase[v] << ") : "
1086
                         << v << " -> " << subs[i] << std::endl;
1087
      Assert(subs[i].getType().isSubtypeOf(v.getType()));
1088
    }
1089
  }
1090
5628
  Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl;
1091
5628
  return d_parent->doAddInstantiation(subs);
1092
}
1093
1094
29419
bool CegInstantiator::isEligibleForInstantiation(Node n) const
1095
{
1096
29419
  Kind nk = n.getKind();
1097
29419
  if (nk != INST_CONSTANT && nk != SKOLEM && nk != BOOLEAN_TERM_VARIABLE)
1098
  {
1099
27948
    return true;
1100
  }
1101
1471
  if (n.getAttribute(VirtualTermSkolemAttribute()))
1102
  {
1103
    // virtual terms are allowed
1104
22
    return true;
1105
  }
1106
  // only legal if current quantified formula contains n
1107
1449
  return expr::hasSubterm(d_quant, n);
1108
}
1109
1110
652545
bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
1111
652545
  Assert(d_prog_var.find(n) != d_prog_var.end());
1112
652545
  if( !non_basic.empty() ){
1113
4936
    for (std::unordered_set<Node>::iterator it = d_prog_var[n].begin();
1114
4936
         it != d_prog_var[n].end();
1115
         ++it)
1116
    {
1117
3479
      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
1118
      {
1119
917
        return false;
1120
      }
1121
    }
1122
  }
1123
651628
  return true;
1124
}
1125
1126
406227
Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop,
1127
                                         std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) {
1128
406227
  n = rewrite(n);
1129
406227
  computeProgVars( n );
1130
406227
  bool is_basic = canApplyBasicSubstitution( n, non_basic );
1131
406227
  if( Trace.isOn("sygus-si-apply-subs-debug") ){
1132
    Trace("sygus-si-apply-subs-debug") << "is_basic = " << is_basic << "  " << tn << std::endl;
1133
    for( unsigned i=0; i<subs.size(); i++ ){
1134
      Trace("sygus-si-apply-subs-debug") << "  " << vars[i] << " -> " << subs[i] << "   types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl;
1135
      Assert(subs[i].getType().isSubtypeOf(vars[i].getType()));
1136
    }
1137
  }
1138
406227
  Node nret;
1139
406227
  if( is_basic ){
1140
405726
    nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1141
  }else{
1142
501
    if( !tn.isInteger() ){
1143
      //can do basic substitution instead with divisions
1144
774
      std::vector< Node > nvars;
1145
774
      std::vector< Node > nsubs;
1146
3655
      for( unsigned i=0; i<vars.size(); i++ ){
1147
3268
        if( !prop[i].d_coeff.isNull() ){
1148
1659
          Assert(vars[i].getType().isInteger());
1149
1659
          Assert(prop[i].d_coeff.isConst());
1150
3318
          Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
1151
1659
          nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn );
1152
1659
          nn = rewrite(nn);
1153
1659
          nsubs.push_back( nn );
1154
        }else{
1155
1609
          nsubs.push_back( subs[i] );
1156
        }
1157
      }
1158
387
      nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() );
1159
114
    }else if( try_coeff ){
1160
      //must convert to monomial representation
1161
228
      std::map< Node, Node > msum;
1162
114
      if (ArithMSum::getMonomialSum(n, msum))
1163
      {
1164
228
        std::map< Node, Node > msum_coeff;
1165
228
        std::map< Node, Node > msum_term;
1166
468
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1167
          //check if in substitution
1168
354
          std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first );
1169
354
          if( its!=vars.end() ){
1170
195
            int index = its-vars.begin();
1171
195
            if( prop[index].d_coeff.isNull() ){
1172
              //apply substitution
1173
72
              msum_term[it->first] = subs[index];
1174
            }else{
1175
              //apply substitution, multiply to ensure no divisibility conflict
1176
123
              msum_term[it->first] = subs[index];
1177
              //relative coefficient
1178
123
              msum_coeff[it->first] = prop[index].d_coeff;
1179
123
              if( pv_prop.d_coeff.isNull() ){
1180
114
                pv_prop.d_coeff = prop[index].d_coeff;
1181
              }else{
1182
9
                pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff );
1183
              }
1184
            }
1185
          }else{
1186
159
            msum_term[it->first] = it->first;
1187
          }
1188
        }
1189
        //make sum with normalized coefficient
1190
114
        if( !pv_prop.d_coeff.isNull() ){
1191
114
          pv_prop.d_coeff = rewrite(pv_prop.d_coeff);
1192
114
          Trace("sygus-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl;
1193
228
          std::vector< Node > children;
1194
468
          for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1195
708
            Node c_coeff;
1196
354
            if( !msum_coeff[it->first].isNull() ){
1197
246
              c_coeff = rewrite(NodeManager::currentNM()->mkConst(
1198
123
                  pv_prop.d_coeff.getConst<Rational>()
1199
369
                  / msum_coeff[it->first].getConst<Rational>()));
1200
            }else{
1201
231
              c_coeff = pv_prop.d_coeff;
1202
            }
1203
354
            if( !it->second.isNull() ){
1204
254
              c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
1205
            }
1206
354
            Assert(!c_coeff.isNull());
1207
708
            Node c;
1208
354
            if( msum_term[it->first].isNull() ){
1209
16
              c = c_coeff;
1210
            }else{
1211
338
              c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
1212
            }
1213
354
            children.push_back( c );
1214
354
            Trace("sygus-si-apply-subs-debug") << "Add child : " << c << std::endl;
1215
          }
1216
228
          Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children );
1217
114
          nretc = rewrite(nretc);
1218
          //ensure that nret does not contain vars
1219
114
          if (!expr::hasSubterm(nretc, vars))
1220
          {
1221
            //result is ( nret / pv_prop.d_coeff )
1222
114
            nret = nretc;
1223
          }else{
1224
            Trace("sygus-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl;
1225
          }
1226
        }else{
1227
          //implies that we have a monomial that has a free variable
1228
          Trace("sygus-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl;
1229
        }
1230
      }else{
1231
        Trace("sygus-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl;
1232
      }
1233
    }
1234
  }
1235
406227
  if( n!=nret && !nret.isNull() ){
1236
201678
    nret = rewrite(nret);
1237
  }
1238
406227
  return nret;
1239
}
1240
1241
246318
Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs,
1242
                                                  std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) {
1243
246318
  computeProgVars( lit );
1244
246318
  bool is_basic = canApplyBasicSubstitution( lit, non_basic );
1245
246318
  Node lret;
1246
246318
  if( is_basic ){
1247
245902
   lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1248
  }else{
1249
832
    Node atom = lit.getKind()==NOT ? lit[0] : lit;
1250
416
    bool pol = lit.getKind()!=NOT;
1251
    //arithmetic inequalities and disequalities
1252
416
    if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){
1253
385
      NodeManager* nm = NodeManager::currentNM();
1254
385
      Assert(atom.getKind() != GEQ || atom[1].isConst());
1255
770
      Node atom_lhs;
1256
770
      Node atom_rhs;
1257
385
      if( atom.getKind()==GEQ ){
1258
384
        atom_lhs = atom[0];
1259
384
        atom_rhs = atom[1];
1260
      }else{
1261
1
        atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]);
1262
1
        atom_lhs = rewrite(atom_lhs);
1263
1
        atom_rhs = nm->mkConst(Rational(0));
1264
      }
1265
      //must be an eligible term
1266
385
      if( isEligible( atom_lhs ) ){
1267
        //apply substitution to LHS of atom
1268
770
        TermProperties atom_lhs_prop;
1269
385
        atom_lhs = applySubstitution(nm->realType(),
1270
                                     atom_lhs,
1271
                                     vars,
1272
                                     subs,
1273
                                     prop,
1274
                                     non_basic,
1275
                                     atom_lhs_prop);
1276
385
        if( !atom_lhs.isNull() ){
1277
385
          if( !atom_lhs_prop.d_coeff.isNull() ){
1278
            atom_rhs = nm->mkNode(MULT, atom_lhs_prop.d_coeff, atom_rhs);
1279
            atom_rhs = rewrite(atom_rhs);
1280
          }
1281
385
          lret = nm->mkNode(atom.getKind(), atom_lhs, atom_rhs);
1282
385
          if( !pol ){
1283
199
            lret = lret.negate();
1284
          }
1285
        }
1286
      }
1287
    }else{
1288
      // don't know how to apply substitution to literal
1289
    }
1290
  }
1291
246318
  if( lit!=lret && !lret.isNull() ){
1292
146885
    lret = rewrite(lret);
1293
  }
1294
246318
  return lret;
1295
}
1296
1297
2776
bool CegInstantiator::check() {
1298
2776
  processAssertions();
1299
3771
  for( unsigned r=0; r<2; r++ ){
1300
3664
    d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
1301
4659
    SolvedForm sf;
1302
3664
    d_stack_vars.clear();
1303
3664
    d_bound_var_index.clear();
1304
3664
    d_solved_asserts.clear();
1305
    //try to add an instantiation
1306
3664
    if (constructInstantiation(sf, 0))
1307
    {
1308
2669
      return true;
1309
    }
1310
  }
1311
107
  Trace("cegqi-engine") << "  WARNING : unable to find CEGQI single invocation instantiation." << std::endl;
1312
107
  return false;
1313
}
1314
1315
2776
void CegInstantiator::processAssertions() {
1316
5552
  Trace("cegqi-proc") << "--- Process assertions, #var = " << d_vars.size()
1317
2776
                     << std::endl;
1318
2776
  d_curr_asserts.clear();
1319
2776
  d_curr_eqc.clear();
1320
2776
  d_curr_type_eqc.clear();
1321
1322
  // must use master equality engine to avoid value instantiations
1323
2776
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
1324
1325
  //for each variable
1326
23216
  for( unsigned i=0; i<d_vars.size(); i++ ){
1327
40880
    Node pv = d_vars[i];
1328
40880
    TypeNode pvtn = pv.getType();
1329
20440
    Trace("cegqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
1330
    //collect information about eqc
1331
20440
    if( ee->hasTerm( pv ) ){
1332
28646
      Node pvr = ee->getRepresentative( pv );
1333
14323
      if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){
1334
8058
        Trace("cegqi-proc") << "Collect equivalence class " << pvr << std::endl;
1335
8058
        eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee );
1336
40042
        while( !eqc_i.isFinished() ){
1337
15992
          d_curr_eqc[pvr].push_back( *eqc_i );
1338
15992
          ++eqc_i;
1339
        }
1340
      }
1341
    }
1342
  }
1343
  //collect assertions for relevant theories
1344
2776
  const LogicInfo& logicInfo = d_qstate.getLogicInfo();
1345
8571
  for (TheoryId tid : d_tids)
1346
  {
1347
5795
    if (!logicInfo.isTheoryEnabled(tid))
1348
    {
1349
779
      continue;
1350
    }
1351
10032
    Trace("cegqi-proc") << "Collect assertions from theory " << tid
1352
5016
                        << std::endl;
1353
5016
    d_curr_asserts[tid].clear();
1354
    // collect all assertions from theory
1355
142992
    for (context::CDList<Assertion>::const_iterator
1356
5016
             it = d_qstate.factsBegin(tid),
1357
5016
             itEnd = d_qstate.factsEnd(tid);
1358
148008
         it != itEnd;
1359
         ++it)
1360
    {
1361
285984
      Node lit = (*it).d_assertion;
1362
285984
      Node atom = lit.getKind() == NOT ? lit[0] : lit;
1363
285984
      if (d_is_nested_quant
1364
427076
          || std::find(d_ce_atoms.begin(), d_ce_atoms.end(), atom)
1365
427076
                 != d_ce_atoms.end())
1366
      {
1367
19015
        d_curr_asserts[tid].push_back(lit);
1368
19015
        Trace("cegqi-proc-debug") << "...add : " << lit << std::endl;
1369
      }
1370
      else
1371
      {
1372
247954
        Trace("cegqi-proc")
1373
123977
            << "...do not consider literal " << tid << " : " << lit
1374
123977
            << " since it is not part of CE body." << std::endl;
1375
      }
1376
    }
1377
  }
1378
  //collect equivalence classes that correspond to relevant theories
1379
2776
  Trace("cegqi-proc-debug") << "...collect typed equivalence classes" << std::endl;
1380
2776
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
1381
247760
  while( !eqcs_i.isFinished() ){
1382
244984
    Node r = *eqcs_i;
1383
244984
    TypeNode rtn = r.getType();
1384
122492
    TheoryId tid = Theory::theoryOf( rtn );
1385
    //if we care about the theory of this eqc
1386
122492
    if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){
1387
104238
      if( rtn.isInteger() || rtn.isReal() ){
1388
10654
        rtn = rtn.getBaseType();
1389
      }
1390
104238
      Trace("cegqi-proc-debug") << "...type eqc: " << r << std::endl;
1391
104238
      d_curr_type_eqc[rtn].push_back( r );
1392
104238
      if( d_curr_eqc.find( r )==d_curr_eqc.end() ){
1393
96180
        Trace("cegqi-proc") << "Collect equivalence class " << r << std::endl;
1394
96180
        Trace("cegqi-proc-debug") << "  ";
1395
96180
        eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
1396
354308
        while( !eqc_i.isFinished() ){
1397
129064
          Trace("cegqi-proc-debug") << *eqc_i << " ";
1398
129064
          d_curr_eqc[r].push_back( *eqc_i );
1399
129064
          ++eqc_i;
1400
        }
1401
96180
        Trace("cegqi-proc-debug") << std::endl;
1402
      }
1403
    }
1404
122492
    ++eqcs_i;
1405
  }
1406
1407
  //remove unecessary assertions
1408
7792
  for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
1409
10032
    std::vector< Node > akeep;
1410
24031
    for( unsigned i=0; i<it->second.size(); i++ ){
1411
38030
      Node n = it->second[i];
1412
      //must be an eligible term
1413
19015
      if( isEligible( n ) ){
1414
        //must contain at least one variable
1415
16212
        if( !d_prog_var[n].empty() ){
1416
15496
          Trace("cegqi-proc") << "...literal[" << it->first << "] : " << n << std::endl;
1417
15496
          akeep.push_back( n );
1418
        }else{
1419
716
          Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl;
1420
        }
1421
      }else{
1422
2803
        Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl;
1423
      }
1424
    }
1425
5016
    it->second.clear();
1426
5016
    it->second.insert( it->second.end(), akeep.begin(), akeep.end() );
1427
  }
1428
1429
  //remove duplicate terms from eqc
1430
107014
  for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
1431
208476
    std::vector< Node > new_eqc;
1432
249294
    for( unsigned i=0; i<it->second.size(); i++ ){
1433
145056
      if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){
1434
145056
        new_eqc.push_back( it->second[i] );
1435
      }
1436
    }
1437
104238
    it->second.clear();
1438
104238
    it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() );
1439
  }
1440
2776
}
1441
1442
57241
Node CegInstantiator::getModelValue( Node n ) {
1443
57241
  return d_treg.getModel()->getValue(n);
1444
}
1445
1446
1101
Node CegInstantiator::getBoundVariable(TypeNode tn)
1447
{
1448
1101
  unsigned index = 0;
1449
  std::unordered_map<TypeNode, unsigned>::iterator itb =
1450
1101
      d_bound_var_index.find(tn);
1451
1101
  if (itb != d_bound_var_index.end())
1452
  {
1453
61
    index = itb->second;
1454
  }
1455
1101
  d_bound_var_index[tn] = index + 1;
1456
1957
  while (index >= d_bound_var[tn].size())
1457
  {
1458
856
    std::stringstream ss;
1459
428
    ss << "x" << index;
1460
856
    Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn);
1461
428
    d_bound_var[tn].push_back(x);
1462
  }
1463
1101
  return d_bound_var[tn][index];
1464
}
1465
1466
249455
bool CegInstantiator::isSolvedAssertion(Node n) const
1467
{
1468
249455
  return d_solved_asserts.find(n) != d_solved_asserts.end();
1469
}
1470
1471
3144
void CegInstantiator::markSolved(Node n, bool solved)
1472
{
1473
3144
  if (solved)
1474
  {
1475
1572
    d_solved_asserts.insert(n);
1476
  }
1477
1572
  else if (isSolvedAssertion(n))
1478
  {
1479
1572
    d_solved_asserts.erase(n);
1480
  }
1481
3144
}
1482
1483
15439
void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
1484
15439
  if( n.getKind()==FORALL ){
1485
42
    d_is_nested_quant = true;
1486
15397
  }else if( visited.find( n )==visited.end() ){
1487
13729
    visited[n] = true;
1488
13729
    if( TermUtil::isBoolConnectiveTerm( n ) ){
1489
21413
      for( unsigned i=0; i<n.getNumChildren(); i++ ){
1490
14217
        collectCeAtoms( n[i], visited );
1491
      }
1492
    }else{
1493
6533
      if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
1494
6533
        Trace("cegqi-ce-atoms") << "CE atoms : " << n << std::endl;
1495
6533
        d_ce_atoms.push_back( n );
1496
      }
1497
    }
1498
  }
1499
15439
}
1500
1501
1125
void CegInstantiator::registerCounterexampleLemma(Node lem,
1502
                                                  std::vector<Node>& ceVars,
1503
                                                  std::vector<Node>& auxLems)
1504
{
1505
1125
  Trace("cegqi-reg") << "Register counterexample lemma..." << std::endl;
1506
1125
  d_input_vars.clear();
1507
1125
  d_input_vars.insert(d_input_vars.end(), ceVars.begin(), ceVars.end());
1508
1509
  //Assert( d_vars.empty() );
1510
1125
  d_vars.clear();
1511
1125
  registerTheoryId(THEORY_UF);
1512
3250
  for (const Node& cv : ceVars)
1513
  {
1514
2125
    Trace("cegqi-reg") << "  register input variable : " << cv << std::endl;
1515
2125
    registerVariable(cv);
1516
  }
1517
1518
  // preprocess with all relevant instantiator preprocessors
1519
2250
  Trace("cegqi-debug") << "Preprocess based on theory-specific methods..."
1520
1125
                      << std::endl;
1521
2250
  std::vector<Node> pvars;
1522
1125
  pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
1523
1769
  for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp)
1524
  {
1525
644
    p.second->registerCounterexampleLemma(lem, pvars, auxLems);
1526
  }
1527
  // must register variables generated by preprocessors
1528
2250
  Trace("cegqi-debug") << "Register variables from theory-specific methods "
1529
2250
                      << d_input_vars.size() << " " << pvars.size() << " ..."
1530
1125
                      << std::endl;
1531
1321
  for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i)
1532
  {
1533
392
    Trace("cegqi-reg") << "  register inst preprocess variable : " << pvars[i]
1534
196
                       << std::endl;
1535
196
    registerVariable(pvars[i]);
1536
  }
1537
1538
  // register variables that were introduced during TheoryEngine preprocessing
1539
2250
  std::unordered_set<Node> ceSyms;
1540
1125
  expr::getSymbols(lem, ceSyms);
1541
2250
  std::unordered_set<Node> qSyms;
1542
1125
  expr::getSymbols(d_quant, qSyms);
1543
  // all variables that are in counterexample lemma but not in quantified
1544
  // formula
1545
6905
  for (const Node& ces : ceSyms)
1546
  {
1547
5780
    if (qSyms.find(ces) != qSyms.end())
1548
    {
1549
      // a free symbol of the quantified formula.
1550
7056
      continue;
1551
    }
1552
3935
    if (std::find(d_vars.begin(), d_vars.end(), ces) != d_vars.end())
1553
    {
1554
      // already processed variable
1555
2089
      continue;
1556
    }
1557
    // must avoid selector symbols, and function skolems introduced by
1558
    // theory preprocessing
1559
2415
    TypeNode ct = ces.getType();
1560
1846
    if (ct.isBoolean() || ct.isFunctionLike())
1561
    {
1562
      // Boolean variables, including the counterexample literal, don't matter
1563
      // since they are always assigned a model value.
1564
1277
      continue;
1565
    }
1566
1138
    Trace("cegqi-reg") << "  register theory preprocess variable : " << ces
1567
569
                       << std::endl;
1568
    // register the variable, which was introduced by TheoryEngine's preprocess
1569
    // method, e.g. an ITE skolem.
1570
569
    registerVariable(ces);
1571
  }
1572
1573
  // determine variable order: must do Reals before Ints
1574
1125
  Trace("cegqi-debug") << "Determine variable order..." << std::endl;
1575
1125
  if (!d_vars.empty())
1576
  {
1577
2250
    std::map<Node, unsigned> voo;
1578
1125
    bool doSort = false;
1579
2250
    std::vector<Node> vars;
1580
2250
    std::map<TypeNode, std::vector<Node> > tvars;
1581
4015
    for (unsigned i = 0, size = d_vars.size(); i < size; i++)
1582
    {
1583
2890
      voo[d_vars[i]] = i;
1584
2890
      d_var_order_index.push_back(0);
1585
5780
      TypeNode tn = d_vars[i].getType();
1586
2890
      if (tn.isInteger())
1587
      {
1588
1432
        doSort = true;
1589
1432
        tvars[tn].push_back(d_vars[i]);
1590
      }
1591
      else
1592
      {
1593
1458
        vars.push_back(d_vars[i]);
1594
      }
1595
    }
1596
1125
    if (doSort)
1597
    {
1598
345
      Trace("cegqi-debug") << "Sort variables based on ordering." << std::endl;
1599
690
      for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
1600
      {
1601
345
        vars.insert(vars.end(), vs.second.begin(), vs.second.end());
1602
      }
1603
1604
345
      Trace("cegqi-debug") << "Consider variables in this order : " << std::endl;
1605
1953
      for (unsigned i = 0; i < vars.size(); i++)
1606
      {
1607
1608
        d_var_order_index[voo[vars[i]]] = i;
1608
3216
        Trace("cegqi-debug") << "  " << vars[i] << " : " << vars[i].getType()
1609
1608
                            << ", index was : " << voo[vars[i]] << std::endl;
1610
1608
        d_vars[i] = vars[i];
1611
      }
1612
345
      Trace("cegqi-debug") << std::endl;
1613
    }
1614
    else
1615
    {
1616
780
      d_var_order_index.clear();
1617
    }
1618
  }
1619
1620
  // collect atoms from all lemmas: we will only solve for literals coming from
1621
  // the original body
1622
1125
  d_is_nested_quant = false;
1623
2250
  std::map< Node, bool > visited;
1624
1125
  collectCeAtoms(lem, visited);
1625
1222
  for (const Node& alem : auxLems)
1626
  {
1627
97
    collectCeAtoms(alem, visited);
1628
  }
1629
1125
}
1630
1631
1985
Instantiator::Instantiator(Env& env, TypeNode tn) : EnvObj(env), d_type(tn)
1632
{
1633
1985
  d_closed_enum_type = tn.isClosedEnumerable();
1634
1985
}
1635
1636
5
bool Instantiator::processEqualTerm(CegInstantiator* ci,
1637
                                    SolvedForm& sf,
1638
                                    Node pv,
1639
                                    TermProperties& pv_prop,
1640
                                    Node n,
1641
                                    CegInstEffort effort)
1642
{
1643
5
  pv_prop.d_type = CEG_TT_EQUAL;
1644
5
  return ci->constructInstantiationInc(pv, n, pv_prop, sf);
1645
}
1646
1647
}  // namespace quantifiers
1648
}  // namespace theory
1649
22746
}  // namespace cvc5