Express that a function is constant on a set - isabelle

I’m trying to express that a function f is constant on a set S, with value r My first idea was
f ` S = {r}
but that does not work, as S can be empty. So I am currently working with
f ` S ⊆ {r}
and it works okish, but I have the impression that this is still not ideal for the standard automation. In particular, auto would fail leaving this goal (irrelevant facts erased)
2. ⋀xa. thunks (delete x Γ) ⊆ thunks Γ ⟹
ae ` thunks Γ ⊆ {up⋅0} ⟹
xa ∈ thunks (delete x Γ) ⟹
ae xa = up⋅0
Sledgehammer of course has no problem (metis image_eqI singletonD subsetCE), but there are a few occurrences of this. (In general, ⊆ does not seem to work with auto as good as I’d expect).
There there a better way to express this, i.e. one that can be used by auto more easily when occurring as an assumption?

I didn't try it, since I didn't have any examples handy. But you might try the following setup.
definition "const f S r ≡ ∀x ∈ S. f x = r"
Which is equivalent to your definition:
lemma
"const f S r ⟷ f ` S ⊆ {r}"
by (auto simp: const_def)
Then employ the following simp rule:
lemma [simp]:
"const f S r ⟹ x ∈ S ⟹ f x = r"
by (simp add: const_def)

The Analysis library defines
definition constant_on (infixl "(constant'_on)" 50)
where "f constant_on A \<equiv> \<exists>y. \<forall>x\<in>A. f x = y"

Related

Isabelle order type-class on lambda expressions

I found this expression somewhere in Isabelle's standard library and tried to see what value does with it
value "(λ x::bool . ¬x) ≤ (λ x . x)"
It outputs False. What is the meaning of ≤ here? Ideally, where can I find the exact instantiation of it? When I Ctrl+Click on the lambda symbol, jEdit doesn't take me anywhere. Is λ part of meta logic then? Where is it defined?
This and many other things are defined in Lattices.thy theory in Main library
https://isabelle.in.tum.de/library/HOL/HOL/Lattices.html
under the following section.
subsection ‹Lattice on \<^typ>‹_ ⇒ _››
instantiation "fun" :: (type, semilattice_sup) semilattice_sup
begin
definition "f ⊔ g = (λx. f x ⊔ g x)"
lemma sup_apply [simp, code]: "(f ⊔ g) x = f x ⊔ g x"
by (simp add: sup_fun_def)
instance
by standard (simp_all add: le_fun_def)
end

Isabelle/ZF nat inequality

I am new to Isabelle and I tried to prove something like this:
lemma refl_add_help: "[| n:nat; m:nat |] ==> 0 #+ n \<le> m #+ n"
by(rule add_le_mono1, simp)
theorem mult_le_self: "[| 0 < m; n:nat; m:nat |] ==> n \<le> n #* m"
apply(case_tac m, auto)
apply(simp add: refl_add_help)
oops
I also tried to prove a lemma:
lemma "[| n:nat; m:nat |] ==> n \<le> m #+ n"
but I could not success either. Can anyone give me some advice on how to solve the problem? Thank you very much.
By the way, is it not possible to display value in ZF like
value "{m:nat. m < 5}"
I have imported the theory like this:
theory mytheory
imports ZF.Arith
I'm not very familiar with Isabelle/ZF. That said, you can prove your results as follows:
theorem mult_le_self: "⟦ 0 < m; n:nat; m:nat ⟧ ⟹ n ≤ n #* m"
apply (case_tac m, simp)
apply (frule_tac ?m="n #* x" in refl_add_help)
apply (auto simp add: add_commute)
done
lemma "⟦ n:nat; m:nat ⟧ ⟹ n ≤ m #+ n"
by (frule refl_add_help, auto)
For more information regarding the frule and frule_tac methods please refer to The Isabelle/Isar Reference Manual, sections 9.2 and 7.3 respectively. However, I encourage you to use Isabelle/Isar instead of proof scripts. For example, your lemma can be proven as follows:
lemma "⟦ n:nat; m:nat ⟧ ⟹ n ≤ m #+ n"
proof -
assume "n:nat" and "m:nat"
then show ?thesis using refl_add_help by simp
qed
Or, more compactly, as follows:
lemma
assumes "n:nat" and "m:nat"
shows "n ≤ m #+ n"
using assms and refl_add_help by simp
Regarding the value command, I think it does not work in Isabelle/ZF.

Using the type-to-sets approach for defining quotients

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

Can erule produce erroneous subgoals?

I have the following grammar defined in Isabelle:
inductive S where
S_empty: "S []" |
S_append: "S xs ⟹ S ys ⟹ S (xs # ys)" |
S_paren: "S xs ⟹ S (Open # xs # [Close])"
Then I define a gramar T that conceptually only adds the following rule:
T_left: "T xs ⟹ T (Open # xs)"
Then I tried to proof the following theorem:
theorem T_S:
"T xs ⟹ count xs Open = count xs Close ⟹ S xs"
apply(erule T.induct)
apply(simp add: S_empty)
apply(simp add: S_append)
apply(simp add: S_paren)
oops
To my surprise the final goal seems to be false:
⋀xsa. count xs Open = count xs Close ⟹ T xsa ⟹ S xsa ⟹ S (Open # xsa)
So here S (Open # xsa) cannot hold because there is no such production in the grammar assuming S xsa.
This situation makes no-sense to me? Is erule producing goals that are false?
Induction rules like T.induct should usually be used with the induction proof method rather than erule. The induction method ensures that the whole statement becomes part of the inductive statements whereas with erule only the conclusion is part of the inductive argument; other assumptions are basically ignored for the induction. This can be seen in the last goal state where the inductive statement involves the goal parameter xsa whereas the crucial assumption count xs Open = count xs Close still talks about the variable xs. So, the proof step should be apply(induction rule: T.induct). Then there is a chance to prove this statement.

Theory level obtain command

In a local proof block in Isabelle I can use the very convenient obtain command, which allows me to define a constant with given properties:
proof
...
from `∃x. P x ∧ Q x`
obtain x where "P x" and "Q x" by blast
...
What is the most convenient way to do that on the theory or locale level?
I can do it by hand using SOME, but it seems to be unnecessary complicated:
lemma ex: "∃x. P x ∧ Q x"
sorry
definition x where "x = (SOME x. P x ∧ Q x)"
lemma P_x: "P x" and Q_x: "Q x"
unfolding atomize_conj x_def by (rule someI_ex, rule ex)
Another, more direct, way seems to be specification:
consts x :: nat
specification (x) P_x: "P x" Q_x: "Q x" by (rule ex)
but it requires the somewhat low-level consts command, and worse, it does not work in a local context.
Would it be possible to have something as nice as the obtain command on the theory level?

Resources