Theory of Bit-Vectors

examples/api/cpp/bitvectors.cpp

  1/******************************************************************************
  2 * Top contributors (to current version):
  3 *   Aina Niemetz, Liana Hadarean, Andrew Reynolds
  4 *
  5 * This file is part of the cvc5 project.
  6 *
  7 * Copyright (c) 2009-2024 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 * A simple demonstration of the solving capabilities of the cvc5
 14 * bit-vector solver.
 15 *
 16 */
 17
 18#include <cvc5/cvc5.h>
 19
 20#include <iostream>
 21
 22using namespace std;
 23using namespace cvc5;
 24
 25int main()
 26{
 27  TermManager tm;
 28  Solver slv(tm);
 29  slv.setLogic("QF_BV");  // Set the logic
 30
 31  // The following example has been adapted from the book A Hacker's Delight by
 32  // Henry S. Warren.
 33  //
 34  // Given a variable x that can only have two values, a or b. We want to
 35  // assign to x a value other than the current one. The straightforward code
 36  // to do that is:
 37  //
 38  //(0) if (x == a ) x = b;
 39  //    else x = a;
 40  //
 41  // Two more efficient yet equivalent methods are:
 42  //
 43  //(1) x = a ⊕ b ⊕ x;
 44  //
 45  //(2) x = a + b - x;
 46  //
 47  // We will use cvc5 to prove that the three pieces of code above are all
 48  // equivalent by encoding the problem in the bit-vector theory.
 49
 50  // Creating a bit-vector type of width 32
 51  Sort bitvector32 = tm.mkBitVectorSort(32);
 52
 53  // Variables
 54  Term x = tm.mkConst(bitvector32, "x");
 55  Term a = tm.mkConst(bitvector32, "a");
 56  Term b = tm.mkConst(bitvector32, "b");
 57
 58  // First encode the assumption that x must be equal to a or b
 59  Term x_eq_a = tm.mkTerm(Kind::EQUAL, {x, a});
 60  Term x_eq_b = tm.mkTerm(Kind::EQUAL, {x, b});
 61  Term assumption = tm.mkTerm(Kind::OR, {x_eq_a, x_eq_b});
 62
 63  // Assert the assumption
 64  slv.assertFormula(assumption);
 65
 66  // Introduce a new variable for the new value of x after assignment.
 67  Term new_x = tm.mkConst(bitvector32, "new_x");  // x after executing code (0)
 68  Term new_x_ =
 69      tm.mkConst(bitvector32, "new_x_");  // x after executing code (1) or (2)
 70
 71  // Encoding code (0)
 72  // new_x = x == a ? b : a;
 73  Term ite = tm.mkTerm(Kind::ITE, {x_eq_a, b, a});
 74  Term assignment0 = tm.mkTerm(Kind::EQUAL, {new_x, ite});
 75
 76  // Assert the encoding of code (0)
 77  cout << "Asserting " << assignment0 << " to cvc5 " << endl;
 78  slv.assertFormula(assignment0);
 79  cout << "Pushing a new context." << endl;
 80  slv.push();
 81
 82  // Encoding code (1)
 83  // new_x_ = a xor b xor x
 84  Term a_xor_b_xor_x = tm.mkTerm(Kind::BITVECTOR_XOR, {a, b, x});
 85  Term assignment1 = tm.mkTerm(Kind::EQUAL, {new_x_, a_xor_b_xor_x});
 86
 87  // Assert encoding to cvc5 in current context;
 88  cout << "Asserting " << assignment1 << " to cvc5 " << endl;
 89  slv.assertFormula(assignment1);
 90  Term new_x_eq_new_x_ = tm.mkTerm(Kind::EQUAL, {new_x, new_x_});
 91
 92  cout << " Check sat assuming: " << new_x_eq_new_x_.notTerm() << endl;
 93  cout << " Expect UNSAT. " << endl;
 94  cout << " cvc5: " << slv.checkSatAssuming(new_x_eq_new_x_.notTerm()) << endl;
 95  cout << " Popping context. " << endl;
 96  slv.pop();
 97
 98  // Encoding code (2)
 99  // new_x_ = a + b - x
100  Term a_plus_b = tm.mkTerm(Kind::BITVECTOR_ADD, {a, b});
101  Term a_plus_b_minus_x = tm.mkTerm(Kind::BITVECTOR_SUB, {a_plus_b, x});
102  Term assignment2 = tm.mkTerm(Kind::EQUAL, {new_x_, a_plus_b_minus_x});
103
104  // Assert encoding to cvc5 in current context;
105  cout << "Asserting " << assignment2 << " to cvc5 " << endl;
106  slv.assertFormula(assignment2);
107
108  cout << " Check sat assuming: " << new_x_eq_new_x_.notTerm() << endl;
109  cout << " Expect UNSAT. " << endl;
110  cout << " cvc5: " << slv.checkSatAssuming(new_x_eq_new_x_.notTerm()) << endl;
111
112  Term x_neq_x = tm.mkTerm(Kind::EQUAL, {x, x}).notTerm();
113  std::vector<Term> v{new_x_eq_new_x_, x_neq_x};
114  Term query = tm.mkTerm(Kind::AND, {v});
115  cout << " Check sat assuming: " << query.notTerm() << endl;
116  cout << " Expect SAT. " << endl;
117  cout << " cvc5: " << slv.checkSatAssuming(query.notTerm()) << endl;
118
119  // Assert that a is odd
120  Op extract_op = tm.mkOp(Kind::BITVECTOR_EXTRACT, {0, 0});
121  Term lsb_of_a = tm.mkTerm(extract_op, {a});
122  cout << "Sort of " << lsb_of_a << " is " << lsb_of_a.getSort() << endl;
123  Term a_odd = tm.mkTerm(Kind::EQUAL, {lsb_of_a, tm.mkBitVector(1u, 1u)});
124  cout << "Assert " << a_odd << endl;
125  cout << "Check satisfiability." << endl;
126  slv.assertFormula(a_odd);
127  cout << " Expect sat. " << endl;
128  cout << " cvc5: " << slv.checkSat() << endl;
129  return 0;
130}