z3ansi-c

Example equation solution with Z3 in GNU/ANSI-C


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))

Solution

  • 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