GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/ceg_instantiator.cpp Lines: 818 899 91.0 %
Date: 2021-11-07 Branches: 1642 3362 48.8 %

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
359
CegTermType mkStrictCTT(CegTermType c)
43
{
44
359
  Assert(!isStrictCTT(c));
45
359
  if (c == CEG_TT_LOWER)
46
  {
47
208
    return CEG_TT_LOWER_STRICT;
48
  }
49
151
  else if (c == CEG_TT_UPPER)
50
  {
51
151
    return CEG_TT_UPPER_STRICT;
52
  }
53
  return c;
54
}
55
56
3695
CegTermType mkNegateCTT(CegTermType c)
57
{
58
3695
  if (c == CEG_TT_LOWER)
59
  {
60
984
    return CEG_TT_UPPER;
61
  }
62
2711
  else if (c == CEG_TT_UPPER)
63
  {
64
2711
    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
359
bool isStrictCTT(CegTermType c)
77
{
78
359
  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
17963
bool isUpperBoundCTT(CegTermType c)
85
{
86
17963
  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
37
void TermProperties::composeProperty(TermProperties& p)
129
{
130
37
  if (p.d_coeff.isNull())
131
  {
132
    return;
133
  }
134
37
  if (d_coeff.isNull())
135
  {
136
21
    d_coeff = p.d_coeff;
137
  }
138
  else
139
  {
140
16
    NodeManager* nm = NodeManager::currentNM();
141
32
    d_coeff = nm->mkConst(Rational(d_coeff.getConst<Rational>()
142
16
                                   * p.d_coeff.getConst<Rational>()));
143
  }
144
}
145
146
// push the substitution pv_prop.getModifiedTerm(pv) -> n
147
38966
void SolvedForm::push_back(Node pv, Node n, TermProperties& pv_prop)
148
{
149
38966
  d_vars.push_back(pv);
150
38966
  d_subs.push_back(n);
151
38966
  d_props.push_back(pv_prop);
152
38966
  if (pv_prop.isBasic())
153
  {
154
38766
    return;
155
  }
156
200
  d_non_basic.push_back(pv);
157
  // update theta value
158
400
  Node new_theta = getTheta();
159
200
  if (new_theta.isNull())
160
  {
161
136
    new_theta = pv_prop.d_coeff;
162
  }
163
  else
164
  {
165
64
    Assert(new_theta.getKind() == CONST_RATIONAL);
166
64
    Assert(pv_prop.d_coeff.getKind() == CONST_RATIONAL);
167
64
    NodeManager* nm = NodeManager::currentNM();
168
64
    new_theta = nm->mkConst(Rational(new_theta.getConst<Rational>()
169
                                     * pv_prop.d_coeff.getConst<Rational>()));
170
  }
171
200
  d_theta.push_back(new_theta);
172
}
173
// pop the substitution pv_prop.getModifiedTerm(pv) -> n
174
4414
void SolvedForm::pop_back(Node pv, Node n, TermProperties& pv_prop)
175
{
176
4414
  d_vars.pop_back();
177
4414
  d_subs.pop_back();
178
4414
  d_props.pop_back();
179
4414
  if (pv_prop.isBasic())
180
  {
181
4396
    return;
182
  }
183
18
  d_non_basic.pop_back();
184
  // update theta value
185
18
  d_theta.pop_back();
186
}
187
188
1932
CegInstantiator::CegInstantiator(Env& env,
189
                                 Node q,
190
                                 QuantifiersState& qs,
191
                                 TermRegistry& tr,
192
1932
                                 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
1932
      d_effort(CEG_INST_EFFORT_NONE)
200
{
201
1932
}
202
203
5796
CegInstantiator::~CegInstantiator() {
204
5462
  for (std::pair<Node, Instantiator*> inst : d_instantiator)
205
  {
206
3530
    delete inst.second;
207
  }
208
2670
  for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
209
  {
210
738
    delete instp.second;
211
  }
212
3864
}
213
214
3132732
void CegInstantiator::computeProgVars( Node n ){
215
3132732
  if( d_prog_var.find( n )==d_prog_var.end() ){
216
64090
    d_prog_var[n].clear();
217
64090
    if (n.getKind() == kind::WITNESS)
218
    {
219
544
      Assert(d_prog_var.find(n[0][0]) == d_prog_var.end());
220
544
      d_prog_var[n[0][0]].clear();
221
    }
222
64090
    if (d_vars_set.find(n) != d_vars_set.end())
223
    {
224
3197
      d_prog_var[n].insert(n);
225
    }
226
60893
    else if (!isEligibleForInstantiation(n))
227
    {
228
3095
      d_inelig.insert(n);
229
3095
      return;
230
    }
231
147399
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
232
86404
      computeProgVars( n[i] );
233
86404
      if( d_inelig.find( n[i] )!=d_inelig.end() ){
234
12505
        d_inelig.insert(n);
235
      }
236
      // all variables in child are contained in this
237
86404
      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
121990
    if (n.getKind() == APPLY_SELECTOR_TOTAL
241
121990
        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
242
    {
243
60
      d_prog_var[n].insert(n);
244
    }
245
60995
    if (n.getKind() == kind::WITNESS)
246
    {
247
544
      d_prog_var.erase(n[0][0]);
248
    }
249
  }
250
}
251
252
874881
bool CegInstantiator::isEligible( Node n ) {
253
  //compute d_subs_fv, which program variables are contained in n, and determines if eligible
254
874881
  computeProgVars( n );
255
874881
  return d_inelig.find( n )==d_inelig.end();
256
}
257
258
56106
CegHandledStatus CegInstantiator::isCbqiKind(Kind k)
259
{
260
141327
  if (quantifiers::TermUtil::isBoolConnective(k) || k == PLUS || k == GEQ
261
15081
      || k == EQUAL || k == MULT || k == NONLINEAR_MULT || k == DIVISION
262
9242
      || k == DIVISION_TOTAL || k == INTS_DIVISION || k == INTS_DIVISION_TOTAL
263
9106
      || k == INTS_MODULUS || k == INTS_MODULUS_TOTAL || k == TO_INTEGER
264
65112
      || k == IS_INTEGER)
265
  {
266
47104
    return CEG_HANDLED;
267
  }
268
269
  // CBQI typically works for satisfaction-complete theories
270
9002
  TheoryId t = kindToTheoryId(k);
271
9002
  if (t == THEORY_BV || t == THEORY_FP || t == THEORY_DATATYPES
272
5829
      || t == THEORY_BOOL)
273
  {
274
3173
    return CEG_HANDLED;
275
  }
276
5829
  return CEG_UNHANDLED;
277
}
278
279
7861
CegHandledStatus CegInstantiator::isCbqiTerm(Node n)
280
{
281
7861
  CegHandledStatus ret = CEG_HANDLED;
282
15722
  std::unordered_set<TNode> visited;
283
15722
  std::vector<TNode> visit;
284
15722
  TNode cur;
285
7861
  visit.push_back(n);
286
103139
  do
287
  {
288
111000
    cur = visit.back();
289
111000
    visit.pop_back();
290
111000
    if (visited.find(cur) == visited.end())
291
    {
292
90746
      visited.insert(cur);
293
90746
      if (cur.getKind() != BOUND_VARIABLE && TermUtil::hasBoundVarAttr(cur))
294
      {
295
64301
        if (cur.getKind() == FORALL || cur.getKind() == WITNESS)
296
        {
297
8195
          visit.push_back(cur[1]);
298
        }
299
        else
300
        {
301
56106
          CegHandledStatus curr = isCbqiKind(cur.getKind());
302
56106
          if (curr < ret)
303
          {
304
5829
            ret = curr;
305
11658
            Trace("cegqi-debug2") << "Non-cbqi kind : " << cur.getKind()
306
5829
                                 << " in " << n << std::endl;
307
5829
            if (curr == CEG_UNHANDLED)
308
            {
309
5829
              return CEG_UNHANDLED;
310
            }
311
          }
312
157403
          for (const Node& nc : cur)
313
          {
314
107126
            visit.push_back(nc);
315
          }
316
        }
317
      }
318
    }
319
105171
  } while (!visit.empty());
320
2032
  return ret;
321
}
322
323
25898
CegHandledStatus CegInstantiator::isCbqiSort(TypeNode tn)
324
{
325
51796
  std::map<TypeNode, CegHandledStatus> visited;
326
51796
  return isCbqiSort(tn, visited);
327
}
328
329
31078
CegHandledStatus CegInstantiator::isCbqiSort(
330
    TypeNode tn, std::map<TypeNode, CegHandledStatus>& visited)
331
{
332
31078
  std::map<TypeNode, CegHandledStatus>::iterator itv = visited.find(tn);
333
31078
  if (itv != visited.end())
334
  {
335
3011
    return itv->second;
336
  }
337
28067
  CegHandledStatus ret = CEG_UNHANDLED;
338
72637
  if (tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector()
339
42273
      || tn.isFloatingPoint())
340
  {
341
13874
    ret = CEG_HANDLED;
342
  }
343
14193
  else if (tn.isDatatype())
344
  {
345
    // recursive calls to this datatype are handlable
346
2317
    visited[tn] = CEG_HANDLED;
347
    // we initialize to handled, we remain handled as long as all subfields
348
    // of this datatype are not unhandled.
349
2317
    ret = CEG_HANDLED;
350
2317
    const DType& dt = tn.getDType();
351
4799
    for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
352
    {
353
      // get the constructor type
354
6486
      TypeNode consType;
355
4004
      if (dt.isParametric())
356
      {
357
        // if parametric, must instantiate the argument types
358
36
        consType = dt[i].getSpecializedConstructorType(tn);
359
      }
360
      else
361
      {
362
3968
        consType = dt[i].getConstructor().getType();
363
      }
364
7662
      for (const TypeNode& crange : consType)
365
      {
366
5180
        CegHandledStatus cret = isCbqiSort(crange, visited);
367
5180
        if (cret == CEG_UNHANDLED)
368
        {
369
3044
          Trace("cegqi-debug2")
370
1522
              << "Non-cbqi sort : " << tn << " due to " << crange << std::endl;
371
1522
          visited[tn] = CEG_UNHANDLED;
372
1522
          return CEG_UNHANDLED;
373
        }
374
3658
        else if (cret < ret)
375
        {
376
          ret = cret;
377
        }
378
      }
379
    }
380
  }
381
  // sets, arrays, functions and others are not supported
382
26545
  visited[tn] = ret;
383
26545
  return ret;
384
}
385
386
19735
CegHandledStatus CegInstantiator::isCbqiQuantPrefix(Node q)
387
{
388
19735
  CegHandledStatus hmin = CEG_HANDLED_UNCONDITIONAL;
389
33702
  for (const Node& v : q[0])
390
  {
391
39808
    TypeNode tn = v.getType();
392
25841
    CegHandledStatus handled = isCbqiSort(tn);
393
25841
    if (handled == CEG_UNHANDLED)
394
    {
395
11874
      return CEG_UNHANDLED;
396
    }
397
13967
    else if (handled < hmin)
398
    {
399
8180
      hmin = handled;
400
    }
401
  }
402
7861
  return hmin;
403
}
404
405
24534
CegHandledStatus CegInstantiator::isCbqiQuant(Node q)
406
{
407
24534
  Assert(q.getKind() == FORALL);
408
  // compute attributes
409
49068
  QAttributes qa;
410
24534
  QuantAttributes::computeQuantAttributes(q, qa);
411
24534
  if (qa.d_quant_elim)
412
  {
413
96
    return CEG_HANDLED;
414
  }
415
24438
  if (qa.d_sygus)
416
  {
417
548
    return CEG_UNHANDLED;
418
  }
419
23890
  Assert(!qa.d_quant_elim_partial);
420
  // if has an instantiation pattern, don't do it
421
23890
  if (q.getNumChildren() == 3)
422
  {
423
6135
    for (const Node& pat : q[2])
424
    {
425
5316
      if (pat.getKind() == INST_PATTERN)
426
      {
427
4155
        return CEG_UNHANDLED;
428
      }
429
    }
430
  }
431
19735
  CegHandledStatus ret = CEG_HANDLED;
432
  // if quantifier has a non-handled variable, then do not use cbqi
433
19735
  CegHandledStatus ncbqiv = CegInstantiator::isCbqiQuantPrefix(q);
434
39470
  Trace("cegqi-quant-debug") << "isCbqiQuantPrefix returned " << ncbqiv
435
19735
                            << std::endl;
436
19735
  if (ncbqiv == CEG_UNHANDLED)
437
  {
438
    // unhandled variable type
439
11874
    ret = CEG_UNHANDLED;
440
  }
441
  else
442
  {
443
7861
    CegHandledStatus cbqit = CegInstantiator::isCbqiTerm(q);
444
7861
    Trace("cegqi-quant-debug") << "isCbqiTerm returned " << cbqit << std::endl;
445
7861
    if (cbqit == CEG_UNHANDLED)
446
    {
447
5829
      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
5829
        ret = CEG_UNHANDLED;
458
      }
459
    }
460
2032
    else if (cbqit == CEG_PARTIALLY_HANDLED)
461
    {
462
      ret = CEG_PARTIALLY_HANDLED;
463
    }
464
  }
465
19735
  if (ret == CEG_UNHANDLED && options::cegqiAll())
466
  {
467
    // try but not exclusively
468
17
    ret = CEG_PARTIALLY_HANDLED;
469
  }
470
19735
  return ret;
471
}
472
473
403739
bool CegInstantiator::hasVariable( Node n, Node pv ) {
474
403739
  computeProgVars( n );
475
403739
  return d_prog_var[n].find( pv )!=d_prog_var[n].end();
476
}
477
478
39070
void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
479
{
480
39070
  if( d_instantiator.find( v )==d_instantiator.end() ){
481
7060
    TypeNode tn = v.getType();
482
    Instantiator * vinst;
483
3530
    if( tn.isReal() ){
484
2021
      vinst = new ArithInstantiator(d_env, tn, d_parent->getVtsTermCache());
485
1509
    }else if( tn.isDatatype() ){
486
54
      vinst = new DtInstantiator(d_env, tn);
487
1455
    }else if( tn.isBitVector() ){
488
1224
      vinst = new BvInstantiator(d_env, tn, d_parent->getBvInverter());
489
231
    }else if( tn.isBoolean() ){
490
219
      vinst = new ModelValueInstantiator(d_env, tn);
491
    }else{
492
      //default
493
12
      vinst = new Instantiator(d_env, tn);
494
    }
495
3530
    d_instantiator[v] = vinst;
496
  }
497
39070
  d_curr_subs_proc[v].clear();
498
39070
  d_curr_index[v] = index;
499
39070
  d_curr_iphase[v] = CEG_INST_PHASE_NONE;
500
39070
}
501
502
4518
void CegInstantiator::deactivateInstantiationVariable(Node v)
503
{
504
4518
  d_curr_subs_proc.erase(v);
505
4518
  d_curr_index.erase(v);
506
4518
  d_curr_iphase.erase(v);
507
4518
}
508
509
61321
bool CegInstantiator::hasTriedInstantiation(Node v)
510
{
511
61321
  return !d_curr_subs_proc[v].empty();
512
}
513
514
5431
void CegInstantiator::registerTheoryIds(TypeNode tn,
515
                                        std::map<TypeNode, bool>& visited)
516
{
517
5431
  if (visited.find(tn) == visited.end())
518
  {
519
5377
    visited[tn] = true;
520
5377
    TheoryId tid = Theory::theoryOf(tn);
521
5377
    registerTheoryId(tid);
522
5377
    if (tn.isDatatype())
523
    {
524
66
      const DType& dt = tn.getDType();
525
170
      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
526
      {
527
222
        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
528
        {
529
118
          registerTheoryIds(dt[i].getArgType(j), visited);
530
        }
531
      }
532
    }
533
  }
534
5431
}
535
536
7309
void CegInstantiator::registerTheoryId(TheoryId tid)
537
{
538
7309
  if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
539
  {
540
    // setup any theory-specific preprocessors here
541
3937
    if (tid == THEORY_BV)
542
    {
543
738
      d_tipp[tid] = new BvInstantiatorPreprocess;
544
    }
545
3937
    d_tids.push_back(tid);
546
  }
547
7309
}
548
549
5313
void CegInstantiator::registerVariable(Node v)
550
{
551
5313
  Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
552
5313
  d_vars.push_back(v);
553
5313
  d_vars_set.insert(v);
554
10626
  TypeNode vtn = v.getType();
555
10626
  Trace("cegqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
556
5313
                           << v << std::endl;
557
  // collect relevant theories for this variable
558
10626
  std::map<TypeNode, bool> visited;
559
5313
  registerTheoryIds(vtn, visited);
560
5313
}
561
562
45040
bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
563
{
564
45040
  if( i==d_vars.size() ){
565
    //solved for all variables, now construct instantiation
566
    bool needsPostprocess =
567
5970
        sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty();
568
11940
    std::vector< Instantiator * > pp_inst;
569
11940
    std::map< Instantiator *, Node > pp_inst_to_var;
570
44936
    for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){
571
116898
      if (ita->second->needsPostProcessInstantiationForVariable(
572
77932
              this, sf, ita->first, d_effort))
573
      {
574
221
        needsPostprocess = true;
575
221
        pp_inst_to_var[ ita->second ] = ita->first;
576
      }
577
    }
578
5970
    if( needsPostprocess ){
579
      //must make copy so that backtracking reverts sf
580
4336
      SolvedForm sf_tmp = sf;
581
2168
      bool postProcessSuccess = true;
582
2371
      for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){
583
663
        if (!itp->first->postProcessInstantiationForVariable(
584
442
                this, sf_tmp, itp->second, d_effort))
585
        {
586
18
          postProcessSuccess = false;
587
18
          break;
588
        }
589
      }
590
2168
      if( postProcessSuccess ){
591
2150
        return doAddInstantiation(sf_tmp.d_vars, sf_tmp.d_subs);
592
      }else{
593
18
        return false;
594
      }
595
    }else{
596
3802
      return doAddInstantiation(sf.d_vars, sf.d_subs);
597
    }
598
  }else{
599
39070
    bool is_sv = false;
600
78140
    Node pv;
601
39070
    if( d_stack_vars.empty() ){
602
39010
      pv = d_vars[i];
603
    }else{
604
60
      pv = d_stack_vars.back();
605
60
      is_sv = true;
606
60
      d_stack_vars.pop_back();
607
    }
608
39070
    activateInstantiationVariable(pv, i);
609
610
    //get the instantiator object
611
39070
    Assert(d_instantiator.find(pv) != d_instantiator.end());
612
39070
    Instantiator* vinst = d_instantiator[pv];
613
39070
    Assert(vinst != NULL);
614
39070
    d_active_instantiators[pv] = vinst;
615
39070
    vinst->reset(this, sf, pv, d_effort);
616
    // if d_effort is full, we must choose at least one model value
617
39070
    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
37756
      if (constructInstantiation(sf, vinst, pv))
622
      {
623
24635
        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
43265
    if ((options().quantifiers.cegqiMultiInst || !hasTriedInstantiation(pv))
633
25887
        && (vinst->useModelValue(this, sf, pv, d_effort) || is_sv)
634
40158
        && vinst->allowModelValue(this, sf, pv, d_effort))
635
    {
636
12659
      Node mv = getModelValue( pv );
637
12659
      TermProperties pv_prop_m;
638
11288
      Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
639
11288
      d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
640
11288
      CegInstEffort prev = d_effort;
641
11288
      if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
642
      {
643
        // update the effort level to indicate we have used a model value
644
2087
        d_effort = CEG_INST_EFFORT_STANDARD_MV;
645
      }
646
11288
      if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
647
      {
648
9917
        return true;
649
      }
650
1371
      d_effort = prev;
651
    }
652
653
4518
    Trace("cegqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl;
654
4518
    if (is_sv)
655
    {
656
      d_stack_vars.push_back( pv );
657
    }
658
4518
    d_active_instantiators.erase( pv );
659
4518
    deactivateInstantiationVariable(pv);
660
4518
    return false;
661
  }
662
}
663
664
37756
bool CegInstantiator::constructInstantiation(SolvedForm& sf,
665
                                             Instantiator* vinst,
666
                                             Node pv)
667
{
668
75512
  TypeNode pvtn = pv.getType();
669
75512
  TypeNode pvtnb = pvtn.getBaseType();
670
75512
  Node pvr = pv;
671
37756
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
672
37756
  if (ee->hasTerm(pv))
673
  {
674
26231
    pvr = ee->getRepresentative(pv);
675
  }
676
75512
  Trace("cegqi-inst-debug") << "[Find instantiation for " << pv
677
37756
                           << "], rep=" << pvr << ", instantiator is "
678
37756
                           << vinst->identify() << std::endl;
679
75512
  Node pv_value;
680
37756
  if (options().quantifiers.cegqiModel)
681
  {
682
37756
    pv_value = getModelValue(pv);
683
37756
    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
37756
  if (vinst->hasProcessEqualTerm(this, sf, pv, d_effort))
689
  {
690
116
    Trace("cegqi-inst-debug")
691
58
        << "[1] try based on equivalence class." << std::endl;
692
58
    d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
693
58
    std::map<Node, std::vector<Node> >::iterator it_eqc = d_curr_eqc.find(pvr);
694
58
    if (it_eqc != d_curr_eqc.end())
695
    {
696
      // std::vector< Node > eq_candidates;
697
116
      Trace("cegqi-inst-debug2")
698
58
          << "...eqc has size " << it_eqc->second.size() << std::endl;
699
164
      for (const Node& n : it_eqc->second)
700
      {
701
120
        if (n != pv)
702
        {
703
148
          Trace("cegqi-inst-debug")
704
74
              << "...try based on equal term " << n << std::endl;
705
          // must be an eligible term
706
74
          if (isEligible(n))
707
          {
708
94
            Node ns;
709
            // coefficient of pv in the equality we solve (null is 1)
710
94
            TermProperties pv_prop;
711
54
            bool proc = false;
712
54
            if (!d_prog_var[n].empty())
713
            {
714
46
              ns = applySubstitution(pvtn, n, sf, pv_prop, false);
715
46
              if (!ns.isNull())
716
              {
717
46
                computeProgVars(ns);
718
                // substituted version must be new and cannot contain pv
719
46
                proc = d_prog_var[ns].find(pv) == d_prog_var[ns].end();
720
              }
721
            }
722
            else
723
            {
724
8
              ns = n;
725
8
              proc = true;
726
            }
727
54
            if (proc)
728
            {
729
14
              if (vinst->processEqualTerm(this, sf, pv, pv_prop, ns, d_effort))
730
              {
731
14
                return true;
732
              }
733
              else if (!options().quantifiers.cegqiMultiInst
734
                       && hasTriedInstantiation(pv))
735
              {
736
                return false;
737
              }
738
              // Do not consider more than one equal term,
739
              // this helps non-monotonic strategies that may encounter
740
              // duplicate instantiations.
741
              break;
742
            }
743
          }
744
        }
745
      }
746
44
      if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
747
      {
748
34
        return true;
749
      }
750
20
      else if (!options().quantifiers.cegqiMultiInst
751
20
               && hasTriedInstantiation(pv))
752
      {
753
        return false;
754
      }
755
    }
756
    else
757
    {
758
      Trace("cegqi-inst-debug2") << "...eqc not found." << std::endl;
759
    }
760
  }
761
762
  //[2] : we can solve an equality for pv
763
  /// iterate over equivalence classes to find cases where we can solve for
764
  /// the variable
765
37708
  if (vinst->hasProcessEquality(this, sf, pv, d_effort))
766
  {
767
51988
    Trace("cegqi-inst-debug")
768
25994
        << "[2] try based on solving equalities." << std::endl;
769
25994
    d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
770
25994
    std::vector<Node>& cteqc = d_curr_type_eqc[pvtnb];
771
772
359092
    for (const Node& r : cteqc)
773
    {
774
345552
      std::map<Node, std::vector<Node> >::iterator it_reqc = d_curr_eqc.find(r);
775
678650
      std::vector<Node> lhs;
776
678650
      std::vector<bool> lhs_v;
777
678650
      std::vector<TermProperties> lhs_prop;
778
345552
      Assert(it_reqc != d_curr_eqc.end());
779
1170786
      for (const Node& n : it_reqc->second)
780
      {
781
837688
        Trace("cegqi-inst-debug2") << "...look at term " << n << std::endl;
782
        // must be an eligible term
783
837688
        if (isEligible(n))
784
        {
785
1367878
          Node ns;
786
1367878
          TermProperties pv_prop;
787
690166
          if (!d_prog_var[n].empty())
788
          {
789
635034
            ns = applySubstitution(pvtn, n, sf, pv_prop);
790
635034
            if (!ns.isNull())
791
            {
792
635034
              computeProgVars(ns);
793
            }
794
          }
795
          else
796
          {
797
55132
            ns = n;
798
          }
799
690166
          if (!ns.isNull())
800
          {
801
690166
            bool hasVar = d_prog_var[ns].find(pv) != d_prog_var[ns].end();
802
1380332
            Trace("cegqi-inst-debug2") << "... " << ns << " has var " << pv
803
690166
                                      << " : " << hasVar << std::endl;
804
1367878
            std::vector<TermProperties> term_props;
805
1367878
            std::vector<Node> terms;
806
690166
            term_props.push_back(pv_prop);
807
690166
            terms.push_back(ns);
808
1445853
            for (unsigned j = 0, size = lhs.size(); j < size; j++)
809
            {
810
              // if this term or the another has pv in it, try to solve for it
811
768141
              if (hasVar || lhs_v[j])
812
              {
813
82060
                Trace("cegqi-inst-debug") << "......try based on equality "
814
41030
                                         << lhs[j] << " = " << ns << std::endl;
815
41030
                term_props.push_back(lhs_prop[j]);
816
41030
                terms.push_back(lhs[j]);
817
41030
                if (vinst->processEquality(
818
41030
                        this, sf, pv, term_props, terms, d_effort))
819
                {
820
11672
                  return true;
821
                }
822
58716
                else if (!options().quantifiers.cegqiMultiInst
823
58716
                         && hasTriedInstantiation(pv))
824
                {
825
782
                  return false;
826
                }
827
28576
                term_props.pop_back();
828
28576
                terms.pop_back();
829
              }
830
            }
831
677712
            lhs.push_back(ns);
832
677712
            lhs_v.push_back(hasVar);
833
677712
            lhs_prop.push_back(pv_prop);
834
          }
835
          else
836
          {
837
            Trace("cegqi-inst-debug2")
838
                << "... term " << n << " is ineligible after substitution."
839
                << std::endl;
840
          }
841
        }
842
        else
843
        {
844
295044
          Trace("cegqi-inst-debug2")
845
147522
              << "... term " << n << " is ineligible." << std::endl;
846
        }
847
      }
848
    }
849
  }
850
  //[3] directly look at assertions
851
25254
  if (!vinst->hasProcessAssertion(this, sf, pv, d_effort))
852
  {
853
6845
    return false;
854
  }
855
18409
  Trace("cegqi-inst-debug") << "[3] try based on assertions." << std::endl;
856
18409
  d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
857
36818
  std::unordered_set<Node> lits;
858
55227
  for (unsigned r = 0; r < 2; r++)
859
  {
860
36818
    TheoryId tid = r == 0 ? Theory::theoryOf(pvtn) : THEORY_UF;
861
36818
    Trace("cegqi-inst-debug2") << "  look at assertions of " << tid << std::endl;
862
    std::map<TheoryId, std::vector<Node> >::iterator ita =
863
36818
        d_curr_asserts.find(tid);
864
36818
    if (ita != d_curr_asserts.end())
865
    {
866
453658
      for (const Node& lit : ita->second)
867
      {
868
430620
        if (lits.find(lit) == lits.end())
869
        {
870
421427
          lits.insert(lit);
871
842854
          Node plit;
872
421427
          if (options().quantifiers.cegqiRepeatLit || !isSolvedAssertion(lit))
873
          {
874
415819
            plit = vinst->hasProcessAssertion(this, sf, pv, lit, d_effort);
875
          }
876
421427
          if (!plit.isNull())
877
          {
878
403815
            Trace("cegqi-inst-debug2") << "  look at " << lit;
879
403815
            if (plit != lit)
880
            {
881
9245
              Trace("cegqi-inst-debug2") << "...processed to : " << plit;
882
            }
883
403815
            Trace("cegqi-inst-debug2") << std::endl;
884
            // apply substitutions
885
807630
            Node slit = applySubstitutionToLiteral(plit, sf);
886
403815
            if (!slit.isNull())
887
            {
888
              // check if contains pv
889
403739
              if (hasVariable(slit, pv))
890
              {
891
35420
                Trace("cegqi-inst-debug")
892
17710
                    << "...try based on literal " << slit << "," << std::endl;
893
17710
                Trace("cegqi-inst-debug") << "...from " << lit << std::endl;
894
17710
                if (vinst->processAssertion(this, sf, pv, slit, lit, d_effort))
895
                {
896
                  return true;
897
                }
898
35420
                else if (!options().quantifiers.cegqiMultiInst
899
35420
                         && hasTriedInstantiation(pv))
900
                {
901
                  return false;
902
                }
903
              }
904
            }
905
          }
906
        }
907
      }
908
    }
909
  }
910
18409
  if (vinst->processAssertions(this, sf, pv, d_effort))
911
  {
912
12915
    return true;
913
  }
914
5494
  return false;
915
}
916
917
60
void CegInstantiator::pushStackVariable( Node v ) {
918
60
  d_stack_vars.push_back( v );
919
60
}
920
921
void CegInstantiator::popStackVariable() {
922
  Assert(!d_stack_vars.empty());
923
  d_stack_vars.pop_back();
924
}
925
926
38966
bool CegInstantiator::constructInstantiationInc(Node pv,
927
                                                Node n,
928
                                                TermProperties& pv_prop,
929
                                                SolvedForm& sf,
930
                                                bool revertOnSuccess)
931
{
932
77932
  Node cnode = pv_prop.getCacheNode();
933
38966
  if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
934
38966
    d_curr_subs_proc[pv][n][cnode] = true;
935
38966
    if( Trace.isOn("cegqi-inst-debug") ){
936
      for( unsigned j=0; j<sf.d_subs.size(); j++ ){
937
        Trace("cegqi-inst-debug") << " ";
938
      }
939
      Trace("cegqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv]
940
                         << ") ";
941
      Node mod_pv = pv_prop.getModifiedTerm( pv );
942
      Trace("cegqi-inst-debug") << mod_pv << " -> " << n << std::endl;
943
      Assert(n.getType().isSubtypeOf(pv.getType()));
944
    }
945
    //must ensure variables have been computed for n
946
38966
    computeProgVars( n );
947
38966
    Assert(d_inelig.find(n) == d_inelig.end());
948
949
    //substitute into previous substitutions, when applicable
950
77932
    std::vector< Node > a_var;
951
38966
    a_var.push_back( pv );
952
77932
    std::vector< Node > a_subs;
953
38966
    a_subs.push_back( n );
954
77932
    std::vector< TermProperties > a_prop;
955
38966
    a_prop.push_back( pv_prop );
956
77932
    std::vector< Node > a_non_basic;
957
38966
    if( !pv_prop.isBasic() ){
958
200
      a_non_basic.push_back( pv );
959
    }
960
38966
    bool success = true;
961
77932
    std::map< int, Node > prev_subs;
962
77932
    std::map< int, TermProperties > prev_prop;
963
77932
    std::map< int, Node > prev_sym_subs;
964
77932
    std::vector< Node > new_non_basic;
965
38966
    Trace("cegqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl;
966
774979
    for( unsigned j=0; j<sf.d_subs.size(); j++ ){
967
736013
      Trace("cegqi-inst-debug2") << "  Apply for " << sf.d_subs[j]  << std::endl;
968
736013
      Assert(d_prog_var.find(sf.d_subs[j]) != d_prog_var.end());
969
736013
      if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
970
26975
        prev_subs[j] = sf.d_subs[j];
971
53950
        TNode tv = pv;
972
53950
        TNode ts = n;
973
53950
        TermProperties a_pv_prop;
974
53950
        Node new_subs = applySubstitution( sf.d_vars[j].getType(), sf.d_subs[j], a_var, a_subs, a_prop, a_non_basic, a_pv_prop, true );
975
26975
        if( !new_subs.isNull() ){
976
26975
          sf.d_subs[j] = new_subs;
977
          // the substitution apply to this term resulted in a non-basic substitution relationship
978
26975
          if( !a_pv_prop.isBasic() ){
979
            // we are processing:
980
            //    sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n }
981
982
            // based on the above substitution, we have:
983
            //   x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n }
984
            // is equivalent to
985
            //   a_pv_prop.getModifiedTerm( x ) = new_subs
986
987
            // thus we must compose substitutions:
988
            //   a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs
989
990
37
            prev_prop[j] = sf.d_props[j];
991
37
            bool prev_basic = sf.d_props[j].isBasic();
992
993
            // now compose the property
994
37
            sf.d_props[j].composeProperty( a_pv_prop );
995
996
            // if previously was basic, becomes non-basic
997
37
            if( prev_basic && !sf.d_props[j].isBasic() ){
998
21
              Assert(std::find(sf.d_non_basic.begin(),
999
                               sf.d_non_basic.end(),
1000
                               sf.d_vars[j])
1001
                     == sf.d_non_basic.end());
1002
21
              new_non_basic.push_back( sf.d_vars[j] );
1003
21
              sf.d_non_basic.push_back( sf.d_vars[j] );
1004
            }
1005
          }
1006
26975
          if( sf.d_subs[j]!=prev_subs[j] ){
1007
26971
            computeProgVars( sf.d_subs[j] );
1008
26971
            Assert(d_inelig.find(sf.d_subs[j]) == d_inelig.end());
1009
          }
1010
26975
          Trace("cegqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl;
1011
        }else{
1012
          Trace("cegqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl;
1013
          success = false;
1014
          break;
1015
        }
1016
      }else{
1017
709038
        Trace("cegqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl;
1018
      }
1019
    }
1020
38966
    if( success ){
1021
38966
      Trace("cegqi-inst-debug2") << "Adding to vectors..." << std::endl;
1022
38966
      sf.push_back( pv, n, pv_prop );
1023
38966
      Trace("cegqi-inst-debug2") << "Recurse..." << std::endl;
1024
38966
      unsigned i = d_curr_index[pv];
1025
38966
      success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
1026
38966
      if (!success || revertOnSuccess)
1027
      {
1028
4414
        Trace("cegqi-inst-debug2") << "Removing from vectors..." << std::endl;
1029
4414
        sf.pop_back( pv, n, pv_prop );
1030
      }
1031
    }
1032
38966
    if (success && !revertOnSuccess)
1033
    {
1034
34552
      return true;
1035
    }else{
1036
4414
      Trace("cegqi-inst-debug2") << "Revert substitutions..." << std::endl;
1037
      //revert substitution information
1038
6180
      for (std::map<int, Node>::iterator it = prev_subs.begin();
1039
6180
           it != prev_subs.end();
1040
           ++it)
1041
      {
1042
1766
        sf.d_subs[it->first] = it->second;
1043
      }
1044
4414
      for (std::map<int, TermProperties>::iterator it = prev_prop.begin();
1045
4414
           it != prev_prop.end();
1046
           ++it)
1047
      {
1048
        sf.d_props[it->first] = it->second;
1049
      }
1050
4414
      for( unsigned i=0; i<new_non_basic.size(); i++ ){
1051
        sf.d_non_basic.pop_back();
1052
      }
1053
4414
      return success;
1054
    }
1055
  }else{
1056
    //already tried this substitution
1057
    return false;
1058
  }
1059
}
1060
1061
5952
bool CegInstantiator::doAddInstantiation(std::vector<Node>& vars,
1062
                                         std::vector<Node>& subs)
1063
{
1064
5952
  if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
1065
  {
1066
2150
    Trace("cegqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
1067
4300
    std::map< Node, Node > subs_map;
1068
36416
    for( unsigned i=0; i<subs.size(); i++ ){
1069
34266
      subs_map[vars[i]] = subs[i];
1070
    }
1071
2150
    subs.clear();
1072
24276
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1073
    {
1074
22126
      std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
1075
22126
      Assert(it != subs_map.end());
1076
44252
      Node n = it->second;
1077
44252
      Trace("cegqi-inst-debug") << "  " << d_input_vars[i] << " -> " << n
1078
22126
                               << std::endl;
1079
22126
      Assert(n.getType().isComparableTo(d_input_vars[i].getType()));
1080
22126
      subs.push_back( n );
1081
    }
1082
  }
1083
5952
  if (Trace.isOn("cegqi-inst"))
1084
  {
1085
    Trace("cegqi-inst") << "Ceg Instantiator produced : " << std::endl;
1086
    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
1087
    {
1088
      Node v = d_input_vars[i];
1089
      Trace("cegqi-inst") << i << " (" << d_curr_iphase[v] << ") : "
1090
                         << v << " -> " << subs[i] << std::endl;
1091
      Assert(subs[i].getType().isComparableTo(v.getType()));
1092
    }
1093
  }
1094
5952
  Trace("cegqi-inst-debug") << "Do the instantiation...." << std::endl;
1095
5952
  return d_parent->doAddInstantiation(subs);
1096
}
1097
1098
60951
bool CegInstantiator::isEligibleForInstantiation(Node n) const
1099
{
1100
60951
  Kind nk = n.getKind();
1101
60951
  if (nk != INST_CONSTANT && nk != SKOLEM && nk != BOOLEAN_TERM_VARIABLE)
1102
  {
1103
57002
    return true;
1104
  }
1105
3949
  if (n.getAttribute(VirtualTermSkolemAttribute()))
1106
  {
1107
    // virtual terms are allowed
1108
89
    return true;
1109
  }
1110
  // only legal if current quantified formula contains n
1111
3860
  return expr::hasSubterm(d_quant, n);
1112
}
1113
1114
1066691
bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
1115
1066691
  Assert(d_prog_var.find(n) != d_prog_var.end());
1116
1066691
  if( !non_basic.empty() ){
1117
13087
    for (std::unordered_set<Node>::iterator it = d_prog_var[n].begin();
1118
13087
         it != d_prog_var[n].end();
1119
         ++it)
1120
    {
1121
9088
      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
1122
      {
1123
2028
        return false;
1124
      }
1125
    }
1126
  }
1127
1064663
  return true;
1128
}
1129
1130
662876
Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop,
1131
                                         std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) {
1132
662876
  n = rewrite(n);
1133
662876
  computeProgVars( n );
1134
662876
  bool is_basic = canApplyBasicSubstitution( n, non_basic );
1135
662876
  if( Trace.isOn("sygus-si-apply-subs-debug") ){
1136
    Trace("sygus-si-apply-subs-debug") << "is_basic = " << is_basic << "  " << tn << std::endl;
1137
    for( unsigned i=0; i<subs.size(); i++ ){
1138
      Trace("sygus-si-apply-subs-debug") << "  " << vars[i] << " -> " << subs[i] << "   types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl;
1139
      Assert(subs[i].getType().isSubtypeOf(vars[i].getType()));
1140
    }
1141
  }
1142
662876
  Node nret;
1143
662876
  if( is_basic ){
1144
661745
    nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1145
  }else{
1146
1131
    if( !tn.isInteger() ){
1147
      //can do basic substitution instead with divisions
1148
1654
      std::vector< Node > nvars;
1149
1654
      std::vector< Node > nsubs;
1150
6816
      for( unsigned i=0; i<vars.size(); i++ ){
1151
5989
        if( !prop[i].d_coeff.isNull() ){
1152
2396
          Assert(vars[i].getType().isInteger());
1153
2396
          Assert(prop[i].d_coeff.isConst());
1154
4792
          Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
1155
2396
          nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn );
1156
2396
          nn = rewrite(nn);
1157
2396
          nsubs.push_back( nn );
1158
        }else{
1159
3593
          nsubs.push_back( subs[i] );
1160
        }
1161
      }
1162
827
      nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() );
1163
304
    }else if( try_coeff ){
1164
      //must convert to monomial representation
1165
608
      std::map< Node, Node > msum;
1166
304
      if (ArithMSum::getMonomialSum(n, msum))
1167
      {
1168
608
        std::map< Node, Node > msum_coeff;
1169
608
        std::map< Node, Node > msum_term;
1170
1521
        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1171
          //check if in substitution
1172
1217
          std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first );
1173
1217
          if( its!=vars.end() ){
1174
601
            int index = its-vars.begin();
1175
601
            if( prop[index].d_coeff.isNull() ){
1176
              //apply substitution
1177
288
              msum_term[it->first] = subs[index];
1178
            }else{
1179
              //apply substitution, multiply to ensure no divisibility conflict
1180
313
              msum_term[it->first] = subs[index];
1181
              //relative coefficient
1182
313
              msum_coeff[it->first] = prop[index].d_coeff;
1183
313
              if( pv_prop.d_coeff.isNull() ){
1184
304
                pv_prop.d_coeff = prop[index].d_coeff;
1185
              }else{
1186
9
                pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff );
1187
              }
1188
            }
1189
          }else{
1190
616
            msum_term[it->first] = it->first;
1191
          }
1192
        }
1193
        //make sum with normalized coefficient
1194
304
        if( !pv_prop.d_coeff.isNull() ){
1195
304
          pv_prop.d_coeff = rewrite(pv_prop.d_coeff);
1196
304
          Trace("sygus-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl;
1197
608
          std::vector< Node > children;
1198
1521
          for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
1199
2434
            Node c_coeff;
1200
1217
            if( !msum_coeff[it->first].isNull() ){
1201
626
              c_coeff = rewrite(NodeManager::currentNM()->mkConst(
1202
313
                  pv_prop.d_coeff.getConst<Rational>()
1203
939
                  / msum_coeff[it->first].getConst<Rational>()));
1204
            }else{
1205
904
              c_coeff = pv_prop.d_coeff;
1206
            }
1207
1217
            if( !it->second.isNull() ){
1208
960
              c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
1209
            }
1210
1217
            Assert(!c_coeff.isNull());
1211
2434
            Node c;
1212
1217
            if( msum_term[it->first].isNull() ){
1213
54
              c = c_coeff;
1214
            }else{
1215
1163
              c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
1216
            }
1217
1217
            children.push_back( c );
1218
1217
            Trace("sygus-si-apply-subs-debug") << "Add child : " << c << std::endl;
1219
          }
1220
608
          Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children );
1221
304
          nretc = rewrite(nretc);
1222
          //ensure that nret does not contain vars
1223
304
          if (!expr::hasSubterm(nretc, vars))
1224
          {
1225
            //result is ( nret / pv_prop.d_coeff )
1226
304
            nret = nretc;
1227
          }else{
1228
            Trace("sygus-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl;
1229
          }
1230
        }else{
1231
          //implies that we have a monomial that has a free variable
1232
          Trace("sygus-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl;
1233
        }
1234
      }else{
1235
        Trace("sygus-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl;
1236
      }
1237
    }
1238
  }
1239
662876
  if( n!=nret && !nret.isNull() ){
1240
328913
    nret = rewrite(nret);
1241
  }
1242
662876
  return nret;
1243
}
1244
1245
403815
Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs,
1246
                                                  std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) {
1247
403815
  computeProgVars( lit );
1248
403815
  bool is_basic = canApplyBasicSubstitution( lit, non_basic );
1249
403815
  Node lret;
1250
403815
  if( is_basic ){
1251
402918
   lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
1252
  }else{
1253
1794
    Node atom = lit.getKind()==NOT ? lit[0] : lit;
1254
897
    bool pol = lit.getKind()!=NOT;
1255
    //arithmetic inequalities and disequalities
1256
897
    if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){
1257
821
      NodeManager* nm = NodeManager::currentNM();
1258
821
      Assert(atom.getKind() != GEQ || atom[1].isConst());
1259
1642
      Node atom_lhs;
1260
1642
      Node atom_rhs;
1261
821
      if( atom.getKind()==GEQ ){
1262
813
        atom_lhs = atom[0];
1263
813
        atom_rhs = atom[1];
1264
      }else{
1265
8
        atom_lhs = nm->mkNode(MINUS, atom[0], atom[1]);
1266
8
        atom_lhs = rewrite(atom_lhs);
1267
8
        atom_rhs = nm->mkConst(Rational(0));
1268
      }
1269
      //must be an eligible term
1270
821
      if( isEligible( atom_lhs ) ){
1271
        //apply substitution to LHS of atom
1272
1642
        TermProperties atom_lhs_prop;
1273
821
        atom_lhs = applySubstitution(nm->realType(),
1274
                                     atom_lhs,
1275
                                     vars,
1276
                                     subs,
1277
                                     prop,
1278
                                     non_basic,
1279
                                     atom_lhs_prop);
1280
821
        if( !atom_lhs.isNull() ){
1281
821
          if( !atom_lhs_prop.d_coeff.isNull() ){
1282
            atom_rhs = nm->mkNode(MULT, atom_lhs_prop.d_coeff, atom_rhs);
1283
            atom_rhs = rewrite(atom_rhs);
1284
          }
1285
821
          lret = nm->mkNode(atom.getKind(), atom_lhs, atom_rhs);
1286
821
          if( !pol ){
1287
377
            lret = lret.negate();
1288
          }
1289
        }
1290
      }
1291
    }else{
1292
      // don't know how to apply substitution to literal
1293
    }
1294
  }
1295
403815
  if( lit!=lret && !lret.isNull() ){
1296
235581
    lret = rewrite(lret);
1297
  }
1298
403815
  return lret;
1299
}
1300
1301
4760
bool CegInstantiator::check() {
1302
4760
  processAssertions();
1303
6374
  for( unsigned r=0; r<2; r++ ){
1304
6074
    d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
1305
7688
    SolvedForm sf;
1306
6074
    d_stack_vars.clear();
1307
6074
    d_bound_var_index.clear();
1308
6074
    d_solved_asserts.clear();
1309
    //try to add an instantiation
1310
6074
    if (constructInstantiation(sf, 0))
1311
    {
1312
4460
      return true;
1313
    }
1314
  }
1315
300
  Trace("cegqi-engine") << "  WARNING : unable to find CEGQI single invocation instantiation." << std::endl;
1316
300
  return false;
1317
}
1318
1319
4760
void CegInstantiator::processAssertions() {
1320
9520
  Trace("cegqi-proc") << "--- Process assertions, #var = " << d_vars.size()
1321
4760
                     << std::endl;
1322
4760
  d_curr_asserts.clear();
1323
4760
  d_curr_eqc.clear();
1324
4760
  d_curr_type_eqc.clear();
1325
1326
  // must use master equality engine to avoid value instantiations
1327
4760
  eq::EqualityEngine* ee = d_qstate.getEqualityEngine();
1328
1329
  //for each variable
1330
40569
  for( unsigned i=0; i<d_vars.size(); i++ ){
1331
71618
    Node pv = d_vars[i];
1332
71618
    TypeNode pvtn = pv.getType();
1333
35809
    Trace("cegqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
1334
    //collect information about eqc
1335
35809
    if( ee->hasTerm( pv ) ){
1336
49624
      Node pvr = ee->getRepresentative( pv );
1337
24812
      if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){
1338
13815
        Trace("cegqi-proc") << "Collect equivalence class " << pvr << std::endl;
1339
13815
        eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee );
1340
71717
        while( !eqc_i.isFinished() ){
1341
28951
          d_curr_eqc[pvr].push_back( *eqc_i );
1342
28951
          ++eqc_i;
1343
        }
1344
      }
1345
    }
1346
  }
1347
  //collect assertions for relevant theories
1348
4760
  const LogicInfo& logicInfo = d_qstate.getLogicInfo();
1349
14803
  for (TheoryId tid : d_tids)
1350
  {
1351
10043
    if (!logicInfo.isTheoryEnabled(tid))
1352
    {
1353
2026
      continue;
1354
    }
1355
16034
    Trace("cegqi-proc") << "Collect assertions from theory " << tid
1356
8017
                        << std::endl;
1357
8017
    d_curr_asserts[tid].clear();
1358
    // collect all assertions from theory
1359
356816
    for (context::CDList<Assertion>::const_iterator
1360
8017
             it = d_qstate.factsBegin(tid),
1361
8017
             itEnd = d_qstate.factsEnd(tid);
1362
364833
         it != itEnd;
1363
         ++it)
1364
    {
1365
713632
      Node lit = (*it).d_assertion;
1366
713632
      Node atom = lit.getKind() == NOT ? lit[0] : lit;
1367
713632
      if (d_is_nested_quant
1368
1060138
          || std::find(d_ce_atoms.begin(), d_ce_atoms.end(), atom)
1369
1060138
                 != d_ce_atoms.end())
1370
      {
1371
36298
        d_curr_asserts[tid].push_back(lit);
1372
36298
        Trace("cegqi-proc-debug") << "...add : " << lit << std::endl;
1373
      }
1374
      else
1375
      {
1376
641036
        Trace("cegqi-proc")
1377
320518
            << "...do not consider literal " << tid << " : " << lit
1378
320518
            << " since it is not part of CE body." << std::endl;
1379
      }
1380
    }
1381
  }
1382
  //collect equivalence classes that correspond to relevant theories
1383
4760
  Trace("cegqi-proc-debug") << "...collect typed equivalence classes" << std::endl;
1384
4760
  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
1385
782234
  while( !eqcs_i.isFinished() ){
1386
777474
    Node r = *eqcs_i;
1387
777474
    TypeNode rtn = r.getType();
1388
388737
    TheoryId tid = Theory::theoryOf( rtn );
1389
    //if we care about the theory of this eqc
1390
388737
    if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){
1391
328295
      if( rtn.isInteger() || rtn.isReal() ){
1392
22192
        rtn = rtn.getBaseType();
1393
      }
1394
328295
      Trace("cegqi-proc-debug") << "...type eqc: " << r << std::endl;
1395
328295
      d_curr_type_eqc[rtn].push_back( r );
1396
328295
      if( d_curr_eqc.find( r )==d_curr_eqc.end() ){
1397
314480
        Trace("cegqi-proc") << "Collect equivalence class " << r << std::endl;
1398
314480
        Trace("cegqi-proc-debug") << "  ";
1399
314480
        eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
1400
1067758
        while( !eqc_i.isFinished() ){
1401
376639
          Trace("cegqi-proc-debug") << *eqc_i << " ";
1402
376639
          d_curr_eqc[r].push_back( *eqc_i );
1403
376639
          ++eqc_i;
1404
        }
1405
314480
        Trace("cegqi-proc-debug") << std::endl;
1406
      }
1407
    }
1408
388737
    ++eqcs_i;
1409
  }
1410
1411
  //remove unecessary assertions
1412
12777
  for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
1413
16034
    std::vector< Node > akeep;
1414
44315
    for( unsigned i=0; i<it->second.size(); i++ ){
1415
72596
      Node n = it->second[i];
1416
      //must be an eligible term
1417
36298
      if( isEligible( n ) ){
1418
        //must contain at least one variable
1419
30114
        if( !d_prog_var[n].empty() ){
1420
29059
          Trace("cegqi-proc") << "...literal[" << it->first << "] : " << n << std::endl;
1421
29059
          akeep.push_back( n );
1422
        }else{
1423
1055
          Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl;
1424
        }
1425
      }else{
1426
6184
        Trace("cegqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl;
1427
      }
1428
    }
1429
8017
    it->second.clear();
1430
8017
    it->second.insert( it->second.end(), akeep.begin(), akeep.end() );
1431
  }
1432
1433
  //remove duplicate terms from eqc
1434
333055
  for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
1435
656590
    std::vector< Node > new_eqc;
1436
733885
    for( unsigned i=0; i<it->second.size(); i++ ){
1437
405590
      if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){
1438
405590
        new_eqc.push_back( it->second[i] );
1439
      }
1440
    }
1441
328295
    it->second.clear();
1442
328295
    it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() );
1443
  }
