Isabelle unification error - isabelle

I am new to Isabelle and this is a simplification of my first program
theory Scratch
imports Main
begin
record flow =
Src :: "nat"
Dest :: "nat"
record diagram =
DataFlows :: "flow set"
Transitions :: "nat set"
Markings :: "flow set"
fun consume :: "diagram × (nat set) ⇒ (flow set)"
where
"(consume dia trans) = {n . n ∈ (Markings dia) ∧ (∃ t ∈ trans . (Dest n) = t)}"
end
The function give the error:
Type unification failed: Clash of types "_ ⇒ " and " set"
Type error in application: operator not of function type
Operator: consume dia :: flow set
Operand: trans :: (??'a × ??'a) set ⇒ bool
What should I do for the the code to compile?

First of all, you give two parameters to your consume function, but the way you defined its type, it takes a single tuple. This is unusual and often inconvenient – defined curried functions instead, like this:
fun consume :: "diagram ⇒ (nat set) ⇒ (flow set)"
Also, trans is a constant; it is the property that a relation is transitive. You can see that by observing that trans is black to indicate that it is a constant and the other variable is blue, indicating that it is a free variable.
I therefore recommend using another name, like ts:
where
"consume dia ts = {n . n ∈ (Markings dia) ∧ (∃ t ∈ ts . (Dest n) = t)}"

Related

Locale: Codegen fails when instantiating with unit (code_pred: "Tactic failed")

I am trying to use code_pred for an inductive predicate defined inside a locale. I came across this email which shows how this can be done:
locale l = fixes x :: 'a assumes "x = x"
inductive (in l) is_x where "is_x x"
global_interpretation i: l "0 :: nat" defines i_is_x = "i.is_x" by unfold_locales simp
declare i.is_x.intros[code_pred_intro]
code_pred i_is_x by(rule i.is_x.cases)
However, when I change the global_interpretation to use () :: unit instead of 0 :: nat, then code_pred fails with the following message:
Tactic failed
The error(s) above occurred for the goal statement⌂:
i_is_x_i x = Predicate.bind (Predicate.single x) (λx. case x of () ⇒ Predicate.single ())
I tried to do the prove manually, but at some point I got the same error.
Does anyone know how to solve this?
I don't exactly understand what is happening here, but the code generator already uses unit internally and the tactic (corresponding to before single intro rule) fails on your example.
The error does not come from the proof, but comes from proof done internally in the done part. So changing the proof does not change the issue (and you even see with sorry).
A possible work-around: use a type isomorphic to unit:
datatype myunit = MyUnit
locale l = fixes x :: 'a assumes "x = x"
inductive (in l) is_x where "is_x x"
definition X where ‹X = ()›
global_interpretation i: l "MyUnit :: myunit" defines i_is_x = "i.is_x" by unfold_locales simp
declare i.is_x.intros[code_pred_intro]
code_pred i_is_x
by (rule i.is_x.cases)

How to use type's argument as a value in a function?

I'm trying to define a simple type system with a custom set type:
notation bot ("⊥")
typedef 'a myset = "UNIV :: 'a fset option set" ..
copy_bnf 'a myset
setup_lifting type_definition_myset
lift_definition myset :: "'a fset ⇒ 'a myset" is Some .
instantiation myset :: (type) bot
begin
lift_definition bot_myset :: "'a myset" is None .
instance ..
end
free_constructors case_myset for
myset
| "⊥ :: 'a myset"
apply (simp_all add: bot_myset_def myset_def)
apply (metis Rep_myset_inverse option.collapse)
apply (metis Abs_myset_inverse iso_tuple_UNIV_I option.inject)
apply (metis Abs_myset_inverse iso_tuple_UNIV_I option.distinct(1))
done
lift_definition map_myset :: "('a ⇒ 'b) ⇒ 'a myset ⇒ 'b myset"
is "map_option ∘ fimage" .
Type system has integer, real and set types:
datatype type =
IType
| RType
| SType type
Also there are 3 kinds of values:
datatype val =
IVal int
| RVal real
| SVal "val myset"
I need to define a function type_of which determines a type of a value:
fun elem_type :: "val myset ⇒ type" and
type_of :: "val ⇒ type" where
"elem_type xs = ???"
| "type_of (IVal x) = IType"
| "type_of (RVal x) = RType"
| "type_of (SVal x) = SType (elem_type x)"
value "type_of (SVal (myset {|IVal 1, IVal 2|}))"
value "type_of (SVal (myset {|RVal 1, RVal 2|}))"
value "type_of (SVal (myset {|SVal (myset {|IVal 1|})|}))"
Could you suggest how to get element type of myset?
I would say there is a fundamental problem with your modelling: your type_of function seems to suggest that every value has exactly one type.
In his comment, Lars has already pointed out that there are some values (e.g. a set containing both integers and real values) that you would probably consider to be invalid and that therefore have no type at all. That you could handle by returning ‘undefined’ or something like that, perhaps, and introduce some kind of additional ‘well-formedness’ predicate for values, but I'm not sure that's a good idea.
Another problem is that there are some values that are polymorphic, i.e. that have more than one type, in a sense: For instance, what should your type_of function return for the empty set, i.e. SVal (myset {|})? There are infinitely many reasonable types that this thing could have.
The usual approach to handle this is to introduce a typing relation instead of a typing function so that each value can have several types – or none at all. Usually, you do this with the inductive command, defining an inductive predicate like has_type v t which states that the value v has the type t (or ‘can be given the type t’ in case of polymorphism).
Also, on an unrelated note, I am not sure why you define a new type and use copy_bnf, free_constructors etc. I don't know what you're planning to do but my guess would be that whatever it is does probably not get easier with that typedef; it will probably just cause some annoyances.

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).

