how to get isabelle to recognize an obvious conclusion - isabelle

I'm trying to prove that the frontier, interior and exterior of a set are disjoint in isabelle. On the line I have marked '***', the fact that c \<inter> d = {} clearly follows from the previous line given the assumption at the start of the block, so how would I get isabelle to understand this?
theory Scratch
imports
"~~/src/HOL/Multivariate_Analysis/Topology_Euclidean_Space"
"~~/src/HOL/Probability/Sigma_Algebra"
begin
lemma boundary_disjoint: "disjoint {frontier S, interior S, interior (-S)}"
proof (rule disjointI)
fix c d assume sets:
"c \<in> {frontier S, interior S, interior (-S)}"
"d \<in> {frontier S, interior S, interior (-S)}"
and "c \<noteq> d"
show "c \<inter> d = {}"
proof cases
assume "c = frontier S \<and> d = interior S"
then show ?thesis using frontier_def by auto
next
assume "c = frontier S \<and> d = interior (-S)"
have "closure S \<inter> interior (-S) = {}" by (simp add: closure_interior)
hence "frontier S \<inter> interior (-S) = {}" using frontier_def by auto
*** then show ?thesis by auto
next
qed
qed
end

In Isar, you have to explicitly reference the facts you want to use. If you say that your goal follows from the previous line and the local assumption you made, you should give the assumption a name by writing assume A: "c = frontier S ∧ d = interior (-S)", and then you can prove your goal by with A have ?thesis by auto.
Why did I write have and not show? Well, there is another problem. You did a proof cases, but that uses the rule (P ⟹ Q) ⟹ (¬P ⟹ Q) ⟹ Q, i.e. it does a case distinction of the kind ‘Is P true or false?’. That is not what you want here.
One way to do your case distiction is by something like this:
from sets show "c ∩ d = {}"
proof (elim singletonE insertE)
insertE is an elimination rule for facts of the form x ∈ insert y A, and since {a,b,c} is just syntactic sugar for insert a (insert b (insert c A)), this is what you want. singletonE is similar, but specifically for x ∈ {y}; using singletonE instead of insertE means you do not get trivial cases with assumptions like x ∈ {}.
This gives you 9 cases, of which 3 are trivially solved by simp_all. The rest you have to prove yourself in Isar if you want to, but they can be solved quite easily by auto as well:
from sets and `c ≠ d` show "c ∩ d = {}"
by (auto simp: frontier_def closure_def interior_closure)

Related

Why is this seemingly incorrect proof OK with Isabelle?

While copying the following proof from the PDF tutorial of Isabelle 2020 into the IDE (about Cantor’s theorem that a function from a set to its powerset cannot be surjective), I made a typo on the "from 1 have 2" line.
lemma "¬ surj (f :: 'a ⇒ 'a set)"
proof
assume 0: "surj f"
from 0 have 1: "∀ A. ∃ a. A = f a" by(simp add: surj_def )
from 1 have 2: "∃ a. {x. x ∉ f x} = f a" by blast
from 2 show "False" by blast
qed
, so that the line now reads (with a wrong forall quantifier)
from 1 have 2: "∀ a. {x. x ∉ f x} = f a" by blast
Strangely, both the original proof in the example and this changed version work. But the changed version is incorrect, isn't it?
Am I missing something or can someone explain how the changed version (below) is correct?
lemma "¬ surj (f :: 'a ⇒ 'a set)"
proof
assume 0: "surj f"
from 0 have 1: "∀ A. ∃ a. A = f a" by(simp add: surj_def )
from 1 have 2: "∀ a. {x. x ∉ f x} = f a" by blast
from 2 show "False" by blast
qed
--- Update ---
To help diagnose the problem, below is the output when I place the mouse on the "from 2 show ..." line. It mentions an exported rule, which seems to be the theorem to be proven. (I don't remember exporting the rule myself, other than maybe accidentally getting the quantifier right in a few trials.)
show False
Successful attempt to solve goal by exported rule:
(surj f) ⟹ False
proof (state)
this:
False
goal:
No subgoals!
I just tried closing Isabelle and reopening the same .thy file, and got the same result. (As you can see, I am new to the Isabelle environment). Did I just save the theorem somewhere when I entered the right text?
Which Isabelle version are you using? On mine the blast call does not terminate (within a few seconds), as highlighted by the background:
However, Isabelle is optimistic: it assumes that blast will eventually terminate (it won't). Hence the next step is checked (and that one holds because types are not empty: "∀ a. P a", then "∃ a. P a"). That might give you the impression that the proof is going through, but it is not the case.

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

How can I use proved goals of locale interpretation to prove the remaining ones

I define a strict order locale as follows:
locale strict_order =
fixes ls::"'a set ⇒ 'a set ⇒ bool"
assumes
irrefl:"¬ ls a a" and
trans:"ls a c ∧ ls c g ⟹ ls a g" and
asym:"ls a c ⟹ ¬ ls c a"
Then, I declare a type as interpretation of strict_order
interpretation nest:strict_order "op ≪"
proof
fix a
show "¬ a ≪ a"
proof (rule contra, auto)
....
qed
next
fix a c g
assume a:"a ≪ c ∧ c ≪ g"
show " a ≪ g"
proof -
(* uses the fact that ¬ a<<a *)
The proof "trans" property for type nest needs at some point "irrefl" property which has been successfully proved inside the interpretation block. How can I label and use it? Or there is no way but moving it outside the interpretation block?
Thanks.
If you state a fact with show, you can name it just like with have, e.g., show irrefl: "¬ a ≪ a". However, next drops everything that you have proven so far, so you have to avoid next. Conceptually, next corresponds to closing a block and opening a new one, i.e., next essentially means } {.
Hence, you could write something like the following:
proof
{ fix a
show "¬ a ≪ a"
proof (rule contra, auto) .... qed }
note irrefl = this
{ fix a c g
assume a: "a ≪ c ∧ c ≪ g"
show "a ≪ g"
proof - ... (* can reference irrefl *) qed }
qed
Note that you can name the irreflexivity law only after closing the block, because you want the fixed a being generalised, which only happens upon export from the block. If you are using Isabelle2016 or later, you can write the cases more concisely using for and if clauses. This saves you all the boilerplate with } and {.
proof
show irrefl: "¬ a ≪ a" for a
proof (rule contra, auto) .... qed
show "a ≪ g" if a: "a ≪ c ∧ c ≪ g" for a c g
proof - ... (* can reference irrefl *) qed
qed

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?

Express that a function is constant on a set

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"

Resources