1444
4760
}
1445
1446
108284
Node CegInstantiator::getModelValue( Node n ) {
1447
108284
  return d_treg.getModel()->getValue(n);
1448
}
1449
1450
1160
Node CegInstantiator::getBoundVariable(TypeNode tn)
1451
{
1452
1160
  unsigned index = 0;
1453
  std::unordered_map<TypeNode, unsigned>::iterator itb =
1454
1160
      d_bound_var_index.find(tn);
1455
1160
  if (itb != d_bound_var_index.end())
1456
  {
1457
90
    index = itb->second;
1458
  }
1459
1160
  d_bound_var_index[tn] = index + 1;
1460
2138
  while (index >= d_bound_var[tn].size())
1461
  {
1462
978
    std::stringstream ss;
1463
489
    ss << "x" << index;
1464
978
    Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn);
1465
489
    d_bound_var[tn].push_back(x);
1466
  }
1467
1160
  return d_bound_var[tn][index];
1468
}
1469
1470
423695
bool CegInstantiator::isSolvedAssertion(Node n) const
1471
{
1472
423695
  return d_solved_asserts.find(n) != d_solved_asserts.end();
1473
}
1474
1475
4536
void CegInstantiator::markSolved(Node n, bool solved)
1476
{
1477
4536
  if (solved)
1478
  {
1479
2268
    d_solved_asserts.insert(n);
1480
  }
1481
2268
  else if (isSolvedAssertion(n))
1482
  {
1483
2268
    d_solved_asserts.erase(n);
1484
  }
1485
4536
}
1486
1487
28666
void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
1488
28666
  if( n.getKind()==FORALL ){
1489
174
    d_is_nested_quant = true;
1490
28492
  }else if( visited.find( n )==visited.end() ){
1491
26468
    visited[n] = true;
1492
26468
    if( TermUtil::isBoolConnectiveTerm( n ) ){
1493
40266
      for( unsigned i=0; i<n.getNumChildren(); i++ ){
1494
26595
        collectCeAtoms( n[i], visited );
1495
      }
1496
    }else{
1497
12797
      if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
1498
12797
        Trace("cegqi-ce-atoms") << "CE atoms : " << n << std::endl;
1499
12797
        d_ce_atoms.push_back( n );
1500
      }
1501
    }
