text‹Did you ever dream about records with multiple inheritance? Then you should definitely have a look at statespaces. They may be what you are dreaming of. Or at least almost \dots›
text‹Isabelle allows to add new top-level commands to the system. Building on the locale infrastructure, we provide a command 🪙‹statespace› l
statespace vars =
n::nat
b::bool
print_locale vars_namespace print_locale vars_valuetypes print_locale vars
text‹\noindent This resembles a 🪙‹record› definition,
but introduces sophisticated locale
infrastructure instead of HOL type schemes. The resulting context
postulates two distinct names 🍋‹n›and🍋‹b›and
projection~/ injection functions that convert from abstract values to 🍋‹nat›and‹bool›. The logical content of the localeis:›
locale vars' = fixes n::'name and b::'name assumes"distinct [n, b]"
text‹\noindent The HOL predicate 🍋‹distinct› describes
distinctness of all names in the context. Locale‹vars'› defines the raw logical content that is defined in the state space locale. We also maintain non-logical context information to support
the user:
🪙Syntaxfor state lookup and updates that automatically inserts
the corresponding projection and injection functions. 🪙Setupfor the proof tools that exploit the distinctness
information and the cancellation of projections and injections in
deductions and simplifications.
This extra-logical information is added to the localein form of
declarations, which associate the name of a variable to the
corresponding projection and injection functions to handle the syntax
transformations, and a link from the variable name to the
corresponding distinctness theorem. As state spaces are merged or
extended there are multiple distinctness theoremsin the context. Our
declarations take care that the link always points to the strongest
distinctness assumption. With these declarations in place, a lookup
can be written as ‹s⋅n›, which is translated to‹project_nat (s n)›, and an
update as ‹s⟨n := 2⟩›, which is translated to‹s(n := inject_nat 2)›.
We can now establish the
following lemma:›
lemma (in vars) foo: "s⋅b = s⋅b"by simp
text‹\noindent Here the simplifier was able to refer to distinctness of 🍋‹b› a
The resulting lemmaisalso recorded inlocale‹vars›for
later useandis automatically propagated to all its interpretations.
Here is another example:›
statespace 'a varsX = NB: vars [n=N, b=B] + vars + x::'a
text‹\noindent The state space ‹varsX› imports two copies
of the state space ‹vars›, where one has the variables renamed to upper-case letters, and adds another variable 🍋‹x› of type 🍋‹'a›. This type is fixed inside the state space but may get
instantiated later on, analogous to type parameters of an ML-functor.
The distinctness assumption is now ‹distinct [N, B, n, b, x]›, from this we can derive both 🍋‹distinct [N,B]›and🍋‹distinct [n,b]›,
the distinction assumptions for the two versions of locale‹vars› above. Moreover we have all necessary
projection and injection assumptions available. These assumptions
together allow us to establish state space 🍋‹varsX› as an interpretation of both instances of locale🍋‹vars›. Hence we
inherit both variants of theorem‹foo›: ‹s⟨N := 2⟩⋅B = s⋅B›
consequences of the localeinterpretation action.
The declarations forsyntaxand the distinctness theoremsalso observe
the morphisms generated by the locale package due to the renaming 🍋‹n = N›:›
lemma (in varsX) foo: "s⟨N := 2⟩⋅x = s⋅x"by simp
text‹To assure scalability towards many distinct names, the distinctness predicate is refined to operate on balanced trees. Thus we get logarithmic certificates for the distinctness of two names by the distinctness of the paths in the tree. Asked for the distinctness of two names, our tool produces the paths of the variables in the tree (this is implemented in Isabelle/ML, outside the logic) and returns a certificate corresponding to the different paths. Merging state spaces requires to prove that the combined distinctness assumption implies the distinctness assumptions of the components. Such a proof is of the order $m \cdot\log n$, where $n$ and $m$ are the number of nodes in the larger and smaller tree, respectively.›
text‹We continue with more examples.›
statespace 'a foo =
f::"nat==>nat"
a::int
b::nat
c::'a
lemma (in foo) foo1: shows"s⟨a := i⟩⋅a = i" by simp
lemma (in foo) foo2: shows"(s⟨a:=i⟩)⋅a = i" by simp
lemma (in foo) foo3: shows"(s⟨a:=i⟩)⋅b = s⋅b" by simp
lemma (in foo) foo4: shows"(s⟨a:=i,b:=j,c:=k,a:=x⟩) = (s⟨b:=j,c:=k,a:=x⟩)" by simp
statespace bar =
b::bool
c::string
lemma (in bar) bar1: shows"(s⟨b:=True⟩)⋅c = s⋅c" by simp
text‹You can define a derived state space by inheriting existing state spaces, renaming of components if you like, and by declaring new components. ›
statespace ('a,'b) loo = 'a foo + bar [b=B,c=C] +
X::'b
lemma (in loo) loo1: shows"s⟨a:=i⟩⋅B = s⋅B" proof - thm foo1 txt‹The Lemma @{thm [source] foo1} from the parent state space is also available here: \begin{center}@{thm foo1}\end{center}› have"s⋅a = i" by (rule foo1) thm bar1 txt‹Note the renaming of the parameters in Lemma @{thm [source] bar1}: \begin{center}@{thm bar1}\end{center}› have"s⋅C = s⋅C" by (rule bar1) show ?thesis by simp qed
statespace 'a dup = FA: 'a foo [f=F, a=A] + 'a foo +
x::int
text‹In contrast to the statespace @{locale loo} there is no 'inter' statespace distinctness between the names of @{locale foo} and @{locale bar}.› end
text‹Sharing of names in side-by-side statespaces is also possible as long as they are mapped to the same type.›
text‹Note that the distinctness theorem for @{locale vars1} is selected here to do the proof.› lemma"s⋅m = s⋅m" by simp
text‹Note that the distinctness theorem for @{locale vars2} is selected here to do the proof.› lemma"s⋅k = s⋅k" by simp
text‹Still there is no inter-statespace distinctness.› lemma"s⋅m = s⋅m" (* apply simp *) oops end
statespace merge_vars1_vars2 = vars1 + vars2
context merge_vars1_vars2 begin text‹When defining a statespace instead of a side-by-side locale we get the distinctness of all variables.› lemma"s⋅m = s⋅m" by simp end
subsection‹Benchmarks›
text‹Here are some bigger examples for benchmarking.›
ML ‹ fun make_benchmark n = writeln (Active.sendback_markup_command ("statespace benchmark" ^ string_of_int n ^ " =\n" ^ (cat_lines (map (fn i => "A" ^ string_of_int i ^ "::nat") (1 upto n))))); ›
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.