static void tst_get_implied_equalities1() {
    Z3_config cfg = Z3_mk_config();
    Z3_context ctx = Z3_mk_context(cfg);
    Z3_del_config(cfg);
    Z3_sort int_ty = Z3_mk_int_sort(ctx);
    Z3_ast a = mk_int_var(ctx,"a");
    Z3_ast b = mk_int_var(ctx,"b");
    Z3_ast c = mk_int_var(ctx,"c");
    Z3_ast d = mk_int_var(ctx,"d");
    Z3_func_decl f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx,"f"), 1, &int_ty, int_ty);
    Z3_ast fa = Z3_mk_app(ctx, f, 1, &a);
    Z3_ast fb = Z3_mk_app(ctx, f, 1, &b);
    Z3_ast fc = Z3_mk_app(ctx, f, 1, &c);
    unsigned const num_terms = 7;
    unsigned i;
    Z3_ast terms[7] = { a, b, c, d, fa, fb, fc };
    unsigned class_ids[7] = { 0, 0, 0, 0, 0, 0, 0 };
    Z3_solver solver = Z3_mk_simple_solver(ctx);
    Z3_solver_inc_ref(ctx, solver);
        
    Z3_solver_assert(ctx, solver, Z3_mk_eq(ctx, a, b));
    Z3_solver_assert(ctx, solver, Z3_mk_eq(ctx, b, d));
    Z3_solver_assert(ctx, solver, Z3_mk_le(ctx, fa, fc));
    Z3_solver_assert(ctx, solver, Z3_mk_le(ctx, fc, d));
    
    Z3_get_implied_equalities(ctx, solver, num_terms, terms, class_ids);
    for (i = 0; i < num_terms; ++i) {
        printf("Class %s |-> %d\n", Z3_ast_to_string(ctx, terms[i]), class_ids[i]);
    }
    SASSERT(class_ids[1] == class_ids[0]);
    SASSERT(class_ids[2] != class_ids[0]);
    SASSERT(class_ids[3] == class_ids[0]);
    SASSERT(class_ids[4] != class_ids[0]);
    SASSERT(class_ids[5] != class_ids[0]);
    SASSERT(class_ids[6] != class_ids[0]);
    SASSERT(class_ids[4] == class_ids[5]);

    printf("asserting b <= f(a)\n");
    Z3_solver_assert(ctx, solver, Z3_mk_le(ctx, b, fa));
    Z3_get_implied_equalities(ctx, solver, num_terms, terms, class_ids);
    for (i = 0; i < num_terms; ++i) {
        printf("Class %s |-> %d\n", Z3_ast_to_string(ctx, terms[i]), class_ids[i]);
    }
    SASSERT(class_ids[1] == class_ids[0]);
    SASSERT(class_ids[2] != class_ids[0]);
    SASSERT(class_ids[3] == class_ids[0]);
    SASSERT(class_ids[4] == class_ids[0]);
    SASSERT(class_ids[5] == class_ids[0]);
    SASSERT(class_ids[6] == class_ids[0]);

    
    Z3_solver_dec_ref(ctx, solver);
    /* delete logical context */
    Z3_del_context(ctx);    
}
Beispiel #2
0
/**
   \brief Create a counter circuit to count the number of "ones" in lits.
   The function returns an array of bits (i.e. boolean expressions) containing the output of the circuit.
   The size of the array is stored in out_sz.
*/
Z3_ast * mk_counter_circuit(Z3_context ctx, unsigned n, Z3_ast * lits, unsigned * out_sz) 
{
    unsigned num_ins  = n;
    unsigned num_bits = 1;
    Z3_ast * aux_1;
    Z3_ast * aux_2;
    if (n == 0)
        return 0;
    aux_1    = (Z3_ast *) malloc(sizeof(Z3_ast) * (n + 1)); 
    aux_2    = (Z3_ast *) malloc(sizeof(Z3_ast) * (n + 1)); 
    memcpy(aux_1, lits, sizeof(Z3_ast) * n);
    while (num_ins > 1) {
        unsigned new_num_ins;
        Z3_ast * tmp;
        mk_adder_pairs(ctx, num_bits, num_ins, aux_1, &new_num_ins, aux_2);
        num_ins = new_num_ins;
        num_bits++;
#ifdef MAXSAT_DEBUG
        {
            unsigned i;
            printf("num_bits: %d, num_ins: %d \n", num_bits, num_ins);
            for (i = 0; i < num_ins * num_bits; i++) {
                printf("bit %d:\n%s\n", i, Z3_ast_to_string(ctx, aux_2[i]));
            }
            printf("-----------\n");
        }
#endif
        tmp   = aux_1;
        aux_1 = aux_2;
        aux_2 = tmp;
    }
    *out_sz = num_bits;
    free(aux_2);
    return aux_1;
}
Beispiel #3
0
string Z3Expr::ToString(u32 Verbosity) const
{
    if (Ctx != Z3Ctx::NullPtr && AST != nullptr) {
        return Z3_ast_to_string(*Ctx, AST);
    } else {
        return "nullexpr";
    }
}
Beispiel #4
0
int find_core_assumption_index(Z3_context ctx, Z3_ast * assumptions, unsigned n, Z3_ast p){

  int i;

  for(i=0;i<n;i++){
    if ( Z3_is_eq_ast(ctx,assumptions[i],p) )
      return i;
  }
  
  fprintf(stderr,"BUG: find_core_assumption_index. \n");
  fprintf(stderr," %s not found\n",Z3_ast_to_string(ctx, p));
  for(i=0;i<n;i++){
    fprintf(stderr," %s | ",Z3_ast_to_string(ctx,assumptions[i]));
  }
  fprintf(stderr,"\n");
  exit(1);
}
 string Z3Expr::ToString() const
 {
     if (Ctx != nullptr && AST != nullptr) {
         return string(Z3_ast_to_string(Ctx, AST));
     } else {
         throw InternalError((string)"ToString() called on null Z3Expr object");
     }
 }
