summaryrefslogtreecommitdiff
path: root/lib/lib_utils.ml
blob: 5dcbfd7ba774e168f48835a86d4f74c2e107704e (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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
(* Utility functions *)

open Types

(* Converts an interpretation to a substitution *)
let rec sub_of_interpr = function
  | [] -> []
  | (s, b) :: tl -> (s, if b then True else False) :: (sub_of_interpr tl)

(* Removes instances of True or False literals via simplification as well as repeated Nots *)
let rec simplify_true_false = function
  | True -> True
  | False -> False
  | Lit symbol -> Lit symbol
  | Not p ->
    begin
      match simplify_true_false p with
      | True -> False
      | False -> True
      | Not p' -> p'
      | p' -> Not(p')
    end
  | And (p1, p2) ->
    begin
      match simplify_true_false p1, simplify_true_false p2 with
      | False, _ -> False
      | _, False -> False
      | True, p2' -> p2'
      | p1', True -> p1'
      | p1', p2' -> And(p1', p2')
    end
  | Or (p1, p2) ->
    begin
      match simplify_true_false p1, simplify_true_false p2 with
      | True, _ -> True
      | _, True -> True
      | False, p2' -> p2'
      | p1', False -> p1'
      | p1', p2' -> Or(p1', p2')
    end
  | Implies (p1, p2) ->
    begin
      match simplify_true_false p1, simplify_true_false p2 with
      | False, _ -> True
      | True, p2' -> p2'
      | p1', p2' -> Implies(p1', p2')
    end
  | Iff (p1, p2) ->
    begin
      match simplify_true_false p1, simplify_true_false p2 with
      | True, p2' -> p2'
      | p1', True -> p1'
      | False, p2' ->
        begin (* need to simplify Not(p2'), which depends on the form of p2' *)
          match p2' with
          | True -> False
          | False -> True
          | Not p -> p
          | p -> Not(p)
        end
      | p1', False ->
        begin (* need to simplify Not(p1') *)
          match p1' with
          | True -> False
          | False -> True
          | Not p -> p
          | p -> Not(p)
        end
      | p1', p2' -> Iff(p1', p2')
    end

(* Finds a symbol in a list of substitutions and returns the value to substitute for that symbol *)
let rec replace sub symbol =
  match sub with
  | [] -> Lit symbol
  | (s, value) :: sub -> if s = symbol then value else replace sub symbol

(* Substitutes propositions for symbols as specified by the sub argument *)
let rec substitute (prop : proposition) (sub : substitution) : proposition =
  match prop with
  | True -> True
  | False -> False
  | Lit s -> replace sub s
  | Not p -> Not (substitute p sub)
  | And(p1, p2) -> And(substitute p1 sub, substitute p2 sub)
  | Or(p1, p2) -> Or(substitute p1 sub, substitute p2 sub)
  | Implies(p1, p2) -> Implies(substitute p1 sub, substitute p2 sub)
  | Iff(p1, p2) -> Iff(substitute p1 sub, substitute p2 sub)

(* Converts a proposition to negation normal form *)
let to_nnf prop =
  let rec to_nnf = function
    | True -> True
    | False -> False
    | Lit symbol -> Lit symbol
    | Not p ->
      begin
        match p with
        | True -> False
        | False -> True
        | Lit s -> Not(Lit s)
        | Not p' -> to_nnf p'
        | And(p1, p2) -> Or(to_nnf (Not(p1)), to_nnf (Not(p2))) (* De Morgan's Laws *)
        | Or(p1, p2) -> And(to_nnf (Not(p1)), to_nnf (Not(p2)))
        | Implies(p1, p2) -> And(to_nnf p1, to_nnf (Not(p2))) (* not (A -> B) = A and not B*)
        | Iff(p1, p2) -> Or(And(to_nnf p1, to_nnf (Not(p2))), And(to_nnf (Not(p1)), to_nnf p2))
      end
    | And(p1, p2) -> And(to_nnf p1, to_nnf p2)
    | Or(p1, p2) -> Or(to_nnf p1, to_nnf p2)
    | Implies(p1, p2) -> to_nnf (Or(Not(p1), p2))
    | Iff(p1, p2) -> to_nnf (And(Implies(p1, p2), Implies(p2, p1)))
  in
  to_nnf (simplify_true_false prop)

(* Applies an interpretation to a proposition and returns the resulting proposition *)
let interpret prop i = simplify_true_false (substitute prop (sub_of_interpr i))

(* Tests whether a proposition holds under a given interpretation *)
let test_interpretation prop i =
  match interpret prop i with
  | True -> Some true
  | False -> Some false
  | _ -> None (* return None if cannot be determined *)