GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/bv/bitblast/eager_bitblaster.cpp Lines: 69 132 52.3 %
Date: 2021-09-10 Branches: 93 553 16.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Liana Hadarean, 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
 * Bitblaster for the eager bv solver.
14
 */
15
16
#include "theory/bv/bitblast/eager_bitblaster.h"
17
18
#include "cvc5_private.h"
19
#include "options/base_options.h"
20
#include "options/bv_options.h"
21
#include "options/smt_options.h"
22
#include "prop/cnf_stream.h"
23
#include "prop/sat_solver_factory.h"
24
#include "smt/smt_engine.h"
25
#include "smt/smt_statistics_registry.h"
26
#include "theory/bv/bv_solver_layered.h"
27
#include "theory/bv/theory_bv.h"
28
#include "theory/theory_model.h"
29
30
namespace cvc5 {
31
namespace theory {
32
namespace bv {
33
34
2
EagerBitblaster::EagerBitblaster(BVSolverLayered* theory_bv,
35
2
                                 context::Context* c)
36
    : TBitblaster<Node>(),
37
      d_context(c),
38
      d_satSolver(),
39
2
      d_bitblastingRegistrar(new BitblastingRegistrar(this)),
40
      d_bv(theory_bv),
41
      d_bbAtoms(),
42
      d_variables(),
43
4
      d_notify()
44
{
45
2
  prop::SatSolver *solver = nullptr;
46
2
  switch (options::bvSatSolver())
47
  {
48
2
    case options::SatSolverMode::MINISAT:
49
    {
50
      prop::BVSatSolverInterface* minisat =
51
4
          prop::SatSolverFactory::createMinisat(
52
              d_nullContext.get(),
53
              smtStatisticsRegistry(),
54
2
              "theory::bv::EagerBitblaster::");
55
2
      d_notify.reset(new MinisatEmptyNotify());
56
2
      minisat->setNotify(d_notify.get());
57
2
      solver = minisat;
58
2
      break;
59
    }
60
    case options::SatSolverMode::CADICAL:
61
      solver = prop::SatSolverFactory::createCadical(
62
          smtStatisticsRegistry(), "theory::bv::EagerBitblaster::");
63
      break;
64
    case options::SatSolverMode::CRYPTOMINISAT:
65
      solver = prop::SatSolverFactory::createCryptoMinisat(
66
          smtStatisticsRegistry(), "theory::bv::EagerBitblaster::");
67
      break;
68
    case options::SatSolverMode::KISSAT:
69
      solver = prop::SatSolverFactory::createKissat(
70
          smtStatisticsRegistry(), "theory::bv::EagerBitblaster::");
71
      break;
72
    default: Unreachable() << "Unknown SAT solver type";
73
  }
74
2
  d_satSolver.reset(solver);
75
2
  ResourceManager* rm = smt::currentResourceManager();
76
6
  d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(),
77
2
                                        d_bitblastingRegistrar.get(),
78
2
                                        d_nullContext.get(),
79
                                        nullptr,
80
                                        rm,
81
                                        prop::FormulaLitPolicy::INTERNAL,
82
2
                                        "EagerBitblaster"));
83
2
}
84
85
4
EagerBitblaster::~EagerBitblaster() {}
86
87
4
void EagerBitblaster::bbFormula(TNode node)
88
{
89
  /* For incremental eager solving we assume formulas at context levels > 1. */
90
4
  if (options::incrementalSolving() && d_context->getLevel() > 1)
91
  {
92
    d_cnfStream->ensureLiteral(node);
93
  }
94
  else
95
  {
96
4
    d_cnfStream->convertAndAssert(node, false, false);
97
  }
98
4
}
99
100
/**
101
 * Bitblasts the atom, assigns it a marker literal, adding it to the SAT solver
102
 * NOTE: duplicate clauses are not detected because of marker literal
103
 * @param node the atom to be bitblasted
104
 *
105
 */
106
68
void EagerBitblaster::bbAtom(TNode node)
107
{
108
68
  node = node.getKind() == kind::NOT ? node[0] : node;
109
136
  if (node.getKind() == kind::BITVECTOR_BITOF
110
136
      || node.getKind() == kind::CONST_BOOLEAN || hasBBAtom(node))
111
  {
112
64
    return;
113
  }
114
115
4
  Debug("bitvector-bitblast") << "Bitblasting node " << node << "\n";
116
117
  // the bitblasted definition of the atom
118
8
  Node normalized = Rewriter::rewrite(node);
119
  Node atom_bb =
120
4
      normalized.getKind() != kind::CONST_BOOLEAN
121
4
          ? d_atomBBStrategies[normalized.getKind()](normalized, this)
122
12
          : normalized;
123
124
4
  atom_bb = Rewriter::rewrite(atom_bb);
125
126
  // asserting that the atom is true iff the definition holds
127
  Node atom_definition =
128
8
      NodeManager::currentNM()->mkNode(kind::EQUAL, node, atom_bb);
129
130
4
  AlwaysAssert(options::bitblastMode() == options::BitblastMode::EAGER);
131
4
  storeBBAtom(node, atom_bb);
132
4
  d_cnfStream->convertAndAssert(atom_definition, false, false);
133
}
134
135
4
void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
136
4
  d_bbAtoms.insert(atom);
137
4
}
138
139
12
void EagerBitblaster::storeBBTerm(TNode node, const Bits& bits) {
140
12
  d_termCache.insert(std::make_pair(node, bits));
141
12
}
142
143
4
bool EagerBitblaster::hasBBAtom(TNode atom) const {
144
4
  return d_bbAtoms.find(atom) != d_bbAtoms.end();
145
}
146
147
18
void EagerBitblaster::bbTerm(TNode node, Bits& bits) {
148
18
  Assert(node.getType().isBitVector());
149
150
18
  if (hasBBTerm(node)) {
151
6
    getBBTerm(node, bits);
152
6
    return;
153
  }
154
155
12
  d_bv->spendResource(Resource::BitblastStep);
156
12
  Debug("bitvector-bitblast") << "Bitblasting node " << node << "\n";
157
158
12
  d_termBBStrategies[node.getKind()](node, bits, this);
159
160
12
  Assert(bits.size() == utils::getSize(node));
161
162
12
  storeBBTerm(node, bits);
163
}
164
165
4
void EagerBitblaster::makeVariable(TNode var, Bits& bits) {
166
4
  Assert(bits.size() == 0);
167
68
  for (unsigned i = 0; i < utils::getSize(var); ++i) {
168
64
    bits.push_back(utils::mkBitOf(var, i));
169
  }
170
4
  d_variables.insert(var);
171
4
}
172
173
Node EagerBitblaster::getBBAtom(TNode node) const { return node; }
174
175
/**
176
 * Calls the solve method for the Sat Solver.
177
 *
178
 * @return true for sat, and false for unsat
179
 */