static void tst_get_implied_equalities2() {
    enable_trace("after_search");
    enable_trace("get_implied_equalities");
    enable_trace("implied_equalities");
    Z3_config cfg = Z3_mk_config();
    Z3_context ctx = Z3_mk_context(cfg);
    Z3_del_config(cfg);
    Z3_solver solver = Z3_mk_simple_solver(ctx);
    Z3_solver_inc_ref(ctx, solver);
    Z3_sort int_ty = Z3_mk_int_sort(ctx);
    Z3_ast a = mk_int_var(ctx,"a");
    Z3_ast b = mk_int_var(ctx,"b");
    Z3_ast one = Z3_mk_numeral(ctx, "1", int_ty);
    Z3_ast two = Z3_mk_numeral(ctx, "2", int_ty);
    Z3_ast x = Z3_mk_const_array(ctx, int_ty, one);
    Z3_ast y = Z3_mk_store(ctx, x, one, a);
    Z3_ast z = Z3_mk_store(ctx, y, two , b);
    Z3_ast u = Z3_mk_store(ctx, x, two , b);
    Z3_ast v = Z3_mk_store(ctx, u, one , a);
    unsigned const num_terms = 5;
    unsigned i;
    Z3_ast terms[5] = { x, y, z, u, v};
    unsigned class_ids[5] = { 0, 0, 0, 0, 0};
    
    Z3_get_implied_equalities(ctx, solver, num_terms, terms, class_ids);
    for (i = 0; i < num_terms; ++i) {
        printf("Class %s |-> %d\n", Z3_ast_to_string(ctx, terms[i]), class_ids[i]);
    }

    SASSERT(class_ids[1] != class_ids[0]);
    SASSERT(class_ids[2] != class_ids[0]);
    SASSERT(class_ids[3] != class_ids[0]);
    SASSERT(class_ids[4] != class_ids[0]);
    SASSERT(class_ids[4] == class_ids[2]);
    SASSERT(class_ids[2] != class_ids[1]);
    SASSERT(class_ids[3] != class_ids[1]);
    SASSERT(class_ids[4] != class_ids[1]);  
    SASSERT(class_ids[3] != class_ids[2]);

    /* delete logical context */
    Z3_solver_dec_ref(ctx, solver);
    Z3_del_context(ctx);    
}
void get_function(z3_wrapper *z3, Z3_func_decl fun, uint32_t fun_arity, struct fun *kfun) {
  Z3_model m = Z3_solver_get_model(z3->ctx, z3->solver);
  assert(m);
  
  /* printf("------\n%s\n------\n", Z3_model_to_string(z3->ctx, m)); */
  
  Z3_model_inc_ref(z3->ctx, m);
  
  fun_init(kfun, fun_arity);
  for(size_t xs = 0; xs < int_pow(K, fun_arity); ++xs) {
    /* represent `xs` in the K-ary form,
     * with digits[0] being the highest digit. */
    uint32_t digits[fun_arity];
    get_K_digits(digits, fun_arity, xs);
    Z3_ast args[fun_arity];
    for(size_t i = 0; i < fun_arity; ++i) {
      args[i] = z3->Ek_consts[digits[i]];
    }
    
    /* eval func on given args */
    Z3_ast t = Z3_mk_app(z3->ctx, fun, fun_arity, args);
    Z3_ast res;
 
    assert(Z3_model_eval(z3->ctx, m, t, 1, &res) == Z3_TRUE);


    /* printf("%s == %s\n", Z3_ast_to_string(z3->ctx, t), Z3_ast_to_string(z3->ctx, res)); */
    
    /* interpret the result of function application */
    uint64_t y;
    sscanf(Z3_ast_to_string(z3->ctx, res), "V%lu", &y);
    fun_set_val(kfun, xs, y);
  }
  
  Z3_model_dec_ref(z3->ctx, m);
}
Beispiel #8
0
int main(int argc, const char **argv) {

  /* Create a Z3 context to contain formulas */

  Z3_config cfg = Z3_mk_config();
  Z3_context ctx = iz3_mk_context(cfg);
  Z3_set_error_handler(ctx, throw_z3_error);
    
  /* Make some constraints, by parsing an smtlib formatted file given as arg 1 */

  try {
    Z3_parse_smtlib_file(ctx, argv[1], 0, 0, 0, 0, 0, 0);
  }
  catch(const z3_error &err){
    std::cerr << "Z3 error: " << Z3_get_error_msg(err.c) << "\n";
    std::cerr << Z3_get_smtlib_error(ctx) << "\n";
    return(1);
  } 

  /* Get the constraints from the parser. */

  int num = Z3_get_smtlib_num_formulas(ctx);

  if(num == 0){
    std::cerr << "iZ3 error: File contains no formulas.\n";
    return 1;
  }


  Z3_ast *constraints = (Z3_ast *)malloc(num * sizeof(Z3_ast));

  int i;
  for (i = 0; i < num; i++)
    constraints[i] = Z3_get_smtlib_formula(ctx, i);

  /* if we get only one formula, and it is a conjunction, split it into conjuncts. */
  if(num == 1){
    Z3_app app = Z3_to_app(ctx,constraints[0]);
    Z3_func_decl func = Z3_get_app_decl(ctx,app);
    Z3_decl_kind dk = Z3_get_decl_kind(ctx,func);
    if(dk == Z3_OP_AND){
      int nconjs = Z3_get_app_num_args(ctx,app);
      if(nconjs > 1){
	std::cout << "Splitting formula into " << nconjs << " conjuncts...\n";
	num = nconjs;
	constraints = new Z3_ast[num];
	for(int k = 0; k < num; k++)
	  constraints[k] = Z3_get_app_arg(ctx,app,k);
      }
    }
  }


  /* print out the result for grins. */

  // Z3_string smtout = Z3_benchmark_to_smtlib_string (ctx, "foo", "QFLIA", "sat", "", num, constraints, Z3_mk_true(ctx));

  // Z3_string smtout = Z3_ast_to_string(ctx,constraints[0]);
  // Z3_string smtout = Z3_context_to_string(ctx);
  // puts(smtout);

  // iz3_print(ctx,num,constraints,"iZ3temp.smt");

  /* Make room for interpolants. */

  Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast));

  /* Make room for the model. */

  Z3_model model = 0;

  /* Call the prover */

  Z3_lbool result = iz3_interpolate(ctx, num, constraints, interpolants, &model);

  switch (result) {
  
    /* If UNSAT, print the interpolants */
  case Z3_L_FALSE:
    printf("unsat, interpolants:\n");
    for(i = 0; i < num-1; i++)
      printf("%s\n", Z3_ast_to_string(ctx, interpolants[i]));
    std::cout << "Checking interpolants...\n";
    const char *error;
    if(iZ3_check_interpolant(ctx, num, constraints, 0, interpolants, &error))
      std::cout << "Interpolant is correct\n";
    else {
      std::cout << "Interpolant is incorrect\n";
      std::cout << error << "\n";
    }
    break;
  case Z3_L_UNDEF:
    printf("fail\n");
    break;
  case Z3_L_TRUE:
    printf("sat\n");
    printf("model:\n%s\n", Z3_model_to_string(ctx, model));
    break;
  }

  /* Delete the model if there is one */
  
  if (model)
    Z3_del_model(ctx, model);
  
  /* Delete logical context (note, we call iz3_del_context, not
     Z3_del_context */

  iz3_del_context(ctx);

  return 0;
}
Beispiel #9
0
int main(int argc, const char **argv) {
    
  bool tree_mode = false;
  bool check_mode = false;
  bool profile_mode = false;
  bool incremental_mode = false;
  std::string output_file;
  bool flat_mode = false;
  bool anonymize = false;
  bool write = false;

  Z3_config cfg = Z3_mk_config();
  // Z3_interpolation_options options = Z3_mk_interpolation_options();
  Z3_params options = 0;

  /* Parse the command line */
  int argn = 1;
  while(argn < argc-1){
    std::string flag = argv[argn];
    if(flag[0] == '-'){
      if(flag == "-t" || flag == "--tree")
	tree_mode = true;
      else if(flag == "-c" || flag == "--check")
	check_mode = true;
      else if(flag == "-p" || flag == "--profile")
	profile_mode = true;
#if 0
      else if(flag == "-w" || flag == "--weak")
        Z3_set_interpolation_option(options,"weak","1");
      else if(flag == "--secondary")
        Z3_set_interpolation_option(options,"secondary","1");
#endif
      else if(flag == "-i" || flag == "--incremental")
        incremental_mode = true;
      else if(flag == "-o"){
        argn++;
        if(argn >= argc) return usage(argv);
        output_file = argv[argn];
      }
      else if(flag == "-f" || flag == "--flat")
        flat_mode = true;
      else if(flag == "-a" || flag == "--anon")
        anonymize = true;
      else if(flag == "-w" || flag == "--write")
        write = true;
      else if(flag == "-s" || flag == "--simple")
        Z3_set_param_value(cfg,"PREPROCESS","false");
      else
        return usage(argv);
    }
    argn++;
  }
  if(argn != argc-1)
    return usage(argv);
  const char *filename = argv[argn];


  /* Create a Z3 context to contain formulas */
  Z3_context ctx = Z3_mk_interpolation_context(cfg);

  if(write || anonymize)
    Z3_set_ast_print_mode(ctx,Z3_PRINT_SMTLIB2_COMPLIANT);
  else if(!flat_mode)
    Z3_set_ast_print_mode(ctx,Z3_PRINT_SMTLIB_COMPLIANT);
  
  /* Read an interpolation problem */

  unsigned num;
  Z3_ast *constraints;
  unsigned *parents = 0;
  const char *error;
  bool ok;
  unsigned num_theory;
  Z3_ast *theory;

  ok = Z3_read_interpolation_problem(ctx, &num, &constraints, tree_mode ? &parents : 0, filename, &error, &num_theory, &theory);

  /* If parse failed, print the error message */

  if(!ok){
    std::cerr << error << "\n";
    return 1;
  }

  /* if we get only one formula, and it is a conjunction, split it into conjuncts. */
  if(!tree_mode && num == 1){
    Z3_app app = Z3_to_app(ctx,constraints[0]);
    Z3_func_decl func = Z3_get_app_decl(ctx,app);
    Z3_decl_kind dk = Z3_get_decl_kind(ctx,func);
    if(dk == Z3_OP_AND){
      int nconjs = Z3_get_app_num_args(ctx,app);
      if(nconjs > 1){
	std::cout << "Splitting formula into " << nconjs << " conjuncts...\n";
	num = nconjs;
	constraints = new Z3_ast[num];
	for(int k = 0; k < num; k++)
	  constraints[k] = Z3_get_app_arg(ctx,app,k);
      }
    }
  }

  /* Write out anonymized version. */

  if(write || anonymize){
#if 0
    Z3_anonymize_ast_vector(ctx,num,constraints);
#endif
    std::string ofn = output_file.empty() ? "iz3out.smt2" : output_file;
    Z3_write_interpolation_problem(ctx, num, constraints, parents, ofn.c_str(), num_theory,  theory);
    std::cout << "anonymized problem written to " << ofn << "\n";
    exit(0);
  }

  /* Compute an interpolant, or get a model. */

  Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast));
  Z3_model model = 0;
  Z3_lbool result;

  if(!incremental_mode){
    /* In non-incremental mode, we just pass the constraints. */
      result = Z3_L_UNDEF; // FIXME: Z3_interpolate(ctx, num, constraints, parents,  options, interpolants, &model, 0, false, num_theory, theory);
  }
  else {

    /* This is a somewhat useless demonstration of incremental mode.
      Here, we assert the constraints in the context, then pass them to
      iZ3 in an array, so iZ3 knows the sequence. Note it's safe to pass
      "true", even though we haven't techically asserted if. */

    Z3_push(ctx);
    std::vector<Z3_ast> asserted(num);

    /* We start with nothing asserted. */
    for(int i = 0; i < num; i++)
      asserted[i] = Z3_mk_true(ctx);

    /* Now we assert the constrints one at a time until UNSAT. */

    for(int i = 0; i < num; i++){
      asserted[i] = constraints[i];
      Z3_assert_cnstr(ctx,constraints[i]);  // assert one constraint
      result = Z3_L_UNDEF; // FIXME: Z3_interpolate(ctx, num, &asserted[0], parents,  options, interpolants, &model, 0, true, 0, 0);
      if(result == Z3_L_FALSE){
	for(unsigned j = 0; j < num-1; j++)
          /* Since we want the interpolant formulas to survive a "pop", we
            "persist" them here. */
          Z3_persist_ast(ctx,interpolants[j],1);
        break;
      }
    }
    Z3_pop(ctx,1);
  }
  
  switch (result) {
  
    /* If UNSAT, print the interpolants */
  case Z3_L_FALSE:
    printf("unsat\n");
    if(output_file.empty()){
      printf("interpolant:\n");
      for(int i = 0; i < num-1; i++)
        printf("%s\n", Z3_ast_to_string(ctx, interpolants[i]));
    }
    else {
#if 0
      Z3_write_interpolation_problem(ctx,num-1,interpolants,0,output_file.c_str());
      printf("interpolant written to %s\n",output_file.c_str());
#endif
    }
#if 1
    if(check_mode){
      std::cout << "Checking interpolant...\n";
      bool chk;
      chk = Z3_check_interpolant(ctx,num,constraints,parents,interpolants,&error,num_theory,theory);  
      if(chk)
	std::cout << "Interpolant is correct\n";
      else {
        std::cout << "Interpolant is incorrect\n";
        std::cout << error;
        return 1;
      }
    }
#endif
    break;
  case Z3_L_UNDEF:
    printf("fail\n");
    break;
  case Z3_L_TRUE:
    printf("sat\n");
    printf("model:\n%s\n", Z3_model_to_string(ctx, model));
    break;
  }

  if(profile_mode)
    std::cout << Z3_interpolation_profile(ctx);

  /* Delete the model if there is one */
  
  if (model)
    Z3_del_model(ctx, model);
  
  /* Delete logical context. */

  Z3_del_context(ctx);
  free(interpolants);

  return 0;
}
Beispiel #10
0
int test(){
  int i;

  /* Create a Z3 context to contain formulas */

  Z3_config cfg = Z3_mk_config();
  Z3_context ctx = iz3_mk_context(cfg);
    
  int num = 2;

  Z3_ast *constraints = (Z3_ast *)malloc(num * sizeof(Z3_ast));

#if 1
  Z3_sort arr = Z3_mk_array_sort(ctx,Z3_mk_int_sort(ctx),Z3_mk_bool_sort(ctx)); 
  Z3_symbol  as  = Z3_mk_string_symbol(ctx, "a");
  Z3_symbol  bs  = Z3_mk_string_symbol(ctx, "b");
  Z3_symbol  xs  = Z3_mk_string_symbol(ctx, "x");

  Z3_ast a = Z3_mk_const(ctx,as,arr);
  Z3_ast b = Z3_mk_const(ctx,bs,arr);
  Z3_ast x = Z3_mk_const(ctx,xs,Z3_mk_int_sort(ctx));
  
  Z3_ast c1 = Z3_mk_eq(ctx,a,Z3_mk_store(ctx,b,x,Z3_mk_true(ctx)));
  Z3_ast c2 = Z3_mk_not(ctx,Z3_mk_select(ctx,a,x));
#else
  Z3_symbol  xs  = Z3_mk_string_symbol(ctx, "x");
  Z3_ast x = Z3_mk_const(ctx,xs,Z3_mk_bool_sort(ctx));
  Z3_ast c1 = Z3_mk_eq(ctx,x,Z3_mk_true(ctx));
  Z3_ast c2 = Z3_mk_eq(ctx,x,Z3_mk_false(ctx));

#endif

  constraints[0] = c1;
  constraints[1] = c2;
  
  /* print out the result for grins. */

  // Z3_string smtout = Z3_benchmark_to_smtlib_string (ctx, "foo", "QFLIA", "sat", "", num, constraints, Z3_mk_true(ctx));

  // Z3_string smtout = Z3_ast_to_string(ctx,constraints[0]);
  // Z3_string smtout = Z3_context_to_string(ctx);
  // puts(smtout);

  iz3_print(ctx,num,constraints,"iZ3temp.smt");

  /* Make room for interpolants. */

  Z3_ast *interpolants = (Z3_ast *)malloc((num-1) * sizeof(Z3_ast));

  /* Make room for the model. */

  Z3_model model = 0;

  /* Call the prover */

  Z3_lbool result = iz3_interpolate(ctx, num, constraints, interpolants, &model);

  switch (result) {
  
    /* If UNSAT, print the interpolants */
  case Z3_L_FALSE:
    printf("unsat, interpolants:\n");
    for(i = 0; i < num-1; i++)
      printf("%s\n", Z3_ast_to_string(ctx, interpolants[i]));
    break;
  case Z3_L_UNDEF:
    printf("fail\n");
    break;
  case Z3_L_TRUE:
    printf("sat\n");
    printf("model:\n%s\n", Z3_model_to_string(ctx, model));
    break;
  }

  /* Delete the model if there is one */
  
  if (model)
    Z3_del_model(ctx, model);
  
  /* Delete logical context (note, we call iz3_del_context, not
     Z3_del_context */

  iz3_del_context(ctx);

  return 1;
}
Beispiel #11
0
 Z3_API char const * Z3_pattern_to_string(Z3_context c, Z3_pattern p) {
     return Z3_ast_to_string(c, reinterpret_cast<Z3_ast>(p));
 }
