Theory Default_St_Base
theory Default_St_Base
imports "Voblint_VIMP.VIMP_Syntax" "HOL-Library.AList"
begin
section ‹Finite default-map representation›
text ‹
An abstract state has to be a finite thing before a solver can run on it. A
‹default_dict› is a finite dictionary that answers every name it does not
list with a default. A ‹default_st_rep› is two of them, one per partition:
a local dictionary and a global one. Reading a location consults the
dictionary of its partition. Nothing forces a stored value to differ from
its default.
Two such pairs can describe the same reading, so the type is quotiented by
agreement of all lookups. That identifies list order and redundant duplicate
entries only where they do not affect the reading: \<^const>‹map_of› answers
with the first match, so reordering entries that disagree on a key is a
genuine change and the quotient keeps it.
This theory settles the representation, that quotient, and the order,
equality and point update defined on it. It does not decide which variable
names are local and which are global -- a ‹location› records a
classification this theory never makes. That classifier arrives only in
‹Default_St_Transfer›, which is built on this.
›
text ‹
❙‹Why two defaults, rather than a sparse map over a fixed ‹top›.›
Nipkow's ‹Abs_State› stores only the variables it has heard of and reads
every other one as ‹top›. That is the smaller representation, and it makes
the order and the join shorter to state, so the extra pair of defaults here
needs a reason. Three, in fact, and each is load-bearing on its own.
▪ ❙‹C zero-initialization.› Every domain's entry state gives globals a
non-‹top› value and locals ‹top› --- ‹⟪(STop, []), (SZero, [])⟫› for
Sign, and the parity, interval and product analyses match it. It
over-approximates ‹cinit_stores 𝒢 = {s. ∀x. 𝒢 x ⟶ s x = 0}›, which
quantifies over ∗‹all› names the classifier calls global, for an arbitrary
classifier and with no finiteness hypothesis. A fixed-‹top› map can only
express that by materializing every global, which makes the entry state a
function of the program's declaration list and pushes that dependency into
every soundness statement that mentions it.
▪ ❙‹The ownership split needs ‹bot› on the discarded side.› Publishing a
state's global half to a shared unknown sends locals to ‹bot›, and ‹bot› is
what makes that half a unit for the join that combines publications from
every call site. ‹top› there would not be a unit. These half-states are not
transient: they are stored in solver unknowns and compared against the
solution.
▪ ❙‹The solver needs a least element on this type.› The ownership-split
specification types both its local and global unknowns at this carrier and
demands ‹bounded_semilattice_sup_bot› of it, so unknowns can start at
‹bot›. That element is the everywhere-‹bot› state, which a sparse map over a
fixed ‹top› cannot represent at all.
What the defaults cost is visible throughout this theory: the order has to
compare them, extensional equality has to pin them, and the emptiness test in
‹Default_St_Reachability› has to reason about them. That cost is the price of the
three points above, not an accident of the first representation tried.
›
subsection ‹Default dictionaries›
type_synonym 'a default_dict = "'a × (vname × 'a) list"
fun default_dict_get :: "'a default_dict => vname => 'a" where
"default_dict_get (d, ps) x = (case map_of ps x of Some a => a | None => d)"
fun default_dict_set :: "'a default_dict => vname => 'a => 'a default_dict" where
"default_dict_set (d, ps) x a = (d, (x, a) # AList.delete x ps)"
lemma map_of_resolved_delete:
"map_of (AList.delete k ps) k' =
(if k = k' then None else map_of ps k')"
by (simp add: AList.delete_conv')
lemma map_of_resolved_none_iff:
"map_of ps k = None ⟷ k ∉ set (map fst ps)"
by (induction ps) auto
lemma default_dict_get_set [simp]:
"default_dict_get (default_dict_set m x a) y =
(if x = y then a else default_dict_get m y)"
by (cases m) (simp add: map_of_resolved_delete)
text ‹
A name escaping a finite list, drawn from any infinite supply. It is not
listed, so a dictionary answers it with its default. Consumers instantiate
the supply with all vnames, or with the ones a classifier leaves local.
›
lemma obtain_fresh_vname:
assumes "infinite A"
obtains x where "x ∈ A" and "x ∉ set xs"
proof -
have "infinite (A - set xs)"
by (rule Diff_infinite_finite[OF _ assms]) simp
then obtain x where "x ∈ A - set xs"
using infinite_imp_nonempty by blast
then have "x ∈ A" "x ∉ set xs" by simp_all
then show thesis by (rule that)
qed
text ‹
The order on one dictionary compares the defaults and the finitely many
listed names. An unlisted name reads the default on both sides, so this
decides the pointwise order over all names.
›
fun le_default_dict :: "('a::order) default_dict => 'a default_dict => bool" where
"le_default_dict (d, ps) (e, qs) ⟷
d ≤ e ∧
list_all (λx. default_dict_get (d, ps) x ≤ default_dict_get (e, qs) x)
(map fst ps @ map fst qs)"
lemma le_default_dict_iff:
"le_default_dict m n ⟷ (∀x. default_dict_get m x ≤ default_dict_get n x)"
proof -
obtain d ps where m: "m = (d, ps)" by (cases m)
obtain e qs where n: "n = (e, qs)" by (cases n)
show ?thesis
proof
assume le: "le_default_dict m n"
show "∀x. default_dict_get m x ≤ default_dict_get n x"
proof
fix x
show "default_dict_get m x ≤ default_dict_get n x"
proof (cases "x ∈ set (map fst ps @ map fst qs)")
case True
with le show ?thesis unfolding m n
by (auto simp: list_all_iff simp del: default_dict_get.simps)
next
case False
then have "map_of ps x = None" "map_of qs x = None"
by (simp_all add: map_of_resolved_none_iff)
with le show ?thesis unfolding m n by simp
qed
qed
next
assume le: "∀x. default_dict_get m x ≤ default_dict_get n x"
obtain y :: vname where "y ∈ UNIV" and fresh: "y ∉ set (map fst ps @ map fst qs)"
by (rule obtain_fresh_vname[OF infinite_literal])
then have "map_of ps y = None" "map_of qs y = None"
by (simp_all add: map_of_resolved_none_iff)
with le[rule_format, of y] have "d ≤ e" unfolding m n by simp
with le show "le_default_dict m n" unfolding m n by (simp add: list_all_iff)
qed
qed
subsection ‹Locations and raw lookup›
text ‹
A ‹location› names a local or a global variable, and a raw state is a
pair of dictionaries read by ‹default_st_rep_get›.
›