Proving topology statement in Isabelle - isabelle

I have been working with limits and topology in and I want to prove the following lemma:
lemma fixes f g :: "real ⇒ real"
assumes
"open S"
"∀a b. a < b <--> f a < f b"
"∀a. (f a)>0"
"continuous_on UNIV (f)"
"∀w∈S. ∀h. (w+h)∈S --> h * (f w) ≤ g (w+h) - g w"
shows "∀w∈S. eventually (λh. f w ≤ (g (w + h) - g w)/h) (at 0)"
using assms unfolding eventually_at
apply (auto simp: divide_simps mult_ac)
I have managed to prove it for two different scenerios:
Here, all instances of h in the inequalities is replaced by |h|. A solution is found almost instantly.
lemma
fixes f g :: "real ⇒ real"
assumes "open S" "∀w∈S. ∀h. (w+h)∈S --> abs(h) * (f w) ≤ g (w+abs(h)) - g w"
shows "∀w∈S. eventually (λh. f w ≤ (g (w + abs(h)) - g w)/abs(h)) (at 0)"
using assms unfolding eventually_at
apply (simp add: divide_simps mult_ac)
by (metis (no_types, hide_lams) add.commute diff_0 diff_add_cancel
diff_minus_eq_add dist_norm open_real_def)
In another scenerio, instead of having a set S, I use the set of real numbers instead (UNIV), and after (simp add: ) I am left with only one case to prove for which sledgehammer finds a solution.
lemma compuniv:
fixes f g :: "real ⇒ real"
assumes "S=UNIV" "open S"
"∀w∈S. ∀h. (w+h)∈S --> h * (f w) ≤ g (w+h) - g w"
shows "∀w∈S. eventually (λh. f w ≤ (g (w + h) - g w)/h) (at 0)"
using assms unfolding eventually_at
apply (simp add: divide_simps mult_ac)
Specifically, I am struggling to understand why when S=UNIV, a solution can be found. Even a method to reduce the problem to proving one sub-case (as when S=UNIV) will help greatly. How can I extend the proofs of the above two cases to prove the main problem?
The bigger picture
This result forms the foundation to proof a result using the real_tendsto_sandwich theorem.
lemma
fixes f g :: "real ⇒ real"
assumes
"open S"
"∀a b. a < b <-> f a < f b"
"∀a. f a > 0"
"continuous_on S (f)"
"∀w∈S. (λh. f (w+h)) -- 0 --> f w"
"∀w∈S. (λh. f w) -- 0 --> f w"
"∀w∈S. eventually (λh. (h ≥ 0 --> f (w+h) ≥ (g (w + h) - g w)/h) ∧
(h ≤ 0 --> f (w+h) ≤ (g (w + h) - g w)/h)) (at 0)"
"∀w∈S. eventually (λh. (h ≥ 0 --> f w ≤ (g (w + h) - g w)/h) ∧
(h ≤ 0 --> f w ≥ (g (w + h) - g w)/h)) (at 0)"
shows "∀w∈S. ((λh. (g (w+h) - g w)/h) ---> f w) (at 0)"
using assms real_tendsto_sandwich`
From the assumptions, it is clear (g (w + h) - g w)/h) is bounded by the f (w+h) and f w when h ≥ 0 and h ≤ 0 therefore taking the limit has h --> 0 yields the result (g (w + h) - g w)/h) --> f w in both cases. Therefore mathematically the final result would be the same. The difficulty is that how can I combine the result when h ≥ 0 and h ≤ 0 to prove the final result?

(Update: I was wrong in my informal explanation, but I think I fixed it. I added some opinions of mine, but I put them at the end, since you didn't ask for them.)
(I assume your use of <--> is a mistake, and it should be <->.)
In all this, I'm working with intuitive ideas of what I think the math means in Topological_Spaces.thy. It's good that you're working on some calculus; this give me a little hope.
(General complaining: The level of formalism in the THY is fairly high, it doesn't sync up directly with ZFC based theories, and as is typical with all the developers of src/HOL and the AFP, the authors don't explain any of it in textbook style, not even in monograph style, not in any style. Style requires the absence of a void.)
If what I give you here is not what you want, you can tell me to delete it, to keep it unanswered so that maybe someone else will come along with something better.
Overview
Below, first I discuss some things about UNIV, and mention some other problems in your last lemma, and with what you say in the last two paragraphs.
I then focus on the fact that the key to all of this is figuring out how h > 0 and h < 0 affects the inequalities, when moving the h from one side to the other.
You might not understand what UNIV is
A key phrase you use in your 2nd to last paragraph is "instead of having a set S, I use the set of real numbers instead (UNIV)".
If you mean S::real set as any subset of the real numbers, versus UNIV::real set, which is all of the real numbers, then that makes sense, but S in all your lemmas is of type real set, type inference, as can be seen in the output panel if types are shown.
Additionally, UNIV is a polymorphic type, 'a set, as shown by this source in src/HOL/Set.thy#l60.
subsubsection {* The universal set -- UNIV *}
abbreviation UNIV :: "'a set" where
"UNIV ≡ top"
lemma UNIV_def:
"UNIV = {x. True}"
by (simp add: top_set_def top_fun_def)
I don't understand what solution you're talking about with "I am struggling to understand why when S=UNIV, a solution can be found", or what two cases you're talking about. I only see one proof goal in all the lemmas. Below, though, I end up using 2 cases as part of a conjunction.
Eliminating UNIV from your lemmas
I don't think UNIV is of key importance here. Also, there might be some conditions in your lemmas that aren't required, though I try to change things as little as possible.
I do get rid of UNIV, because if I can prove a theorem for any real set, then it's also true for UNIV::real set. Consider this:
lemma "(∀S. continuous_on S f) ==> continuous_on UNIV f"
by(simp)
There is also this:
lemma "open (UNIV::real set)"
by(simp)
The first part of your last theorem is this:
lemma
fixes f g :: "real => real"
assumes "S = UNIV"
and "open S"
...
Because you assume S = UNIV, then you don't need open S. Because of that, and because not understanding some things you've said, I now move away from your last lemma, and the last two paragraphs.
I put two use of abs in your 1st lemma, and get rid of UNIV
My goal, like your goal, is to prove theorems with no use of abs h. A mid-level point was inserting two uses of abs h in your 1st lemma, based on what you did:
lemma
fixes f g :: "real => real"
assumes "open S"
and "∀a b. a < b <-> f a < f b"
and "∀a. f a > 0"
and "continuous_on S f"
and "∀w∈S. ∀h. (w + h)∈S --> abs h * f w ≤ g (w + h) - g w"
shows "∀w∈S. eventually (λh. f w ≤ (g (w + h) - g w)/abs h) (at 0)"
using assms unfolding eventually_at
apply (auto simp: divide_simps mult_ac)
by(metis (no_types, hide_lams) add.commute add_diff_cancel add_left_cancel
assms(2) assms(3) diff_0 diff_0_right diff_minus_eq_add dist_norm
monoid_add_class.add.left_neutral mult.commute open_real_def)
There, I eliminated the use of UNIV, and used S, any set of reals.
What's positive or negative in the inequalities is a key point
Related to this is the following basic inequality:
lemma "∀h > 0::real. h * x ≤ y <-> x ≤ y/h"
by(auto simp add: mult_imp_le_div_pos less_eq_real_def mult.commute
pos_less_divide_eq)
In the equality, when the multiplier h is positive, then life is easy, because the direction of the inequality won't change, regardless of the sign of x and y.
At least with Sledgehammer, that's why it's easy to prove the theorems when abs h is used. We don't have to worry about the formula f w ≤ g (w + h) - g w, about whether either side is positive or negative.
Here's how I finally modified your 1st lemma
It's likes this:
lemma
fixes f g :: "real => real"
assumes "open S"
and "∀a b. a < b <-> f a < f b"
and "∀a. f a > 0"
and "continuous_on S f"
and "∀w∈S. ∀h. (w + h)∈S --> h * f w ≤ g (w + h) - g w"
shows "∀w∈S. eventually (λh.
(h > 0 --> f w ≤ (g (w + h) - g w)/h) ∧
(h < 0 --> f w ≥ (g (w + h) - g w)/h)) (at 0)"
using assms unfolding eventually_at
apply (auto simp: divide_simps mult_ac)
by(metis add.commute add_diff_cancel assms(3) assms(4) assms(5) diff_0_right
dist_norm not_less open_real_def)
Here's my explanation (cases: for h > 0 and h < 0)
Two of the conditions in the lemma are these, ∀a b. a < b <-> f a < f b and ∀a. f a > 0, and so f is a positive, monotone increasing function. I don't see that either of those gets used.
Case: h > 0 and (w + h) an element of S
Because ∀w ∈ S. ∀h. (w + h) ∈ S --> h * f w ≤ g (w + h) - g w, then when h > 0 and (w + h) ∈ S, then
h * f w ≤ g (w + h) - g w.
We can multiply by 1/h, if h is not equal to 0, and the direction of the inequality stays the same. In the eventually, I assume the dummy variable is never equal to 0, so the first half the conjunction will eventually be true as h goes to 0.
Case: h < 0 and (w + h) an element of S
Likewise, when h < 0 and (w + h) ∈ S, then
h * f w ≤ g (w + h) - g w.
But because h < 0, if we multiply by 1/h, we have to reverse the direction of the inequality.
Therefore, the second half of the conjunction in the lambda function will eventually be true, as h goes to 0.
Obnoxious update: You didn't ask for my opinion about Stackoverflow etiquette, and I can be an abuser of etiquette myself, such as maybe with this answer, but I think each "tag community" should work to police their own. Unfortunately, etiquette rules aren't clearly stated here, such as at the reddit Rust site, reddit.com/r/rust. I end up doing this, and that's no good either, but maybe it could help influence someone who actually has some influence.
I don't care if you accept my answer here, and you may have reasons for not accepting some of the answers already given to you, but as an example, it's my opinion that you should accept the answer given by R. Thiemann for Substitution in Isabelle.
By not accepting an answer, you're basically saying, "I've not yet received an answer which gives me the information that I want". Additionally, answers not accepted show under the Isabelle tag unanswered category.
I think everyone should understand how few people there are in the world who can answer questions about non-trivial math problems, when implemented in Isabelle/HOL. I'll guess that's there's about 200 people worldwide who actively use Isabelle, who can be considered knowledgeable, proficient users. Out of those, there are fewer even who keep calculus, real analysis, and topology fresh on their mind, and as it's implemented in Isabelle/HOL
The use of Isabelle is a hybrid discipline, combining formal math, logic, and computer science, and at a level of formalism that would typically be at the post-4-year-degree level, partly because there aren't textbooks that explain the Isabelle/HOL logic and math, at an undergraduate level, and partly because it's just hard, graduate-level logic and mathematics.
The quantity of people needed, who have graduate-level knowledge about topology, and who have the time and desire to answers questions about topology, are more likely to operate on mathoverflow.net (this links to a question), and math.stackexchange.com. (Note: I picked that question and answer to show that many answers, on that site, are long or longish, because they try to explain the underlying math of proofs. With Isabelle, if a person is into that kind of thing, like me, then there's even more to explain many times. There can be the math to explain, and then the details of what the Isabelle/HOL syntax means mathematically, such as my comments about UNIV below.)
I say the above because, personally, when I ask a question, I start out with the assumption that I'm not going to get an answer, if a person has to think more than, lets say, 15 minutes. No, make that 5 minutes.
If I get useful information that gives me some insight, then I accept the answer. I would not accept an answer if it was extremely important I get the right information. For math problems, there are always more questions to ask than can be explained by people, so at best, generally, you can only expect to be pointed in the right direction.
You didn't ask for 8 paragraphs of my opinion, but I'm sort of not just talking to you. The problem of people trying to learn to do mathematics in Isabelle/HOL is a big problem, as I see it. We can't say, "Oh, you need to look at Topology in Isabelle/HOL, by James Munkres. There are things like Topology on the AFP, but that's a far cry from a decently written textbook or monograph.
I can delete this answer, or this part of the answer, if that ends up being what I should do.

Related

Revisiting Gauss sum with Isabelle

I'm interested in a variation of the argument that stablishes:
"(∑ i=1..k . i) = k*(k+1) div 2"
We know this follows from a simple induction but the intution is a bit different. A way to see this formula is that if you sum the extremes of the sequence of numbers 1..k you get
1+k = 2 + (k-1) = ...
and then you just multiply the right number of times to get the complete sum.
I would like to reproduce this argument to show the following inequality:
"(∑n = 1..k - 1. cmod (f (int n))) ≤ 2 * (∑n ≤ k div 2. cmod (f (int n)))"
Here I know that cmod (f (int k - n)) = cmod (cnj (f n)) for every n.
Do you see an elegant way of proving this in Isabelle?
The trick to do this proof in an elegant way is to realise that ∑i=1..k. i is the same as ∑i=1..k. k + 1 - i and then adding that to the original sum so that the i cancels. This is a simple re-indexing argument:
lemma "(∑i=1..k. i :: nat) = k * (k + 1) div 2"
proof -
have "(∑i=1..k. i) = (∑i=1..k. k + 1 - i)"
by (rule sum.reindex_bij_witness[of _ "λi. k + 1 - i" "λi. k + 1 - i"]) auto
hence "2 * (∑i=1..k. i) = (∑i=1..k. i) + (∑i=1..k. k + 1 - i)"
by simp
also have "… = k * (k + 1)"
by (simp add: sum.distrib [symmetric])
finally show ?thesis by simp
qed
For the other thing you mentioned, I think that the best way to do this is to first split the sum into the elements less that k div 2 and the rest. Then you can reindex the second sum similarly to the one above. Then the inequality part comes in because you might have one extra leftover element ‘in the middle’ if k is odd and you have to throw that away.
Brief sketch of the important part of the proof:
lemma
assumes "⋀i. f i ≥ 0"
shows "(∑i=1..<k. f (i::nat) :: real) = T"
proof -
(* Separate summation domain into two disjoint parts *)
have "(∑i=1..<k. f i) = (∑i∈{1..k div 2}∪{k div 2<..<k}. f i)"
by (intro sum.cong) auto
(* Pull sum apart *)
also have "… = (∑i∈{1..k div 2}. f i) + (∑i∈{k div 2<..<k}. f i)"
by (subst sum.union_disjoint) auto
(* Reindex the second sum *)
also have "(∑i∈{k div 2<..<k}. f i) = (∑i∈{1..<k - k div 2}. f (k - i))"
by (rule sum.reindex_bij_witness[of _ "λi. k - i" "λi. k - i"]) auto
(* Throw away the element in the middle if k is odd *)
also have "… ≤ (∑i∈{1..k div 2}. f (k - i))"
using assms by (intro sum_mono2) auto
finally have "(∑i=1..<k. f i) ≤ (∑i=1..k div 2. f i + f (k - i))"
by (simp add: sum.distrib)
Figuring out how to do these sum manipulations idiomatically in Isabelle takes some experience. sum.reindex_bij_witness is a very useful rule (as you can see). Things like sum.mono_neutral_left/right can also help a lot.

Proving the cardinality of a more involved set

Supposing I have a set involving three conjunctions {k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2}.
How can I prove in Isabelle that the cardinality of this set is 1 ? (Namely only k=6 has gcd 3 6 = 2.) I.e., how can I prove lemma a_set : "card {k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = 1" ?
Using sledgehammer (or try) again doesn't yield results - I find it very difficult to find what exactly I need to give the proof methods to make them able to to the proof. (Even removing, e.g. gcd 3 k = 2, doesn't make it amenable to auto or sledgehammer.)
Your proposition is incorrect. The set you described is actually empty, as gcd 3 6 = 3. Sledgehammer can prove that the cardinality is zero without problems, although the resulting proof is again a bit ugly, as is often the case with Sledgehammer proofs:
lemma "card {k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = 0"
by (metis (mono_tags, lifting) card.empty coprime_Suc_nat
empty_Collect_eq eval_nat_numeral(3) gcd_nat.left_idem
numeral_One numeral_eq_iff semiring_norm(85))
Let's do it by hand, just to illustrate how to do it. These sorts of proofs do tend to get a little ugly, especially when you don't know the system well.
lemma "{k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = {}"
proof safe
fix x :: nat
assume "x > 2" "x ≤ 7" "gcd 3 x = 2"
from ‹x > 2› and ‹x ≤ 7› have "x = 3 ∨ x = 4 ∨ x = 5 ∨ x = 6 ∨ x = 7" by auto
with ‹gcd 3 x = 2› show "x ∈ {}" by (auto simp: gcd_non_0_nat)
qed
Another, much simpler way (but also perhaps more dubious one) would be to use eval. This uses the code generator as an oracle, i.e. it compiles the expression to ML code, compiles it, runs it, looks if the result is True, and then accepts this as a theorem without going through the Isabelle kernel like for normal proofs. One should think twice before using this, in my opinion, but for toy examples, it is perfectly all right:
lemma "card {k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = 0"
proof -
have "{k::nat. 2<k ∧ k ≤ 7 ∧ gcd 3 k = 2} = Set.filter (λk. gcd 3 k = 2) {2<..7}"
by (simp add: Set.filter_def)
also have "card … = 0" by eval
finally show ?thesis .
qed
Note that I had to massage the set a bit first (use Set.filter instead of the set comprehension) in order for eval to accept it. (Code generation can be a bit tricky)
UPDATE:
For the other statement from the comments, the proof has to look like this:
lemma "{k::nat. 0<k ∧ k ≤ 5 ∧ gcd 5 k = 1} = {1,2,3,4}"
proof (intro equalityI subsetI)
fix x :: nat
assume x: "x ∈ {k. 0 < k ∧ k ≤ 5 ∧ coprime 5 k}"
from x have "x = 1 ∨ x = 2 ∨ x = 3 ∨ x = 4 ∨ x = 5" by auto
with x show "x ∈ {1,2,3,4}" by (auto simp: gcd_non_0_nat)
qed (auto simp: gcd_non_0_nat)
The reason why this looks so different is because the right-hand side of the goal is no longer simply {}, so safe behaves differently and generates a pretty complicated mess of subgoals (just look at the proof state after the proof safe). With intro equalityI subsetI, we essentially just say that we want to prove that A = B by proving a ∈ A ⟹ a ∈ B and the other way round for arbitrary a. This is probably more robust than safe.

how to get isabelle to recognize an obvious conclusion

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)

Ignoring a case to prove a goal through elimination

I have the following lemma to show the derivative of f at x is D.
lemma lm1:
assumes "(∀h. (f (x + h) - f x) = D*h)"
shows "DERIV f x :> D"
proof cases
assume notzero: "∀h. h ≠ 0"
have cs1: "(λh. (f (x + h) - f x) / h) -- 0 --> D" using assms notzero by auto
from this DERIV_def show ?thesis by auto
From the assumptions, I can easily prove the lemma by taking the limit then using DERIV_def. For this I have to assume that h ≠ 0. Continuing with the proof by cases I have to show that even when h = 0, the goal is true, however this can't be done when h = 0 as the assumption becomes 0 = 0. The lemma becomes trivial.
Is there a way I can prove the goal, which is this case is that f has derivative D at x, without the additional assumption that h ≠ 0?
edit: After further research, I came across the use of elimination rules in Isabelle which may be helpful. Also, I understand that the lemma is correct as the if the function is continuous, then the derivative at 0 also exists.
I have been searching for the correct use and implementation of the the above information. How can I improve my search, and where should I be looking?

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