180
181
2
bool EagerBitblaster::solve() {
182
2
  if (Trace.isOn("bitvector")) {
183
    Trace("bitvector") << "EagerBitblaster::solve(). \n";
184
  }
185
2
  Debug("bitvector") << "EagerBitblaster::solve(). \n";
186
  // TODO: clear some memory
187
  // if (something) {
188
  //   NodeManager* nm= NodeManager::currentNM();
189
  //   Rewriter::garbageCollect();
190
  //   nm->reclaimZombiesUntil(options::zombieHuntThreshold());
191
  // }
192
2
  return prop::SAT_VALUE_TRUE == d_satSolver->solve();
193
}
194
195
bool EagerBitblaster::solve(const std::vector<Node>& assumptions)
196
{
197
  std::vector<prop::SatLiteral> assumpts;
198
  for (const Node& assumption : assumptions)
199
  {
200
    Assert(d_cnfStream->hasLiteral(assumption));
201
    assumpts.push_back(d_cnfStream->getLiteral(assumption));
202
  }
203
  return prop::SAT_VALUE_TRUE == d_satSolver->solve(assumpts);
204
}
205
206
/**
207
 * Returns the value a is currently assigned to in the SAT solver
208
 * or null if the value is completely unassigned.
209
 *
210
 * @param a
211
 * @param fullModel whether to create a "full model," i.e., add
212
 * constants to equivalence classes that don't already have them
213
 *
214
 * @return
215
 */
216
Node EagerBitblaster::getModelFromSatSolver(TNode a, bool fullModel) {
217
  if (!hasBBTerm(a)) {
218
    return fullModel ? utils::mkConst(utils::getSize(a), 0u) : Node();
219
  }
220
221
  Bits bits;
222
  getBBTerm(a, bits);
223
  Integer value(0);
224
  for (int i = bits.size() - 1; i >= 0; --i) {
225
    prop::SatValue bit_value;
226
    if (d_cnfStream->hasLiteral(bits[i])) {
227
      prop::SatLiteral bit = d_cnfStream->getLiteral(bits[i]);
228
      bit_value = d_satSolver->value(bit);
229
      Assert(bit_value != prop::SAT_VALUE_UNKNOWN);
230
    } else {
231
      if (!fullModel) return Node();
232
      // unconstrained bits default to false
233
      bit_value = prop::SAT_VALUE_FALSE;
234
    }
235
    Integer bit_int =
236
        bit_value == prop::SAT_VALUE_TRUE ? Integer(1) : Integer(0);
237
    value = value * 2 + bit_int;
238
  }
239
  return utils::mkConst(bits.size(), value);
240
}
241
242
bool EagerBitblaster::collectModelInfo(TheoryModel* m, bool fullModel)
243
{
244
  NodeManager* nm = NodeManager::currentNM();
245
246
  // Collect the values for the bit-vector variables
247
  TNodeSet::iterator it = d_variables.begin();
248
  for (; it != d_variables.end(); ++it) {
249
    TNode var = *it;
250
    if (d_bv->isLeaf(var) || isSharedTerm(var) ||
251
        (var.isVar() && var.getType().isBoolean())) {
252
      // only shared terms could not have been bit-blasted
253
      Assert(hasBBTerm(var) || isSharedTerm(var));
254
255
      Node const_value = getModelFromSatSolver(var, true);
256
257
      if (const_value != Node()) {
258
        Debug("bitvector-model")
259
            << "EagerBitblaster::collectModelInfo (assert (= " << var << " "
260
            << const_value << "))\n";
261
        if (!m->assertEquality(var, const_value, true))
262
        {
263
          return false;
264
        }
265
      }
266
    }
267
  }
268
269
  // Collect the values for the Boolean variables
270
  std::vector<TNode> vars;
271
  d_cnfStream->getBooleanVariables(vars);
272
  for (TNode var : vars)
273
  {
274
    Assert(d_cnfStream->hasLiteral(var));
275
    prop::SatLiteral bit = d_cnfStream->getLiteral(var);
276
    prop::SatValue value = d_satSolver->value(bit);
277
    Assert(value != prop::SAT_VALUE_UNKNOWN);
278
    if (!m->assertEquality(
279
            var, nm->mkConst(value == prop::SAT_VALUE_TRUE), true))
280
    {
281
      return false;
282
    }
283
  }
284
  return true;
285
}
286
287
bool EagerBitblaster::isSharedTerm(TNode node) {
288
  return d_bv->d_sharedTermsSet.find(node) != d_bv->d_sharedTermsSet.end();
289
}
290
291
292
}  // namespace bv
293
}  // namespace theory
294
29502
}  // namespace cvc5