GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/cegqi/ceg_bv_instantiator.cpp Lines: 299 351 85.2 %
Date: 2021-09-15 Branches: 658 1684 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
4373
  CegInstantiatorBvInverterQuery(CegInstantiator* ci)
40
4373
      : BvInverterQuery(), d_ci(ci)
41
  {
42
4373
  }
43
4373
  ~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
1112
  Node getBoundVariable(TypeNode tn) override
48
  {
49
1112
    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
1110
BvInstantiator::BvInstantiator(TypeNode tn, BvInverter* inv)
58
1110
    : 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
1110
}
66
67
2220
BvInstantiator::~BvInstantiator() {}
68
5947
void BvInstantiator::reset(CegInstantiator* ci,
69
                           SolvedForm& sf,
70
                           Node pv,
71
                           CegInstEffort effort)
72
{
73
5947
  d_inst_id_counter = 0;
74
5947
  d_var_to_inst_id.clear();
75
5947
  d_inst_id_to_term.clear();
76
5947
  d_inst_id_to_alit.clear();
77
5947
  d_var_to_curr_inst_id.clear();
78
5947
  d_alit_to_model_slack.clear();
79
5947
}
80
81
4699
void BvInstantiator::processLiteral(CegInstantiator* ci,
82
                                    SolvedForm& sf,
83
                                    Node pv,
84
                                    Node lit,
85
                                    Node alit,
86
                                    CegInstEffort effort)
87
{
88
4699
  Assert(d_inverter != NULL);
89
  // find path to pv
90
9398
  std::vector<unsigned> path;
91
9398
  Node sv = d_inverter->getSolveVariable(pv.getType());
92
9398
  Node pvs = ci->getModelValue(pv);
93
4699
  Trace("cegqi-bv") << "Get path to " << pv << " : " << lit << std::endl;
94
  Node slit =
95
9398
      d_inverter->getPathToPv(lit, pv, sv, pvs, path, options::cegqiBvSolveNl());
96
4699
  if (!slit.isNull())
97
  {
98
8746
    CegInstantiatorBvInverterQuery m(ci);
99
4373
    unsigned iid = d_inst_id_counter;
100
4373
    Trace("cegqi-bv") << "Solve lit to bv inverter : " << slit << std::endl;
101
8746
    Node inst = d_inverter->solveBvLit(sv, slit, path, &m);
102
4373
    if (!inst.isNull())
103
    {
104
3353
      inst = Rewriter::rewrite(inst);
105
3353
      if (inst.isConst() || !ci->hasNestedQuantification())
106
      {
107
3333
        Trace("cegqi-bv") << "...solved form is " << inst << std::endl;
108
        // store information for id and increment
109
3333
        d_var_to_inst_id[pv].push_back(iid);
110
3333
        d_inst_id_to_term[iid] = inst;
111
3333
        d_inst_id_to_alit[iid] = alit;
112
3333
        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
326
    Trace("cegqi-bv") << "...no path." << std::endl;
123
  }
124
4699
}
125
126
5137
bool BvInstantiator::hasProcessAssertion(CegInstantiator* ci,
127
                                         SolvedForm& sf,
128
                                         Node pv,
129
                                         CegInstEffort effort)
130
{
131
5137
  return true;
132
}
133
134
27337
Node BvInstantiator::hasProcessAssertion(CegInstantiator* ci,
135
                                         SolvedForm& sf,
136
                                         Node pv,
137
                                         Node lit,
138
                                         CegInstEffort effort)
139
{
140
27337
  if (effort == CEG_INST_EFFORT_FULL)
141
  {
142
    // always use model values at full effort
143
9181
    return Node::null();
144
  }
145
36312
  Node atom = lit.getKind() == NOT ? lit[0] : lit;
146
18156
  bool pol = lit.getKind() != NOT;
147
18156
  Kind k = atom.getKind();
148
18156
  if (k != EQUAL && k != BITVECTOR_ULT && k != BITVECTOR_SLT)
149
  {
150
    // others are unhandled
151
2424
    return Node::null();
152
  }
153
15732
  else if (!atom[0].getType().isBitVector())
154
  {
155
    return Node::null();
156
  }
157
31464
  else if (options::cegqiBvIneqMode() == options::CegqiBvIneqMode::KEEP
158
15732
           || (pol && k == EQUAL))
159
  {
160
6987
    return lit;
161
  }
162
8745
  NodeManager* nm = NodeManager::currentNM();
163
17490
  Node s = atom[0];
164
17490
  Node t = atom[1];
165
166
17490
  Node sm = ci->getModelValue(s);
167
17490
  Node tm = ci->getModelValue(t);
168
8745
  Assert(!sm.isNull() && sm.isConst());
169
8745
  Assert(!tm.isNull() && tm.isConst());
170
8745
  Trace("cegqi-bv") << "Model value: " << std::endl;
171
17490
  Trace("cegqi-bv") << "   " << s << " " << k << " " << t << " is "
172
8745
                    << std::endl;
173
8745
  Trace("cegqi-bv") << "   " << sm << " <> " << tm << std::endl;
174
175
17490
  Node ret;
176
8745
  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
8745
    if (k == EQUAL)
200
    {
201
3120
      if (Random::getRandom().pickWithProb(0.5))
202
      {
203
1460
        std::swap(s, t);
204
      }
205
3120
      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
8745
    if (!pol)
215
    {
216
3685
      ret = s.eqNode(t);
217
    }
218
    else
219
    {
220
10120
      Node bv_one = bv::utils::mkOne(bv::utils::getSize(s));
221
5060
      ret = nm->mkNode(BITVECTOR_ADD, s, bv_one).eqNode(t);
222
    }
223
  }
224
8745
  Trace("cegqi-bv") << "Process " << lit << " as " << ret << std::endl;
225
8745
  return ret;
226
}
227
228
5657
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
5657
  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
9398
    Node rlit = rewriteAssertionForSolvePv(ci, pv, lit);
243
4699
    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
4699
    if (!rlit.isNull())
253
    {
254
4699
      processLiteral(ci, sf, pv, rlit, alit, effort);
255
    }
256
  }
257
5657
  return false;
258
}
259
260
3684
bool BvInstantiator::useModelValue(CegInstantiator* ci,
261
                                   SolvedForm& sf,
262
                                   Node pv,
263
                                   CegInstEffort effort)
