(* * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) * * SPDX-License-Identifier: GPL-2.0-only *) chapter \Wellformedness of Specifications\ (*<*) theory Wellformed_CAMKES imports Types_CAMKES Helpers_CAMKES Lib.GenericTag begin (*>*) text \ 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. \ subsection \\label{subsec:winterfaces}Interfaces\ text \ 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. \ definition wellformed_method :: "method \ bool" where "wellformed_method m \ (m_name m \ set (map p_name (m_parameters m)) \ distinct (map p_name (m_parameters m)))" text \ The code generated for a procedure is within a single namespace and thus the names of all methods in a procedure must be distinct. \ definition wellformed_procedure :: "procedure \ bool" where "wellformed_procedure i \ (\x \ set i. wellformed_method x) \ distinct (map m_name i)" text \ The implementation currently only supports 32 distinct events (0 - 31). This limitation may be removed in a future iteration. \ definition wellformed_event :: "event \ bool" where "wellformed_event e \ e < 32" text \ Dataports do not have any attributes beyond their type, so their wellformedness is trivial. \ definition wellformed_dataport :: "dataport \ bool" where "wellformed_dataport d \ True" definition wellformed_interface :: "interface \ bool" where "wellformed_interface i \ (case i of Procedure p \ wellformed_procedure p | Event e \ wellformed_event e | Dataport d \ wellformed_dataport d)" subsection \\label{subsec:wcomponents}Components\ text \ For a component to be valid internally, its interfaces must not conflict and must themselves be wellformed. \ definition wellformed_component :: "component \ bool" where "wellformed_component c \ \ \No symbol collisions\ distinct (map fst (requires c) @ map fst (provides c) @ map fst (dataports c) @ map fst (emits c) @ map fst (consumes c)) \ \ \No C symbol collisions.\ (\x \ set (requires c). wellformed_procedure (snd (snd x))) \ (\x \ set (provides c). wellformed_procedure (snd x)) \ \ \Events valid.\ (\x \ set (emits c). wellformed_event (snd x)) \ (\x \ set (consumes c). wellformed_event (snd (snd x))) \ \ \Dataports valid.\ (\x \ set (dataports c). wellformed_dataport (snd x))" subsection \\label{subsec:wconnectors}Connectors\ text \ For now, we don't really restrict what combinations of communication mechanisms connectors can use. This can be refined later. \ definition wellformed_connector :: "connector \ bool" where "wellformed_connector c \ True" subsection \\label{subsec:wconnections}Connections\ definition wellformed_connection :: "connection \ bool" where "wellformed_connection c \ True" subsection \\label{subsec:wsymbols}ADL Symbol Resolution\ text \ 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. \ definition ex_one :: "'a list \ ('a \ bool) \ bool" where "ex_one xs P \ length (filter P xs) = 1" text \ More convenient syntax for @{const ex_one}. \ syntax "_ex_one" :: "pttrn \ 'a set \ bool \ bool" ("(4\1 _\_./ _)" [0, 0, 10] 10) translations "\1 x\xs. P" == "CONST ex_one xs (\x. P)" text \ 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. \ definition refs_valid_procedures :: "adl_symbol \ (adl_symbol \ (InterfaceRequired \ procedure)) list \ (adl_symbol \ connection) list \ bool" where "refs_valid_procedures component_instance procedures conns \ \(name, (req, proc)) \ set procedures. req = InterfaceRequired \ proc \ [] \ (\1 z \ (concat (map (\y. conn_from (snd y)) conns)). z = (component_instance, name))" text \ For events and dataports, an interface can be left unconnected in a system with no adverse effects. \ definition refs_valid_components :: "(adl_symbol \ component) list \ (adl_symbol \ connection) list \ bool" where "refs_valid_components comps conns \ \x \ set comps. refs_valid_procedures (fst x) (requires (snd x)) conns" text \ Each connection must be connecting interfaces of the same underlying type. \ definition refs_valid_connection :: "connection \ (adl_symbol \ component) list \ bool" where "refs_valid_connection conn component_list \ wellformed_connector (conn_type conn) \ (\ \Every to- and from-end of the component must exist.\ \(from_name, from_interface) \ set (conn_from conn). \1from \ component_list. fst from = from_name \ (\(to_name, to_interface) \ set (conn_to conn). \1to \ component_list. fst to = to_name \ \ \The following checks that the component interfaces have the correct type.\ (case connector_interface (conn_type conn) of RPCInterface \ from_interface \ fst ` set (requires (snd from)) \ to_interface \ fst ` set (provides (snd to)) | EventInterface \ from_interface \ fst ` set (emits (snd from)) \ to_interface \ fst ` set (consumes (snd to)) \ \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.\ | DataportInterface \ from_interface \ fst ` set (dataports (snd from)) \ to_interface \ fst ` set (dataports (snd to)) ) \ \ \Next, we check that the kind of components being connected are appropriate.\ (case connector_type (conn_type conn) of \ \Both endpoints must be regular components.\ NativeConnector \ \ hardware (snd from) \ \ hardware (snd to) \ \At least one endpoint must be a hardware component. FIXME: might not be quite what we want.\ | HardwareConnector \ hardware (snd from) \ hardware (snd to) | ExportConnector \ undefined ''compound components not supported yet'' ) ) )" definition refs_valid_connections :: "(adl_symbol \ connection) list \ (adl_symbol \ component) list \ bool" where "refs_valid_connections conns comps \ \x \ set conns. refs_valid_connection (snd x) comps" definition refs_valid_composition :: "composition \ bool" where "refs_valid_composition c \ refs_valid_components (components c) (connections c) \ refs_valid_connections (connections c) (components c)" subsection \\label{subsec:wsystem}Overall System\ text \ We obtain a guarantee of the correctness of a component composition by composing the required properties of its constituents. \ definition wellformed_composition :: "composition \ bool" where "wellformed_composition c \ \ \This system contains @{text \\ 1\} active component.\ (\x \ set (components c). control (snd x)) \ \ \All references resolve.\ refs_valid_composition c \ \ \The @{const group_labels} mapping refers to existing ADL names.\ (\(comp, group) \ set (group_labels c). comp \ (fst ` set (components c) \ fst ` set (connections c))) \ \ \All connectors and components have distinct names. These names will correspond to integrity policy labels.\ distinct (map fst (components c) @ map fst (connections c)) \ \ \All components are valid.\ (\x \ set (components c). wellformed_component (snd x)) \ \ \All connections are valid.\ (\x \ set (connections c). wellformed_connection (snd x))" (*<*) lemma wellformed_composition_is_nonempty: "\wellformed_composition c\ \ components c \ []" by (fastforce simp:wellformed_composition_def) (*>*) definition wellformed_configuration :: "configuration \ bool" where "wellformed_configuration conf \ True" (* TODO *) definition wellformed_assembly :: "assembly \ bool" where "wellformed_assembly a \ wellformed_composition (composition a) \ (case (configuration a) of None \ True | Some x \ wellformed_configuration x)" (*<*) text \ These are alternative definitions that have annotations, to help debug assemblies that are processed by the CAmkES proof toolchain. \ abbreviation "check_wellformed entity P \ generic_tag ''Wellformed_CAMKES'' entity P" lemma wellformed_method_ann: "wellformed_method m = check_wellformed (wellformed_method, m) (m_name m \ set (map p_name (m_parameters m)) \ 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) ((\x \ set i. wellformed_method x) \ 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) ( \ \No symbol collisions\ (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)) \ \ \No C symbol collisions.\ (\x \ set (requires c). wellformed_procedure (snd (snd x))) \ (\x \ set (provides c). wellformed_procedure (snd x)) \ \ \Events valid.\ (\x \ set (emits c). wellformed_event (snd x)) \ (\x \ set (consumes c). wellformed_event (snd (snd x))) \ \ \Dataports valid.\ (\x \ 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 = (\(name, (req, proc)) \ set procedures. req = InterfaceRequired \ check_wellformed (refs_valid_procedures, name) (proc \ [] \ (\1 z \ (concat (map (\y. conn_from (snd y)) conns)). z = (component_instance, name))))" by (simp only: refs_valid_procedures_def remove_generic_tag simp_thms) text \ For events and dataports, an interface can be left unconnected in a system with no adverse effects. \ lemma refs_valid_components_ann: "refs_valid_components comps conns = (\x \ 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 \ Each connection must be connecting interfaces of the same underlying type. \ lemma refs_valid_connection_ann: "refs_valid_connection conn component_list = (wellformed_connector (conn_type conn) \ (\ \Every to- and from-end of the component must exist.\ \(from_name, from_interface) \ set (conn_from conn). \1from \ component_list. fst from = from_name \ (\(to_name, to_interface) \ set (conn_to conn). \1to \ component_list. fst to = to_name \ \ \The following checks that the component interfaces have the correct type.\ check_wellformed ((refs_valid_connection, ''interface''), (from_name, to_name)) (case connector_interface (conn_type conn) of RPCInterface \ from_interface \ fst ` set (requires (snd from)) \ to_interface \ fst ` set (provides (snd to)) | EventInterface \ from_interface \ fst ` set (emits (snd from)) \ to_interface \ fst ` set (consumes (snd to)) \ \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.\ | DataportInterface \ from_interface \ fst ` set (dataports (snd from)) \ to_interface \ fst ` set (dataports (snd to)) ) \ \ \Next, we check that the kind of components being connected are appropriate.\ check_wellformed ((refs_valid_connection, ''component''), (from_name, to_name)) (case connector_type (conn_type conn) of \ \Both endpoints must be regular components.\ NativeConnector \ \ hardware (snd from) \ \ hardware (snd to) \ \At least one endpoint must be a hardware component. FIXME: might not be quite what we want.\ | HardwareConnector \ hardware (snd from) \ hardware (snd to) | ExportConnector \ 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 = (\x \ 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 = ( \ \This system contains @{text \\ 1\} active component.\ check_wellformed (wellformed_composition, ''control'', map fst (components c)) (\x \ set (components c). control (snd x)) \ \ \All references resolve.\ refs_valid_composition c \ \ \The @{const group_labels} mapping refers to existing ADL names.\ (\(comp, group) \ set (group_labels c). check_wellformed (wellformed_composition, ''group_labels'', comp) (comp \ (fst ` set (components c) \ fst ` set (connections c)))) \ \ \All connectors and components have distinct names. These names will correspond to integrity policy labels.\ check_wellformed (wellformed_composition, ''distinct'', map fst (components c) @ map fst (connections c)) (distinct (map fst (components c) @ map fst (connections c))) \ \ \All components are valid.\ (\x \ set (components c). check_wellformed (wellformed_composition, ''component'', fst x) (wellformed_component (snd x))) \ \ \All connections are valid.\ (\x \ 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 \Automation for proving wellformedness properties.\ named_theorems wellformed_CAMKES_simps 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 \These currently have trivial definitions and don't need annotations.\ 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 \Helper to visualise nested check failures.\ 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 \ check_wellformed_args \ ('a, 'b) check_wellformed_conds" ("(1\_ \/ _\)") "_check_wellformed_arg" :: "'a \ check_wellformed_args" ("_") "_check_wellformed_args" :: "'a \ check_wellformed_args \ check_wellformed_args" ("_ \ _") translations "\x \ y\" \ "CONST check_wellformed_conds x y" "_check_wellformed_conds x (_check_wellformed_args y z)" \ "_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 (\x \ y\) P" by (simp add: remove_generic_tag) (* example *) term "check_wellformed \x \ y \ z\ P" end (*>*)