1502
  }
1503
28666
}
1504
1505
1932
void CegInstantiator::registerCounterexampleLemma(Node lem,
1506
                                                  std::vector<Node>& ceVars,
1507
                                                  std::vector<Node>& auxLems)
1508
{
1509
1932
  Trace("cegqi-reg") << "Register counterexample lemma..." << std::endl;
1510
1932
  d_input_vars.clear();
1511
1932
  d_input_vars.insert(d_input_vars.end(), ceVars.begin(), ceVars.end());
1512
1513
  //Assert( d_vars.empty() );
1514
1932
  d_vars.clear();
1515
1932
  registerTheoryId(THEORY_UF);
1516
5903
  for (const Node& cv : ceVars)
1517
  {
1518
3971
    Trace("cegqi-reg") << "  register input variable : " << cv << std::endl;
1519
3971
    registerVariable(cv);
1520
  }
1521
1522
  // preprocess with all relevant instantiator preprocessors
1523
3864
  Trace("cegqi-debug") << "Preprocess based on theory-specific methods..."
1524
1932
                      << std::endl;
1525
3864
  std::vector<Node> pvars;
1526
1932
  pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
1527
2663
  for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp)
1528
  {
1529
731
    p.second->registerCounterexampleLemma(lem, pvars, auxLems);
1530
  }
