GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/bv/bv_subtheory_algebraic.cpp Lines: 1 600 0.2 %
Date: 2021-09-18 Branches: 2 2403 0.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Liana Hadarean, Aina Niemetz, 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
 * Algebraic solver.
14
 */
15
#include "theory/bv/bv_subtheory_algebraic.h"
16
17
#include <unordered_set>
18
19
#include "expr/node_algorithm.h"
20
#include "options/bv_options.h"
21
#include "printer/printer.h"
22
#include "smt/dump.h"
23
#include "smt/smt_engine.h"
24
#include "smt/smt_engine_scope.h"
25
#include "smt/smt_statistics_registry.h"
26
#include "smt_util/boolean_simplification.h"
27
#include "theory/bv/bv_quick_check.h"
28
#include "theory/bv/bv_solver_layered.h"
29
#include "theory/bv/theory_bv_utils.h"
30
#include "theory/rewriter.h"
31
#include "theory/theory_model.h"
32
#include "util/bitvector.h"
33
34
using namespace cvc5::context;
35
using namespace cvc5::prop;
36
using namespace cvc5::theory::bv::utils;
37
using namespace std;
38
39
namespace cvc5 {
40
namespace theory {
41
namespace bv {
42
43
/* ------------------------------------------------------------------------- */
44
45
namespace {
46
47
/* Collect all variables under a given a node.  */
48
void collectVariables(TNode node, utils::NodeSet& vars)
49
{
50
  std::vector<TNode> stack;
51
  std::unordered_set<TNode> visited;
52
53
  stack.push_back(node);
54
  while (!stack.empty())
55
  {
56
    Node n = stack.back();
57
    stack.pop_back();
58
59
    if (vars.find(n) != vars.end()) continue;
60
    if (visited.find(n) != visited.end()) continue;
61
    visited.insert(n);
62
63
    if (Theory::isLeafOf(n, THEORY_BV) && n.getKind() != kind::CONST_BITVECTOR)
64
    {
65
      vars.insert(n);
66
      continue;
67
    }
68
    stack.insert(stack.end(), n.begin(), n.end());
69
  }
70
}
71
72
};
73
74
/* ------------------------------------------------------------------------- */
75
76
bool hasExpensiveBVOperators(TNode fact);
77
Node mergeExplanations(const std::vector<Node>& expls);
78
Node mergeExplanations(TNode expl1, TNode expl2);
79
80
81
SubstitutionEx::SubstitutionEx(theory::SubstitutionMap* modelMap)
82
  : d_substitutions()
83
  , d_cache()
84
  , d_cacheInvalid(true)
85
  , d_modelMap(modelMap)
86
{}
87
88
bool SubstitutionEx::addSubstitution(TNode from, TNode to, TNode reason) {
89
  Debug("bv-substitution") << "SubstitutionEx::addSubstitution: "<< from
90
                           <<" => "<< to << "\n" << " reason "<<reason << "\n";
91
  Assert(from != to);
92
  if (d_substitutions.find(from) != d_substitutions.end()) {
93
    return false;
94
  }
95
96
  d_modelMap->addSubstitution(from, to);
97
98
  d_cacheInvalid = true;
99
  d_substitutions[from] = SubstitutionElement(to, reason);
100
  return true;
101
}
102
103
Node SubstitutionEx::apply(TNode node) {
104
  Debug("bv-substitution") << "SubstitutionEx::apply("<< node <<")\n";
105
  if (d_cacheInvalid) {
106
    d_cache.clear();
107
    d_cacheInvalid = false;
108
  }
109
110
  SubstitutionsCache::iterator it = d_cache.find(node);
111
112
  if (it != d_cache.end()) {
113
    Node res = it->second.to;
114
    Debug("bv-substitution") << "   =>"<< res <<"\n";
115
    return res;
116
  }
117
118
  Node result = internalApply(node);
119
  Debug("bv-substitution") << "   =>"<< result <<"\n";
120
  return result;
121
}
122
123
Node SubstitutionEx::internalApply(TNode node) {
124
  if (d_substitutions.empty())
125
    return node;
126
127
  vector<SubstitutionStackElement> stack;
128
  stack.push_back(SubstitutionStackElement(node));
129
130
  while (!stack.empty()) {
131
    SubstitutionStackElement head = stack.back();
132
    stack.pop_back();
133
134
    TNode current = head.node;
135
136
    if (hasCache(current)) {
137
      continue;
138
    }
139
140
    // check if it has substitution
141
    Substitutions::const_iterator it = d_substitutions.find(current);
142
    if (it != d_substitutions.end()) {
143
      vector<Node> reasons;
144
      TNode to = it->second.to;
145
      reasons.push_back(it->second.reason);
146
      // check if the thing we subsituted to has substitutions
147
      TNode res = internalApply(to);
148
      // update reasons
149
      reasons.push_back(getReason(to));
150
      Node reason = mergeExplanations(reasons);
151
      storeCache(current, res, reason);
152
      continue;
153
    }
154
155
    // if no children then just continue
156
    if(current.getNumChildren() == 0) {
157
      storeCache(current, current, utils::mkTrue());
158
      continue;
159
    }
160
161
    // children already processed
162
    if (head.childrenAdded) {
163
      NodeBuilder nb(current.getKind());
164
      std::vector<Node> reasons;
165
166
      if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
167
        TNode op = current.getOperator();
168
        Assert(hasCache(op));
169
        nb << getCache(op);
170
        reasons.push_back(getReason(op));
171
      }
172
      for (unsigned i = 0; i < current.getNumChildren(); ++i) {
173
        Assert(hasCache(current[i]));
174
        nb << getCache(current[i]);
175
        reasons.push_back(getReason(current[i]));
176
      }
177
      Node result = nb;
178
      // if the node is new apply substitutions to it
179
      Node subst_result = result;
180
      if (result != current) {
181
        subst_result = result!= current? internalApply(result) : result;
182
        reasons.push_back(getReason(result));
183
      }
184
      Node reason = mergeExplanations(reasons);
185
      storeCache(current, subst_result, reason);
186
      continue;
187
    } else {
188
      // add children to stack
189
      stack.push_back(SubstitutionStackElement(current, true));
190
      if (current.getMetaKind() == kind::metakind::PARAMETERIZED) {
191
        stack.push_back(SubstitutionStackElement(current.getOperator()));
192
      }
193
      for (unsigned i = 0; i < current.getNumChildren(); ++i) {
194
        stack.push_back(SubstitutionStackElement(current[i]));
195
      }
196
    }
197
  }
198
199
  Assert(hasCache(node));
200
  return getCache(node);
201
}
202
203
Node SubstitutionEx::explain(TNode node) const {
204
  if(!hasCache(node)) {
205
    return utils::mkTrue();
206
  }
207
208
  Debug("bv-substitution") << "SubstitutionEx::explain("<< node <<")\n";
209
  Node res = getReason(node);
210
  Debug("bv-substitution") << "  with "<< res <<"\n";
211
  return res;
212
}
213
214
Node SubstitutionEx::getReason(TNode node) const {
215
  Assert(hasCache(node));
216
  SubstitutionsCache::const_iterator it = d_cache.find(node);
217
  return it->second.reason;
218
}
219
220
bool SubstitutionEx::hasCache(TNode node) const {
221
  return d_cache.find(node) != d_cache.end();
222
}
223
224
Node SubstitutionEx::getCache(TNode node) const {
225
  Assert(hasCache(node));
226
  return d_cache.find(node)->second.to;
227
}
228
229
void SubstitutionEx::storeCache(TNode from, TNode to, Node reason) {
230
  //  Debug("bv-substitution") << "SubstitutionEx::storeCache(" << from <<", " << to <<", "<< reason<<")\n";
231
  Assert(!hasCache(from));
232
  d_cache[from] = SubstitutionElement(to, reason);
233
}
234
235
AlgebraicSolver::AlgebraicSolver(context::Context* c, BVSolverLayered* bv)
236
    : SubtheorySolver(c, bv),
237
      d_modelMap(),
238
      d_quickSolver(new BVQuickCheck("theory::bv::algebraic", bv)),
239
      d_isComplete(c, false),
240
      d_isDifficult(c, false),
241
      d_budget(options::bitvectorAlgebraicBudget()),
242
      d_explanations(),
243
      d_inputAssertions(),
244
      d_ids(),
245
      d_numSolved(0),
246
      d_numCalls(0),
247
      d_quickXplain(),
248
      d_statistics()
249
{
250
  if (options::bitvectorQuickXplain())
251
  {
252
    d_quickXplain.reset(
253
        new QuickXPlain("theory::bv::algebraic", d_quickSolver.get()));
254
  }
255
}
256
257
AlgebraicSolver::~AlgebraicSolver() {}
258
259
bool AlgebraicSolver::check(Theory::Effort e)
260
{
261
  Assert(options::bitblastMode() == options::BitblastMode::LAZY);
262
263
  if (!Theory::fullEffort(e)) { return true; }
264
  if (!useHeuristic()) { return true; }
265
266
  TimerStat::CodeTimer algebraicTimer(d_statistics.d_solveTime);
267
  Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check (" << e << ")\n";
268
  ++(d_numCalls);
269
  ++(d_statistics.d_numCallstoCheck);
270
271
  d_explanations.clear();
272
  d_ids.clear();
273
  d_inputAssertions.clear();
274
275
  std::vector<WorklistElement> worklist;
276
277
  uint64_t original_bb_cost = 0;
278
279
  NodeSet seen_assertions;
280
  // Processing assertions from scratch
281
  for (AssertionQueue::const_iterator it = assertionsBegin(); it != assertionsEnd(); ++it) {
282
    Debug("bv-subtheory-algebraic") << "   " << *it << "\n";
283
    TNode assertion = *it;
284
    unsigned id = worklist.size();
285
    d_ids[assertion] = id;
286
    worklist.push_back(WorklistElement(assertion, id));
287
    d_inputAssertions.insert(assertion);
288
    storeExplanation(assertion);
289
290
    uint64_t assertion_size = d_quickSolver->computeAtomWeight(assertion, seen_assertions);
291
    Assert(original_bb_cost <= original_bb_cost + assertion_size);
292
    original_bb_cost+= assertion_size;
293
  }
294
295
  for (unsigned i = 0; i < worklist.size(); ++i) {
296
    d_ids[worklist[i].node] = worklist[i].id;
297
  }
298
299
  Debug("bv-subtheory-algebraic") << "Assertions " << worklist.size() <<" : \n";
300
301
  Assert(d_explanations.size() == worklist.size());
302
303
  d_modelMap.reset(new SubstitutionMap(d_context));
304
  SubstitutionEx subst(d_modelMap.get());
305
306
  // first round of substitutions
307
  processAssertions(worklist, subst);
308
309
  if (!d_isDifficult.get()) {
310
    // skolemize all possible extracts
311
    ExtractSkolemizer skolemizer(d_modelMap.get());
312
    skolemizer.skolemize(worklist);
313
    // second round of substitutions
314
    processAssertions(worklist, subst);
315
  }
316
317
  NodeSet subst_seen;
318
  uint64_t subst_bb_cost = 0;
319
320
  unsigned r = 0;
321
  unsigned w = 0;
322
323
  for (; r < worklist.size(); ++r) {
324
325
    TNode fact = worklist[r].node;
326
    unsigned id = worklist[r].id;
327
328
    if (fact.isConst() &&
329
        fact.getConst<bool>() == true) {
330
      continue;
331
    }
332
333
    if (fact.isConst() &&
334
        fact.getConst<bool>() == false) {
335
      // we have a conflict
336
      Node conflict = BooleanSimplification::simplify(d_explanations[id]);
337
      d_bv->setConflict(conflict);
338
      d_isComplete.set(true);
339
      Debug("bv-subtheory-algebraic") << " UNSAT: assertion simplfies to false with conflict: "<< conflict << "\n";
340
341
      ++(d_statistics.d_numSimplifiesToFalse);
342
      ++(d_numSolved);
343
      return false;
344
    }
345
346
    subst_bb_cost+= d_quickSolver->computeAtomWeight(fact, subst_seen);
347
    worklist[w] = WorklistElement(fact, id);
348
    Node expl =  BooleanSimplification::simplify(d_explanations[id]);
349
    storeExplanation(id, expl);
350
    d_ids[fact] = id;
351
    ++w;
352
  }
353
354
  worklist.resize(w);
355
356
357
  if(Debug.isOn("bv-subtheory-algebraic")) {
358
    Debug("bv-subtheory-algebraic") << "Assertions post-substitutions " << worklist.size() << ":\n";
359
    for (unsigned i = 0; i < worklist.size(); ++i) {
360
      Debug("bv-subtheory-algebraic") << "   " << worklist[i].node << "\n";
361
    }
362
  }
363
364
365
  // all facts solved to true
366
  if (worklist.empty()) {
367
    Debug("bv-subtheory-algebraic") << " SAT: everything simplifies to true.\n";
368
    ++(d_statistics.d_numSimplifiesToTrue);
369
    ++(d_numSolved);
370
    return true;
371
  }
372
373
  double ratio = ((double)subst_bb_cost)/original_bb_cost;
374
  if (ratio > 0.5 ||
375
      !d_isDifficult.get()) {
376
    // give up if problem not reduced enough
377
    d_isComplete.set(false);
378
    return true;
379
  }
380
381
  d_quickSolver->clearSolver();
382
383
  d_quickSolver->push();
384
  std::vector<Node> facts;
385
  for (unsigned i = 0; i < worklist.size(); ++i) {
386
    facts.push_back(worklist[i].node);
387
  }
388
  bool ok = quickCheck(facts);
389
390
  Debug("bv-subtheory-algebraic") << "AlgebraicSolver::check done " << ok << ".\n";
391
  return ok;
392
}
393
394
bool AlgebraicSolver::quickCheck(std::vector<Node>& facts) {
395
  SatValue res = d_quickSolver->checkSat(facts, d_budget);
396
397
  if (res == SAT_VALUE_UNKNOWN) {
398
    d_isComplete.set(false);
399
    Debug("bv-subtheory-algebraic") << " Unknown.\n";
400
    ++(d_statistics.d_numUnknown);
401
    return true;
402
  }
403
404
  if (res == SAT_VALUE_TRUE) {
405
    Debug("bv-subtheory-algebraic") << " Sat.\n";
406
    ++(d_statistics.d_numSat);
407
    ++(d_numSolved);
408
    d_isComplete.set(true);
409
    return true;
410
  }
411
412
  Assert(res == SAT_VALUE_FALSE);
413
  Assert(d_quickSolver->inConflict());
414
  d_isComplete.set(true);
415
  Debug("bv-subtheory-algebraic") << " Unsat.\n";
416
  ++(d_numSolved);
417
  ++(d_statistics.d_numUnsat);
418
419
420
  Node conflict = d_quickSolver->getConflict();
421
  Debug("bv-subtheory-algebraic") << " Conflict: " << conflict << "\n";
422
423
  // singleton conflict
424
  if (conflict.getKind() != kind::AND) {
425
    Assert(d_ids.find(conflict) != d_ids.end());
426
    unsigned id = d_ids[conflict];
427
    Assert(id < d_explanations.size());
428
    Node theory_confl = d_explanations[id];
429
    d_bv->setConflict(theory_confl);
430
    return false;
431
  }
432
433
  Assert(conflict.getKind() == kind::AND);
434
  if (options::bitvectorQuickXplain()) {
435
    d_quickSolver->popToZero();
436
    Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck original conflict size " << conflict.getNumChildren() << "\n";
437
    conflict = d_quickXplain->minimizeConflict(conflict);
438
    Debug("bv-quick-xplain") << "AlgebraicSolver::quickCheck minimized conflict size " << conflict.getNumChildren() << "\n";
439
  }
440
441
  vector<TNode> theory_confl;
442
  for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
443
    TNode c = conflict[i];
444
445
    Assert(d_ids.find(c) != d_ids.end());
446
    unsigned c_id = d_ids[c];
447
    Assert(c_id < d_explanations.size());
448
    TNode c_expl = d_explanations[c_id];
449
    theory_confl.push_back(c_expl);
450
  }
451
452
  Node confl = BooleanSimplification::simplify(utils::mkAnd(theory_confl));
453
454
  Debug("bv-subtheory-algebraic") << " Out Conflict: " << confl << "\n";
455
  setConflict(confl);
456
  return false;
457
}
458
459
void AlgebraicSolver::setConflict(TNode conflict)
460
{
461
  Node final_conflict = conflict;
462
  if (options::bitvectorQuickXplain() &&
463
      conflict.getKind() == kind::AND &&
464
      conflict.getNumChildren() > 4) {
465
    final_conflict = d_quickXplain->minimizeConflict(conflict);
466
  }
467
  d_bv->setConflict(final_conflict);
468
}
469
470
bool AlgebraicSolver::solve(TNode fact, TNode reason, SubstitutionEx& subst) {
471
  if (fact.getKind() != kind::EQUAL) return false;
472
473
  NodeManager* nm = NodeManager::currentNM();
474
  TNode left = fact[0];
475
  TNode right = fact[1];
476
477
  if (left.isVar() && !expr::hasSubterm(right, left))
478
  {
479
    bool changed = subst.addSubstitution(left, right, reason);
480
    return changed;
481
  }
482
  if (right.isVar() && !expr::hasSubterm(left, right))
483
  {
484
    bool changed = subst.addSubstitution(right, left, reason);
485
    return changed;
486
  }
487
488
  // xor simplification
489
  if (right.getKind() == kind::BITVECTOR_XOR &&
490
      left.getKind() == kind::BITVECTOR_XOR) {
491
    TNode var = left[0];
492
    if (var.getMetaKind() != kind::metakind::VARIABLE)
493
      return false;
494
495
    // simplify xor with same variable on both sides
496
    if (expr::hasSubterm(right, var))
497
    {
498
      std::vector<Node> right_children;
499
      for (unsigned i = 0; i < right.getNumChildren(); ++i) {
500
        if (right[i] != var)
501
          right_children.push_back(right[i]);
502
      }
503
      Assert(right_children.size());
504
      Node new_right = utils::mkNaryNode(kind::BITVECTOR_XOR, right_children);
505
      std::vector<Node> left_children;
506
      for (unsigned i = 1; i < left.getNumChildren(); ++i) {
507
        left_children.push_back(left[i]);
508
      }
509
      Node new_left = utils::mkNaryNode(kind::BITVECTOR_XOR, left_children);
510
      Node new_fact = nm->mkNode(kind::EQUAL, new_left, new_right);
511
      bool changed = subst.addSubstitution(fact, new_fact, reason);
512
      return changed;
513
    }
514
515
    NodeBuilder nb(kind::BITVECTOR_XOR);
516
    for (unsigned i = 1; i < left.getNumChildren(); ++i) {
517
      nb << left[i];
518
    }
519
    Node inverse = left.getNumChildren() == 2? (Node)left[1] : (Node)nb;
520
    Node new_right = nm->mkNode(kind::BITVECTOR_XOR, right, inverse);
521
    bool changed = subst.addSubstitution(var, new_right, reason);
522
523
    return changed;
524
  }
525
526
  // (a xor t = a) <=> (t = 0)
527
  if (left.getKind() == kind::BITVECTOR_XOR
528
      && right.getMetaKind() == kind::metakind::VARIABLE
529
      && expr::hasSubterm(left, right))
530
  {
531
    TNode var = right;
532
    Node new_left = nm->mkNode(kind::BITVECTOR_XOR, var, left);
533
    Node zero = utils::mkConst(utils::getSize(var), 0u);
534
    Node new_fact = nm->mkNode(kind::EQUAL, zero, new_left);
535
    bool changed = subst.addSubstitution(fact, new_fact, reason);
536
    return changed;
537
  }
538
539
  if (right.getKind() == kind::BITVECTOR_XOR
540
      && left.getMetaKind() == kind::metakind::VARIABLE
541
      && expr::hasSubterm(right, left))
542
  {
543
    TNode var = left;
544
    Node new_right = nm->mkNode(kind::BITVECTOR_XOR, var, right);
545
    Node zero = utils::mkConst(utils::getSize(var), 0u);
546
    Node new_fact = nm->mkNode(kind::EQUAL, zero, new_right);
547
    bool changed = subst.addSubstitution(fact, new_fact, reason);
548
    return changed;
549
  }
550
551
  // (a xor b = 0) <=> (a = b)
552
  if (left.getKind() == kind::BITVECTOR_XOR &&
553
      left.getNumChildren() == 2 &&
554
      right.getKind() == kind::CONST_BITVECTOR &&
555
      right.getConst<BitVector>() == BitVector(utils::getSize(left), 0u)) {
556
    Node new_fact = nm->mkNode(kind::EQUAL, left[0], left[1]);
557
    bool changed = subst.addSubstitution(fact, new_fact, reason);
558
    return changed;
559
  }
560
561
562
  return false;
563
}
564
565
bool AlgebraicSolver::isSubstitutableIn(TNode node, TNode in)
566
{
567
  if (node.getMetaKind() == kind::metakind::VARIABLE
568
      && !expr::hasSubterm(in, node))
569
    return true;
570
  return false;
571
}
572
573
void AlgebraicSolver::processAssertions(std::vector<WorklistElement>& worklist, SubstitutionEx& subst) {
574
  NodeManager* nm = NodeManager::currentNM();
575
  bool changed = true;
576
  while(changed) {
577
    // d_bv->spendResource();
578
    changed = false;
579
    for (unsigned i = 0; i < worklist.size(); ++i) {
580
      // apply current substitutions
581
      Node current = subst.apply(worklist[i].node);
582
      unsigned current_id = worklist[i].id;
583
      Node subst_expl = subst.explain(worklist[i].node);
584
      worklist[i] = WorklistElement(Rewriter::rewrite(current), current_id);
585
      // explanation for this assertion
586
      Node old_expl = d_explanations[current_id];
587
      Node new_expl = mergeExplanations(subst_expl, old_expl);
588
      storeExplanation(current_id, new_expl);
589
590
      // use the new substitution to solve
591
      if(solve(worklist[i].node, new_expl, subst)) {
592
        changed = true;
593
      }
594
    }
595
596
    // check for concat slicings
597
    for (unsigned i = 0; i < worklist.size(); ++i) {
598
      TNode fact = worklist[i].node;
599
      unsigned current_id = worklist[i].id;
600
601
      if (fact.getKind() != kind::EQUAL) {
602
        continue;
603
      }
604
605
      TNode left = fact[0];
606
      TNode right = fact[1];
607
      if (left.getKind() != kind::BITVECTOR_CONCAT ||
608
          right.getKind() != kind::BITVECTOR_CONCAT ||
609
          left.getNumChildren() != right.getNumChildren()) {
610
        continue;
611
      }
612
613
      bool can_slice = true;
614
      for (unsigned j = 0; j < left.getNumChildren(); ++j) {
615
        if (utils::getSize(left[j]) != utils::getSize(right[j]))
616
          can_slice = false;
617
      }
618
619
      if (!can_slice) {
620
        continue;
621
      }
622
623
      for (unsigned j = 0; j < left.getNumChildren(); ++j) {
624
        Node eq_j = nm->mkNode(kind::EQUAL, left[j], right[j]);
625
        unsigned id = d_explanations.size();
626
        TNode expl = d_explanations[current_id];
627
        storeExplanation(expl);
628
        worklist.push_back(WorklistElement(eq_j, id));
629
        d_ids[eq_j] = id;
630
      }
631
      worklist[i] = WorklistElement(utils::mkTrue(), worklist[i].id);
632
      changed = true;
633
    }
634
    Assert(d_explanations.size() == worklist.size());
635
  }
636
}
637
638
void AlgebraicSolver::storeExplanation(unsigned id, TNode explanation) {
639
  Assert(checkExplanation(explanation));
640
  d_explanations[id] = explanation;
641
}
642
643
void AlgebraicSolver::storeExplanation(TNode explanation) {
644
  Assert(checkExplanation(explanation));
645
  d_explanations.push_back(explanation);
646
}
647
648
bool AlgebraicSolver::checkExplanation(TNode explanation) {
649
  Node simplified_explanation = explanation; //BooleanSimplification::simplify(explanation);
650
  if (simplified_explanation.getKind() != kind::AND) {
651
    return d_inputAssertions.find(simplified_explanation) != d_inputAssertions.end();
652
  }
653
  for (unsigned i = 0; i < simplified_explanation.getNumChildren(); ++i) {
654
    if (d_inputAssertions.find(simplified_explanation[i]) == d_inputAssertions.end()) {
655
      return false;
656
    }
657
  }
658
  return true;
659
}
660
661
662
bool AlgebraicSolver::isComplete() {
663
  return d_isComplete.get();
664
}
665
666
bool AlgebraicSolver::useHeuristic() {
667
  if (d_numCalls == 0)
668
    return true;
669
670
  double success_rate = double(d_numSolved)/double(d_numCalls);
671
  d_statistics.d_useHeuristic.set(success_rate);
672
  return success_rate > 0.8;
673
}
674
675
676
void AlgebraicSolver::assertFact(TNode fact) {
677
  d_assertionQueue.push_back(fact);
678
  d_isComplete.set(false);
679
  if (!d_isDifficult.get()) {
680
    d_isDifficult.set(hasExpensiveBVOperators(fact));
681
  }
682
}
683
684
EqualityStatus AlgebraicSolver::getEqualityStatus(TNode a, TNode b) {
685
  return EQUALITY_UNKNOWN;
686
}
687
688
bool AlgebraicSolver::collectModelValues(TheoryModel* model,
689
                                         const std::set<Node>& termSet)
690
{
691
  Debug("bitvector-model") << "AlgebraicSolver::collectModelValues\n";
692
  AlwaysAssert(!d_quickSolver->inConflict());
693
694
  // collect relevant terms that the bv theory abstracts to variables
695
  // (variables and parametric terms such as select apply_uf)
696
  std::vector<TNode> variables;
697
  std::vector<Node> values;
698
  for (set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) {
699
    TNode term = *it;
700
    if (term.getType().isBitVector() &&
701
        (term.getMetaKind() == kind::metakind::VARIABLE ||
702
         Theory::theoryOf(term) != THEORY_BV)) {
703
      variables.push_back(term);
704
      values.push_back(term);
705
    }
706
  }
707
708
  NodeSet leaf_vars;
709
  Debug("bitvector-model") << "Substitutions:\n";
710
  for (unsigned i = 0; i < variables.size(); ++i) {
711
    TNode current = variables[i];
712
    TNode subst = Rewriter::rewrite(d_modelMap->apply(current));
713
    Debug("bitvector-model") << "   " << current << " => " << subst << "\n";
714
    values[i] = subst;
715
    collectVariables(subst, leaf_vars);
716
  }
717
718
  Debug("bitvector-model") << "Model:\n";
719
720
  for (NodeSet::const_iterator it = leaf_vars.begin(); it != leaf_vars.end(); ++it) {
721
    TNode var = *it;
722
    Node value = d_quickSolver->getVarValue(var, true);
723
    Assert(!value.isNull());
724
725
    // may be a shared term that did not appear in the current assertions
726
    // AJR: need to check whether already in map for cases where collectModelInfo is called multiple times in the same context
727
    if (!value.isNull() && !d_modelMap->hasSubstitution(var)) {
728
      Debug("bitvector-model") << "   " << var << " => " << value << "\n";
729
      Assert(value.getKind() == kind::CONST_BITVECTOR);
730
      d_modelMap->addSubstitution(var, value);
731
    }
732
  }
733
734
  Debug("bitvector-model") << "Final Model:\n";
735
  for (unsigned i = 0; i < variables.size(); ++i) {
736
    TNode current = values[i];
737
    TNode subst = Rewriter::rewrite(d_modelMap->apply(current));
738
    Debug("bitvector-model") << "AlgebraicSolver:   " << variables[i] << " => " << subst << "\n";
739
    // Doesn't have to be constant as it may be irrelevant
740
    Assert(subst.getKind() == kind::CONST_BITVECTOR);
741
    if (!model->assertEquality(variables[i], subst, true))
742
    {
743
      return false;
744
    }
745
  }
746
  return true;
747
 }
748
749
Node AlgebraicSolver::getModelValue(TNode node) {
750
  return Node::null();
751
}
752
753
AlgebraicSolver::Statistics::Statistics()
754
    : d_numCallstoCheck(smtStatisticsRegistry().registerInt(
755
        "theory::bv::algebraic::NumCallsToCheck")),
756
      d_numSimplifiesToTrue(smtStatisticsRegistry().registerInt(
757
          "theory::bv::algebraic::NumSimplifiesToTrue")),
758
      d_numSimplifiesToFalse(smtStatisticsRegistry().registerInt(
759
          "theory::bv::algebraic::NumSimplifiesToFalse")),
760
      d_numUnsat(smtStatisticsRegistry().registerInt(
761
          "theory::bv::algebraic::NumUnsat")),
762
      d_numSat(
763
          smtStatisticsRegistry().registerInt("theory::bv::algebraic::NumSat")),
764
      d_numUnknown(smtStatisticsRegistry().registerInt(
765
          "theory::bv::algebraic::NumUnknown")),
766
      d_solveTime(smtStatisticsRegistry().registerTimer(
767
          "theory::bv::algebraic::SolveTime")),
768
      d_useHeuristic(smtStatisticsRegistry().registerValue<double>(
769
          "theory::bv::algebraic::UseHeuristic", 0.2))
770
{
771
}
772
773
bool hasExpensiveBVOperatorsRec(TNode fact, TNodeSet& seen) {
774
  if (fact.getKind() == kind::BITVECTOR_MULT
775
      || fact.getKind() == kind::BITVECTOR_UDIV
776
      || fact.getKind() == kind::BITVECTOR_UREM)
777
  {
778
    return true;
779
  }
780
781
  if (seen.find(fact) != seen.end()) {
782
    return false;
783
  }
784
785
  if (fact.getNumChildren() == 0) {
786
    return false;
787
  }
788
  for (unsigned i = 0; i < fact.getNumChildren(); ++i) {
789
    bool difficult = hasExpensiveBVOperatorsRec(fact[i], seen);
790
    if (difficult)
791
      return true;
792
  }
793
  seen.insert(fact);
794
  return false;
795
}
796
797
bool hasExpensiveBVOperators(TNode fact) {
798
  TNodeSet seen;
799
  return hasExpensiveBVOperatorsRec(fact, seen);
800
}
801
802
void ExtractSkolemizer::skolemize(std::vector<WorklistElement>& facts) {
803
  TNodeSet seen;
804
  for (unsigned i = 0; i < facts.size(); ++i) {
805
    TNode current = facts[i].node;
806
    collectExtracts(current, seen);
807
  }
808
809
  for (VarExtractMap::iterator it = d_varToExtract.begin(); it != d_varToExtract.end(); ++it) {
810
    ExtractList& el = it->second;
811
    TNode var = it->first;
812
    Base& base = el.base;
813
814
    unsigned bw = utils::getSize(var);
815
    // compute decomposition
816
    std::vector<unsigned> cuts;
817
    for (unsigned i = 1; i <= bw; ++i) {
818
      if (base.isCutPoint(i)) {
819
        cuts.push_back(i);
820
      }
821
    }
822
    unsigned previous = 0;
823
    unsigned current = 0;
824
    std::vector<Node> skolems;
825
    for (unsigned i = 0; i < cuts.size(); ++i) {
826
      current = cuts[i];
827
      Assert(current > 0);
828
      int size = current - previous;
829
      Assert(size > 0);
830
      Node sk = utils::mkVar(size);
831
      skolems.push_back(sk);
832
      previous = current;
833
    }
834
    if (current < bw -1) {
835
      int size = bw - current;
836
      Assert(size > 0);
837
      Node sk = utils::mkVar(size);
838
      skolems.push_back(sk);
839
    }
840
    NodeBuilder skolem_nb(kind::BITVECTOR_CONCAT);
841
842
    for (int i = skolems.size() - 1; i >= 0; --i) {
843
      skolem_nb << skolems[i];
844
    }
845
846
    Node skolem_concat = skolems.size() == 1 ? (Node)skolems[0] : (Node) skolem_nb;
847
    Assert(utils::getSize(skolem_concat) == utils::getSize(var));
848
    storeSkolem(var, skolem_concat);
849
850
    for (unsigned i = 0; i < el.extracts.size(); ++i) {
851
      unsigned h = el.extracts[i].high;
852
      unsigned l = el.extracts[i].low;
853
      Node extract = utils::mkExtract(var, h, l);
854
      Node skolem_extract = Rewriter::rewrite(utils::mkExtract(skolem_concat, h, l));
855
      Assert(skolem_extract.getMetaKind() == kind::metakind::VARIABLE
856
             || skolem_extract.getKind() == kind::BITVECTOR_CONCAT);
857
      storeSkolem(extract, skolem_extract);
858
    }
859
  }
860
861
  for (unsigned i = 0; i < facts.size(); ++i) {
862
    facts[i] = WorklistElement(skolemize(facts[i].node), facts[i].id);
863
  }
864
}
865
866
Node ExtractSkolemizer::mkSkolem(Node node) {
867
  Assert(node.getKind() == kind::BITVECTOR_EXTRACT
868
         && node[0].getMetaKind() == kind::metakind::VARIABLE);
869
  Assert(!d_skolemSubst.hasSubstitution(node));
870
  return utils::mkVar(utils::getSize(node));
871
}
872
873
void ExtractSkolemizer::unSkolemize(std::vector<WorklistElement>& facts) {
874
  for (unsigned i = 0; i < facts.size(); ++i) {
875
    facts[i] = WorklistElement(unSkolemize(facts[i].node), facts[i].id);
876
  }
877
}
878
879
void ExtractSkolemizer::storeSkolem(TNode node, TNode skolem) {
880
  d_skolemSubst.addSubstitution(node, skolem);
881
  d_modelMap->addSubstitution(node, skolem);
882
  d_skolemSubstRev.addSubstitution(skolem, node);
883
}
884
885
Node ExtractSkolemizer::unSkolemize(TNode node) {
886
  return d_skolemSubstRev.apply(node);
887
}
888
889
Node ExtractSkolemizer::skolemize(TNode node) {
890
  return d_skolemSubst.apply(node);
891
}
892
893
void ExtractSkolemizer::ExtractList::addExtract(Extract& e) {
894
  extracts.push_back(e);
895
  base.sliceAt(e.low);
896
  base.sliceAt(e.high+1);
897
}
898
899
void ExtractSkolemizer::storeExtract(TNode var, unsigned high, unsigned low) {
900
  Assert(var.getMetaKind() == kind::metakind::VARIABLE);
901
  if (d_varToExtract.find(var) == d_varToExtract.end()) {
902
    d_varToExtract[var] = ExtractList(utils::getSize(var));
903
  }
904
  VarExtractMap::iterator it = d_varToExtract.find(var);
905
  ExtractList& el = it->second;
906
  Extract e(high, low);
907
  el.addExtract(e);
908
}
909
910
void ExtractSkolemizer::collectExtracts(TNode node, TNodeSet& seen) {
911
  if (seen.find(node) != seen.end()) {
912
    return;
913
  }
914
915
  if (node.getKind() == kind::BITVECTOR_EXTRACT &&
916
      node[0].getMetaKind() == kind::metakind::VARIABLE) {
917
    unsigned high = utils::getExtractHigh(node);
918
    unsigned low = utils::getExtractLow(node);
919
    TNode var = node[0];
920
    storeExtract(var, high, low);
921
    seen.insert(node);
922
    return;
923
  }
924
925
  if (node.getNumChildren() == 0)
926
    return;
927
928
  for (unsigned i = 0; i < node.getNumChildren(); ++i) {
929
    collectExtracts(node[i], seen);
930
  }
931
  seen.insert(node);
932
}
933
934
ExtractSkolemizer::ExtractSkolemizer(theory::SubstitutionMap* modelMap)
935
  : d_emptyContext()
936
  , d_varToExtract()
937
  , d_modelMap(modelMap)
938
  , d_skolemSubst(&d_emptyContext)
939
  , d_skolemSubstRev(&d_emptyContext)
940
{}
941
942
ExtractSkolemizer::~ExtractSkolemizer() {
943
}
944
945
Node mergeExplanations(const std::vector<Node>& expls) {
946
  TNodeSet literals;
947
  for (unsigned i = 0; i < expls.size(); ++i) {
948
    TNode expl = expls[i];
949
    Assert(expl.getType().isBoolean());
950
    if (expl.getKind() == kind::AND) {
951
      for (const TNode& child : expl)
952
      {
953
        if (child == utils::mkTrue()) continue;
954
        literals.insert(child);
955
      }
956
    } else if (expl != utils::mkTrue()) {
957
      literals.insert(expl);
958
    }
959
  }
960
961
  if (literals.size() == 0) {
962
    return utils::mkTrue();
963
  }else if (literals.size() == 1) {
964
    return *literals.begin();
965
  }
966
967
  NodeBuilder nb(kind::AND);
968
969
  for (TNodeSet::const_iterator it = literals.begin(); it!= literals.end(); ++it) {
970
    nb << *it;
971
  }
972
  return nb;
973
}
974
975
Node mergeExplanations(TNode expl1, TNode expl2) {
976
  std::vector<Node> expls;
977
  expls.push_back(expl1);
978
  expls.push_back(expl2);
979
  return mergeExplanations(expls);
980
}
981
982
}  // namespace bv
983
}  // namespace theory
984
29574
}  // namespace cvc5