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