1531
  // must register variables generated by preprocessors
1532
3864
  Trace("cegqi-debug") << "Register variables from theory-specific methods "
1533
3864
                      << d_input_vars.size() << " " << pvars.size() << " ..."
1534
1932
                      << std::endl;
1535
2212
  for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i)
1536
  {
1537
560
    Trace("cegqi-reg") << "  register inst preprocess variable : " << pvars[i]
1538
280
                       << std::endl;
1539
280
    registerVariable(pvars[i]);
1540
  }
1541
1542
  // register variables that were introduced during TheoryEngine preprocessing
1543
3864
  std::unordered_set<Node> ceSyms;
1544
1932
  expr::getSymbols(lem, ceSyms);
1545
3864
  std::unordered_set<Node> qSyms;
1546
1932
  expr::getSymbols(d_quant, qSyms);
1547
  // all variables that are in counterexample lemma but not in quantified
1548
  // formula
1549
12173
  for (const Node& ces : ceSyms)
1550
  {
1551
10241
    if (qSyms.find(ces) != qSyms.end())
1552
    {
1553
      // a free symbol of the quantified formula.
1554
12279
      continue;
1555
    }
1556
7141
    if (std::find(d_vars.begin(), d_vars.end(), ces) != d_vars.end())
1557
    {
1558
      // already processed variable
1559
3925
      continue;
1560
    }
1561
    // must avoid selector symbols, and function skolems introduced by
1562
    // theory preprocessing
1563
4278
    TypeNode ct = ces.getType();
1564
3216
    if (ct.isBoolean() || ct.isFunctionLike())
1565
    {
1566
      // Boolean variables, including the counterexample literal, don't matter
1567
      // since they are always assigned a model value.
1568
2154
      continue;
1569
    }
1570
2124
    Trace("cegqi-reg") << "  register theory preprocess variable : " << ces
1571
1062
                       << std::endl;
1572
    // register the variable, which was introduced by TheoryEngine's preprocess
1573
    // method, e.g. an ITE skolem.
1574
1062
    registerVariable(ces);
1575
  }
