How to fix the bug of No code equations for star in isabelle - isabelle

theory AReg imports Main begin
datatype ('v)regexp = Alp 'v| Alter "('v) regexp" "('v) regexp" (infix "||" 55) | Dot (".")|
Star "'v regexp" ("_*") | Plus "('v) regexp"("_+") | Ques "('v) regexp"("_?")
inductive_set star :: "'a list set \<Rightarrow> 'a list set"
for r :: "'a list set" where
"[] \<in> star r"|
"x \<in> r\<Longrightarrow> x#x \<in> star r"
primrec sem_reg :: "('a) regexp \<Rightarrow> 'a \<Rightarrow> 'a list set" where
"sem_reg (Alp a) v = (if a = v then {[v]} else {})"|
"sem_reg (Dot) a= {[a]}"|
"sem_reg (v1||v2) a = (sem_reg v1 a) \<union> (sem_reg v2 a)"|
"sem_reg (Star a) v = star (sem_reg a v)"|
"sem_reg (Plus a) v = star (sem_reg a v) - {[]}"|
"sem_reg (Ques v) a = {[]} \<union> (sem_reg v a)"
value "sem_reg (Star a) v"
value "sem_reg Dot (1::nat)"
I try to definition the semantics of regular expression. But when I test the Star function, it warns that No code equations for star. How to fix it?

The error message tells you that Isabelle does not know how to evaluate star. Given that the set in infinite, you will not be able to define a function that returns all the possible values.
A possible workaround is to use a different evaluation, namely the simplifier:
value [simp] "sem_reg (Star (a::nat regexp)) v"
value [simp] "sem_reg Dot (1::nat)"
This avoids relying on the code generator. But, exactly as you would expect, star is not evaluated.

Related

How to type boldface symbols in Isabelle

The definition of semigroup and monoid uses bold * and bold 1
locale semigroup =
fixes f :: "'a ⇒ 'a ⇒ 'a" (infixl "❙*" 70)
assumes assoc [ac_simps]: "a ❙* b ❙* c = a ❙* (b ❙* c)"
locale monoid = semigroup +
fixes z :: 'a ("❙1")
assumes left_neutral [simp]: "❙1 ❙* a = a"
assumes right_neutral [simp]: "a ❙* ❙1 = a"
(They don't print well outside of jEdit and instead there is the ❙ symbol)
How do I type those symbols in jEdit? Or more generally, is there some way to lookup ASCII version of any symbol in jEdit?
You need to type \<^bold> (usually just typing \b is enough for autosuggestion to pop up). This will give you the bar ❙. Any symbol you place after the bar will become bold.

How to use a definition written on locale parameters in the assumptions of the locale?

If there is some definition on the parameters of a locale which would make the assumptions of the locale easier to write and/or read and/or understand (either because the function is quite complicated so would simplify the statement of the assumptions, or its name makes the assumptions easier to read and understand), what is the best way to define that function?
As a contrived example, say we want to incorporate the function fg into the statement of the assumptions (not actually useful here of course):
locale defined_after =
fixes f :: "'a ⇒ 'b ⇒ 'c"
and g :: "'b ⇒ 'a"
assumes "∀a. ∃b. f a b = f (g b) b"
and univ: "(UNIV::'b set) = {b}"
begin
definition fg :: "'b ⇒ 'c" where
"fg b ≡ f (g b) b"
lemma "∀b b'. fg b = fg b'" using univ the_elem_eq by (metis (full_types))
(* etc *)
end
One might think to use defines:
locale defined_during =
fixes f :: "'a ⇒ 'b ⇒ 'c"
and g :: "'b ⇒ 'a"
and fg :: "'b ⇒ 'c"
defines fg_def: "fg b ≡ f (g b) b"
assumes "∀a. ∃b. f a b = fg b"
and univ: "(UNIV::'b set) = {b}"
begin
lemma "∀b b'. fg b = fg b'" using univ the_elem_eq by (metis (full_types))
end
but the locales.pdf document seems to suggest it is deprecated (but by what I'm not sure):
The grammar is complete with the exception of the context elements constrains and defines, which are provided for backward compatibility.
Ctrl-hovering over fg in the lemma in the locale defined_after names it as constant "local.fg" whereas in defined_during it is fixed fg\nfree variable. It does however achieve defined_after_def being equal to defined_during_def (i.e. there are no additional parameters or assumptions in the latter), which the third option does not:
locale extra_defined_during =
fixes f :: "'a ⇒ 'b ⇒ 'c"
and g :: "'b ⇒ 'a"
and fg :: "'b ⇒ 'c"
assumes fg_def: "fg b ≡ f (g b) b"
and "∀a. ∃b. f a b = fg b"
and univ: "(UNIV::'b set) = {b}"
begin
lemma "∀b b'. fg b = fg b'" using univ the_elem_eq by (metis (full_types))
end
which also has the same Ctrl-hover text for fg in the lemma as the defined_during locale does.
Maybe there's something about it in one of the PDFs on the website, or in the NEWS file, but I can't find anything obvious. isar-ref.pdf makes a comment:
Both assumes and defines elements contribute to the locale specification. When defining an operation derived from the parameters, definition (§5.4) is usually more appropriate.
But I'm not sure how to use this information. Presumably it is saying that when one doesn't gain much by doing what I am asking about, one should proceed as in the locale defined_after (unless the quote means one can use definition inside a locale definition), which is not what I want. (As an aside: the first sentence of this quote would have suggested to me that defines is somehow equivalent to the third option which introduces an extra parameter and assumption, but that isn't the case. Maybe understanding what the possibly-subtler-than-it-appears-Isabelle-jargon "locale specification" means would explain what is causing the Ctrl-hover text to differ between the first and second option, I don't know.)
The specification element defines is indeed nothing that I would recommend to use. It goes back to a time when definition was not available inside a locale context and all definitions had to be done in the locale declaration itself.
Nowadays, the standard approach to your problem is to split the locale into two parts: First define a locale l1 without the complicated assumption, but with the relevant parameters. (If you need some assumptions to justify the definition, e.g. for the termination proof of function, include those assumptions.) Then define your function fg inside l1 as usual. Finally, define your actual locale l that extends l1. You can then use the definition of fg in the assumptions of l.
locale l = l1 + assumes "... fg ..."

Using a definition to produce an specific example of a locale in Isabelle

I'm working on a theory that requires usage of rings, so I imported the following theories: https://www.isa-afp.org/browser_info/devel/AFP/Group-Ring-Module/
Right now, I have defined a set X of a certain type and I'd like to define operations on it to make it a ring, as in the locale "Ring" of the imported theory.
How do I define a ring with carrier X and have it recognized as an instance of the locale "Ring"?
The locale "Ring" is declared by extending "aGroup", which in turn is declared by extending "Group", which is in the theory "Algebra2.thy":
record 'a Group = "'a carrier" +
top :: "['a, 'a ] ⇒ 'a" (infixl "⋅ı" 70)
iop :: "'a ⇒ 'a" ("ρı _" [81] 80)
one :: "'a" ("𝟭ı")
locale Group =
fixes G (structure)
assumes top_closed: "top G ∈ carrier G → carrier G → carrier G"
and tassoc : "⟦a ∈ carrier G; b ∈ carrier G; c ∈ carrier G⟧ ⟹
(a ⋅ b) ⋅ c = a ⋅ (b ⋅ c)"
and iop_closed:"iop G ∈ carrier G → carrier G"
and l_i :"a ∈ carrier G ⟹ (ρ a) ⋅ a = 𝟭"
and unit_closed: "𝟭 ∈ carrier G"
and l_unit:"a ∈ carrier G ⟹ 𝟭 ⋅ a = a"
Another possible problem I antecipate: if I'm not mistaken, the carrier must be of type 'a set, but my set X is of type ('a set \times 'a) set set. Is there a workaround?
EDIT: In order to better formulate the sequential question in the comments, here are some pieces of what I did. All that follows is within the context of a locale presheaf, that fixes (among other things):
T :: 'a set set and
objectsmap :: "'a set ⇒ ('a, 'm) Ring_scheme" and
restrictionsmap:: "('a set ×'a set) ⇒ ('a ⇒ 'a)"
I then introduced the following:
definition prestalk :: "'a ⇒('a set × 'a) set" where
"prestalk x = { (U,s). (U ∈ T) ∧ x ∈U ∧ (s ∈ carrier (objectsmap U))}"
definition stalkrel :: "'a ⇒ ( ('a set × 'a) × ('a set × 'a) ) set" where
"stalkrel x = {( (U,s), (V,t) ). (U,s) ∈ prestalk x ∧ (V,t) ∈ prestalk x ∧ (∃W. W ⊆ U∩V ∧ x∈W ∧
restrictionsmap (V,W) t = restrictionsmap (U,W)) s} "
I then proved that for each x, stalkrel x is an equivalence relation, and defined:
definition germ:: "'a ⇒ 'a set ⇒ 'a ⇒ ('a set × 'a) set" where
"germ x U s = {(V,t). ((U,s),(V,t)) ∈ stalkrel x}"
definition stalk:: "'a ⇒( ('a set × 'a) set) set" where
"stalk x = {w. (∃ U s. w = germ x U s ∧ (U,s) ∈ prestalk x) }"
I'm trying to show that for each x this stalk x is a ring, and the ring operation is "built" out of the ring operations of rings objectsmap (U∩V) , i.e, I'd like germ x U s + germ x V t to be germ x (U∩V) (restrictionsmap (U, (U∩V)) s + restrictionsmap (V, (U∩V)) t), where this last sum is the sum of ring objectsmap (U∩V).
A multiplicative Group in the AFP entry mentioned is a record with four fields: a set carrier for the carrier, the binary group operation top, the inverse operation iop and the neutral element one. Similarly, a Ring is a record which extends an additive group (record aGroup with fields carrier, pop, mop, zero) with the binary multiplicative operation tp and the multiplicative unit un. If you want to define an instance of a group or record, you must define something of the appropriate record type. For example,
definition my_ring :: "<el> Ring" where
"my_ring =
(|carrier = <c>,
pop = <plus>,
mop = <minus>,
zero = <0>,
tp = <times>,
un = <unit>|)"
where you have to replace all the <...> by the types and terms for your ring. That is, <el> is the type of the ring elements, <c> is the carrier set, etc. Note that you can specialise the type of ring elements as needed.
In order to prove that my_ring is indeed a ring, you must show that it satisfies the assumptions of the corresponding locale Ring:
lemma "Ring my_ring"
proof unfold_locales
...
qed
If you want to use the theorems that have been proven abstractly for arbitrary rings, you may want to interpret the locale using interpretation.

Isabelle: linord proof

My attempt to create a custom linear order for a custom data type failed, Below is my code:
theory Scratch
imports Main
begin
datatype st = Str "string"
fun solf_str_int:: "string ⇒ int" where
"solf_str_int str = (if (size str) > 0
then int(nat_of_char (hd str) + 1) + 100 * (solf_str_int (tl str))
else 0)"
fun soflord:: "st ⇒ st ⇒ bool" where
"soflord s1 s2 = (case s1 of Str ss1 ⇒ (case s2 of Str ss2 ⇒
(solf_str_int ss1) ≤ (solf_str_int ss2)))"
instantiation st :: linorder
begin
definition nleq: "less_eq n1 n2 == soflord n1 n2"
definition neq: "eq n1 n2 == (n1 ≤ n2) ∧ (n2 ≤ n1)"
definition nle: "less n1 n2 == (n1 ≤ n2) ∧ (¬(n1 = n2))" (* ++ *)
instance proof
fix n1 n2 x y :: st
show "n1 ≤ n1" by (simp add:nleq split:st.split)
show "(n1 ≤ n2) ∨ (n2 ≤ n1)" by (simp add:nleq split:st.split) (*why is 'by ()' highlited?*)
(*this fail if I comment line ++ out*)
show "(x < y) = (x ≤ y ∧ (¬ (y ≤ x)))" by (simp add:nleq neq split:node.split)
qed
end
end
The definition marked with (* ++ *) is not right and if delete it the last show give problems.
How do I correct the prove?
Why is the second last show partially highlighted?
When you define the operations of a type class (less_eq and less in the case of linorder), the name of the overloaded operation can only be used if the inferred type of the operation matches exactly the overloaded instance that is being defined. In particular, the type is not specialised if it turns out to be too general.
The definition for less_eq works because soflord restricts the types of n1 and n2 to st, so less_eq is used with type st => st => bool, which is precisely what is needed here. For less, type inference computes the most general type 'b :: ord => 'b => bool. As this is not of the expected type st => st => bool, Isabelle does not recognize the definition as a definition of an overloaded operation and consequently complains that you want to redefine an existing operation in its full generality. If you restrict the types as necessary, then the definition works as expected.
definition nle: "less n1 (n2 :: st) == (n1 ≤ n2) ∧ (¬(n1 = n2))"
However, your definitions do not define a linear order on st. The problem is that antisymmetry is violated. For example, the two strings Str ''d'' and Str [Char Nibble0 Nibble0, Char Nibble0 Nibble0] (i.e., the string consisting of two characters at codepoint 0) are "equivalent" in your order, although they are different values. You attempt to define equality on st, too, but in higher-order logic, equality cannot be defined. It is determined by the way you constructed your type. If you really want to identify strings that are equivalent according to your order, you have to construct a quotient first, e.g., using the quotient package.
The purple highlighting of by(simp ...) indicates that the proof method simp is still running. In your case, it will not terminate, because simp will keep unfolding the defining equation for solf_str_int: its right-hand side contains an instance of the left-hand side. I recommend that you define your functions by pattern-matching on the left-hand side of =. Then, the equations are only used when they can consume a pattern. Thus, you have to trigger case distinctions yourself (e.g. using cases), but you also get more control over the automated tactics.

