I am striving to find a simple (hello world-like, really) example of using Z3 bindings (z3.h
) in plain C. My primary concern is solving equations (or rather systems thereof) so what I need to see is mainly declaring a variable, setting an assertion, checking, and finally retrieving a variable value.
I am aware of the Z3 example on GitHub but at over 3000 lines it is hardly minimalistic, plus it does not even provide a Makefile
and a naïve compile with gcc
does not work either.
I have been resorting to generating SMT2 code from my C program instead, and running it through z3
in command line, but I'd like to be able to use the bindings. For example this very simple equation: how would I set it up in a C program?
(declare-const x Real) (assert (= (+ (* x 4) 4) 20)) (check-sat) (get-value (x))
Apologies, for providing a non ANSI-C
answer early on.
I generated this by asking ChatGPT to convert the other example to ANSI-C and to replace z3++.h
with z3.h
. This time it required several iterations, and a walk through gdb
, to fix bugs it introduced.
#include <z3.h>
#include <stdio.h>
int main() {
/* Create Z3 context */
Z3_config cfg = Z3_mk_config();
Z3_context c = Z3_mk_context(cfg);
/* Declare a real variable x */
Z3_sort real_sort = Z3_mk_real_sort(c);
Z3_symbol x_symbol = Z3_mk_string_symbol(c, "x");
Z3_ast x = Z3_mk_const(c, x_symbol, real_sort);
/* Create the equation: (+ (* x 4) 4) = 20 */
Z3_solver s = Z3_mk_solver(c);
Z3_ast four = Z3_mk_real(c, 4, 1);
Z3_ast twenty = Z3_mk_real(c, 20, 1);
Z3_ast mul_args[2] = {x, four};
Z3_ast x_times_4 = Z3_mk_mul(c, 2, mul_args);
Z3_ast sum_args[2] = {x_times_4, four};
Z3_ast equation = Z3_mk_add(c, 2, sum_args);
Z3_ast assertion = Z3_mk_eq(c, equation, twenty);
Z3_solver_assert(c, s, assertion);
/* Check satisfiability */
Z3_lbool result = Z3_solver_check(c, s);
if (result == Z3_L_TRUE) {
/* Get the model */
Z3_model m;
m = Z3_solver_get_model(c, s);
/* Get the value of x from the model */
Z3_ast x_value;
Z3_model_eval(c, m, x, Z3_L_TRUE, &x_value);
/* Print the result */
printf("Satisfiable. x = %s\n", Z3_ast_to_string(c, x_value));
} else if (result == Z3_L_FALSE) {
printf("Unsatisfiable.\n");
} else {
printf("Unknown result.\n");
}
/* Clean up */
Z3_del_context(c);
Z3_del_config(cfg);
return 0;
}
Check it is ANSI-C
with option -std=c89
:
~$ gcc test.c -lz3 -std=c89 -Wall -Wextra -Werror -o test.x
~$ ./test.x
Satisfiable. x = 4.0