summaryrefslogtreecommitdiff
path: root/lib/satisfiability/satisfiable.ml
blob: 6eccc273dfc3e677b608c043e3b812d7c82ee937 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
(* Find a satisfying interpretation via brute force *)

open Types
open Lib_utils

(* lazy list *)
type 'a seq = Nil | Cons of 'a * (unit -> 'a seq)

let head = function
  | Nil -> None
  | Cons(x, _) -> Some x

let tail = function
  | Nil -> None
  | Cons(_, tl) -> Some tl

let rec get k s =
  match k, s with
  | 0, _ -> []
  | _, Nil -> []
  | k, Cons(x, f) -> x :: get (k - 1) (f ())

(* Find all the literals in a formula *)
let extract_symbols (prop : proposition) =
  let rec search prop acc =
    match prop with
    | True -> acc
    | False -> acc
    | Lit s -> Lit s :: acc
    | Not p -> search p acc
    | And(p1, p2) -> search p1 (search p2 acc)
    | Or(p1, p2) -> search p1 (search p2 acc)
    | Implies(p1, p2) -> search p1 (search p2 acc)
    | Iff(p1, p2) -> search p1 (search p2 acc)
  in
  search prop []

(* Generate all possible truth assignments for a list of symbols *)
let rec generate_truth_vals symbols =
  let rec prepend_all x llist = (* prepend x to each item in the lazy list *)
    match llist with
    | Nil -> Nil
    | Cons(xs, fn) -> Cons(x::xs, fun () -> prepend_all x (fn ()))
  in
  let rec interleave s1 s2 =
    match s1, s2 with
    | _, Nil -> s1
    | Nil, _ -> s2
    | Cons(x1, f1), _ -> Cons(x1, fun () -> interleave s2 (f1 ()))
  in
  match symbols with
  | [] -> Cons ([], fun () -> Nil)
  | Lit s :: tl ->
      let tl_vals = generate_truth_vals tl in
      let s_true = prepend_all (s, true) tl_vals in
      let s_false = prepend_all (s, false) tl_vals in
      interleave s_true s_false
  | _ -> failwith "discovered a bug"

(* brute force search for a satisfying interpretation *)
let satisfy prop =
  let symbols = extract_symbols prop in
  let truth_vals = generate_truth_vals symbols in
  let rec try_next truth_vals =
    match truth_vals with
    | Nil -> None
    | Cons(i, f) ->
      begin
        match test_interpretation prop i with
        | Some true -> Some i
        | _ -> try_next (f ())
      end
  in
  try_next truth_vals