How to generate code for reverse sorting

What is the easiest way to generate code for a sorting algorithm that sorts its argument in reverse order, while building on top of the existing List.sort?
I came up with two solutions that are shown below in my answer. But both of them are not really satisfactory.
Any other ideas how this could be done?
I came up with two possible solutions. But both have (severe) drawbacks. (I would have liked to obtain the result almost automatically.)
Introduce a Haskell-style newtype. E.g., if we wanted to sort lists of nats, something like
datatype 'a new = New (old : 'a)
instantiation new :: (linorder) linorder
begin
definition "less_eq_new x y ⟷ old x ≥ old y"
definition "less_new x y ⟷ old x > old y"
instance by (default, case_tac [!] x) (auto simp: less_eq_new_def less_new_def)
end
At this point
value [code] "sort_key New [0::nat, 1, 0, 0, 1, 2]"
yields the desired reverse sorting. While this is comparatively easy, it is not as automatic as I would like the solution to be and in addition has a small runtime overhead (since Isabelle doesn't have Haskell's newtype).
Via a locale for the dual of a linear order. First we more or less copy the existing code for insertion sort (but instead of relying on a type class, we make the parameter that represents the comparison explicit).
fun insort_by_key :: "('b ⇒ 'b ⇒ bool) ⇒ ('a ⇒ 'b) ⇒ 'a ⇒ 'a list ⇒ 'a list"
where
"insort_by_key P f x [] = [x]"
| "insort_by_key P f x (y # ys) =
(if P (f x) (f y) then x # y # ys else y # insort_by_key P f x ys)"
definition "revsort_key f xs = foldr (insort_by_key (op ≥) f) xs []"
at this point we have code for revsort_key.
value [code] "revsort_key id [0::nat, 1, 0, 0, 1, 2]"
but we also want all the nice results that have already been proved in the linorder locale (that derives from the linorder class). To this end, we introduce the dual of a linear order and use a "mixin" (not sure if I'm using the correct naming here) to replace all occurrences of linorder.sort_key (which does not allow for code generation) by our new "code constant" revsort_key.
interpretation dual_linorder!: linorder "op ≥ :: 'a::linorder ⇒ 'a ⇒ bool" "op >"
where
"linorder.sort_key (op ≥ :: 'a ⇒ 'a ⇒ bool) f xs = revsort_key f xs"
proof -
show "class.linorder (op ≥ :: 'a ⇒ 'a ⇒ bool) (op >)" by (rule dual_linorder)
then interpret rev_order: linorder "op ≥ :: 'a ⇒ 'a ⇒ bool" "op >" .
have "rev_order.insort_key f = insort_by_key (op ≥) f"
by (intro ext) (induct_tac xa; simp)
then show "rev_order.sort_key f xs = revsort_key f xs"
by (simp add: rev_order.sort_key_def revsort_key_def)
qed
While with this solution we do not have any runtime penalty, it is far too verbose for my taste and is not easily adaptable to changes in the standard code setup (e.g., if we wanted to use the mergesort implementation from the Archive of Formal Proofs for all of our sorting operations).

Resources