module Hornify
use import formula.ConjunctiveNormalForm as CNF
use import formula.Horn as Horn
use int.Int, setstheory.BoolSet, setstheory.PropositionalFormulaSet, option.Option
use import booltheory.BoolImplementation as BI
clone import set.SetApp with type elt = pliteral
exception MoreThanOnePositive
function eval_domain (phi: clause_cnf) (s: set) (p: option rightside) (f: i -> BI.t) : BI.t
= eval_clause_cnf phi f \*/ eval_negative s f \*/ eval_optionrightside p f
function eval_codomain (s: set) (p: option rightside) (f: i -> BI.t) : BI.t
= eval_negative s f \*/ eval_optionrightside p f
let convertLiteralToR (pl: pliteral) : (rightside)
ensures{ forall f. CNF.eval_pliteral pl f = Horn.eval_rightside (assign_rightside result f) }
= match pl with
| LBottom -> RProp bot
| LVar x -> RVar x
end
let addLiterals (pl: pliteral) (nl: pliteral) (s: set) (p: option rightside) : (rs: set, rp: option rightside)
requires{ p = None }
ensures{ (not is_empty rs) }
ensures { forall f. (eval_pliteral pl f \*/ (neg (eval_pliteral nl f)) \*/ eval_negative s f \*/ eval_optionrightside p f) = (eval_negative rs f \*/ eval_optionrightside rp f) }
= match pl with
| LBottom -> let rbottom = Some (RProp bot) in
match nl with
| LBottom -> ((add (LBottom) s), rbottom)
| LVar x -> ((add (LVar x) s), rbottom)
end
| LVar x -> let rvar = Some (RVar x) in
match nl with
| LBottom -> ((add (LBottom) s), rvar)
| LVar x -> ((add (LVar x) s), rvar)
end
end
let processCombination (pl: pliteral) (nl: pliteral) (s: set) (p: option rightside) : (rs: set, rp: option rightside)
raises{ MoreThanOnePositive }
ensures{ (not is_empty rs) }
ensures { forall f. (eval_pliteral pl f \*/ (neg (eval_pliteral nl f)) \*/ eval_negative s f \*/ eval_optionrightside p f) = (eval_negative rs f \*/ eval_optionrightside rp f) }
= match p with
| None -> addLiterals pl nl s p
| Some _ -> raise MoreThanOnePositive
end
let rec hornify_aux (phi: clause_cnf) (s: set) (p: option rightside) : (rs: set, rp: option rightside)
requires{ exists x y. phi = COr_cnf x y }
ensures{ (not is_empty rs) }
ensures{ forall f. eval_domain phi s p f = eval_codomain rs rp f }
ensures{ forall f. eval_domain phi s p f = ((eval_positive rs f) ->* (eval_optionrightside rp f)) }
raises{ MoreThanOnePositive }
variant{ phi }
= match phi with
| COr_cnf (CLiteral _) (CLiteral _) -> raise MoreThanOnePositive
| COr_cnf (CLiteral pl) (CNeg_cnf nl) | COr_cnf (CNeg_cnf nl) (CLiteral pl) ->
processCombination pl nl s p
| COr_cnf (CNeg_cnf nl1) (CNeg_cnf nl2) -> ((add (nl1) (add nl2 s)), p)
| COr_cnf (COr_cnf phi1 phi2) (CLiteral pl) | COr_cnf (CLiteral pl) (COr_cnf phi1 phi2) ->
match p with
| None -> hornify_aux (COr_cnf phi1 phi2) s (Some (convertLiteralToR pl))
| Some _ -> raise MoreThanOnePositive
end
| COr_cnf (COr_cnf phi1 phi2) (CNeg_cnf nl) | COr_cnf (CNeg_cnf nl) (COr_cnf phi1 phi2) ->
hornify_aux (COr_cnf phi1 phi2) (add nl s) p
| COr_cnf phi1 phi2 -> let (s1,p1) = hornify_aux phi1 s p in
hornify_aux phi2 s1 p1
| _ -> absurd
end
let conjunction (s: set): leftside
requires{not is_empty s}
ensures{forall f. eval_positive s f = eval_leftside result f }
= let rec build (s: set)
requires{not is_empty s}
ensures{forall f. eval_positive s f = Horn.eval_positive result f}
variant{cardinal s}
= if((cardinal s) = 1) then CPL (choose s) else
let element = choose s in
CPAnd (CPL (element)) (build (remove (element) s)) in
LPos (build s)
let getPositive (p: option rightside) : rightside
ensures{forall f. eval_optionrightside p f = eval_rightside (assign_rightside result f)}
= match p with
| None -> RProp bot
| Some x -> x
end
let getBasicHorn (phi: clause_cnf) : basichornclause
ensures{ forall f. eval_clause_cnf phi f = eval_basichornclause result f }
raises{ MoreThanOnePositive }
= match phi with
| CLiteral (LVar x) -> BImpl (LTop) (RVar x)
| CLiteral (LBottom) -> BImpl (LTop) (RProp bot)
| CNeg_cnf (LVar x) -> BImpl (LPos (CPL (LVar x))) (RProp bot)
| CNeg_cnf (LBottom) -> BImpl (LTop) (RProp top)
| COr_cnf _ _ -> let (s,p) = hornify_aux phi (empty ()) None in
BImpl (conjunction s) (getPositive p)
end
let rec hornify (phi: formula_cnf) : hornclause
raises{ MoreThanOnePositive }
ensures{forall f. eval_formula_cnf phi f = eval_hornclause result f}
variant{ phi }
= match phi with
| FClause_cnf phi1 -> HBasic (getBasicHorn phi1)
| FAnd_cnf phi1 phi2 -> HAnd (hornify phi1) (hornify phi2)
end
end