diff --git a/examples/technical_report/Isabelle_DOF-Manual/04_RefMan.thy b/examples/technical_report/Isabelle_DOF-Manual/04_RefMan.thy index 239b97c..f4045db 100755 --- a/examples/technical_report/Isabelle_DOF-Manual/04_RefMan.thy +++ b/examples/technical_report/Isabelle_DOF-Manual/04_RefMan.thy @@ -234,15 +234,16 @@ A document class\<^bindex>\document class\ can be defined using the We call document classes with an \accepts_clause\ \<^emph>\monitor classes\ or \<^emph>\monitors\ for short. \<^rail>\ @@{command "doc_class"} class_id '=' (class_id '+')? (attribute_decl+) \ - (invariant_decl*) + (invariant_decl?) (accepts_clause rejects_clause?)?\ \<^item> \attribute_decl\:\<^index>\attribute\_decl@\attribute_decl\\ \<^rail>\ name '::' '"' type '"' default_clause? \ \<^item> \invariant_decl\:\<^index>\invariant\_decl@\invariant_decl\\ Invariants can be specified as predicates over document classes represented as records in HOL. Note that sufficient type information must be provided in order to - disambiguate the argument of the \\\-expression. - \<^rail>\ 'inv' (name '::')? '"' term '"' \ + disambiguate the argument of the expression + and the \<^boxed_text>\\\ symbol is reserved to reference the instance of the class itself. + \<^rail>\ 'invariant' name '::' '"' term '"' + 'and' \ \<^item> \accepts_clause\:\<^index>\accepts\_clause@\accepts_clause\\ \<^rail>\ 'accepts' '"' regexpr '"'\ \<^item> \rejects_clause\:\<^index>\rejects\_clause@\rejects_clause\\ @@ -900,39 +901,43 @@ schemata: section*["sec:advanced"::technical]\Advanced ODL Concepts\ +text\This section will be based on the following example.\ -text\For example, assume the following local ontology: +subsection*["sec:example"::technical]\Example\ +text\Assume the following local ontology: -@{boxed_theory_text [display] \ +@{boxed_theory_text [display]\ doc_class title = - short_title :: "string option" <= "None" -doc_class author = email :: "string" <= "''''" + short_title :: "string option" <= "None" +doc_class author = + email :: "string" <= "''''" datatype classification = SIL0 | SIL1 | SIL2 | SIL3 | SIL4 doc_class abstract = - keywordlist :: "string list" <= [] safety_level :: "classification" <= "SIL3" + keywordlist :: "string list" <= "[]" + safety_level :: "classification" <= "SIL3" doc_class text_section = - authored_by :: "author set" <= "{}" level :: "int option" <= "None" + authored_by :: "author set" <= "{}" + level :: "int option" <= "None" type_synonym notion = string doc_class introduction = text_section + - authored_by :: "author set" <= "UNIV" - uses :: "notion set" + authored_by :: "author set" <= "UNIV" + uses :: "notion set" doc_class claim = introduction + - based_on :: "notion list" + based_on :: "notion list" doc_class technical = text_section + - formal_results :: "thm list" + formal_results :: "thm list" doc_class "definition" = technical + - is_formal :: "bool" - property :: "term list" <= "[]" -datatype kind = expert_opinion | argument | proof + is_formal :: "bool" + property :: "term list" <= "[]" +datatype kind = expert_opinion | argument | "proof" doc_class result = technical + - evidence :: kind - property :: "thm list" <= "[]" + evidence :: kind + property :: "thm list" <= "[]" doc_class example = technical + - referring_to :: "(notion + definition) set" <= "{}" + referring_to :: "(notion + definition) set" <= "{}" doc_class "conclusion" = text_section + - establish :: "(claim \ result) set" -\ -} + establish :: "(claim \ result) set" +\} \ subsection\Meta-types as Types\ @@ -950,20 +955,101 @@ text\ conventional type-checking that this string represents actually a defined entity in the context of the system state \<^boxed_theory_text>\\\. For example, the \<^boxed_theory_text>\establish\ - attribute in the previous section is the power of the ODL: here, we model + attribute in our example is the power of the ODL: here, we model a relation between \<^emph>\claims\ and \<^emph>\results\ which may be a formal, machine-check theorem of type \<^ML_type>\thm\ denoted by, for example: \<^boxed_theory_text>\property = "[@{thm "system_is_safe"}]"\ in a system context \<^boxed_theory_text>\\\ where this theorem is established. Similarly, attribute values like - \<^boxed_theory_text>\property = "@{term \A \ B\}"\ - require that the HOL-string \<^boxed_theory_text>\A \ B\ is + \<^boxed_theory_text>\property = "@{term \A \ B\}"\ + require that the HOL-string \<^boxed_theory_text>\A \ B\ is again type-checked and represents indeed a formula in \\\. Another instance of this process, which we call \second-level type-checking\, are term-constants generated from the ontology such as \<^boxed_theory_text>\@{definition }\. \ +(*<*) +declare_reference*["sec:monitors"::technical] +declare_reference*["sec:low_level_inv"::technical] +(*>*) + +subsection*["sec:class_inv"::technical]\ODL Class Invariants\ + + +text\ + Ontological classes as described so far are too liberal in many situations. + There is a first high-level syntax implementation for class invariants. + These invariants can be checked when an instance of the class is defined. + To enable the checking of the invariants, the \<^boxed_theory_text>\invariants_checking\ + theory attribute must be set: + @{boxed_theory_text [display]\ + declare[[invariants_checking = true]]\} + + For example, let's define the following two classes: + @{boxed_theory_text [display]\ + doc_class class_inv1 = + int1 :: "int" + invariant inv1 :: "int1 \ \ 3" + + doc_class class_inv2 = class_inv1 + + int2 :: "int" + invariant inv2 :: "int2 \ < 2" + \} + + The \<^boxed_theory_text>\\\ symbol is reserved and references the future instance class. + By relying on the implementation of the Records + in Isabelle/HOL~@{cite "wenzel:isabelle-isar:2020"}, + one can reference an attribute of an instance using its selector function. + For example, \<^boxed_theory_text>\int1 \\ denotes the value + of the \<^boxed_theory_text>\int1\ attribute + of the future instance of the class \<^boxed_theory_text>\class_inv1\. + + Now let's define two instances, one of each class: + + @{boxed_theory_text [display]\ + text*[testinv1::class_inv1, int1=4]\lorem ipsum...\ + text*[testinv2::class_inv2, int1=3, int2=1]\lorem ipsum...\ + \} + + The value of each attribute defined for the instances is checked against their classes invariants. + As the class \<^boxed_theory_text>\class_inv2\ is a subsclass + of the class \<^boxed_theory_text>\class_inv1\, it inherits \<^boxed_theory_text>\class_inv1\ invariants. + Hence the \<^boxed_theory_text>\inv1\ invariant is checked + when the instance \<^boxed_theory_text>\testinv2\ is defined. + + Now let's add some invariants to our example in \<^technical>\sec:example\. + For example, one + would like to express that any instance of a \<^boxed_theory_text>\result\ class finally has + a non-empty property list, if its \<^boxed_theory_text>\kind\ is \<^boxed_theory_text>\proof\, or that + the \<^boxed_theory_text>\establish\ relation between \<^boxed_theory_text>\claim\ and + \<^boxed_theory_text>\result\ is total. + In a high-level syntax, this type of constraints could be expressed, \<^eg>, by: + @{boxed_theory_text [display]\ + doc_class introduction = text_section + + authored_by :: "author set" <= "UNIV" + uses :: "notion set" + invariant author_finite :: "finite (authored_by \)" + doc_class result = technical + + evidence :: kind + property :: "thm list" <= "[]" + invariant has_property :: "evidence \ = proof \ property \ \ []" + doc_class example = technical + + referring_to :: "(notion + definition) set" <= "{}" + doc_class conclusion = text_section + + establish :: "(claim \ result) set" + invariant total_rel :: "\ x. x \ Domain (establish \) + \ (\ y \ Range (establish \). (x, y) \ establish \)" + \} + All specified constraints are already checked in the IDE of \<^dof> while editing. + The invariant \<^boxed_theory_text>\author_finite\ enforces that the user sets the + \<^boxed_theory_text>\authored_by\ set. + There are still some limitations with this high-level syntax. + For now, the high-level syntax does not support monitors (see \<^technical>\sec:monitors\). + For example, one would like to delay a final error message till the + closing of a monitor. + For this use-case you can use low-level class invariants (see \<^technical>\sec:low_level_inv\). +\ subsection*["sec:monitors"::technical]\ODL Monitors\ text\ @@ -1014,49 +1100,33 @@ text\ smaller than the others. Thus, an introduction is forced to have a header delimiting the borders of its representation. Class invariants on monitors allow for specifying structural properties on document - sections.\ + sections. + For now, the high-level syntax of invariants is not supported for monitors and you must use the + the low-level class invariants (see \<^technical>\sec:low_level_inv\.\ -subsection*["sec:class_inv"::technical]\ODL Class Invariants\ - +subsection*["sec:low_level_inv"::technical]\ODL Low-level Class Invariants\ text\ - Ontological classes as described so far are too liberal in many situations. For example, one - would like to express that any instance of a \<^boxed_theory_text>\result\ class finally has a - non-empty property list, if its \<^boxed_theory_text>\kind\ is \<^boxed_theory_text>\proof\, or that - the \<^boxed_theory_text>\establish\ relation between \<^boxed_theory_text>\claim\ and - \<^boxed_theory_text>\result\ is surjective. - - In a high-level syntax, this type of constraints could be expressed, \<^eg>, by: - -@{boxed_theory_text [display]\ -(* 1 *) \ x \ result. x@evidence = proo$$f \ x@property \ [] -(* 2 *) \ x \ conclusion. \ y \ Domain(x@establish) - \ \ y \ Range(x@establish). (y,z) \ x@establish -(* 3 *) \ x \ introduction. finite(x@authored_by) -\} - - where \<^boxed_theory_text>\result\, \<^boxed_theory_text>\conclusion\, and \<^boxed_theory_text>\introduction\ are the set of - all possible instances of these document classes. All specified constraints are already checked - in the IDE of \<^dof> while editing; it is however possible to delay a final error message till the - closing of a monitor (see next section). The third constraint enforces that the user sets the - \<^boxed_theory_text>\authored_by\ set, otherwise an error will be reported. - - For the moment, there is no high-level syntax for the definition of class invariants. A - formulation, in SML, of the first class-invariant in \<^technical>\sec:class_inv\ is straight-forward: + If one want to go over the limitations of the actual high-level syntax of the invariant, + one can define a function using SML. + A formulation, in SML, of the class-invariant \<^boxed_theory_text>\has_property\ + in \<^technical>\sec:class_inv\, defined in the supposedly \Low_Level_Syntax_Invariants\ theory + (note the long name of the class), + is straight-forward: \begin{sml} fun check_result_inv oid {is_monitor:bool} ctxt = - let val kind = compute_attr_access ctxt "kind" oid <@>{here} <@>{here} - val prop = compute_attr_access ctxt "property" oid <@>{here} <@>{here} + let val kind = AttributeAccess.compute_attr_access ctxt "evidence" oid <@>{here} <@>{here} + val prop = AttributeAccess.compute_attr_access ctxt "property" oid <@>{here} <@>{here} val tS = HOLogic.dest_list prop - in case kind_term of + in case kind of <@>{term "proof"} => if not(null tS) then true else error("class result invariant violation") | _ => false end val _ = Theory.setup (DOF_core.update_class_invariant - "tiny_cert.result" check_result_inv) + "Low_Level_Syntax_Invariants.result" check_result_inv) \end{sml} The \<^ML>\Theory.setup\-command (last line) registers the \<^boxed_theory_text>\check_result_inv\ function diff --git a/examples/technical_report/Isabelle_DOF-Manual/05_Implementation.thy b/examples/technical_report/Isabelle_DOF-Manual/05_Implementation.thy index 14150b3..eeb5d0e 100755 --- a/examples/technical_report/Isabelle_DOF-Manual/05_Implementation.thy +++ b/examples/technical_report/Isabelle_DOF-Manual/05_Implementation.thy @@ -180,27 +180,7 @@ text\ section\Programming Class Invariants\ text\ - For the moment, there is no high-level syntax for the definition of class invariants. A - formulation, in SML, of the first class-invariant in @{docitem "sec:class_inv"} is straight-forward: - -@{boxed_sml [display] -\fun check_result_inv oid {is_monitor:bool} ctxt = - let val kind = compute_attr_access ctxt "kind" oid <@>{here} <@>{here} - val prop = compute_attr_access ctxt "property" oid <@>{here} <@>{here} - val tS = HOLogic.dest_list prop - in case kind_term of - <@>{term "proof"} => if not(null tS) then true - else error("class result invariant violation") - | _ => false - end - val _ = Theory.setup (DOF_core.update_class_invariant - "tiny_cert.result" check_result_inv)\} - - The \<^boxed_sml>\setup\-command (last line) registers the \<^boxed_theory_text>\check_result_inv\ function - into the \<^isadof> kernel, which activates any creation or modification of an instance of - \<^boxed_theory_text>\result\. We cannot replace \<^boxed_theory_text>\compute_attr_access\ by the corresponding - antiquotation \<^boxed_theory_text>\@{docitem_value kind::oid}\, since \<^boxed_theory_text>\oid\ is - bound to a variable here and can therefore not be statically expanded. + See \<^technical>\sec:low_level_inv\. \ section\Implementing Monitors\ diff --git a/src/DOF/Isa_DOF.thy b/src/DOF/Isa_DOF.thy index 6826442..f163c05 100644 --- a/src/DOF/Isa_DOF.thy +++ b/src/DOF/Isa_DOF.thy @@ -63,8 +63,14 @@ val docclassN = "doc_class"; (** name components **) -val makeN = "make"; +val defN = "def" +val def_suffixN = "_" ^ defN +val defsN = defN ^ "s" val instances_of_suffixN = "_instances" +val invariant_suffixN = "_inv" +val invariantN = "\" +val makeN = "make" +val schemeN = "_scheme" (* derived from: theory_markup *) fun docref_markup_gen refN def name id pos = @@ -534,13 +540,13 @@ fun get_object_local oid ctxt = case get_object_local_opt oid ctxt of |SOME(bbb) => bbb fun get_doc_class_global cid thy = - if cid = default_cid then error("default class acces") (* TODO *) + if cid = default_cid then error("default class access") (* TODO *) else let val t = #docclass_tab(get_data_global thy) in (Symtab.lookup t cid) end fun get_doc_class_local cid ctxt = - if cid = default_cid then error("default class acces") (* TODO *) + if cid = default_cid then error("default class access") (* TODO *) else let val t = #docclass_tab(get_data ctxt) in (Symtab.lookup t cid) end @@ -799,11 +805,20 @@ val _ = val (strict_monitor_checking, strict_monitor_checking_setup) = Attrib.config_bool \<^binding>\strict_monitor_checking\ (K false); +val (invariants_checking, invariants_checking_setup) + = Attrib.config_bool \<^binding>\invariants_checking\ (K false); + +val (invariants_checking_with_tactics, invariants_checking_with_tactics_setup) + = Attrib.config_bool \<^binding>\invariants_checking_with_tactics\ (K false); + + end (* struct *) \ -setup\DOF_core.strict_monitor_checking_setup\ +setup\DOF_core.strict_monitor_checking_setup + #> DOF_core.invariants_checking_setup + #> DOF_core.invariants_checking_with_tactics_setup\ section\ Syntax for Term Annotation Antiquotations (TA)\ @@ -1121,7 +1136,6 @@ fun declare_class_instances_annotation thy doc_class_name = val qual = Long_Name.qualifier long_name val transformer_name = Long_Name.qualify qual (DOF_core.get_doc_class_name_without_ISA_prefix (Binding.name_of bind')) - val _ = writeln ("transformer_name: " ^ transformer_name) in DOF_core.update_isa_global (transformer_name, {check=check_identity, elaborate= elaborate_instances_list}) thy end) @@ -1258,7 +1272,6 @@ fun cid_2_cidType cid_long thy = fun fathers cid_long = case Symtab.lookup t cid_long of NONE => let val ctxt = Proof_Context.init_global thy val tty = Syntax.parse_typ (Proof_Context.init_global thy) cid_long - val _ = writeln ("XXX"^(Syntax.string_of_typ ctxt tty)) in error("undefined doc class id :"^cid_long) end | SOME ({inherits_from=NONE, ...}) => [cid_long] @@ -1413,9 +1426,59 @@ fun register_oid_cid_in_open_monitors oid pos cid_long thy = DOF_core.map_data_global(update_automatons) end +fun check_invariants thy oid = + let + val value = the (DOF_core.get_value_global oid thy) + val cid = #cid (the (DOF_core.get_object_global oid thy)) + fun get_all_invariants cid thy = + let val invs = #invs (the (DOF_core.get_doc_class_global cid thy)) + in case DOF_core.get_doc_class_global cid thy of + NONE => error("undefined class id for invariants: " ^ cid) + | SOME ({inherits_from=NONE, ...}) => invs + | SOME ({inherits_from=SOME(_,father), ...}) => (invs) @ (get_all_invariants father thy) + end + val invariants = get_all_invariants cid thy + val inv_and_apply_list = + let fun mk_inv_and_apply inv value thy = + let val ((s, pos), _ (*term*)) = inv + val inv_def = Syntax.read_term_global thy (s ^ invariant_suffixN) + val inv_def_typ = Term.type_of value + in case inv_def of + Const (s, Type (st, [_ (*ty*), ty'])) => + ((s, pos), Const (s, Type (st,[inv_def_typ, ty'])) $ value) + | _ => ((s, pos), inv_def $ value) + end + in map (fn inv => mk_inv_and_apply inv value thy) invariants + end + fun check_invariants' ((inv_name, pos), term) = + let val ctxt = Proof_Context.init_global thy + val evaluated_term = Value_Command.value ctxt term + handle ERROR e => + if (String.isSubstring "Wellsortedness error" e) + andalso (Config.get_global thy DOF_core.invariants_checking_with_tactics) + then (warning("Invariants checking uses proof tactics"); + let val prop_term = HOLogic.mk_Trueprop term + val thms = Proof_Context.get_thms ctxt (inv_name ^ def_suffixN) + (* Get the make definition (def(1) of the record) *) + val thms' = + (Proof_Context.get_thms ctxt (Long_Name.append cid defsN)) @ thms + val _ = Goal.prove ctxt [] [] prop_term + (K ((unfold_tac ctxt thms') THEN (auto_tac ctxt))) + |> Thm.close_derivation \<^here> + (* If Goal.prove does not fail, then the evaluation is considered True, + else an error is triggered by Goal.prove *) + in @{term True} end) + else (error e) + in (if evaluated_term = \<^term>\True\ + then ((inv_name, pos), term) + else ISA_core.err ("Invariant " ^ inv_name ^ " violated") pos) + end + val _ = map check_invariants' inv_and_apply_list + in thy end fun create_and_check_docitem is_monitor {is_inline=is_inline} oid pos cid_pos doc_attrs thy = - let val id = serial (); + let + val id = serial (); val _ = Position.report pos (docref_markup true oid id pos); (* creates a markup label for this position and reports it to the PIDE framework; this label is used as jump-target for point-and-click feature. *) @@ -1442,7 +1505,8 @@ fun create_and_check_docitem is_monitor {is_inline=is_inline} oid pos cid_pos do val (value_term', _(*ty*), _) = calc_update_term thy cid_long assns' defaults in value_term' end val check_inv = (DOF_core.get_class_invariant cid_long thy oid is_monitor) - o Context.Theory + o Context.Theory + in thy |> DOF_core.define_object_global (oid, {pos = pos, thy_name = Context.theory_name thy, value = value_term, @@ -1452,6 +1516,9 @@ fun create_and_check_docitem is_monitor {is_inline=is_inline} oid pos cid_pos do vcid = vcid}) |> register_oid_cid_in_open_monitors oid pos cid_long |> (fn thy => (check_inv thy; thy)) + |> (fn thy => if Config.get_global thy DOF_core.invariants_checking = true + then check_invariants thy oid + else thy) end @@ -2134,15 +2201,39 @@ fun mk_meta_eq (t, u) = meta_eq_const (fastype_of t) $ t $ u; fun define_cond binding f_sty cond_suffix read_cond (ctxt:local_theory) = let val bdg = Binding.suffix_name cond_suffix binding - val eq = mk_meta_eq(Free(Binding.name_of bdg, f_sty),read_cond ctxt) + val eq = mk_meta_eq(Free(Binding.name_of bdg, f_sty),read_cond) val args = (SOME(bdg,NONE,NoSyn), (Binding.empty_atts,eq),[],[]) in def_cmd args true ctxt end fun define_inv cid_long ((lbl, pos), inv) thy = - let val bdg = (* Binding.suffix_name cid_long *) (Binding.make (lbl,pos)) - fun inv_term ctxt = Syntax.read_term ctxt inv - val inv_ty = (Syntax.read_typ_global thy cid_long) --> HOLogic.boolT - in thy |> Named_Target.theory_map (define_cond bdg inv_ty "_inv" inv_term) end + let val bdg = Binding.make (lbl,pos) + val inv_term = Syntax.read_term (Proof_Context.init_global thy) inv + fun update_attribute_type thy class_scheme_ty + (Const (s, Type (st,[ty, ty'])) $ t) = + let + val cid = Long_Name.qualifier s + in case DOF_core.get_doc_class_global cid thy of + NONE => Const (s, Type(st,[ty, ty'])) + $ (update_attribute_type thy class_scheme_ty t) + | SOME _ => Const(s, Type(st,[class_scheme_ty, ty'])) + $ (update_attribute_type thy class_scheme_ty t) + end + | update_attribute_type thy class_scheme_ty (t $ t') = + (update_attribute_type thy class_scheme_ty t) + $ (update_attribute_type thy class_scheme_ty t') + | update_attribute_type thy class_scheme_ty (Abs(s, ty, t)) = + Abs(s, ty, update_attribute_type thy class_scheme_ty t) + | update_attribute_type _ class_scheme_ty (Free(s, ty)) = if s = invariantN + then Free (s, class_scheme_ty) + else Free (s, ty) + | update_attribute_type _ _ t = t + val inv_ty = Syntax.read_typ (Proof_Context.init_global thy) ("'a " ^ cid_long ^ schemeN) + (* Update the type of each attribute update function to match the type of the + current class. *) + val inv_term' = update_attribute_type thy inv_ty inv_term + val eq_inv_ty = inv_ty --> HOLogic.boolT + val abs_term = Term.lambda (Free (invariantN, inv_ty)) inv_term' + in thy |> Named_Target.theory_map (define_cond bdg eq_inv_ty invariant_suffixN abs_term) end fun add_doc_class_cmd overloaded (raw_params, binding) raw_parent raw_fieldsNdefaults reject_Atoms regexps invariants thy = diff --git a/src/ontologies/Conceptual/Conceptual.thy b/src/ontologies/Conceptual/Conceptual.thy index 68a7c6c..8857b2f 100755 --- a/src/ontologies/Conceptual/Conceptual.thy +++ b/src/ontologies/Conceptual/Conceptual.thy @@ -118,9 +118,9 @@ doc_class F = to an association class. It can be used to track claims to result - relations, for example.*) b' :: "(A \ C) list" <= "[]" - invariant br :: "\\::F. r \ \ [] \ card(b \) \ 3" - and br':: "\\::F. r \ \ [] \ length(b' \) \ 3" - and cr :: "\\::F. properties \ \ []" + invariant br :: "r \ \ [] \ card(b \) \ 3" + and br':: "r \ \ [] \ length(b' \) \ 3" + and cr :: "properties \ \ []" text\The effect of the invariant declaration is to provide intern definitions for validation functions of this invariant. They can be referenced as follows:\ diff --git a/src/ontologies/scholarly_paper/scholarly_paper.thy b/src/ontologies/scholarly_paper/scholarly_paper.thy index 749f381..de669b4 100755 --- a/src/ontologies/scholarly_paper/scholarly_paper.thy +++ b/src/ontologies/scholarly_paper/scholarly_paper.thy @@ -137,7 +137,7 @@ doc_class technical = text_section + definition_list :: "string list" <= "[]" status :: status <= "description" formal_results :: "thm list" - invariant L1 :: "\\::technical. the (level \) > 0" + invariant L1 :: "the (level \) > 0" type_synonym tc = technical (* technical content *) @@ -186,8 +186,8 @@ doc_class math_content = tc + short_name :: string <= "''''" status :: status <= "semiformal" mcc :: "math_content_class" <= "thm" - invariant s1 :: "\ \::math_content. \referentiable \ \ short_name \ = ''''" - invariant s2 :: "\ \::math_content. technical.status \ = semiformal" + invariant s1 :: "\referentiable \ \ short_name \ = ''''" + invariant s2 :: "technical.status \ = semiformal" type_synonym math_tc = math_content text\The class \<^typ>\math_content\ is perhaps more adequaltely described as "math-alike content". @@ -236,27 +236,28 @@ text\The key class definitions are motivated by the AMS style.\ doc_class "definition" = math_content + referentiable :: bool <= True mcc :: "math_content_class" <= "defn" - invariant d1 :: "\ \::definition. mcc \ = defn" (* can not be changed anymore. *) + invariant d1 :: "mcc \ = defn" (* can not be changed anymore. *) + doc_class "theorem" = math_content + referentiable :: bool <= True mcc :: "math_content_class" <= "thm" - invariant d2 :: "\ \::theorem. mcc \ = thm" + invariant d2 :: "mcc \ = thm" doc_class "lemma" = math_content + referentiable :: bool <= "True" mcc :: "math_content_class" <= "lem" - invariant d3 :: "\ \::lemma. mcc \ = lem" + invariant d3 :: "mcc \ = lem" doc_class "corollary" = math_content + referentiable :: bool <= "True" mcc :: "math_content_class" <= "cor" - invariant d4 :: "\ \::corollary. mcc \ = thm" + invariant d4 :: "mcc \ = thm" doc_class "math_example" = math_content + referentiable :: bool <= "True" mcc :: "math_content_class" <= "expl" - invariant d5 :: "\ \::math_example. mcc \ = expl" + invariant d5 :: "mcc \ = expl" subsubsection\Ontological Macros \<^verbatim>\Definition*\ , \<^verbatim>\Lemma**\, \<^verbatim>\Theorem*\ ... \ diff --git a/src/tests/Concept_ExampleInvariant.thy b/src/tests/Concept_Example_Low_Level_Invariant.thy similarity index 99% rename from src/tests/Concept_ExampleInvariant.thy rename to src/tests/Concept_Example_Low_Level_Invariant.thy index a363f76..c1fa53e 100755 --- a/src/tests/Concept_ExampleInvariant.thy +++ b/src/tests/Concept_Example_Low_Level_Invariant.thy @@ -14,7 +14,7 @@ chapter\Setting and modifying attributes of doc-items\ theory - Concept_ExampleInvariant + Concept_Example_Low_Level_Invariant imports "Isabelle_DOF.Conceptual" (* we use the generic "Conceptual" ontology *) begin diff --git a/src/tests/High_Level_Syntax_Invariants.thy b/src/tests/High_Level_Syntax_Invariants.thy new file mode 100644 index 0000000..805cc59 --- /dev/null +++ b/src/tests/High_Level_Syntax_Invariants.thy @@ -0,0 +1,114 @@ +chapter\High level syntax Invariants\ + +theory High_Level_Syntax_Invariants + imports "Isabelle_DOF.Isa_DOF" +begin + +text\ + Ontological classes as described so far are too liberal in many situations. + There is a first high-level syntax implementation for class invariants. + These invariants can be checked when an instance of the class is defined. + To enable the checking of the invariants, the \invariants_checking\ + theory attribute must be set:\ + + +declare[[invariants_checking = true]] + +text\For example, let's define the following two classes:\ + +doc_class class_inv1 = + int1 :: "int" + invariant inv1 :: "int1 \ \ 3" + +doc_class class_inv2 = class_inv1 + + int2 :: "int" + invariant inv2 :: "int2 \ < 2" + +text\The symbol \<^term>\\\ is reserved and references the future instance class. + By relying on the implementation of the Records + in Isabelle/HOL~@{cite "wenzel:isabelle-isar:2020"}, + one can reference an attribute of an instance using its selector function. + For example, \<^term>\int1 \\ denotes the value + of the \<^term>\int1\ attribute + of the future instance of the class @{doc_class class_inv1}. + Now let's define two instances, one of each class:\ + +text*[testinv1::class_inv1, int1=4]\lorem ipsum...\ +text*[testinv2::class_inv2, int1=3, int2=1]\lorem ipsum...\ + +text\ + The value of each attribute defined for the instances is checked against their classes invariants. + As the class @{doc_class class_inv2} is a subsclass of the class @{doc_class class_inv1}, + it inherits @{doc_class class_inv1} invariants. + Hence the \<^term>\int1\ invariant is checked when the instance @{docitem testinv2} is defined.\ + +text\Now assume the following ontology:\ + +doc_class title = + short_title :: "string option" <= "None" + +doc_class author = + email :: "string" <= "''''" + +datatype classification = SIL0 | SIL1 | SIL2 | SIL3 | SIL4 + +doc_class abstract = + keywordlist :: "string list" <= "[]" + safety_level :: "classification" <= "SIL3" + +doc_class text_section = + authored_by :: "author set" <= "{}" + level :: "int option" <= "None" + +type_synonym notion = string + +doc_class introduction = text_section + + authored_by :: "author set" <= "UNIV" + uses :: "notion set" + invariant author_finite :: "finite (authored_by \)" + +doc_class claim = introduction + + based_on :: "notion list" + +doc_class technical = text_section + + formal_results :: "thm list" + +doc_class "definition" = technical + + is_formal :: "bool" + property :: "term list" <= "[]" + +datatype kind = expert_opinion | argument | "proof" + +doc_class result = technical + + evidence :: kind + property :: "thm list" <= "[]" + invariant has_property :: "evidence \ = proof \ property \ \ []" +doc_class example = technical + + referring_to :: "(notion + definition) set" <= "{}" + +doc_class conclusion = text_section + + establish :: "(claim \ result) set" + invariant total_rel :: "\ x. x \ Domain (establish \) + \ (\ y \ Range (establish \). (x, y) \ establish \)" + +text\Next we define some instances (docitems): \ +text*[church::author, email="\church@lambda.org\"]\\ + +text*[resultProof::result, evidence = "proof", property="[@{thm \HOL.refl\}]"]\\ +text*[resultArgument::result, evidence = "argument"]\\ + +text\The invariants \author_finite\ and \total_rel\ can not be checked directly + and need a little help. + We can set the \invariants_checking_with_tactics\ theory attribute to help the checking. + It will enable a basic tactic, using unfold and auto:\ + +declare[[invariants_checking_with_tactics = true]] + +text*[introductionTest::introduction, authored_by = "{@{author \church\}}"]\\ + +text*[claimNotion::claim, authored_by = "{@{author \church\}}", based_on= "[\Notion1\, \Notion2\]"]\\ + +text*[conclusionProof::conclusion, + establish = "{(@{claim \claimNotion\}, @{result \resultProof\})}"]\\ + +end diff --git a/src/tests/Ontology_Matching_Example.thy b/src/tests/Ontology_Matching_Example.thy new file mode 100644 index 0000000..d374e7c --- /dev/null +++ b/src/tests/Ontology_Matching_Example.thy @@ -0,0 +1,52 @@ +chapter\Ontologys Mathing\ + +theory Ontology_Matching_Example + imports "Isabelle_DOF.Isa_DOF" +begin + +text\Using HOL, we can define a mapping between two ontologies. + It is called ontology matching or ontology alignment. + Here is an example which show how to map two classes. + HOL also allows us to map the invariants (ontological rules) of the classes!\ + +type_synonym UTF8 = string + +definition utf8_to_string + where "utf8_to_string x = x" + + +doc_class A = + first_name :: UTF8 + last_name :: UTF8 + age :: nat + married_to :: "string option" + invariant a :: "age \ < 18 \ married_to \ = None" +doc_class B = + name :: string + adult :: bool + is_married :: bool + invariant b :: "is_married \ \ adult \" + +text\We define the mapping between the two classes, + i.e. how to transform the class @{doc_class A} in to the class @{doc_class B}:\ + +definition A_to_B_morphism + where "A_to_B_morphism X = + \ tag_attribute = A.tag_attribute X + , name = utf8_to_string (first_name X) @ '' '' @ utf8_to_string (last_name X) + , adult = (age X \ 18) + , is_married = (married_to X \ None) \" + +text\Now we check that the invariant is preserved through the morphism:\ + +lemma inv_a_preserved : + "a_inv X \ b_inv (A_to_B_morphism X)" + unfolding a_inv_def b_inv_def A_to_B_morphism_def + by auto + +lemma A_morphism_B_total : + "A_to_B_morphism ` ({X::A. a_inv X}) \ ({X::B. b_inv X})" + using inv_a_preserved + by auto + +end diff --git a/src/tests/ROOT b/src/tests/ROOT index 406d6fb..4ef831b 100755 --- a/src/tests/ROOT +++ b/src/tests/ROOT @@ -2,8 +2,10 @@ session "Isabelle_DOF-tests" = "Isabelle_DOF" + options [document = false] theories "AssnsLemmaThmEtc" - "Concept_ExampleInvariant" + "Concept_Example_Low_Level_Invariant" "Concept_Example" "TermAntiquotations" "Attributes" "Evaluation" + "High_Level_Syntax_Invariants" + "Ontology_Matching_Example"