lh-l4v/camkes/adl-spec/Wellformed_CAMKES.thy

448 lines
20 KiB
Plaintext
Raw Normal View History

2014-07-14 19:32:44 +00:00
(*
2020-03-09 06:18:30 +00:00
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
2014-07-14 19:32:44 +00:00
*
2020-03-09 06:18:30 +00:00
* SPDX-License-Identifier: GPL-2.0-only
2014-07-14 19:32:44 +00:00
*)
2019-06-05 10:18:48 +00:00
chapter \<open>Wellformedness of Specifications\<close>
2014-07-14 19:32:44 +00:00
(*<*)
theory Wellformed_CAMKES
imports
Types_CAMKES
Helpers_CAMKES
Lib.GenericTag
2014-07-14 19:32:44 +00:00
begin
(*>*)
2019-06-05 10:18:48 +00:00
text \<open>
2014-07-14 19:32:44 +00:00
To prove that a system specification is correct, we need to define what
correctness means for the entities that can exist in a CAmkES specification.
This section provides a definition of wellformedness for each syntactic
element that captures the necessary conditions for it to represent a valid
system configuration. Any wellformed system is capable of being instantiated
in a way that corresponds to its ADL.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
2019-06-05 10:18:48 +00:00
subsection \<open>\label{subsec:winterfaces}Interfaces\<close>
2014-07-14 19:32:44 +00:00
2019-06-05 10:18:48 +00:00
text \<open>
2014-07-14 19:32:44 +00:00
A procedure method is considered wellformed if the symbols of its name and
parameters are distinct. This constraint ensures the code generation process
will produce valid code in the target language.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
wellformed_method :: "method \<Rightarrow> bool"
where
"wellformed_method m \<equiv>
(m_name m \<notin> set (map p_name (m_parameters m)) \<and>
distinct (map p_name (m_parameters m)))"
2019-06-05 10:18:48 +00:00
text \<open>
2014-07-14 19:32:44 +00:00
The code generated for a procedure is within a single namespace and thus
the names of all methods in a procedure must be distinct.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
wellformed_procedure :: "procedure \<Rightarrow> bool"
where
"wellformed_procedure i \<equiv>
(\<forall>x \<in> set i. wellformed_method x) \<and>
2014-07-14 19:32:44 +00:00
distinct (map m_name i)"
2019-06-05 10:18:48 +00:00
text \<open>
2014-07-14 19:32:44 +00:00
The implementation currently only supports 32 distinct events (0 - 31). This
limitation may be removed in a future iteration.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
wellformed_event :: "event \<Rightarrow> bool"
where
"wellformed_event e \<equiv> e < 32"
2019-06-05 10:18:48 +00:00
text \<open>
2014-07-14 19:32:44 +00:00
Dataports do not have any attributes beyond their type, so their wellformedness
is trivial.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
wellformed_dataport :: "dataport \<Rightarrow> bool"
where
"wellformed_dataport d \<equiv> True"
definition
wellformed_interface :: "interface \<Rightarrow> bool"
where
"wellformed_interface i \<equiv> (case i of
Procedure p \<Rightarrow> wellformed_procedure p
| Event e \<Rightarrow> wellformed_event e
| Dataport d \<Rightarrow> wellformed_dataport d)"
2019-06-05 10:18:48 +00:00
subsection \<open>\label{subsec:wcomponents}Components\<close>
text \<open>
2014-07-14 19:32:44 +00:00
For a component to be valid internally, its interfaces must not conflict and
must themselves be wellformed.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
wellformed_component :: "component \<Rightarrow> bool"
where
"wellformed_component c \<equiv>
2019-06-03 01:02:44 +00:00
\<comment> \<open>No symbol collisions\<close>
distinct (map fst (requires c) @ map fst (provides c) @ map fst (dataports c) @
map fst (emits c) @ map fst (consumes c)) \<and>
2019-06-03 01:02:44 +00:00
\<comment> \<open>No C symbol collisions.\<close>
(\<forall>x \<in> set (requires c). wellformed_procedure (snd (snd x))) \<and>
2014-07-14 19:32:44 +00:00
(\<forall>x \<in> set (provides c). wellformed_procedure (snd x)) \<and>
\<comment> \<open>Events valid.\<close>
2014-07-14 19:32:44 +00:00
(\<forall>x \<in> set (emits c). wellformed_event (snd x)) \<and>
(\<forall>x \<in> set (consumes c). wellformed_event (snd (snd x))) \<and>
2019-06-03 01:02:44 +00:00
\<comment> \<open>Dataports valid.\<close>
(\<forall>x \<in> set (dataports c). wellformed_dataport (snd x))"
2014-07-14 19:32:44 +00:00
2019-06-05 10:18:48 +00:00
subsection \<open>\label{subsec:wconnectors}Connectors\<close>
text \<open>
For now, we don't really restrict what combinations of communication
mechanisms connectors can use. This can be refined later.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
wellformed_connector :: "connector \<Rightarrow> bool"
where
"wellformed_connector c \<equiv> True"
2014-07-14 19:32:44 +00:00
2019-06-05 10:18:48 +00:00
subsection \<open>\label{subsec:wconnections}Connections\<close>
2014-07-14 19:32:44 +00:00
definition
wellformed_connection :: "connection \<Rightarrow> bool"
where
"wellformed_connection c \<equiv> True"
2014-07-14 19:32:44 +00:00
2019-06-05 10:18:48 +00:00
subsection \<open>\label{subsec:wsymbols}ADL Symbol Resolution\<close>
text \<open>
2014-07-14 19:32:44 +00:00
All procedures must be satisfied by a unique connection. To define unique connections,
we first define a general predicate @{text ex_one} that is true when a predicate
is satisfied for precisely one element in a list.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
ex_one :: "'a list \<Rightarrow> ('a \<Rightarrow> bool) \<Rightarrow> bool"
where
"ex_one xs P \<equiv> length (filter P xs) = 1"
2019-06-05 10:18:48 +00:00
text \<open>
More convenient syntax for @{const ex_one}.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
syntax
"_ex_one" :: "pttrn \<Rightarrow> 'a set \<Rightarrow> bool \<Rightarrow> bool" ("(4\<exists>1 _\<in>_./ _)" [0, 0, 10] 10)
translations
"\<exists>1 x\<in>xs. P" == "CONST ex_one xs (\<lambda>x. P)"
2019-06-05 10:18:48 +00:00
text \<open>
2014-07-14 19:32:44 +00:00
We can now define valid procedures. For each procedure @{term x} there must be
precisely one connection @{term y} that fits the component instance.
The VirtQueue connector (in global-components) currently uses a dummy empty
procedure that is not a connector, so we ignore empty procedures as a special case.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
refs_valid_procedures ::
"adl_symbol \<Rightarrow> (adl_symbol \<times> (InterfaceRequired \<times> procedure)) list \<Rightarrow>
2014-07-14 19:32:44 +00:00
(adl_symbol \<times> connection) list \<Rightarrow> bool"
where
"refs_valid_procedures component_instance procedures conns \<equiv>
\<forall>(name, (req, proc)) \<in> set procedures.
req = InterfaceRequired \<longrightarrow> proc \<noteq> [] \<longrightarrow>
(\<exists>1 z \<in> (concat (map (\<lambda>y. conn_from (snd y)) conns)). z = (component_instance, name))"
2014-07-14 19:32:44 +00:00
2019-06-05 10:18:48 +00:00
text \<open>
2014-07-14 19:32:44 +00:00
For events and dataports, an interface can be left unconnected in a system with no
adverse effects.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
refs_valid_components ::
"(adl_symbol \<times> component) list \<Rightarrow> (adl_symbol \<times> connection) list \<Rightarrow> bool"
where
"refs_valid_components comps conns \<equiv>
\<forall>x \<in> set comps. refs_valid_procedures (fst x) (requires (snd x)) conns"
2019-06-05 10:18:48 +00:00
text \<open>
2014-07-14 19:32:44 +00:00
Each connection must be connecting interfaces of the same underlying type.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
refs_valid_connection :: "connection \<Rightarrow> (adl_symbol \<times> component) list \<Rightarrow> bool"
where
"refs_valid_connection conn component_list \<equiv>
wellformed_connector (conn_type conn) \<and>
(\<comment> \<open>Every to- and from-end of the component must exist.\<close>
\<forall>(from_name, from_interface) \<in> set (conn_from conn).
\<exists>1from \<in> component_list.
fst from = from_name \<and>
(\<forall>(to_name, to_interface) \<in> set (conn_to conn).
\<exists>1to \<in> component_list.
fst to = to_name \<and>
\<comment> \<open>The following checks that the component interfaces have the correct type.\<close>
(case connector_interface (conn_type conn) of
RPCInterface \<Rightarrow> from_interface \<in> fst ` set (requires (snd from)) \<and>
to_interface \<in> fst ` set (provides (snd to))
| EventInterface \<Rightarrow> from_interface \<in> fst ` set (emits (snd from)) \<and>
to_interface \<in> fst ` set (consumes (snd to))
\<comment> \<open>TODO: the check for memory connectors could be optimised; we don't need to
check all pairs of from- and to- for dataports with many subscribers.\<close>
| DataportInterface \<Rightarrow> from_interface \<in> fst ` set (dataports (snd from)) \<and>
to_interface \<in> fst ` set (dataports (snd to))
)
\<and>
\<comment> \<open>Next, we check that the kind of components being connected are appropriate.\<close>
(case connector_type (conn_type conn) of
\<comment> \<open>Both endpoints must be regular components.\<close>
NativeConnector \<Rightarrow> \<not> hardware (snd from) \<and> \<not> hardware (snd to)
\<comment> \<open>At least one endpoint must be a hardware component.
FIXME: might not be quite what we want.\<close>
| HardwareConnector \<Rightarrow> hardware (snd from) \<or> hardware (snd to)
| ExportConnector \<Rightarrow> undefined ''compound components not supported yet''
)
)
)"
2014-07-14 19:32:44 +00:00
definition
refs_valid_connections ::
"(adl_symbol \<times> connection) list \<Rightarrow> (adl_symbol \<times> component) list \<Rightarrow> bool"
where
"refs_valid_connections conns comps \<equiv>
\<forall>x \<in> set conns. refs_valid_connection (snd x) comps"
definition
refs_valid_composition :: "composition \<Rightarrow> bool"
where
"refs_valid_composition c \<equiv>
refs_valid_components (components c) (connections c) \<and>
refs_valid_connections (connections c) (components c)"
2019-06-05 10:18:48 +00:00
subsection \<open>\label{subsec:wsystem}Overall System\<close>
text \<open>
2014-07-14 19:32:44 +00:00
We obtain a guarantee of the correctness of a component composition by composing
the required properties of its constituents.
2019-06-05 10:18:48 +00:00
\<close>
2014-07-14 19:32:44 +00:00
definition
wellformed_composition :: "composition \<Rightarrow> bool"
where
"wellformed_composition c \<equiv>
2019-06-03 01:02:44 +00:00
\<comment> \<open>This system contains @{text \<open>\<ge> 1\<close>} active component.\<close>
2014-07-14 19:32:44 +00:00
(\<exists>x \<in> set (components c). control (snd x)) \<and>
2019-06-03 01:02:44 +00:00
\<comment> \<open>All references resolve.\<close>
2014-07-14 19:32:44 +00:00
refs_valid_composition c \<and>
\<comment> \<open>The @{const group_labels} mapping refers to existing ADL names.\<close>
(\<forall>(comp, group) \<in> set (group_labels c).
comp \<in> (fst ` set (components c) \<union> fst ` set (connections c))) \<and>
2019-06-03 01:02:44 +00:00
\<comment> \<open>All connectors and components have distinct names.
These names will correspond to integrity policy labels.\<close>
2014-07-14 19:32:44 +00:00
distinct (map fst (components c) @ map fst (connections c)) \<and>
2019-06-03 01:02:44 +00:00
\<comment> \<open>All components are valid.\<close>
2014-07-14 19:32:44 +00:00
(\<forall>x \<in> set (components c). wellformed_component (snd x)) \<and>
2019-06-03 01:02:44 +00:00
\<comment> \<open>All connections are valid.\<close>
2014-07-14 19:32:44 +00:00
(\<forall>x \<in> set (connections c). wellformed_connection (snd x))"
(*<*)
lemma wellformed_composition_is_nonempty:
"\<lbrakk>wellformed_composition c\<rbrakk> \<Longrightarrow> components c \<noteq> []"
by (fastforce simp:wellformed_composition_def)
(*>*)
definition
wellformed_configuration :: "configuration \<Rightarrow> bool"
where
"wellformed_configuration conf \<equiv> True" (* TODO *)
definition
wellformed_assembly :: "assembly \<Rightarrow> bool"
where
"wellformed_assembly a \<equiv>
wellformed_composition (composition a) \<and>
(case (configuration a) of
2014-07-14 19:32:44 +00:00
None \<Rightarrow> True
| Some x \<Rightarrow> wellformed_configuration x)"
(*<*)
text \<open>
These are alternative definitions that have annotations, to help debug
assemblies that are processed by the CAmkES proof toolchain.
\<close>
abbreviation "check_wellformed entity P \<equiv> generic_tag ''Wellformed_CAMKES'' entity P"
lemma wellformed_method_ann:
"wellformed_method m =
check_wellformed (wellformed_method, m)
(m_name m \<notin> set (map p_name (m_parameters m)) \<and>
distinct (map p_name (m_parameters m)))"
by (simp only: wellformed_method_def remove_generic_tag simp_thms)
lemma wellformed_procedure_ann:
"wellformed_procedure i =
check_wellformed (wellformed_procedure, i)
((\<forall>x \<in> set i. wellformed_method x) \<and>
distinct (map m_name i))"
by (simp only: wellformed_procedure_def remove_generic_tag simp_thms)
lemma wellformed_event_ann:
"wellformed_event e =
check_wellformed (wellformed_event, e) (e < 32)"
by (simp only: wellformed_event_def remove_generic_tag simp_thms)
lemma wellformed_component_ann:
"wellformed_component c = check_wellformed (wellformed_component, c) (
\<comment> \<open>No symbol collisions\<close>
(let names = map fst (requires c) @ map fst (provides c) @ map fst (dataports c) @
map fst (emits c) @ map fst (consumes c)
in check_wellformed (wellformed_component, ''distinct'', names) (distinct names)) \<and>
\<comment> \<open>No C symbol collisions.\<close>
(\<forall>x \<in> set (requires c). wellformed_procedure (snd (snd x))) \<and>
(\<forall>x \<in> set (provides c). wellformed_procedure (snd x)) \<and>
\<comment> \<open>Events valid.\<close>
(\<forall>x \<in> set (emits c). wellformed_event (snd x)) \<and>
(\<forall>x \<in> set (consumes c). wellformed_event (snd (snd x))) \<and>
\<comment> \<open>Dataports valid.\<close>
(\<forall>x \<in> set (dataports c). wellformed_dataport (snd x))
)"
by (simp only: wellformed_component_def remove_generic_tag simp_thms Let_def)
lemma refs_valid_procedures_ann:
"refs_valid_procedures component_instance procedures conns =
(\<forall>(name, (req, proc)) \<in> set procedures.
req = InterfaceRequired \<longrightarrow>
check_wellformed (refs_valid_procedures, name)
(proc \<noteq> [] \<longrightarrow> (\<exists>1 z \<in> (concat (map (\<lambda>y. conn_from (snd y)) conns)). z = (component_instance, name))))"
by (simp only: refs_valid_procedures_def remove_generic_tag simp_thms)
text \<open>
For events and dataports, an interface can be left unconnected in a system with no
adverse effects.
\<close>
lemma refs_valid_components_ann:
"refs_valid_components comps conns =
(\<forall>x \<in> set comps. check_wellformed (refs_valid_components, fst x)
(refs_valid_procedures (fst x) (requires (snd x)) conns))"
by (simp only: refs_valid_components_def remove_generic_tag simp_thms)
text \<open>
Each connection must be connecting interfaces of the same underlying type.
\<close>
lemma refs_valid_connection_ann:
"refs_valid_connection conn component_list =
(wellformed_connector (conn_type conn) \<and>
(\<comment> \<open>Every to- and from-end of the component must exist.\<close>
\<forall>(from_name, from_interface) \<in> set (conn_from conn).
\<exists>1from \<in> component_list.
fst from = from_name \<and>
(\<forall>(to_name, to_interface) \<in> set (conn_to conn).
\<exists>1to \<in> component_list.
fst to = to_name \<and>
\<comment> \<open>The following checks that the component interfaces have the correct type.\<close>
check_wellformed ((refs_valid_connection, ''interface''), (from_name, to_name))
(case connector_interface (conn_type conn) of
RPCInterface \<Rightarrow> from_interface \<in> fst ` set (requires (snd from)) \<and>
to_interface \<in> fst ` set (provides (snd to))
| EventInterface \<Rightarrow> from_interface \<in> fst ` set (emits (snd from)) \<and>
to_interface \<in> fst ` set (consumes (snd to))
\<comment> \<open>TODO: the check for memory connectors could be optimised; we don't need to
check all pairs of from- and to- for dataports with many subscribers.\<close>
| DataportInterface \<Rightarrow> from_interface \<in> fst ` set (dataports (snd from)) \<and>
to_interface \<in> fst ` set (dataports (snd to))
)
\<and>
\<comment> \<open>Next, we check that the kind of components being connected are appropriate.\<close>
check_wellformed ((refs_valid_connection, ''component''), (from_name, to_name))
(case connector_type (conn_type conn) of
\<comment> \<open>Both endpoints must be regular components.\<close>
NativeConnector \<Rightarrow> \<not> hardware (snd from) \<and> \<not> hardware (snd to)
\<comment> \<open>At least one endpoint must be a hardware component.
FIXME: might not be quite what we want.\<close>
| HardwareConnector \<Rightarrow> hardware (snd from) \<or> hardware (snd to)
| ExportConnector \<Rightarrow> undefined ''compound components not supported yet''
)
)
))"
by (simp only: refs_valid_connection_def remove_generic_tag simp_thms)
lemma refs_valid_connections_ann:
"refs_valid_connections conns comps =
(\<forall>x \<in> set conns. check_wellformed (refs_valid_connections, (fst x))
(refs_valid_connection (snd x) comps))"
by (simp only: refs_valid_connections_def remove_generic_tag simp_thms)
lemma wellformed_composition_ann:
"wellformed_composition c = (
\<comment> \<open>This system contains @{text \<open>\<ge> 1\<close>} active component.\<close>
check_wellformed (wellformed_composition, ''control'', map fst (components c))
(\<exists>x \<in> set (components c). control (snd x)) \<and>
\<comment> \<open>All references resolve.\<close>
refs_valid_composition c \<and>
\<comment> \<open>The @{const group_labels} mapping refers to existing ADL names.\<close>
(\<forall>(comp, group) \<in> set (group_labels c).
check_wellformed (wellformed_composition, ''group_labels'', comp)
(comp \<in> (fst ` set (components c) \<union> fst ` set (connections c)))) \<and>
\<comment> \<open>All connectors and components have distinct names.
These names will correspond to integrity policy labels.\<close>
check_wellformed (wellformed_composition, ''distinct'', map fst (components c) @ map fst (connections c))
(distinct (map fst (components c) @ map fst (connections c))) \<and>
\<comment> \<open>All components are valid.\<close>
(\<forall>x \<in> set (components c). check_wellformed (wellformed_composition, ''component'', fst x)
(wellformed_component (snd x))) \<and>
\<comment> \<open>All connections are valid.\<close>
(\<forall>x \<in> set (connections c). check_wellformed (wellformed_composition, ''connection'', fst x)
(wellformed_connection (snd x)))
)"
by (simp only: wellformed_composition_def remove_generic_tag simp_thms)
(*>*)
(*<*)
text \<open>Automation for proving wellformedness properties.\<close>
named_theorems wellformed_CAMKES_simps
2014-07-14 19:32:44 +00:00
lemmas [simplified, wellformed_CAMKES_simps] =
wellformed_composition_ann
wellformed_component_ann
wellformed_procedure_ann
wellformed_method_ann
wellformed_event_ann
refs_valid_connections_ann
refs_valid_connection_ann
refs_valid_procedures_ann
refs_valid_components_ann
text \<open>These currently have trivial definitions and don't need annotations.\<close>
lemmas [wellformed_CAMKES_simps] =
wellformed_assembly_def
wellformed_configuration_def
wellformed_connector_def
wellformed_connection_def
wellformed_dataport_def
refs_valid_composition_def
lemmas [wellformed_CAMKES_simps] =
ex_one_def
generic_tag_True
text \<open>Helper to visualise nested check failures.\<close>
datatype ('a, 'b) check_wellformed_conds = check_wellformed_conds 'a 'b
(* clagged from HOL.Product_Type *)
nonterminal check_wellformed_args
syntax
"_check_wellformed_conds" ::
"'a \<Rightarrow> check_wellformed_args \<Rightarrow> ('a, 'b) check_wellformed_conds" ("(1\<langle>_ \<rightarrow>/ _\<rangle>)")
"_check_wellformed_arg" :: "'a \<Rightarrow> check_wellformed_args" ("_")
"_check_wellformed_args" :: "'a \<Rightarrow> check_wellformed_args \<Rightarrow> check_wellformed_args" ("_ \<rightarrow> _")
translations
"\<langle>x \<rightarrow> y\<rangle>" \<rightleftharpoons> "CONST check_wellformed_conds x y"
"_check_wellformed_conds x (_check_wellformed_args y z)" \<rightleftharpoons>
"_check_wellformed_conds x (_check_wellformed_arg (_check_wellformed_conds y z))"
lemma check_wellformed_merge[wellformed_CAMKES_simps]:
"check_wellformed x (check_wellformed y P) = check_wellformed (\<langle>x \<rightarrow> y\<rangle>) P"
by (simp add: remove_generic_tag)
(* example *)
term "check_wellformed \<langle>x \<rightarrow> y \<rightarrow> z\<rangle> P"
end
(*>*)