I'm attempting to write a simple proof about integer exponents in isar.
I've written the argument I want to make in the commented area, but I'm having a very hard time figuring out how to express it. I've been studying src/HOL/Int.thy but I either can't find an example proof along these lines or don't understand what I'm looking at yet. :)
theory Exponents
imports Main
begin
lemma rMulComm: "(a*b ::int) = (b*a ::int)"
by (rule Groups.ab_semigroup_mult_class.mult.commute)
lemma rExpMul: "((a^b)^c ::int) = (a^(b*c) ::int)"
by (rule Int.zpower_zpower)
theorem HELP: "((a^b)^c ::int) = ((a^c)^b :: int)"
(* 0. (a^b)^c
1. a^(b*c) by rExpMul
2. a^(c*b) by rMulComm
3. (a^c)^b by rExpMul *)
end
This isn't a homework assignment, btw. I'm not in school. :)
update: my final version, based on Alexander's answer, below:
theorem "((a^b)^c ::int) = ((a^c)^b :: int)"
proof -
have "(a^b)^c = a^(b*c)" by (simp only: rExpMul)
hence " ... = a^(c*b)" by (simp only: rMulComm)
thus "(a^b)^c = (a^c)^b" by (simp only: rExpMul)
qed
The issue has to do with the types of b and c in the theorem HELP as well as in the lemma rExpMul: the exponent for the operator ^ is a natural number. Therefore rMulComm specified for integers cannot be used to prove the theorem. After restating it for natural numbers
lemma rMulComm: "(a * b :: nat) = (b * a :: nat)"
the proof proceeds immediately:
theorem HELP: "((a^b)^c ::int) = ((a^c)^b :: int)"
proof -
have "(a ^ b) ^ c = a ^ (b * c)" by (simp only: rExpMul)
also have "… = a ^ (c * b)" by (simp only: rMulComm)
finally show ?thesis by (simp only: rExpMul)
qed
and can be shortened to just by (simp only: rExpMul rMulComm).
Related
Isabelle has some automation for quotient reasoning through the quotient package. I would like to see if that automation is of any use for my example. The relevant definitions is:
definition e_proj where "e_proj = e'_aff_bit // gluing"
So I try to write:
typedef e_aff_t = e'_aff_bit
quotient_type e_proj_t = "e'_aff_bit" / "gluing
However, I get the error:
Extra type variables in representing set: "'a"
The error(s) above occurred in typedef "e_aff_t"
Because as Manuel Eberl explains here, we cannot have type definitions that depend on type parameters. In the past, I was suggested to use the type-to-sets approach.
How would that approach work in my example? Would it lead to more automation?
In the past, I was suggested to use the type-to-sets approach ...
The suggestion that was made in my previous answer was to use the standard set-based infrastructure for reasoning about quotients. I only mentioned that there exist other options for completeness.
I still believe that it is best not to use Types-To-Sets, provided that the definition of a quotient type is the only reason why you wish to use Types-To-Sets:
Even with Types-To-Sets, you will only be able to mimic the behavior of a quotient type in a local context with certain additional assumptions. Upon leaving the local context, the theorems that use locally defined quotient types would need to be converted to the set-based theorems that would inevitably rely on the standard set-based infrastructure for reasoning about quotients.
One would need to develop additional Isabelle/ML infrastructure before Local Typedef Rule can be used to define quotient types locally conveniently. It should not be too difficult to develop an infrastructure that is useable, but it would take some time to develop something that is universally applicable. Personally, I do not consider this application to be sufficiently important to invest my time in it.
In my view, it is only viable to use Types-To-Sets for the definition of quotient types locally if you are already using Types-To-Sets for its intended purpose in a given development. Then, the possibility of using the framework for the definition of quotient types locally can be seen as a 'value-added benefit'.
For completeness, I provide an example that I developed for an answer on the mailing list some time ago. Of course, this is merely the demonstration of the concept, not a solution that can be used for work that is meant to be published in some form. To make this useable, one would need to convert this development to an Isabelle/ML command that would take care of all the details automatically.
theory Scratch
imports Main
"HOL-Types_To_Sets.Prerequisites"
"HOL-Types_To_Sets.Types_To_Sets"
begin
locale local_typedef =
fixes R :: "['a, 'a] ⇒ bool"
assumes is_equivalence: "equivp R"
begin
(*The exposition subsumes some of the content of
HOL/Types_To_Sets/Examples/Prerequisites.thy*)
context
fixes S and s :: "'s itself"
defines S: "S ≡ {x. ∃u. x = {v. R u v}}"
assumes Ex_type_definition_S:
"∃(Rep::'s ⇒ 'a set) (Abs::'a set ⇒ 's). type_definition Rep Abs S"
begin
definition "rep = fst (SOME (Rep::'s ⇒ 'a set, Abs). type_definition Rep
Abs S)"
definition "Abs = snd (SOME (Rep::'s ⇒ 'a set, Abs). type_definition Rep
Abs S)"
definition "rep' a = (SOME x. a ∈ S ⟶ x ∈ a)"
definition "Abs' x = (SOME a. a ∈ S ∧ a = {v. R x v})"
definition "rep'' = rep' o rep"
definition "Abs'' = Abs o Abs'"
lemma type_definition_S: "type_definition rep Abs S"
unfolding Abs_def rep_def split_beta'
by (rule someI_ex) (use Ex_type_definition_S in auto)
lemma rep_in_S[simp]: "rep x ∈ S"
and rep_inverse[simp]: "Abs (rep x) = x"
and Abs_inverse[simp]: "y ∈ S ⟹ rep (Abs y) = y"
using type_definition_S
unfolding type_definition_def by auto
definition cr_S where "cr_S ≡ λs b. s = rep b"
lemmas Domainp_cr_S = type_definition_Domainp[OF type_definition_S
cr_S_def, transfer_domain_rule]
lemmas right_total_cr_S = typedef_right_total[OF type_definition_S
cr_S_def, transfer_rule]
and bi_unique_cr_S = typedef_bi_unique[OF type_definition_S cr_S_def,
transfer_rule]
and left_unique_cr_S = typedef_left_unique[OF type_definition_S cr_S_def,
transfer_rule]
and right_unique_cr_S = typedef_right_unique[OF type_definition_S
cr_S_def, transfer_rule]
lemma cr_S_rep[intro, simp]: "cr_S (rep a) a" by (simp add: cr_S_def)
lemma cr_S_Abs[intro, simp]: "a∈S ⟹ cr_S a (Abs a)" by (simp add: cr_S_def)
(* this part was sledgehammered - please do not pay attention to the
(absence of) proof style *)
lemma r1: "∀a. Abs'' (rep'' a) = a"
unfolding Abs''_def rep''_def comp_def
proof-
{
fix s'
note repS = rep_in_S[of s']
then have "∃x. x ∈ rep s'" using S equivp_reflp is_equivalence by force
then have "rep' (rep s') ∈ rep s'"
using repS unfolding rep'_def by (metis verit_sko_ex')
moreover with is_equivalence repS have "rep s' = {v. R (rep' (rep s'))
v}"
by (smt CollectD S equivp_def)
ultimately have arr: "Abs' (rep' (rep s')) = rep s'"
unfolding Abs'_def by (smt repS some_sym_eq_trivial verit_sko_ex')
have "Abs (Abs' (rep' (rep s'))) = s'" unfolding arr by (rule
rep_inverse)
}
then show "∀a. Abs (Abs' (rep' (rep a))) = a" by auto
qed
lemma r2: "∀a. R (rep'' a) (rep'' a)"
unfolding rep''_def rep'_def
using is_equivalence unfolding equivp_def by blast
lemma r3: "∀r s. R r s = (R r r ∧ R s s ∧ Abs'' r = Abs'' s)"
apply(intro allI)
apply standard
subgoal unfolding Abs''_def Abs'_def
using is_equivalence unfolding equivp_def by auto
subgoal unfolding Abs''_def Abs'_def
using is_equivalence unfolding equivp_def
by (smt Abs''_def Abs'_def CollectD S comp_apply local.Abs_inverse
mem_Collect_eq someI_ex)
done
definition cr_Q where "cr_Q = (λx y. R x x ∧ Abs'' x = y)"
lemma quotient_Q: "Quotient R Abs'' rep'' cr_Q"
unfolding Quotient_def
apply(intro conjI)
subgoal by (rule r1)
subgoal by (rule r2)
subgoal by (rule r3)
subgoal by (rule cr_Q_def)
done
(* instantiate the quotient lemmas from the theory Lifting *)
lemmas Q_Quotient_abs_rep = Quotient_abs_rep[OF quotient_Q]
(*...*)
(* prove the statements about the quotient type 's *)
(*...*)
(* transfer the results back to 'a using the capabilities of transfer -
not demonstrated in the example *)
lemma aa: "(a::'a) = (a::'a)"
by auto
end
thm aa[cancel_type_definition]
(* this shows {x. ∃u. x = {v. R u v}} ≠ {} ⟹ ?a = ?a *)
end
Here is a sample theory:
datatype ty = A | B | C
inductive test where
"test A B"
| "test B C"
inductive test2 where
"¬(∃z. test x z) ⟹ test2 x"
code_pred [show_modes] test .
code_pred [show_modes] test2 .
values "{x. test2 A}"
The generated code tries to enumerate over ty. And so it fails.
I'm tring to define an executable version of test predicate:
definition "test_ex x ≡ ∃y. test x y"
definition "test_ex_fun x ≡
Predicate.singleton (λ_. False)
(Predicate.map (λ_. True) (test_i_o x))"
lemma test_ex_code [code_abbrev, simp]:
"test_ex_fun = test_ex"
apply (intro ext)
unfolding test_ex_def test_ex_fun_def Predicate.singleton_def
apply (simp split: if_split)
But I can't prove the lemma. Could you suggest a better approach?
Existential quantifiers over an argument to an inductive predicate can be made executable by introducing another inductive predicate. For example:
inductive test2_aux where "test x z ==> test2_aux x"
inductive test2 where "~ test2_aux x ==> test2 x"
with appropriate code_pred statements. The free variable z in the premise of test2_aux acts like an existential. Since this transformation is canonical, code_pred has a preprocessor to do so:
code_pred [inductify] test2 .
does the job.
Well, values complains about the fact that ty is not of sort enum. So, in this particular case it is easiest to perform this instantiation.
instantiation ty :: enum
begin
definition enum_ty :: "ty list" where
"enum_ty = [A,B,C]"
definition "enum_all_ty f = list_all f [A,B,C]"
definition "enum_ex_ty f = list_ex f [A,B,C]"
instance
proof (intro_classes)
let ?U = "UNIV :: ty set"
show id: "?U = set enum_class.enum"
unfolding enum_ty_def
using ty.exhaust by auto
fix P
show "enum_class.enum_all P = Ball ?U P"
"enum_class.enum_ex P = Bex ?U P"
unfolding id enum_all_ty_def enum_ex_ty_def enum_ty_def by auto
show "distinct (enum_class.enum :: ty list)" unfolding enum_ty_def by auto
qed
Afterwards, your values-command evaluates without problems.
I thought that the lemma is unprovable, and I should find another approach. But it can be proven as follows:
lemma test_ex_code [code_abbrev, simp]:
"Predicate.singleton (λ_. False)
(Predicate.map (λ_. True) (test_i_o x)) = (∃y. test x y)"
apply (intro ext iffI)
unfolding Predicate.singleton_def
apply (simp_all split: if_split)
apply (metis SUP1_E mem_Collect_eq pred.sel test_i_o_def)
apply (intro conjI impI)
apply (smt SUP1_E the_equality)
apply (metis (full_types) SUP1_E SUP1_I mem_Collect_eq pred.sel test_i_o_def)
done
The interesting thing is that the lemma structure and the proof structure seems to be independent of the concrete predicate. I guess there could be a general solution for any predicate.
I need to generate a code calculating all values greater or equal to some value:
datatype ty = A | B | C
instantiation ty :: order
begin
fun less_ty where
"A < x = (x = C)"
| "B < x = (x = C)"
| "C < x = False"
definition "(x :: ty) ≤ y ≡ x = y ∨ x < y"
instance
apply intro_classes
apply (metis less_eq_ty_def less_ty.elims(2) ty.distinct(3) ty.distinct(5))
apply (simp add: less_eq_ty_def)
apply (metis less_eq_ty_def less_ty.elims(2))
using less_eq_ty_def less_ty.elims(2) by fastforce
end
instantiation ty :: enum
begin
definition [simp]: "enum_ty ≡ [A, B, C]"
definition [simp]: "enum_all_ty P ≡ P A ∧ P B ∧ P C"
definition [simp]: "enum_ex_ty P ≡ P A ∨ P B ∨ P C"
instance
apply intro_classes
apply auto
by (case_tac x, auto)+
end
lemma less_eq_code_predI [code_pred_intro]:
"Predicate_Compile.contains {z. x ≤ z} y ⟹ x ≤ y"
(* "Predicate_Compile.contains {z. z ≤ y} x ⟹ x ≤ y"*)
by (simp_all add: Predicate_Compile.contains_def)
code_pred [show_modes] less_eq
by (simp add: Predicate_Compile.containsI)
values "{x. A ≤ x}"
(* values "{x. x ≤ C}" *)
It works fine. But the theory looks over-complicated. Also I can't calculate values less or equal to some value. If one will uncoment the 2nd part of less_eq_code_predI lemma, then less_eq will have only one mode i => i => boolpos.
Is there a simpler and more generic approach?
Can less_eq support i => o => boolpos and o => i => boolpos at the same time?
Is it possible not to declare ty as an instance of enum class? I can declare a function returning a set of elements greater or equal to some element:
fun ge_values where
"ge_values A = {A, C}"
| "ge_values B = {B, C}"
| "ge_values C = {C}"
lemma ge_values_eq_less_eq_ty:
"{y. x ≤ y} = ge_values x"
by (cases x; auto simp add: dual_order.order_iff_strict)
This would allow me to remove enum and code_pred stuff. But in this case I will not be able to use this function in the definition of other predicates. How to replace (≤) by ge_values in the following definition?
inductive pred1 where
"x ≤ y ⟹ pred1 x y"
code_pred [show_modes] pred1 .
I need pred1 to have at least i => o => boolpos mode.
The predicate compiler has an option inductify that tries to convert functional definitions into inductive ones. It is somewhat experimental and does not work in every case, so use it with care. In the above example, the type classes make the whole situation a bit more complicated. Here's what I managed to get working:
case_of_simps less_ty_alt: less_ty.simps
definition less_ty' :: "ty ⇒ ty ⇒ bool" where "less_ty' = (<)"
declare less_ty_alt [folded less_ty'_def, code_pred_def]
code_pred [inductify, show_modes] "less_ty'" .
values "{x. less_ty' A x}"
The first line convertes the pattern-matching equations into one with a case expression on the right. It uses the command case_of_simps from HOL-Library.Simps_Case_Conv.
Unfortunately, the predicate compiler seems to have trouble with compiling type class operations. At least I could not get it to work.
So the second line introduces a new constant for (<) on ty.
The attribute code_pred_def tells the predicate compiler to use the given theorem (namely less_ty_alt with less_ty' instead of (<)) as the "defining equation".
code_pred with the inductify option looks at the equation for less_ty' declared by code_pred_def and derives an inductive definition out of that. inductify usually works well with case expressions, constructors and quantifiers. Everything beyond that is at your own risk.
Alternatively, you could also manually implement the enumeration similar to ge_values and register the connection between (<) and ge_values with the predicate compiler. See the setup block at the end of the Predicate_Compile theory in the distribution for an example with Predicate.contains. Note however that the predicate compiler works best with predicates and not with sets. So you'd have to write ge_values in the predicate monad Predicate.pred.
The following expression is evaluated fine:
value "foldr plus [1::nat, 2] 0"
But the following expressions:
value "Finite_Set.fold plus 0 (set [1::nat, 2])"
value "ffold plus 0 {|1::nat, 2|}"
raise error:
Wellsortedness error:
Type nat not of sort finite
No type arity nat :: finite
I understand that nat is not finite. So nat set is not finite too.
But is it possible to define code equations for these functions? I'm trying to prove one. But I'm stuck:
lemma finite_set_fold_code [code]:
"comp_fun_commute f ⟹
Finite_Set.fold f x (set xs) = foldr f xs x"
apply (rule Finite_Set.comp_fun_commute.fold_equality)
apply simp
apply (induct xs arbitrary: x)
apply (simp add: Finite_Set.fold_graph.emptyI)
apply auto
apply (rule Finite_Set.fold_graph.insertI)
UPDATE:
The lemma doesn't hold and can't be proven. Duplicates must be removed from a list.
interpretation nat_plus_commute: comp_fun_commute "plus :: nat ⇒ nat ⇒ nat"
by standard auto
lemma finite_set_nat_plus [code]:
"Finite_Set.fold plus (y :: nat) (set xs) = fold plus (remdups xs) y"
by (simp add: nat_plus_commute.fold_set_fold_remdups)
But I get the following warning:
Partially applied constant "Groups.plus_class.plus" on left hand side of equation, in theorem:
Finite_Set.fold op + ?y (set ?xs) ≡ fold op + (remdups ?xs) ?y
And still can't evaluate the expression.
UPDATE 2:
Actually I can evaluate it using schematic_goal:
schematic_goal g1:
"Finite_Set.fold plus 0 (set [1::nat, 2]) = ?x"
by (simp add: nat_plus_commute.fold_set_fold_remdups)
thm g1
What should I do to evaluate it using value?
I tried to prove an existential theorem
lemma "∃ x. x * (t :: nat) = t"
proof
obtain y where "y * t = t" by (auto)
but I could not finish the proof. So I have the necessary y but how can I feed it into the original goal?
Soundness of natural deduction requires that you get hold of the witness before you open the existential quantifier. This is why you are not allowed to use obtained variables in show statements. In your example, the proof step implicitly applies the rule exI. This turns the existentially quantified variable x into the schematic variable ?x, which can be instantiated later, but the instantiation may only refer to variables that have been in scope when ?x came into place. In the low-level proof state, obtained variables are meta-quantified (!!) and the instantiations for ?x can only refer to such variables that appear as a parameter to ?x.
Therefore, you have to switch the order in your proof:
lemma "∃ x. x * (t :: nat) = t"
proof - (* method - does not change the goal *)
obtain y where "y * t = t" by (auto)
then show ?thesis by(rule exI)
qed
You can give the witness (i.e. the element you want to put in for x) in the show clause:
lemma "∃ x. x * (t :: nat) = t"
proof
show "1*t = t" by simp
qed
Alternatively, when you already know the witness (1 or Suc 0 here), you can explicitly instantiate the rule exI to introduce the existential term:
lemma "∃ x. x * (t :: nat) = t"
by (rule exI[where x = "Suc 0"], simp)
Here, the existential quantifier introduction rule thm exI is
?P ?x ⟹ ∃x. ?P x
you can explore and instantiate it gradually with the answer.
thm exI[where x = "Suc 0"] is:
?P (Suc 0) ⟹ ∃x. ?P x
and exI[where P = "λ x. x * t = t" and x = "Suc 0"] is
Suc 0 * t = t ⟹ ∃x. x * t = t
And Suc 0 * t = t is only one simplification (simp) away. But the system can figure out the last instantiation P = "λ x. x * t = t" via unification, so it isn't really necessary.
Related:
Instantiating theorems in Isabelle