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

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