# # Bitwuzla: Satisfiability Modulo Theories (SMT) solver. # # Copyright (C) 2023 by the authors listed in the AUTHORS file at # https:#github.com/bitwuzla/bitwuzla/blob/main/AUTHORS # # This file is part of Bitwuzla under the MIT license. See COPYING for more # information at https:#github.com/bitwuzla/bitwuzla/blob/main/COPYING ## from bitwuzla import * if __name__ == "__main__": # First, create a term manager instance. tm = TermManager() # Create a Bitwuzla options instance. options = Options() # Then, enable model generation. options.set(Option.PRODUCE_MODELS, True) # Now, for illustration purposes, we enable CaDiCaL as SAT solver # (CaDiCaL is already configured by default). # Note: This will silently fall back to one of the compiled in SAT solvers # if the selected solver is not compiled in. options.set(Option.SAT_SOLVER, 'cadical') # Then, create a Bitwuzla instance. bitwuzla = Bitwuzla(tm, options) # Create bit-vector sorts of size 4 and 8. sortbv4 = tm.mk_bv_sort(4) sortbv8 = tm.mk_bv_sort(8) # Create function sort. sortfun = tm.mk_fun_sort([sortbv8, sortbv4], sortbv8) # Create array sort. sortarr = tm.mk_array_sort(sortbv8, sortbv8) # Create two bit-vector constants of that sort. x = tm.mk_const(sortbv8, "x") y = tm.mk_const(sortbv8, "y") # Create fun const. f = tm.mk_const(sortfun, "f") # Create array const. a = tm.mk_const(sortarr, "a") # Create bit-vector values one and two of the same sort. one = tm.mk_bv_one(sortbv8) # Alternatively, you can create bit-vector value one with: # one = tm.mk_bv_value(sortbv8, "1", 2) # one = tm.mk_bv_value(sortbv8, 1) two = tm.mk_bv_value(sortbv8, 2) # (bvsdiv x (_ bv2 8)) sdiv = tm.mk_term(Kind.BV_SDIV, [x, two]) # (bvashr y (_ bv1 8)) ashr = tm.mk_term(Kind.BV_ASHR, [y, one]) # ((_ extract 3 0) (bvsdiv x (_ bv2 8))) sdive = tm.mk_term(Kind.BV_EXTRACT, [sdiv], [3, 0]) # ((_ extract 3 0) (bvashr x (_ bv1 8))) ashre = tm.mk_term(Kind.BV_EXTRACT, [ashr], [3, 0]) # (assert # (distinct # ((_ extract 3 0) (bvsdiv x (_ bv2 8))) # ((_ extract 3 0) (bvashr y (_ bv1 8))))) bitwuzla.assert_formula(tm.mk_term(Kind.DISTINCT, [sdive, ashre])) # (assert (= (f x ((_ extract 6 3) x)) y)) bitwuzla.assert_formula(tm.mk_term( Kind.EQUAL, [tm.mk_term(Kind.APPLY, [f, x, tm.mk_term(Kind.BV_EXTRACT, [x], [6, 3])]), y])) # (assert (= (select a x) y)) bitwuzla.assert_formula( tm.mk_term(Kind.EQUAL, [tm.mk_term(Kind.ARRAY_SELECT, [a, x]), y])) # (check-sat) result = bitwuzla.check_sat() print('Expect: sat') print(f'Bitwuzla: {result}') # Print model in SMT-LIBv2 format. print('Model:\n(') for term in [x, y, f, a]: sort = term.sort() symbol = term.symbol() print(f' (define-fun {symbol if symbol else "@t" + term.id()} (', end = '') if sort.is_fun(): value = bitwuzla.get_value(term) assert value.kind() == Kind.LAMBDA assert value.num_children() == 2 while value[1].kind() == Kind.LAMBDA: assert value[0].is_variable() print(f'({value[0]} {value[0].sort()}) ', end = '') value = value[1] assert value[0].is_variable() print(f'({value[0]} {value[0].sort()})) ' \ + f'{sort.fun_codomain()} {value[1]})') else: print(f') {sort} {bitwuzla.get_value(term)})') print(')') print() # Print value for x, y, f and a. # Both x and y are bit-vector terms and their value is a bit-vector # value that can be printed via Term.value(). print(f'value of x: {bitwuzla.get_value(x).value(2)}') print(f'value of y: {bitwuzla.get_value(y).value(2)}') print() # f and a, on the other hand, are a function and array term, respectively. # The value of these terms is not a value term: for f, it is a lambda term, # and the value of a is represented as a store term. Thus we cannot use # Term.value(), but we can print the value of the terms via Term.str(). print('str() representation of value of f:') print(bitwuzla.get_value(f)) print() print('str() representation of value of a:') print(bitwuzla.get_value(a)) print() # Note that the assignment string of bit-vector terms is given as the # pure assignment string, either in binary, hexadecimal or decimal format, # whereas Term.str() prints the value in SMT-LIB2 format (in the given # bit-vector output number format, binary by default). print(f'str() representation of value of x: {bitwuzla.get_value(x)}') print(f'str() representation of value of y: {bitwuzla.get_value(y)}') print() # Query value of bit-vector term that does not occur in the input formula v = bitwuzla.get_value(tm.mk_term(Kind.BV_MUL, [x, x])) print(f'value of v = x * x: {v.value(2)}')