264
{
265
3684
  return effort < CEG_INST_EFFORT_FULL || options::cegqiFullEffort();
266
}
267
268
5137
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
5137
      d_var_to_inst_id.find(pv);
275
5137
  if (iti == d_var_to_inst_id.end())
276
  {
277
    // no bounds
278
2874
    return false;
279
  }
280
4526
  Trace("cegqi-bv") << "BvInstantiator::processAssertions for " << pv
281
2263
                    << std::endl;
282
  // if interleaving, do not do inversion half the time
283
2263
  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
2263
  bool firstVar = sf.empty();
289
  // get inst id list
290
2263
  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
2263
  std::shuffle(iti->second.begin(), iti->second.end(), Random::getRandom());
307
308
2263
  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
2263
  bool ret = false;
345
2263
  bool tryMultipleInst = firstVar && options::cegqiMultiInst();
346
2263
  bool revertOnSuccess = tryMultipleInst;
347
2263
  for (unsigned j = 0, size = iti->second.size(); j < size; j++)
348
  {
349
2263
    unsigned inst_id = iti->second[j];
350
2263
    Assert(d_inst_id_to_term.find(inst_id) != d_inst_id_to_term.end());
351
2263
    Node inst_term = d_inst_id_to_term[inst_id];
352
2263
    Node alit = d_inst_id_to_alit[inst_id];
353
    // try instantiation pv -> inst_term
354
2263
    TermProperties pv_prop_bv;
355
2263
    Trace("cegqi-bv") << "*** try " << pv << " -> " << inst_term << std::endl;
356
2263
    d_var_to_curr_inst_id[pv] = inst_id;
357
2263
    ci->markSolved(alit);
358
2263
    if (ci->constructInstantiationInc(
359
            pv, inst_term, pv_prop_bv, sf, revertOnSuccess))
360
    {
361
1072
      ret = true;
362
    }
363
2263
    ci->markSolved(alit, false);
364
    // we are done unless we try multiple instances
365
2263
    if (!tryMultipleInst)
366
    {
367
2263
      break;
368
    }
369
  }
370
2263
  if (ret)
371
  {
372
1072
    return true;
373
  }
374
1191
  Trace("cegqi-bv") << "...failed to add instantiation for " << pv << std::endl;
375
1191
  d_var_to_curr_inst_id.erase(pv);
376
377
1191
  return false;
378
}
379
380
4699
Node BvInstantiator::rewriteAssertionForSolvePv(CegInstantiator* ci,
381
                                                Node pv,
382
                                                Node lit)
