GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/ceg_bv_instantiator.cpp Lines: 300 351 85.5 %
Date: 2021-05-22 Branches: 671 1718 39.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Andres Noetzli
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 ceg_bv_instantiator
14
 */
15
16
#include "theory/quantifiers/cegqi/ceg_bv_instantiator.h"
17
18
#include <stack>
19
#include "expr/skolem_manager.h"
20
#include "options/quantifiers_options.h"
21
#include "theory/bv/theory_bv_utils.h"
22
#include "theory/quantifiers/cegqi/ceg_bv_instantiator_utils.h"
23
#include "theory/rewriter.h"
24
#include "util/bitvector.h"
25
#include "util/random.h"
26
27
using namespace std;
28
using namespace cvc5::kind;
29
30
namespace cvc5 {
31
namespace theory {
32
namespace quantifiers {
33
34
// this class can be used to query the model value through the CegInstaniator
35
// class
36
class CegInstantiatorBvInverterQuery : public BvInverterQuery
37
{
38
 public:
39
2912
  CegInstantiatorBvInverterQuery(CegInstantiator* ci)
40
2912
      : BvInverterQuery(), d_ci(ci)
41
  {
42
2912
  }
43
2912
  ~CegInstantiatorBvInverterQuery() {}
44
  /** return the model value of n */
45
  Node getModelValue(Node n) override { return d_ci->getModelValue(n); }
46
  /** get bound variable of type tn */
47
1116
  Node getBoundVariable(TypeNode tn) override
48
  {
49
1116
    return d_ci->getBoundVariable(tn);
50
  }
51
52
 protected:
53
  // pointer to class that is able to query model values
54
  CegInstantiator* d_ci;
55
};
56
57
1098
BvInstantiator::BvInstantiator(TypeNode tn, BvInverter* inv)
58
1098
    : Instantiator(tn), d_inverter(inv), d_inst_id_counter(0)
59
{
60
  // The inverter utility d_inverter is global to all BvInstantiator classes.
61
  // This must be global since we need to:
62
  // * process Skolem functions properly across multiple variables within the
63
  // same quantifier
64
  // * cache Skolem variables uniformly across multiple quantified formulas
65
1098
}
66
67
2196
BvInstantiator::~BvInstantiator() {}
68
4108
void BvInstantiator::reset(CegInstantiator* ci,
69
                           SolvedForm& sf,
70
                           Node pv,
71
                           CegInstEffort effort)
72
{
73
4108
  d_inst_id_counter = 0;
74
4108
  d_var_to_inst_id.clear();
75
4108
  d_inst_id_to_term.clear();
76
4108
  d_inst_id_to_alit.clear();
77
4108
  d_var_to_curr_inst_id.clear();
78
4108
  d_alit_to_model_slack.clear();
79
4108
}
80
81
3190
void BvInstantiator::processLiteral(CegInstantiator* ci,
82
                                    SolvedForm& sf,
83
                                    Node pv,
84
                                    Node lit,
85
                                    Node alit,
86
                                    CegInstEffort effort)
87
{
88
3190
  Assert(d_inverter != NULL);
89
  // find path to pv
90
6380
  std::vector<unsigned> path;
91
6380
  Node sv = d_inverter->getSolveVariable(pv.getType());
92
6380
  Node pvs = ci->getModelValue(pv);
93
3190
  Trace("cegqi-bv") << "Get path to " << pv << " : " << lit << std::endl;
94
  Node slit =
95
9570
      d_inverter->getPathToPv(lit, pv, sv, pvs, path, options::cegqiBvSolveNl());
96
3190
  if (!slit.isNull())
97
  {
98
5824
    CegInstantiatorBvInverterQuery m(ci);
99
2912
    unsigned iid = d_inst_id_counter;
100
2912
    Trace("cegqi-bv") << "Solve lit to bv inverter : " << slit << std::endl;
101
5824
    Node inst = d_inverter->solveBvLit(sv, slit, path, &m);
102
2912
    if (!inst.isNull())
103
    {
104
1892
      inst = Rewriter::rewrite(inst);
105
1892
      if (inst.isConst() || !ci->hasNestedQuantification())
106
      {
107
1856
        Trace("cegqi-bv") << "...solved form is " << inst << std::endl;
108
        // store information for id and increment
109
1856
        d_var_to_inst_id[pv].push_back(iid);
110
1856
        d_inst_id_to_term[iid] = inst;
111
1856
        d_inst_id_to_alit[iid] = alit;
112
1856
        d_inst_id_counter++;
113
      }
114
    }
115
    else
116
    {
117
1020
      Trace("cegqi-bv") << "...failed to solve." << std::endl;
118
    }
119
  }
120
  else
121
  {
122
278
    Trace("cegqi-bv") << "...no path." << std::endl;
123
  }
124
3190
}
125
126
3483
bool BvInstantiator::hasProcessAssertion(CegInstantiator* ci,
127
                                         SolvedForm& sf,
128
                                         Node pv,
129
                                         CegInstEffort effort)
130
{
131
3483
  return true;
132
}
133
134
7113
Node BvInstantiator::hasProcessAssertion(CegInstantiator* ci,
135
                                         SolvedForm& sf,
136
                                         Node pv,
137
                                         Node lit,
138
                                         CegInstEffort effort)
139
{
140
7113
  if (effort == CEG_INST_EFFORT_FULL)
141
  {
142
    // always use model values at full effort
143
1338
    return Node::null();
144
  }
145
11550
  Node atom = lit.getKind() == NOT ? lit[0] : lit;
146
5775
  bool pol = lit.getKind() != NOT;
147
5775
  Kind k = atom.getKind();
148
5775
  if (k != EQUAL && k != BITVECTOR_ULT && k != BITVECTOR_SLT)
149
  {
150
    // others are unhandled
151
    return Node::null();
152
  }
153
5775
  else if (!atom[0].getType().isBitVector())
154
  {
155
    return Node::null();
156
  }
157
20378
  else if (options::cegqiBvIneqMode() == options::CegqiBvIneqMode::KEEP
158
5775
           || (pol && k == EQUAL))
159
  {
160
2804
    return lit;
161
  }
162
2971
  NodeManager* nm = NodeManager::currentNM();
163
5942
  Node s = atom[0];
164
5942
  Node t = atom[1];
165
166
5942
  Node sm = ci->getModelValue(s);
167
5942
  Node tm = ci->getModelValue(t);
168
2971
  Assert(!sm.isNull() && sm.isConst());
169
2971
  Assert(!tm.isNull() && tm.isConst());
170
2971
  Trace("cegqi-bv") << "Model value: " << std::endl;
171
5942
  Trace("cegqi-bv") << "   " << s << " " << k << " " << t << " is "
172
2971
                    << std::endl;
173
2971
  Trace("cegqi-bv") << "   " << sm << " <> " << tm << std::endl;
174
175
5942
  Node ret;
176
2971
  if (options::cegqiBvIneqMode() == options::CegqiBvIneqMode::EQ_SLACK)
177
  {
178
    // if using slack, we convert constraints to a positive equality based on
179
    // the current model M, e.g.:
180
    //   (not) s ~ t  --->  s = t + ( s^M - t^M )
181
    if (sm != tm)
182
    {
183
      Node slack = Rewriter::rewrite(nm->mkNode(BITVECTOR_SUB, sm, tm));
184
      Assert(slack.isConst());
185
      // remember the slack value for the asserted literal
186
      d_alit_to_model_slack[lit] = slack;
187
      ret = nm->mkNode(EQUAL, s, nm->mkNode(BITVECTOR_ADD, t, slack));
188
      Trace("cegqi-bv") << "Slack is " << slack << std::endl;
189
    }
190
    else
191
    {
192
      ret = s.eqNode(t);
193
    }
194
  }
195
  else
196
  {
197
    // turn disequality into an inequality
198
    // e.g. s != t becomes s < t or t < s
199
2971
    if (k == EQUAL)
200
    {
201
1263
      if (Random::getRandom().pickWithProb(0.5))
202
      {
203
583
        std::swap(s, t);
204
      }
205
1263
      pol = true;
206
    }
207
    // otherwise, we optimistically solve for the boundary point of an
208
    // inequality, for example:
209
    //   for s < t, we solve s+1 = t
210
    //   for ~( s < t ), we solve s = t
211
    // notice that this equality does not necessarily hold in the model, and
212
    // hence the corresponding instantiation strategy is not guaranteed to be
213
    // monotonic.
214
2971
    if (!pol)
215
    {
216
1027
      ret = s.eqNode(t);
217
    }
218
    else
219
    {
220
3888
      Node bv_one = bv::utils::mkOne(bv::utils::getSize(s));
221
1944
      ret = nm->mkNode(BITVECTOR_ADD, s, bv_one).eqNode(t);
222
    }
223
  }
224
2971
  Trace("cegqi-bv") << "Process " << lit << " as " << ret << std::endl;
225
2971
  return ret;
226
}
227
228
3817
bool BvInstantiator::processAssertion(CegInstantiator* ci,
229
                                      SolvedForm& sf,
230
                                      Node pv,
231
                                      Node lit,
232
                                      Node alit,
233
                                      CegInstEffort effort)
234
{
235
  // if option enabled, use approach for word-level inversion for BV
236
  // instantiation
237
3817
  if (options::cegqiBv())
238
  {
239
    // get the best rewritten form of lit for solving for pv
240
    //   this should remove instances of non-invertible operators, and
241
    //   "linearize" lit with respect to pv as much as possible
242
6380
    Node rlit = rewriteAssertionForSolvePv(ci, pv, lit);
243
3190
    if (Trace.isOn("cegqi-bv"))
244
    {
245
      Trace("cegqi-bv") << "BvInstantiator::processAssertion : solve " << pv
246
                        << " in " << lit << std::endl;
247
      if (lit != rlit)
248
      {
249
        Trace("cegqi-bv") << "...rewritten to " << rlit << std::endl;
250
      }
251
    }
252
3190
    if (!rlit.isNull())
253
    {
254
3190
      processLiteral(ci, sf, pv, rlit, alit, effort);
255
    }
256
  }
257
3817
  return false;
258
}
259
260
2521
bool BvInstantiator::useModelValue(CegInstantiator* ci,
261
                                   SolvedForm& sf,
262
                                   Node pv,
263
                                   CegInstEffort effort)
264
{
265
2521
  return effort < CEG_INST_EFFORT_FULL || options::cegqiFullEffort();
266
}
267
268
3483
bool BvInstantiator::processAssertions(CegInstantiator* ci,
269
                                       SolvedForm& sf,
270
                                       Node pv,
271
                                       CegInstEffort effort)
272
{
273
  std::unordered_map<Node, std::vector<unsigned>>::iterator iti =
274
3483
      d_var_to_inst_id.find(pv);
275
3483
  if (iti == d_var_to_inst_id.end())
276
  {
277
    // no bounds
278
1896
    return false;
279
  }
280
3174
  Trace("cegqi-bv") << "BvInstantiator::processAssertions for " << pv
281
1587
                    << std::endl;
282
  // if interleaving, do not do inversion half the time
283
3174
  if (options::cegqiBvInterleaveValue() && Random::getRandom().pickWithProb(0.5))
284
  {
285
    Trace("cegqi-bv") << "...do not do instantiation for " << pv
286
                      << " (skip, based on heuristic)" << std::endl;
287
  }
288
1587
  bool firstVar = sf.empty();
289
  // get inst id list
290
1587
  if (Trace.isOn("cegqi-bv"))
291
  {
292
    Trace("cegqi-bv") << "  " << iti->second.size()
293
                      << " candidate instantiations for " << pv << " : "
294
                      << std::endl;
295
    if (firstVar)
296
    {
297
      Trace("cegqi-bv") << "  ...this is the first variable" << std::endl;
298
    }
299
  }
300
  // until we have a model-preserving selection function for BV, this must
301
  // be heuristic (we only pick one literal)
302
  // hence we randomize the list
303
  // this helps robustness, since picking the same literal every time may
304
  // lead to a stream of value instantiations, whereas with randomization
305
  // we may find an invertible literal that leads to a useful instantiation.
306
1587
  std::shuffle(iti->second.begin(), iti->second.end(), Random::getRandom());
307
308
1587
  if (Trace.isOn("cegqi-bv"))
309
  {
310
    for (unsigned j = 0, size = iti->second.size(); j < size; j++)
311
    {
312
      unsigned inst_id = iti->second[j];
313
      Assert(d_inst_id_to_term.find(inst_id) != d_inst_id_to_term.end());
314
      Node inst_term = d_inst_id_to_term[inst_id];
315
      Assert(d_inst_id_to_alit.find(inst_id) != d_inst_id_to_alit.end());
316
      Node alit = d_inst_id_to_alit[inst_id];
317
318
      // get the slack value introduced for the asserted literal
319
      Node curr_slack_val;
320
      std::unordered_map<Node, Node>::iterator itms =
321
          d_alit_to_model_slack.find(alit);
322
      if (itms != d_alit_to_model_slack.end())
323
      {
324
        curr_slack_val = itms->second;
325
      }
326
327
      // debug printing
328
      Trace("cegqi-bv") << "   [" << j << "] : ";
329
      Trace("cegqi-bv") << inst_term << std::endl;
330
      if (!curr_slack_val.isNull())
331
      {
332
        Trace("cegqi-bv") << "   ...with slack value : " << curr_slack_val
333
                          << std::endl;
334
      }
335
      Trace("cegqi-bv-debug") << "   ...from : " << alit << std::endl;
336
      Trace("cegqi-bv") << std::endl;
337
    }
338
  }
339
340
  // Now, try all instantiation ids we want to try
341
  // Typically we try only one, otherwise worst-case performance
342
  // for constructing instantiations is exponential on the number of
343
  // variables in this quantifier prefix.
344
1587
  bool ret = false;
345
1587
  bool tryMultipleInst = firstVar && options::cegqiMultiInst();
346
1587
  bool revertOnSuccess = tryMultipleInst;
347
1587
  for (unsigned j = 0, size = iti->second.size(); j < size; j++)
348
  {
349
1587
    unsigned inst_id = iti->second[j];
350
1587
    Assert(d_inst_id_to_term.find(inst_id) != d_inst_id_to_term.end());
351
1587
    Node inst_term = d_inst_id_to_term[inst_id];
352
1587
    Node alit = d_inst_id_to_alit[inst_id];
353
    // try instantiation pv -> inst_term
354
1587
    TermProperties pv_prop_bv;
355
1587
    Trace("cegqi-bv") << "*** try " << pv << " -> " << inst_term << std::endl;
356
1587
    d_var_to_curr_inst_id[pv] = inst_id;
357
1587
    ci->markSolved(alit);
358
1587
    if (ci->constructInstantiationInc(
359
            pv, inst_term, pv_prop_bv, sf, revertOnSuccess))
360
    {
361
894
      ret = true;
362
    }
363
1587
    ci->markSolved(alit, false);
364
    // we are done unless we try multiple instances
365
1587
    if (!tryMultipleInst)
366
    {
367
1587
      break;
368
    }
369
  }
370
1587
  if (ret)
371
  {
372
894
    return true;
373
  }
374
693
  Trace("cegqi-bv") << "...failed to add instantiation for " << pv << std::endl;
375
693
  d_var_to_curr_inst_id.erase(pv);
376
377
693
  return false;
378
}
379
380
3190
Node BvInstantiator::rewriteAssertionForSolvePv(CegInstantiator* ci,
381
                                                Node pv,
382
                                                Node lit)
383
{
384
  // result of rewriting the visited term
385
6380
  std::stack<std::unordered_map<TNode, Node>> visited;
386
3190
  visited.push(std::unordered_map<TNode, Node>());
387
  // whether the visited term contains pv
388
6380
  std::unordered_map<Node, bool> visited_contains_pv;
389
3190
  std::unordered_map<TNode, Node>::iterator it;
390
6380
  std::unordered_map<TNode, Node> curr_subs;
391
6380
  std::stack<std::stack<TNode> > visit;
392
6380
  TNode cur;
393
3190
  visit.push(std::stack<TNode>());
394
3190
  visit.top().push(lit);
395
82400
  do
396
  {
397
85590
    cur = visit.top().top();
398
85590
    visit.top().pop();
399
85590
    it = visited.top().find(cur);
400
401
85590
    if (it == visited.top().end())
402
    {
403
34588
      std::unordered_map<TNode, Node>::iterator itc = curr_subs.find(cur);
404
34588
      if (itc != curr_subs.end())
405
      {
406
114
        visited.top()[cur] = itc->second;
407
      }
408
      else
409
      {
410
34474
        if (cur.getKind() == WITNESS)
411
        {
412
          // must replace variables of choice functions
413
          // with new variables to avoid variable
414
          // capture when considering substitutions
415
          // with multiple literals.
416
228
          Node bv = ci->getBoundVariable(cur[0][0].getType());
417
          // should not have captured variables
418
114
          Assert(curr_subs.find(cur[0][0]) == curr_subs.end());
419
114
          curr_subs[cur[0][0]] = bv;
420
          // we cannot cache the results of subterms
421
          // of this witness expression since we are
422
          // now in the context { cur[0][0] -> bv },
423
          // hence we push a context here
424
114
          visited.push(std::unordered_map<TNode, Node>());
425
114
          visit.push(std::stack<TNode>());
426
        }
427
34474
        visited.top()[cur] = Node::null();
428
34474
        visit.top().push(cur);
429
82400
        for (unsigned i = 0; i < cur.getNumChildren(); i++)
430
        {
431
47926
          visit.top().push(cur[i]);
432
        }
433
      }
434
    }
435
51002
    else if (it->second.isNull())
436
    {
437
68948
      Node ret;
438
34474
      bool childChanged = false;
439
68948
      std::vector<Node> children;
440
34474
      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
441
      {
442
3600
        children.push_back(cur.getOperator());
443
      }
444
34474
      bool contains_pv = (cur == pv);
445
82400
      for (unsigned i = 0; i < cur.getNumChildren(); i++)
446
      {
447
47926
        it = visited.top().find(cur[i]);
448
47926
        Assert(it != visited.top().end());
449
47926
        Assert(!it->second.isNull());
450
47926
        childChanged = childChanged || cur[i] != it->second;
451
47926
        children.push_back(it->second);
452
47926
        contains_pv = contains_pv || visited_contains_pv[cur[i]];
453
      }
454
      // careful that rewrites above do not affect whether this term contains pv
455
34474
      visited_contains_pv[cur] = contains_pv;
456
457
      // rewrite the term
458
34474
      ret = rewriteTermForSolvePv(pv, cur, children, visited_contains_pv);
459
460
      // return original if the above function does not produce a result
461
34474
      if (ret.isNull())
462
      {
463
33962
        if (childChanged)
464
        {
465
2333
          ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
466
        }
467
        else
468
        {
469
31629
          ret = cur;
470
        }
471
      }
472
473
      /* We need to update contains_pv also for rewritten nodes, since
474
       * the normalizePv* functions rely on the information if pv occurs in a
475
       * rewritten node or not. */
476
34474
      if (ret != cur)
477
      {
478
2678
        contains_pv = (ret == pv);
479
9032
        for (unsigned i = 0, size = ret.getNumChildren(); i < size; ++i)
480
        {
481
6354
          contains_pv = contains_pv || visited_contains_pv[ret[i]];
482
        }
483
2678
        visited_contains_pv[ret] = contains_pv;
484
      }
485
486
      // if was witness, pop context
487
34474
      if (cur.getKind() == WITNESS)
488
      {
489
114
        Assert(curr_subs.find(cur[0][0]) != curr_subs.end());
490
114
        curr_subs.erase(cur[0][0]);
491
114
        visited.pop();
492
114
        visit.pop();
493
114
        Assert(visited.size() == visit.size());
494
114
        Assert(!visit.empty());
495
      }
496
497
34474
      visited.top()[cur] = ret;
498
    }
499
85590
  } while (!visit.top().empty());
500
3190
  Assert(visited.size() == 1);
501
3190
  Assert(visited.top().find(lit) != visited.top().end());
502
3190
  Assert(!visited.top().find(lit)->second.isNull());
503
504
3190
  Node result = visited.top()[lit];
505
506
3190
  if (Trace.isOn("cegqi-bv-nl"))
507
  {
508
    std::vector<TNode> trace_visit;
509
    std::unordered_set<TNode> trace_visited;
510
511
    trace_visit.push_back(result);
512
    do
513
    {
514
      cur = trace_visit.back();
515
      trace_visit.pop_back();
516
517
      if (trace_visited.find(cur) == trace_visited.end())
518
      {
519
        trace_visited.insert(cur);
520
        trace_visit.insert(trace_visit.end(), cur.begin(), cur.end());
521
      }
522
      else if (cur == pv)
523
      {
524
        Trace("cegqi-bv-nl")
525
            << "NONLINEAR LITERAL for " << pv << " : " << lit << std::endl;
526
      }
527
    } while (!trace_visit.empty());
528
  }
529
530
6380
  return result;
531
}
532
533
34474
Node BvInstantiator::rewriteTermForSolvePv(
534
    Node pv,
535
    Node n,
536
    std::vector<Node>& children,
537
    std::unordered_map<Node, bool>& contains_pv)
538
{
539
34474
  NodeManager* nm = NodeManager::currentNM();
540
541
  // [1] rewrite cases of non-invertible operators
542
543
34474
  if (n.getKind() == EQUAL)
544
  {
545
13732
    TNode lhs = children[0];
546
13732
    TNode rhs = children[1];
547
548
    /* rewrite: x * x = x -> x < 2 */
549
14142
    if ((lhs == pv && rhs.getKind() == BITVECTOR_MULT && rhs[0] == pv
550
6952
         && rhs[1] == pv)
551
27812
        || (rhs == pv && lhs.getKind() == BITVECTOR_MULT && lhs[0] == pv
552
6960
            && lhs[1] == pv))
553
    {
554
      return nm->mkNode(
555
          BITVECTOR_ULT,
556
          pv,
557
4
          bv::utils::mkConst(BitVector(bv::utils::getSize(pv), Integer(2))));
558
    }
559
560
16719
    if (options::cegqiBvLinearize() && contains_pv[lhs] && contains_pv[rhs])
561
    {
562
336
      Node result = utils::normalizePvEqual(pv, children, contains_pv);
563
168
      if (!result.isNull())
564
      {
565
8
        Trace("cegqi-bv-nl")
566
4
            << "Normalize " << n << " to " << result << std::endl;
567
      }
568
      else
569
      {
570
328
        Trace("cegqi-bv-nl")
571
164
            << "Nonlinear " << n.getKind() << " " << n << std::endl;
572
      }
573
168
      return result;
574
    }
575
  }
576
27522
  else if (n.getKind() == BITVECTOR_MULT || n.getKind() == BITVECTOR_ADD)
577
  {
578
2823
    if (options::cegqiBvLinearize() && contains_pv[n])
579
    {
580
1928
      Node result;
581
1216
      if (n.getKind() == BITVECTOR_MULT)
582
      {
583
262
        result = utils::normalizePvMult(pv, children, contains_pv);
584
      }
585
      else
586
      {
587
954
        result = utils::normalizePvPlus(pv, children, contains_pv);
588
      }
589
1216
      if (!result.isNull())
590
      {
591
1008
        Trace("cegqi-bv-nl")
592
504
            << "Normalize " << n << " to " << result << std::endl;
593
504
        return result;
594
      }
595
      else
596
      {
597
1424
        Trace("cegqi-bv-nl")
598
712
            << "Nonlinear " << n.getKind() << " " << n << std::endl;
599
      }
600
    }
601
  }
602
603
  // [2] try to rewrite non-linear literals -> linear literals
604
605
33798
  return Node::null();
606
}
607
608
/** sort bv extract interval
609
 *
610
 * This sorts lists of bitvector extract terms where
611
 * ((_ extract i1 i2) t) < ((_ extract j1 j2) t)
612
 * if i1>j1 or i1=j1 and i2>j2.
613
 */
614
struct SortBvExtractInterval
615
{
616
82
  bool operator()(Node i, Node j)
617
  {
618
82
    Assert(i.getKind() == BITVECTOR_EXTRACT);
619
82
    Assert(j.getKind() == BITVECTOR_EXTRACT);
620
82
    BitVectorExtract ie = i.getOperator().getConst<BitVectorExtract>();
621
82
    BitVectorExtract je = j.getOperator().getConst<BitVectorExtract>();
622
82
    if (ie.d_high > je.d_high)
623
    {
624
78
      return true;
625
    }
626
4
    else if (ie.d_high == je.d_high)
627
    {
628
2
      Assert(ie.d_low != je.d_low);
629
2
      return ie.d_low > je.d_low;
630
    }
631
2
    return false;
632
  }
633
};
634
635
700
void BvInstantiatorPreprocess::registerCounterexampleLemma(
636
    Node lem, std::vector<Node>& ceVars, std::vector<Node>& auxLems)
637
{
638
  // new variables
639
1400
  std::vector<Node> vars;
640
  // new lemmas
641
1400
  std::vector<Node> new_lems;
642
643
1402
  if (options::cegqiBvRmExtract())
644
  {
645
700
    NodeManager* nm = NodeManager::currentNM();
646
700
    SkolemManager* sm = nm->getSkolemManager();
647
700
    Trace("cegqi-bv-pp") << "-----remove extracts..." << std::endl;
648
    // map from terms to bitvector extracts applied to that term
649
1400
    std::map<Node, std::vector<Node> > extract_map;
650
1400
    std::unordered_set<TNode> visited;
651
700
    Trace("cegqi-bv-pp-debug2") << "Register ce lemma " << lem << std::endl;
652
700
    collectExtracts(lem, extract_map, visited);
653
803
    for (std::pair<const Node, std::vector<Node> >& es : extract_map)
654
    {
655
      // sort based on the extract start position
656
103
      std::vector<Node>& curr_vec = es.second;
657
658
      SortBvExtractInterval sbei;
659
103
      std::sort(curr_vec.begin(), curr_vec.end(), sbei);
660
661
103
      unsigned width = es.first.getType().getBitVectorSize();
662
663
      // list of points b such that:
664
      //   b>0 and we must start a segment at (b-1)  or  b==0
665
206
      std::vector<unsigned> boundaries;
666
103
      boundaries.push_back(width);
667
103
      boundaries.push_back(0);
668
669
103
      Trace("cegqi-bv-pp") << "For term " << es.first << " : " << std::endl;
670
286
      for (unsigned i = 0, size = curr_vec.size(); i < size; i++)
671
      {
672
183
        Trace("cegqi-bv-pp") << "  " << i << " : " << curr_vec[i] << std::endl;
673
        BitVectorExtract e =
674
183
            curr_vec[i].getOperator().getConst<BitVectorExtract>();
675
549
        if (std::find(boundaries.begin(), boundaries.end(), e.d_high + 1)
676
549
            == boundaries.end())
677
        {
678
22
          boundaries.push_back(e.d_high + 1);
679
        }
680
549
        if (std::find(boundaries.begin(), boundaries.end(), e.d_low)
681
549
            == boundaries.end())
682
        {
683
83
          boundaries.push_back(e.d_low);
684
        }
685
      }
686
103
      std::sort(boundaries.rbegin(), boundaries.rend());
687
688
      // make the extract variables
689
206
      std::vector<Node> children;
690
311
      for (unsigned i = 1; i < boundaries.size(); i++)
691
      {
692
208
        Assert(boundaries[i - 1] > 0);
693
        Node ex = bv::utils::mkExtract(
694
416
            es.first, boundaries[i - 1] - 1, boundaries[i]);
695
        Node var =
696
            sm->mkDummySkolem("ek",
697
416
                              ex.getType(),
698
832
                              "variable to represent disjoint extract region");
699
208
        children.push_back(var);
700
208
        vars.push_back(var);
701
      }
702
703
206
      Node conc = nm->mkNode(kind::BITVECTOR_CONCAT, children);
704
103
      Assert(conc.getType() == es.first.getType());
705
206
      Node eq_lem = conc.eqNode(es.first);
706
103
      Trace("cegqi-bv-pp") << "Introduced : " << eq_lem << std::endl;
707
103
      new_lems.push_back(eq_lem);
708
206
      Trace("cegqi-bv-pp") << "...finished processing extracts for term "
709
103
                           << es.first << std::endl;
710
    }
711
700
    Trace("cegqi-bv-pp") << "-----done remove extracts" << std::endl;
712
  }
713
714
700
  if (!vars.empty())
715
  {
716
    // could try applying subs -> vars here
717
    // in practice, this led to worse performance
718
719
114
    Trace("cegqi-bv-pp") << "Adding " << new_lems.size() << " lemmas..."
720
57
                         << std::endl;
721
57
    auxLems.insert(auxLems.end(), new_lems.begin(), new_lems.end());
722
114
    Trace("cegqi-bv-pp") << "Adding " << vars.size() << " variables..."
723
57
                         << std::endl;
724
57
    ceVars.insert(ceVars.end(), vars.begin(), vars.end());
725
  }
726
700
}
727
728
700
void BvInstantiatorPreprocess::collectExtracts(
729
    Node lem,
730
    std::map<Node, std::vector<Node>>& extract_map,
731
    std::unordered_set<TNode>& visited)
732
{
733
1400
  std::vector<TNode> visit;
734
1400
  TNode cur;
735
700
  visit.push_back(lem);
736
8372
  do
737
  {
738
9072
    cur = visit.back();
739
9072
    visit.pop_back();
740
9072
    if (visited.find(cur) == visited.end())
741
    {
742
7866
      visited.insert(cur);
743
7866
      if (cur.getKind() != FORALL)
744
      {
745
7856
        if (cur.getKind() == BITVECTOR_EXTRACT)
746
        {
747
243
          if (cur[0].getKind() == INST_CONSTANT)
748
          {
749
183
            extract_map[cur[0]].push_back(cur);
750
          }
751
        }
752
753
16228
        for (const Node& nc : cur)
754
        {
755
8372
          visit.push_back(nc);
756
        }
757
      }
758
    }
759
9072
  } while (!visit.empty());
760
700
}
761
762
}  // namespace quantifiers
763
}  // namespace theory
764
52272
}  // namespace cvc5