Beispiel #12
0
char * term_to_string(SOLVER_CONTEXT ctx, SOLVER_TERM term){
  return Z3_ast_to_string((Z3_context) ctx, (Z3_ast) term);
}
Beispiel #13
0
static void ev_const(Z3_context ctx, Z3_ast e) {
    Z3_ast r = Z3_simplify(ctx, e);
    TRACE("simplifier", 
          tout << Z3_ast_to_string(ctx, e) << " -> ";
          tout << Z3_ast_to_string(ctx, r) << "\n";);
    void test_smt_relation_api() {

        enable_trace("smt_relation");
        enable_trace("smt_relation2");
        enable_trace("quant_elim");
        Z3_config cfg = Z3_mk_config();
        Z3_set_param_value(cfg, "DL_DEFAULT_RELATION", "smt_relation2");
        Z3_context ctx = Z3_mk_context(cfg);
        Z3_fixedpoint dl = Z3_mk_fixedpoint(ctx);
        Z3_fixedpoint_inc_ref(ctx,dl);
        Z3_del_config(cfg);

        Z3_sort int_sort = Z3_mk_int_sort(ctx);
        Z3_sort bool_sort = Z3_mk_bool_sort(ctx);
        Z3_func_decl nil_decl, is_nil_decl;
        Z3_func_decl cons_decl, is_cons_decl, head_decl, tail_decl;

        Z3_sort list = Z3_mk_list_sort(
            ctx, 
            Z3_mk_string_symbol(ctx, "list"),
            int_sort, 
            &nil_decl,
            &is_nil_decl,
            &cons_decl,
            &is_cons_decl,
            &head_decl,
            &tail_decl);

        Z3_sort listint[2] = { list, int_sort };
        Z3_symbol p_sym = Z3_mk_string_symbol(ctx, "p");
        Z3_symbol q_sym = Z3_mk_string_symbol(ctx, "q");


        Z3_func_decl p = Z3_mk_func_decl(ctx, p_sym, 2, listint, bool_sort);
        Z3_func_decl q = Z3_mk_func_decl(ctx, q_sym, 2, listint, bool_sort);
        Z3_fixedpoint_register_relation(ctx, dl, p);
        Z3_fixedpoint_register_relation(ctx, dl, q);


        Z3_ast zero = Z3_mk_numeral(ctx, "0", int_sort);
        Z3_ast one  = Z3_mk_numeral(ctx, "1", int_sort);
        Z3_ast two  = Z3_mk_numeral(ctx, "2", int_sort);
        Z3_ast x = Z3_mk_bound(ctx, 0, list);
        Z3_ast y = Z3_mk_bound(ctx, 1, int_sort);
        Z3_ast z = Z3_mk_bound(ctx, 2, list);
        Z3_ast zero_x[2] = { zero, x };
        Z3_ast fx = Z3_mk_app(ctx, cons_decl, 2, zero_x);
        Z3_ast zero_fx[2] = { zero, fx };
        Z3_ast ffx = Z3_mk_app(ctx, cons_decl, 2, zero_fx);
        Z3_ast xy[2] = { x, y };
        Z3_ast zy[2] = { z, y };
        // Z3_ast ffxy[2] = { ffx, y };
        // Z3_ast fxy[2] = { fx, y };
        Z3_ast zero_nil[2] = { zero, Z3_mk_app(ctx, nil_decl, 0, 0) };
        Z3_ast f0 = Z3_mk_app(ctx, cons_decl, 2, zero_nil);
        Z3_ast zero_f0[2] = { zero, f0 };
        Z3_ast f1 = Z3_mk_app(ctx, cons_decl, 2, zero_f0);
        Z3_ast zero_f1[2] = { zero, f1 };
        Z3_ast f2 = Z3_mk_app(ctx, cons_decl, 2, zero_f1);
        Z3_ast zero_f2[2] = { zero, f2 };
        Z3_ast f3 = Z3_mk_app(ctx, cons_decl, 2, zero_f2);
        Z3_ast zero_f3[2] = { zero, f3 };
        Z3_ast f4 = Z3_mk_app(ctx, cons_decl, 2, zero_f3);
        Z3_ast zero_f4[2] = { zero, f4 };
        Z3_ast f5 = Z3_mk_app(ctx, cons_decl, 2, zero_f4);
        Z3_ast zero_z[2] = { zero, z };
        Z3_ast fz = Z3_mk_app(ctx, cons_decl, 2, zero_z);
        
        Z3_ast pxy = Z3_mk_app(ctx, p, 2, xy);
        Z3_ast pzy    = Z3_mk_app(ctx, p, 2, zy);
        Z3_ast qxy = Z3_mk_app(ctx, q, 2, xy);
        Z3_ast qzy = Z3_mk_app(ctx, q, 2, zy);
        Z3_ast even_y = Z3_mk_eq(ctx, zero, Z3_mk_mod(ctx, y, two)); 
        Z3_ast odd_y  = Z3_mk_eq(ctx, one, Z3_mk_mod(ctx, y, two));
        

        // p(x, y) :- odd(y), p(z,y), f(z) = x . // dead rule.
        // q(x, y) :- p(f(f(x)), y).
        // p(x, y) :- q(f(x), y)                 // x decreases
        // p(x, y) :- even y, x = f^5(0)         // initial condition.

        Z3_ast body1[3] = { pzy, Z3_mk_eq(ctx, fz, x), odd_y };
        Z3_ast body2[2] = { pzy, Z3_mk_eq(ctx, ffx, z) };
        Z3_ast body3[2] = { qzy, Z3_mk_eq(ctx, fx, z) };
        Z3_ast body4[2] = { even_y, Z3_mk_eq(ctx, x, f5) };
        Z3_fixedpoint_add_rule(ctx, dl, Z3_mk_implies(ctx, Z3_mk_and(ctx, 3, body1), pxy), 0);
        Z3_fixedpoint_add_rule(ctx, dl, Z3_mk_implies(ctx, Z3_mk_and(ctx, 2, body2), qxy), 0);
        Z3_fixedpoint_add_rule(ctx, dl, Z3_mk_implies(ctx, Z3_mk_and(ctx, 2, body3), pxy), 0);
        Z3_fixedpoint_add_rule(ctx, dl, Z3_mk_implies(ctx, Z3_mk_and(ctx, 2, body4), pxy), 0);

        Z3_lbool r = Z3_fixedpoint_query(ctx, dl, pxy);
        if (r != Z3_L_UNDEF) {
            std::cout << Z3_ast_to_string(ctx, Z3_fixedpoint_get_answer(ctx, dl)) << "\n";
        }

        Z3_del_context(ctx);

    }