mirror of
https://github.com/Z3Prover/z3
synced 2025-04-07 01:54:08 +00:00
113 lines
3.5 KiB
OCaml
113 lines
3.5 KiB
OCaml
(*
|
|
queen.exe - JakobL@2007-09-22
|
|
|
|
Demonstration of how Z3 can be used to find solutions to the
|
|
N-Queens problem.
|
|
|
|
See: http://en.wikipedia.org/wiki/Eight_queens_puzzle
|
|
|
|
Problem specification: Is the following constraint system satisfiable,
|
|
for increasing n>=1, what are the models?
|
|
|
|
constant
|
|
n: 8;
|
|
|
|
variable
|
|
row: array n of [0..n-1];
|
|
|
|
rule
|
|
forall i in [0..n-2]:
|
|
(forall j in [i+1..n-1]:
|
|
((row[i] <> row[j]) and
|
|
(i+row[i]) <> (j+row[j]) and
|
|
(i+row[j]) <> (j+row[i])));
|
|
|
|
The answer is yes for n different from 2 and 3. The number of solutions are:
|
|
* n=1: 1
|
|
* n=2: 0
|
|
* n=3: 0
|
|
* n=4: 2
|
|
* n=5: 10
|
|
* n=6: 4
|
|
* n=7: 40
|
|
* n=8: 92
|
|
* n=9: 352
|
|
* n=10: 724
|
|
...
|
|
*)
|
|
|
|
module Z3 = Z3.V3
|
|
|
|
(* Auxillary functions *)
|
|
let ( |> ) x f = f x;;
|
|
let printf = Printf.printf;;
|
|
let mk_var ctx name ty = Z3.mk_const ctx (Z3.mk_int_symbol ctx name) ty;;
|
|
let mk_int_var ctx name = Z3.mk_int_sort ctx |> mk_var ctx name;;
|
|
let mk_int ctx v = Z3.mk_int ctx v (Z3.mk_int_sort ctx);;
|
|
let checkreturn v = match v with | (true,r) -> r | _ -> failwith "checkreturn";;
|
|
let get_numeral_value_int a1 a2 = Z3.get_numeral_int a1 a2 |> checkreturn;;
|
|
let iterate_x lower upper f = for i = lower to upper do f i done;;
|
|
let forall_x ctx lower upper f = Z3.mk_and ctx (Array.init (1+upper-lower) (fun i->f (i+lower)))
|
|
let exist_x ctx lower upper f = Z3.mk_or ctx (Array.init (1+upper-lower) (fun i->f (i+lower)))
|
|
let get_value ctx model f = let (ok, v) = Z3.eval_func_decl ctx model f in (assert ok; v)
|
|
|
|
let queen_n n =
|
|
let ctx = Z3.mk_context_x
|
|
[|("MODEL","true");
|
|
("RELEVANCY","0")|] in
|
|
let ( &&& ) x y = Z3.mk_and ctx [|x;y|] in
|
|
let ( <~> ) x y = Z3.mk_not ctx (Z3.mk_eq ctx x y) in
|
|
let ( <<= ) x y = Z3.mk_le ctx x y in
|
|
let ( +++ ) x y = Z3.mk_add ctx [|x;y|] in
|
|
let row = Array.init n (fun i->mk_int_var ctx i) in
|
|
let c x = mk_int ctx x in (* make constant *)
|
|
let v x = row.(x) in (* make variable *)
|
|
let constraint_domain=forall_x ctx (0) (n-1) (fun x-> ((c 0) <<= (v x)) &&& ((v x) <<= (c (n-1)))) in
|
|
let constraint_queen=
|
|
forall_x ctx (0) (n-2) (fun i->
|
|
forall_x ctx (i+1) (n-1) (fun j->
|
|
((v i) <~> (v j)) &&&
|
|
(((c i)+++(v i)) <~> ((c j)+++(v j))) &&&
|
|
(((c i)+++(v j)) <~> ((c j)+++(v i)))
|
|
)
|
|
) in
|
|
let res = constraint_domain &&& constraint_queen in
|
|
Z3.assert_cnstr ctx res;
|
|
let rec f i =
|
|
(match Z3.check_and_get_model ctx with
|
|
| (Z3.L_FALSE,_) ->
|
|
printf "queen %d, total models: %d\n" n i;
|
|
flush stdout;
|
|
| (Z3.L_UNDEF,_) -> failwith "Z3.L_UNDEF"
|
|
| (Z3.L_TRUE,model) ->
|
|
begin
|
|
let model_constants=Z3.get_model_constants ctx model in
|
|
let vars=Array.map (fun mc->Z3.mk_app ctx mc [||]) model_constants in
|
|
let vals=Array.map (fun mc->get_value ctx model mc |> get_numeral_value_int ctx) model_constants in
|
|
Z3.del_model ctx model;
|
|
|
|
let line = String.make n '-' in
|
|
let q_line i = let r = String.make n ' ' in String.set r i 'Q'; r in
|
|
printf "queen %d, model #%d:\n" n (i+1);
|
|
printf "\n";
|
|
printf " /%s\\\n" line;
|
|
iterate_x 0 (n-1) (fun x->printf " |%s|\n" (q_line (vals.(x))));
|
|
printf " \\%s/\n" line;
|
|
printf "\n";
|
|
flush stdout;
|
|
let negated_model = exist_x ctx 0 (n-1) (fun x->(vars.(x)) <~> (c (vals.(x)))) in
|
|
Z3.assert_cnstr ctx negated_model;
|
|
f (i+1);
|
|
end
|
|
) in
|
|
f 0;
|
|
Z3.del_context ctx;
|
|
();;
|
|
|
|
let queen() =
|
|
for n = 1 to 8 do
|
|
queen_n n
|
|
done;;
|
|
|
|
let _ = queen();;
|