Theory of Bit-Vectors

examples/api/cpp/bitvectors.cpp

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