383
{
384
  // result of rewriting the visited term
385
9398
  std::stack<std::unordered_map<TNode, Node>> visited;
386
4699
  visited.push(std::unordered_map<TNode, Node>());
387
  // whether the visited term contains pv
388
9398
  std::unordered_map<Node, bool> visited_contains_pv;
389
4699
  std::unordered_map<TNode, Node>::iterator it;
390
9398
  std::unordered_map<TNode, Node> curr_subs;
391
9398
  std::stack<std::stack<TNode> > visit;
392
9398
  TNode cur;
393
4699
  visit.push(std::stack<TNode>());
394
4699
  visit.top().push(lit);
395
75012
  do
396
  {
397
79711
    cur = visit.top().top();
398
79711
    visit.top().pop();
399
79711
    it = visited.top().find(cur);
400
401
79711
    if (it == visited.top().end())
402
    {
403
35227
      std::unordered_map<TNode, Node>::iterator itc = curr_subs.find(cur);
404
35227
      if (itc != curr_subs.end())
405
      {
406
52
        visited.top()[cur] = itc->second;
407
      }
408
      else
409
      {
410
35175
        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
104
          Node bv = ci->getBoundVariable(cur[0][0].getType());
417
          // should not have captured variables
418
52
          Assert(curr_subs.find(cur[0][0]) == curr_subs.end());
419
52
          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
52
          visited.push(std::unordered_map<TNode, Node>());
425
52
          visit.push(std::stack<TNode>());
426
        }
427
35175
        visited.top()[cur] = Node::null();
428
35175
        visit.top().push(cur);
429
75012
        for (unsigned i = 0; i < cur.getNumChildren(); i++)
430
        {
431
39837
          visit.top().push(cur[i]);
432
        }
433
      }
434
    }
435
44484
    else if (it->second.isNull())
436
    {
437
70350
      Node ret;
438
35175
      bool childChanged = false;
439
70350
      std::vector<Node> children;
440
35175
      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
441
      {
442
2621
        children.push_back(cur.getOperator());
443
      }
444
35175
      bool contains_pv = (cur == pv);
445
75012
      for (unsigned i = 0; i < cur.getNumChildren(); i++)
446
      {
447
39837
        it = visited.top().find(cur[i]);
448
39837
        Assert(it != visited.top().end());
449
39837
        Assert(!it->second.isNull());
450
39837
        childChanged = childChanged || cur[i] != it->second;
451
39837
        children.push_back(it->second);
452
39837
        contains_pv = contains_pv || visited_contains_pv[cur[i]];
453
      }
454
      // careful that rewrites above do not affect whether this term contains pv
455
35175
      visited_contains_pv[cur] = contains_pv;
456
457
      // rewrite the term
458
35175
      ret = rewriteTermForSolvePv(pv, cur, children, visited_contains_pv);
459
460
      // return original if the above function does not produce a result
461
35175
      if (ret.isNull())
462
      {
463
34319
        if (childChanged)
464
        {
465
1389
          ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
466
        }
467
        else
468
        {
469
32930
          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
35175
      if (ret != cur)
477
      {
478
1784
        contains_pv = (ret == pv);
479
5822
        for (unsigned i = 0, size = ret.getNumChildren(); i < size; ++i)
480
        {
481
4038
          contains_pv = contains_pv || visited_contains_pv[ret[i]];
482
        }
483
1784
        visited_contains_pv[ret] = contains_pv;
484
      }
485
486
      // if was witness, pop context
487
35175
      if (cur.getKind() == WITNESS)
488
      {
489
52
        Assert(curr_subs.find(cur[0][0]) != curr_subs.end());
490
52
        curr_subs.erase(cur[0][0]);
491
52
        visited.pop();
492
52
        visit.pop();
493
52
        Assert(visited.size() == visit.size());
494
52
        Assert(!visit.empty());
495
      }
496
497
35175
      visited.top()[cur] = ret;
498
    }
499
79711
  } while (!visit.top().empty());
500
4699
  Assert(visited.size() == 1);
501
4699
  Assert(visited.top().find(lit) != visited.top().end());
502
4699
  Assert(!visited.top().find(lit)->second.isNull());
503
504
4699
  Node result = visited.top()[lit];
505
506
4699
  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
9398
  return result;
531
}
532
533
35175
Node BvInstantiator::rewriteTermForSolvePv(
534
    Node pv,
535
    Node n,
536
    std::vector<Node>& children,
537
    std::unordered_map<Node, bool>& contains_pv)
538
{
539
35175
  NodeManager* nm = NodeManager::currentNM();
540
541
  // [1] rewrite cases of non-invertible operators
542
543
35175
  if (n.getKind() == EQUAL)
544
  {
545
12743
    TNode lhs = children[0];
546
12743
    TNode rhs = children[1];
547
548
    /* rewrite: x * x = x -> x < 2 */
549
12893
    if ((lhs == pv && rhs.getKind() == BITVECTOR_MULT && rhs[0] == pv
550
6380
         && rhs[1] == pv)
551
25524
        || (rhs == pv && lhs.getKind() == BITVECTOR_MULT && lhs[0] == pv
552
6388
            && 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
6376
    if (options::cegqiBvLinearize() && contains_pv[lhs] && contains_pv[rhs])
561
    {
562
26
      Node result = utils::normalizePvEqual(pv, children, contains_pv);
563
13
      if (!result.isNull())
564
      {
565
8
        Trace("cegqi-bv-nl")
566
4
            << "Normalize " << n << " to " << result << std::endl;
567
      }
568
      else
569
      {
570
18
        Trace("cegqi-bv-nl")
571
9
            << "Nonlinear " << n.getKind() << " " << n << std::endl;
572
      }
573
13
      return result;
574
    }
575
  }
576
28795
  else if (n.getKind() == BITVECTOR_MULT || n.getKind() == BITVECTOR_ADD)
577
  {
578
3550
    if (options::cegqiBvLinearize() && contains_pv[n])
579
    {
580
2384
      Node result;
581
1616
      if (n.getKind() == BITVECTOR_MULT)
582
      {
583
278
        result = utils::normalizePvMult(pv, children, contains_pv);
584
      }
585
      else
586
      {
587
1338
        result = utils::normalizePvPlus(pv, children, contains_pv);
588
      }
589
1616
      if (!result.isNull())
590
      {
591
1696
        Trace("cegqi-bv-nl")
592
848
            << "Normalize " << n << " to " << result << std::endl;
593
848
        return result;
594
      }
595
      else
596
      {
597
1536
        Trace("cegqi-bv-nl")
598
768
            << "Nonlinear " << n.getKind() << " " << n << std::endl;
599
      }
600
    }
601
  }
602
603
  // [2] try to rewrite non-linear literals -> linear literals
604
605
34310
  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
81
  bool operator()(Node i, Node j)
617
  {
618
81
    Assert(i.getKind() == BITVECTOR_EXTRACT);
619
81
    Assert(j.getKind() == BITVECTOR_EXTRACT);
620
81
    BitVectorExtract ie = i.getOperator().getConst<BitVectorExtract>();
621
81
    BitVectorExtract je = j.getOperator().getConst<BitVectorExtract>();
622
81
    if (ie.d_high > je.d_high)
623
    {
624
79
      return true;
625
    }
626
2
    else if (ie.d_high == je.d_high)
627
    {
628
      Assert(ie.d_low != je.d_low);
629
      return ie.d_low > je.d_low;
630
    }
631
2
    return false;
632
  }
633
};
634
635
710
void BvInstantiatorPreprocess::registerCounterexampleLemma(
636
    Node lem, std::vector<Node>& ceVars, std::vector<Node>& auxLems)
637
{
638
  // new variables
639
1420
  std::vector<Node> vars;
640
  // new lemmas
641
1420
  std::vector<Node> new_lems;
642
643
710
  if (options::cegqiBvRmExtract())
644
  {
645
710
    NodeManager* nm = NodeManager::currentNM();
646
710
    SkolemManager* sm = nm->getSkolemManager();
647
710
    Trace("cegqi-bv-pp") << "-----remove extracts..." << std::endl;
648
    // map from terms to bitvector extracts applied to that term
649
1420
    std::map<Node, std::vector<Node> > extract_map;
650
1420
    std::unordered_set<TNode> visited;
651
710
    Trace("cegqi-bv-pp-debug2") << "Register ce lemma " << lem << std::endl;
652
710
    collectExtracts(lem, extract_map, visited);
653
813
    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
23
          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
82
          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
710
    Trace("cegqi-bv-pp") << "-----done remove extracts" << std::endl;
712
  }
713
714
710
  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
710
}
727
728
710
void BvInstantiatorPreprocess::collectExtracts(
729
    Node lem,
730
    std::map<Node, std::vector<Node>>& extract_map,
731
    std::unordered_set<TNode>& visited)
732
{
733
1420
  std::vector<TNode> visit;
734
1420
  TNode cur;
735
710
  visit.push_back(lem);
736
8520
  do
737
  {
738
9230
    cur = visit.back();
739
9230
    visit.pop_back();
740
9230
    if (visited.find(cur) == visited.end())
741
    {
742
7996
      visited.insert(cur);
743
7996
      if (cur.getKind() != FORALL)
744
      {
745
7986
        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
16506
        for (const Node& nc : cur)
754
        {
755
8520
          visit.push_back(nc);
756
        }
757
      }
758
    }
759
9230
  } while (!visit.empty());
760
710
}
761
762
}  // namespace quantifiers
763
}  // namespace theory
764
29577
}  // namespace cvc5