1576
1577
  // determine variable order: must do Reals before Ints
1578
1932
  Trace("cegqi-debug") << "Determine variable order..." << std::endl;
1579
1932
  if (!d_vars.empty())
1580
  {
1581
3864
    std::map<Node, unsigned> voo;
1582
1932
    bool doSort = false;
1583
3864
    std::vector<Node> vars;
1584
3864
    std::map<TypeNode, std::vector<Node> > tvars;
1585
7245
    for (unsigned i = 0, size = d_vars.size(); i < size; i++)
1586
    {
1587
5313
      voo[d_vars[i]] = i;
1588
5313
      d_var_order_index.push_back(0);
1589
10626
      TypeNode tn = d_vars[i].getType();
1590
5313
      if (tn.isInteger())
1591
      {
1592
2910
        doSort = true;
1593
2910
        tvars[tn].push_back(d_vars[i]);
1594
      }
1595
      else
1596
      {
1597
2403
        vars.push_back(d_vars[i]);
1598
      }
1599
    }
1600
1932
    if (doSort)
1601
    {
1602
815
      Trace("cegqi-debug") << "Sort variables based on ordering." << std::endl;
1603
1630
      for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
1604
      {
1605
815
        vars.insert(vars.end(), vs.second.begin(), vs.second.end());
1606
      }
1607
1608
815
      Trace("cegqi-debug") << "Consider variables in this order : " << std::endl;
1609
4024
      for (unsigned i = 0; i < vars.size(); i++)
1610
      {
1611
3209
        d_var_order_index[voo[vars[i]]] = i;
1612
6418
        Trace("cegqi-debug") << "  " << vars[i] << " : " << vars[i].getType()
1613
3209
                            << ", index was : " << voo[vars[i]] << std::endl;
1614
3209
        d_vars[i] = vars[i];
1615
      }
1616
815
      Trace("cegqi-debug") << std::endl;
1617
    }
1618
    else
1619
    {
1620
1117
      d_var_order_index.clear();
1621
    }
1622
  }
1623
1624
  // collect atoms from all lemmas: we will only solve for literals coming from
1625
  // the original body
1626
1932
  d_is_nested_quant = false;
1627
3864
  std::map< Node, bool > visited;
1628
1932
  collectCeAtoms(lem, visited);
1629
2071
  for (const Node& alem : auxLems)
1630
  {
1631
139
    collectCeAtoms(alem, visited);
1632
  }
1633
1932
}
1634
1635
3530
Instantiator::Instantiator(Env& env, TypeNode tn) : EnvObj(env), d_type(tn)
1636
{
1637
3530
  d_closed_enum_type = tn.isClosedEnumerable();
1638
3530
}
1639
1640
14
bool Instantiator::processEqualTerm(CegInstantiator* ci,
1641
                                    SolvedForm& sf,
1642
                                    Node pv,
1643
                                    TermProperties& pv_prop,
1644
                                    Node n,
1645
                                    CegInstEffort effort)
1646
{
1647
14
  pv_prop.d_type = CEG_TT_EQUAL;
1648
14
  return ci->constructInstantiationInc(pv, n, pv_prop, sf);
1649
}
1650
1651
}  // namespace quantifiers
1652
}  // namespace theory
1653
31137
}  // namespace cvc5