Unfold/simp has no effect in a primrec type class instantiation proof

Up until several days ago, I always defined a type, and then proved theorems directly about the type. Now I'm trying to use type classes.
Problem
The problem is that I can't instantiate cNAT for my type myD below, and it appears it's because simp has no effect on the abstract function cNAT, which I've made concrete with my primrec function cNAT_myD. I can only guess what's happening because of the automation that happens after instance proof.
Questions
Q1: Below, at the statement instantiation myD :: (type) cNAT, can you tell me how to finish the proof, and why I can prove the following theorem, but not the type class proof, which requires injective?
theorem dNAT_1_to_1: "(dNAT n = dNAT m) ==> n = m"
assumes injective: "(cNAT n = cNAT m) ==> n = m"
Q2: This is not as important, but at the bottom is this statement:
instantiation myD :: (type) cNAT2
It involves another way I was trying to instantiate cNAT. Can you tell me why I get Failed to refine any pending goal at shows? I put some comments in the source to explain some of what I did to set it up. I used this slightly modified formula for the requirement injective:
assumes injective: "!!n m. (cNAT2 n = cNAT2 m) --> n = m"
Specifics
My contrived datatype is this, which may be useful to me someday: (Update: Well, for another example maybe. A good mental exercise is for me to try and figure out how I can actually get something inside a 'a myD list, other than []. With BNF, something like datatype_new 'a myD = myS "'a myD fset" gives me the warning that there's an unused type variable on the right-hand side)
datatype 'a myD = myL "'a myD list"
The type class is this, which requires an injective function from nat to 'a:
class cNAT =
fixes cNAT :: "nat => 'a"
assumes injective: "(cNAT n = cNAT m) ==> n = m"
dNAT: this non-type class version of cNAT works
fun get_myL :: "'a myD => 'a myD list" where
"get_myL (myL L) = L"
primrec dNAT :: "nat => 'a myD" where
"dNAT 0 = myL []"
|"dNAT (Suc n) = myL (myL [] # get_myL(dNAT n))"
fun myD2nat :: "'a myD => nat" where
"myD2nat (myL []) = 0"
|"myD2nat (myL (x # xs)) = Suc(myD2nat (myL xs))"
theorem left_inverse_1 [simp]:
"myD2nat(dNAT n) = n"
apply(induct n, auto)
by(metis get_myL.cases get_myL.simps)
theorem dNAT_1_to_1:
"(dNAT n = dNAT m) ==> n = m"
apply(induct n)
apply(simp) (*
The simp method expanded dNAT.*)
apply(metis left_inverse_1 myD2nat.simps(1))
by (metis left_inverse_1)
cNAT: type class version that I can't instantiate
instantiation myD :: (type) cNAT
begin
primrec cNAT_myD :: "nat => 'a myD" where
"cNAT_myD 0 = myL []"
|"cNAT_myD (Suc n) = myL (myL [] # get_myL(cNAT_myD n))"
instance
proof
fix n m :: nat
show "cNAT n = cNAT m ==> n = m"
apply(induct n)
apply(simp) (*
The simp method won't expand cNAT to cNAT_myD's definition.*)
by(metis injective)+ (*
Metis proved it without unfolding cNAT_myD. It's useless. Goals always remain,
and the type variables in the output panel are all weird.*)
oops
end
cNAT2: Failed to refine any pending goal at show
(*I define a variation of `injective` in which the `assumes` definition, the
goal, and the `show` statement are exactly the same, and that strange `fails
to refine any pending goal shows up.*)
class cNAT2 =
fixes cNAT2 :: "nat => 'a"
assumes injective: "!!n m. (cNAT2 n = cNAT2 m) --> n = m"
instantiation myD :: (type) cNAT2
begin
primrec cNAT2_myD :: "nat => 'a myD" where
"cNAT2_myD 0 = myL []"
|"cNAT2_myD (Suc n) = myL (myL [] # get_myL(cNAT2_myD n))"
instance
proof (*
goal: !!n m. cNAT2 n = cNAT2 m --> n = m.*)
show
"!!n m. cNAT2 n = cNAT2 m --> n = m"
(*Failed to refine any pending goal
Local statement fails to refine any pending goal
Failed attempt to solve goal by exported rule:
cNAT2 (n::nat) = cNAT2 (m::nat) --> n = m *)
Your function cNAT is polymorphic in its result type, but the type variable does not appear among the parameters. This often causes type inference to compute a type which is more general than you want. In your case for cNAT, Isabelle infers for the two occurrences of cNAT in the show statement the type nat => 'b for some 'b of sort cNAT, but their type in the goal is nat => 'a myD. You can see this in jEdit by Ctrl-hovering over the cNAT occurrences to inspect the types. In ProofGeneral, you can enable printing of types with using [[show_consts]].
Therefore, you have to explicitly constrain types in the show statement as follows:
fix n m
assume "(cNAT n :: 'a myD) = cNAT m"
then show "n = m"
Note that it is usually not a good idea to use Isabelle's meta-connectives !! and ==> inside a show statement, you better rephrase them using fix/assume/show.

Isabelle: Evaluating formula with Quantifiers

Why does the following work:
fun f :: "nat ⇒ bool" where
"f _ = (True ∨ (∀x. x))"
But this fails
fun g :: "nat ⇒ bool" where
"g _ = (True ∨ (∀a. True))"
with
Additional type variable(s) in specification of "g_graph": 'a
Specification depends on extra type variables: "'a"
The error(s) above occurred in "test.g_sumC_def"
The error(s) above occurred in definition "g_sumC_def":
"g_sumC ≡ λx. THE_default undefined (g_graph TYPE('a) x)"
Similarly, the following succeeds,
value "True ∨ (∀x. x)"
but this fails
value "True ∨ (∀x. True)"
with
Wellsortedness error:
Type 'a not of sort enum
Cannot derive subsort relation {} < enum
The short answer is: In your first function definition type inference easily infers that x is of type bool, while in your second definition, the bound variable a is not used anywhere else and thus its type is arbitrary ('a). Which is what Additional type variable(s) in specification ... expresses.
If you constrain the type of a explicitly, e.g.,
fun g :: "nat ⇒ bool" where
"g _ = (True ∨ (∀a::bool. True))"
the function definition is accepted.
A longer answer: Since the definition of g is not recursive you could turn it into using definition instead of fun. Then your first attempt does not fail completely but the result might surprise you. After
definition g :: "nat ⇒ bool" where
"g _ = (True ∨ (∀a. True))"
the type of g is 'a itself => nat => bool instead of the intended nat => bool. The reason is the same as for the failure of fun before. Since a is of arbitrary type, this additional type has to be recorded in the type of g, which is done by introducing an additional dummy argument which just states this additional type explicitly. Here 'a itself is a type whose constructor TYPE(...) -- taking a type as argument -- allows us to encode type information on the term level. E.g.,
TYPE('a) :: 'a itself
TYPE(bool) :: bool itself
TYPE(nat) :: nat itself
Then g TYPE(nat) is the version of g where a is fixed to be of type nat.
Concerning your value statements, the reason for the second one to fail is not really related to the above. In the first statement the universal quantifier binds a variable of type bool whose values can be enumerated explicitly and thus a result can be computed by considering all those values. In contrast, in your second statement the bound variable x is of an arbitrary type 'a whose values cannot be enumerated explicitly.
The following fails:
fun f where "f _ = (∀a. True)"
because the type of a has hidden polymorphism (i.e., there is a type variable inside your function's body that is not present in the function's type signature), which upsets the function package's internal proofs.
If you explicitly give a a type as so:
fun f where "f _ = (∀a::bool. True)"
or is you give a a type that is also in the function's type signature, as so:
fun f where "f _ = (∀a::bool. True)"
the function definition succeeds. Your example:
fun f where "f _ = (∀x. x)"
succeeds, because x is forced to be type bool.
As for your value commands, Isabelle attempts to generate executable code for your expression, and hence needs to not only know the type of your for-all statements, but also be able to enumerate all possible values of it, so that it can test them all. Types such as bool work fine, but type variables like 'a or infinite types such as nat are not enumerable, and hence Isabelle cannot generate code for them.

Resources