Theory MkIfex
text‹
Author: Julius Michaelis
›
theory MkIfex
imports "ROBDD.BDT"
begin
section‹Converting boolean functions to BDTs›
text‹The following function builds an @{typ "'a ifex"}
(a binary decision tree)
from a boolean function and its list of variables
(note that in this development we will be using
boolean functions over sets of the natural numbers
of the form @{term "{..<n::nat}"}).›
fun mk_ifex :: "('a :: linorder) boolfunc ⇒ 'a list ⇒ 'a ifex" where
"mk_ifex f [] = (if f (const False) then Trueif else Falseif)" |
"mk_ifex f (v#vs) = ifex_ite
(IF v Trueif Falseif)
(mk_ifex (bf_restrict v True f) vs)
(mk_ifex (bf_restrict v False f) vs)"
text‹The result of @{term "mk_ifex"} is @{const ifex_ordered}
and @{const ifex_minimal}.›
lemma mk_ifex_ro: "ro_ifex (mk_ifex f vs)"
by(induction vs arbitrary: f; fastforce
intro: order_ifex_ite_invar minimal_ifex_ite_invar
simp del: ifex_ite.simps)
text‹To prove that @{const mk_ifex} has correctly captured a boolean function @{term f},
we need know that all variables that @{term f} depends on were considered by @{const mk_ifex}.
In that regard, one troublesome aspect of @{type boolfunc} from @{theory "ROBDD.Bool_Func"} is that it is too general:
Boolean functions' assignments assign a Boolean value to any natural number,
and functions are not limited to ``reading'' only from a finite set of variables.
This for example allows for the boolean function that asks ``Is the assignment true in a finite number of variables:
@{term "λas. finite {x. as x}"}.''
This function does not depend on any single variable, but on the set of all of them.
A definition that proved to work despite such subtleties is that
a function @{term f} only depends on the variables in set @{term x} iff
for any pair of assignments that agree in @{term x} (but are arbitrary otherwise),
the values of @{term f} agree:›
definition "reads_inside_set f x ≡
(∀assmt1 assmt2. (∀p. p ∈ x ⟶ assmt1 p = assmt2 p) ⟶ f assmt1 = f assmt2)"
lemma reads_inside_set_subset: "reads_inside_set f a ⟹ a ⊆ b ⟹ reads_inside_set f b"
unfolding reads_inside_set_def by blast
lemma reads_inside_set_restrict: "reads_inside_set f s ⟹ reads_inside_set (bf_restrict i v f) (Set.remove i s)"
unfolding reads_inside_set_def bf_restrict_def by force
lemma collect_upd_true: "Collect (x(y:= True)) = insert y (Collect x)" by auto
lemma collect_upd_false: "Collect (x(y:= False)) = Set.remove y (Collect x)" by auto metis
lemma reads_none: "reads_inside_set f {} ⟹ f = bf_True ∨ f = bf_False"
unfolding reads_inside_set_def by fast
lemma val_ifex_ite_subst: "⟦ro_ifex i; ro_ifex t; ro_ifex e⟧ ⟹ val_ifex (ifex_ite i t e) = bf_ite (val_ifex i) (val_ifex t) (val_ifex e)"
using val_ifex_ite by blast
theorem
val_ifex_mk_ifex_equal:
"reads_inside_set f (set vs) ⟹ val_ifex (mk_ifex f vs) assmt = f assmt"
proof(induction vs arbitrary: f assmt)
case Nil
then show ?case using reads_none by auto
next
case (Cons v vs)
have "reads_inside_set (bf_restrict v x f) (set vs)" for x
using reads_inside_set_restrict[OF Cons.prems] reads_inside_set_subset by fastforce
from Cons.IH[OF this] show ?case
unfolding mk_ifex.simps val_ifex.simps bf_restrict_def
by(subst val_ifex_ite_subst; simp add: bf_ite_def fun_upd_idem mk_ifex_ro)
qed
end