type boolean = | True | False | Var of int | Not of boolean | And of (boolean*boolean) | Or of (boolean*boolean) | Impl of (boolean*boolean) | Equiv of (boolean*boolean)With this type, (x∧y)⇒x is written Impl(And(Var 0, Var 1),Var 0).
let rec string_of_boolean f = let comp v f1 f2 = (string_of_boolean f1)^v^(string_of_boolean f2) in let par f1 = "("^f1^")" in match f with True -> "True" | False-> "False" | Var i -> "x"^(string_of_int i) | Not f1 -> "~"^(par (string_of_boolean f1)) | And (f1,f2) -> par (comp "/\\" f1 f2) | Or (f1,f2) -> par (comp "\\/" f1 f2) | Impl (f1,f2) -> par (comp "->" f1 f2) | Equiv (f1,f2) -> par (comp "<->" f1 f2)string_of_boolean (Impl(And(Var 0, Var 1),Var 0)) vale "((x0/\\x1)->x0)".
let rec eval and f = match f with True -> true | False -> false | Var i -> List.nth and i | Not f1 -> not (eval and f1) | And (f1,f2) -> (eval and f1) && (eval and f2) | Or (f1,f2) -> (eval and f1) || (eval and f2) | Impl (f1,f2) -> (eval and f2) || (not (eval and f1)) | Equiv (f1,f2) -> (eval and f1)=(eval and f2)For example,
eval [true;false;true] (Impl (Or (And (Var 0,Var 1), Var 2), Impl (Var 2,And (Var 0, Var 1))))is evaluated to false.
To produce the table, first we need to know the number of variables:
let rec maxI f = match f with True -> 0 | False -> 0 | Var i -> i | Not f1 -> (maxI f1) | And (f1,f2) -> max (maxI f1) (maxI f2) | Or (f1,f2) -> max (maxI f1) (maxI f2) | Impl (f1,f2) -> max (maxI f1) (maxI f2) | Equiv (f1,f2) -> max (maxI f1) (maxI f2)Now
let table f = let n = maxI f in (* Compute the number of digits of k *) let rec digit k = if k < 10 then 1 else 1+digit (k/10) in (* Length of a box *) let size = max 5 ((digit n)+1) in (* A bool as a string *) let string_of_bool b = if b then " true" else "false" in (* Indentation for boolean values *) let indent = (String.make (size-5) ' ')^"|" in (* Generation of the table *) let rec gen and k = match k with 0 -> begin List.iter (fun x -> print_string (string_of_bool x); print_string indent) e; print_string (string_of_bool (eval and f)); print_newline(); end | _ -> gen (false::e) (k-1);gen (true::e) (k-1) in (* Separator *) let sep = String.make ((n+2)*(size+1)) '-' in (* Sep *) print_string sep; print_newline(); (* First line *) for i=0 to n do print_string (String.make (max 0 (size-((digit i)+1))) ' '); print_string "x"; print_int i; print_string "|"; done; print_string (string_of_boolean f); print_newline(); (* Sep *) print_string sep; print_newline(); (* Table *) gen [] (n+1); (* Sep *) print_string sep; print_newline()With table (And (Var 0, Var 1)) we have:
------------------ x0| x1|(x0/\x1) ------------------ false|false|false true|false|false false| true|false true| true| true ------------------
let sat f = let n = maxI f in let rec satn and k = match k with 0 -> eval and f | _ -> if (satn (false::e) (k-1)) then true else satn (true::e) (k-1) in satn [] (n+1)
let taut f = let n = maxI f in let rec tautn and k = match k with 0 -> eval and f | _ -> if (tautn (false::e) (k-1)) then (tautn (true::e) (k-1)) else false in tautn [] (n+1)
Every evaluation is ok, the formula is a tautology.
*A8
Give an evaluation of variables that makes the formula
x⇒ (y ⇒ x) false.
There is no such evaluation, the formula is a tautology.
*A9
Give an evaluation of variables that makes the formula
¬y⇒ (x ∧ y) true.
The formula is equivalent to y, so y=true makes it true.
*A10
Give an evaluation of variables that makes the formula
¬y⇒ (x ∧ y) false.
The formula is equivalent to y, so y=false makes it false.
*A11
Give an evaluation of variables that makes the formula
((x⇒ y) ⇒ x) ⇒ x true.
Every evaluation is ok, the formula is a tautology.
*A12
Give an evaluation of variables that makes the formula
((x⇒ y) ⇒ x) ⇒ x false.
There is no such evaluation, the formula is a tautology.
*A13
Give the truth table for the formula (x∨ ¬y) ⇒ (x ∧ y).
x | y | x∨¬y | x∧y | (x∨ ¬y) ⇒ (x ∧ y) |
false | false | true | true | true |
false | true | true | false | false |
true | false | false | false | true |
true | true | true | false | false |
let exactly_one i j n = let rec f k n1 = if (n1=1) then (Not (Var k)) else And (Not (Var k), f (k+j) (n1-1)) in let rec g k n2 = if (n2=1) then (Var k) else And (Impl (Var k, f (k+j) (n2-1)), Impl (Not (Var k), g (k+j) (n2-1))) in g i n
let at_most_one i j n = let rec f k n1 = if (n1=1) then (Not (Var k)) else And (Not (Var k), f (k+j) (n1-1)) in let rec g k n2 = if (n2=2) then Impl (Var k, f (k+j) (n2-1)) else And (Impl (Var k, f (k+j) (n2-1)),Impl (Not (Var k), g (k+j) (n2-1))) in if (n=1) then True else g i n
let gen_rows n = let rec f k n1 = if (n1=1) then exactly_one k 1 n else And(exactly_one k 1 n, f (k+n) (n1-1)) in f 0 n let gen_cols n = let rec f k n1 = if (n1=1) then exactly_one k n n else And(exactly_one k n n, f (k+1) (n1-1)) in f 0 n let gen_diags n = let rec f k n1 = if (n1=1) then at_most_one k (n-1) n else And (And (And (at_most_one k (n+1) n1, at_most_one k (n-1) (n-n1+1)), And (at_most_one (n*n-k-1) (-(n+1)) n1, at_most_one (n*n-k-1) (-(n-1)) (n-n1+1))), f (k+1) (n1-1)) in if (n=1) then True else And (at_most_one 0 (n+1) n, f 1 (n-1)) let chessboard n = if (n<2) then True else And (And (gen_rows n, gen_cols n), gen_diags n)
let rec expand f = match f with Var _ | True | False -> f | And(a,b) -> And(expand a, expand b) | Or(a,b) -> Or(expand a, expand b) | Not a -> Not (expand a) | Impl(a,b) -> Or(Not (expand a),expand b) | Equiv(a,b) -> And (Or(expand a,Not (expand b)),Or(Not (expand a),expand b))
let check_cnf f = let rec only_neg f = match f with True | False | Var _ -> true | Not a -> only_neg a | _ -> false in let rec only_or f = match f with Or(a,b) -> (only_or a) && (only_or b) | _ -> only_neg f in let rec only_and f = match f with And(a,b) -> (only_and a) && (only_and b) | _ -> only_or f in only_and f
let rec push_neg f = match f with Or (a,b) -> Or (push_neg a, push_neg b) | And (a,b) -> And (push_neg a, push_neg b) | Not a -> rpush_neg a | _ -> f and rpush_neg f = match f with Or (a,b) -> And (rpush_neg a, rpush_neg b) | And (a,b) -> Or (rpush_neg a, rpush_neg b) | Not a -> push_neg a | True -> False | False -> True | _ -> Not f
let push_or f = let rec push_rules a b = match (a,b) with And (a1,a2), _ -> And (push_rules a1 b, push_rules a2 b) | _, And (b1,b2) -> And (push_rules a b1, push_rules a b2) | _ -> Or (a,b) in let rec push f = match f with And (a,b) -> And (push a, push b) | Or (a,b) -> push_rules (push a) (push b) | _ -> f in push f
let cnf f = push_or (push_neg (expand f))
(¬x ∨ z) ∧ (y ∨ z).
(* The type of values: true, false, or unknown *) type value = TRUE | FALSE | NONE (* Find the value of a variable inside the list *) let rec get_env and i = match (e,i) with (v::e1), 0 -> v | (v::e1), _ -> get_env e1 (i-1) | [], _ -> NONE (* The type of the result of the evaluation *) type eval = Satisfied | Contradiction | Vars of boolean list let rec eval_disj and f = match f with Var i -> begin match get_env and i with TRUE -> Satisfied | FALSE -> Contradiction | NONE -> Vars [Var i] end | Not (Var i) -> begin match get_env and i with TRUE -> Contradiction | FALSE -> Satisfied | NONE -> Vars [Not (Var i)] end | Or (f1,f2) -> begin match eval_disj and f1 with Satisfied -> Satisfied | Vars l1 -> begin match eval_disj and f2 with Satisfied -> Satisfied | Contradiction -> Vars l1 | Vars l2 -> Vars (List.append l1 l2) end | Contradiction -> eval_disj and f2 end | False -> Contradiction | _ -> Satisfied
let rec eval_conj and f = match f with And (f1, f2) -> begin match eval_conj and f1 with Contradiction -> Contradiction | Satisfied -> eval_conj and f2 | Vars l1 -> begin match eval_conj and f2 with Satisfied -> Vars l1 | Contradiction -> Contradiction | Vars l2 -> Vars (List.append l1 l2) end end | _ -> begin match eval_disj and f with Satisfied -> Satisfied | Contradiction -> Contradiction | Vars [v1] -> Vars [v1] | Vars _ -> Vars [] end
(* Update the list e so that at index i there is the value v Use the option type to say if this update is possible *) let rec set_env e i v = match (e,i) with (NONE::e1), 0 -> Some (v::e1) | (v1::e1), 0 -> if (v1=v) then (Some e) else None | (v1::e1), _ -> begin match (set_env e1 (i-1) v) with None -> None | Some e2 -> Some (v1::e2) end | [], _ -> set_env [NONE] i v (* Given a list build two lists where the first NONE of the initial list is changed with TRUE and FALSE respectively *) let rec split_env e = match e with [] -> [TRUE],[FALSE] | NONE::e1 -> TRUE::e1, FALSE::e1 | v::e1 -> let l1,l2 = split_env e1 in v::l1,v::l2 (* Assign inside e to v the value TRUE *) let set_var e v = match v with (Var i) -> set_env e i TRUE | (Not (Var i)) -> set_env e i FALSE | _ -> Some e (* Assign to all the variables inside l the value TRUE *) let rec set_vars e l = match l with [] -> Some e | v::l1 -> begin match set_var e v with None -> None | Some e1 -> set_vars e1 l1 end let rec davis f = let rec davisn e = match eval_conj e f with Satisfied -> true | Contradiction -> false | Vars [] -> let e1,e2 = split_env e in if (davisn e1) then true else (davisn e2) | Vars l -> begin match set_vars e l with None -> false | Some e1 -> davisn e1 end in davisn []