Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asymptotics and the Fréchet derivative #748

Merged
merged 11 commits into from
Mar 1, 2019
Merged

asymptotics and the Fréchet derivative #748

merged 11 commits into from
Mar 1, 2019

Conversation

avigad
Copy link
Collaborator

@avigad avigad commented Feb 22, 2019

This is a start on big O and little o calculations and the Fréchet derivative. The header comments in asymptotics and deriv explain what is there.

I am pleased that the proof of the chain rule is reasonably short and readable, a sign that the library is working well.

The next step will be to define the univariate derivative from the Fréchet derivative, so that we can do ordinary calculus, along the lines of #711.

or.elim (lt_or_ge 0 c)
(assume : c > 0, ⟨c, this, hc⟩)
(assume h'c : c ≤ 0,
have {x : α | ∥f x∥ ≤ 1 * ∥g x∥} ∈ l.sets,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor suggestion: I think this proof will be shorter if you use max c 1 as the existential witness

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look, but I don't think that helps.


theorem is_littleo.add {f₁ f₂ : α → β} {g : α → γ} {l : filter α}
(h₁ : is_littleo f₁ g l) (h₂ : is_littleo f₂ g l) :
is_littleo (f₁ + f₂) g l :=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You used addition of functions here, but used lambda addition for is_bigo.{add,sub} and is_littleo.sub. I'm not sure which is better, but it should be consistent in any case. Probably the lambda addition will avoid some superfluous rewrites?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Yes, I favored the lambdas, because they work better with rewrites. I'll fix this.

-/

section
variables {k : Type*} [normed_field k] [normed_space k β] [has_norm γ]
Copy link
Member

@digama0 digama0 Feb 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the field be K instead of k? I won't insist on greek but you use k as a number or function in some theorems and as a type in others, and it's a bit disorienting.

@@ -8,6 +8,7 @@ Continuous linear functions -- functions between normed vector spaces which are
import algebra.field
import tactic.norm_num
import analysis.normed_space.basic
import ..asymptotics
Copy link
Collaborator

@kckennylau kckennylau Feb 22, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be the first use of .. as file path in mathlib

"transitivity" rules
-/

theorem is_bigo_of_is_bigo_of_is_bigo [has_norm β] [normed_group γ] [has_norm δ]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These names look a little unwieldy. How about is_bigo.trans for this and the little o version, and is_littleo.trans_bigo and is_bigo.trans_littleo for the other two? (I admit that they are adhering to the naming convention, though, so maybe an alias is in order, if people actually guess this name.)

is_littleo (f ∘ k) (g ∘ k) (l.comap k) :=
λ c, mem_comap_sets.mpr ⟨_, hfg c, set.subset.refl _⟩

theorem is_bigo.mono {f : α → β} {g : α → γ} {l₁ l₂ : filter α} (h : l₁ ≤ l₂)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might @[monotonicity] be used here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have never used it. If you are sure it is appropriate, I will add it. Otherwise, I will experiment by adding a local attribute later and see if it works.


variables [has_norm β] [normed_group γ]

theorem is_bigo_zero {g : α → γ} {l : filter α} :
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe one can use is_littleo.to_is_bigo to prove this (by using the theorem below).


theorem is_littleo_of_tendsto [normed_field β] {f g : α → β} {l : filter α}
(hgf : ∀ x, g x = 0 → f x = 0) (h : tendsto (λ x, f x / (g x)) l (nhds 0)) :
is_littleo f g l :=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This theorem should be merged with the next one

@[simp]
theorem is_bigo_norm_left {f : α → β} {g : α → γ} {l : filter α} :
is_bigo (λ x, ∥f x∥) g l ↔ is_bigo f g l :=
by simp only [is_bigo, norm_norm]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for using simp only here 😝

intros c cpos,
filter_upwards [h₁ (2 * c), h₂ (2 * c)],
intros x hx₁ hx₂, dsimp at hx₁ hx₂,
have : 0 < (2 : real), by norm_num,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two_pos

theorem is_bigo_mul_left {f : α → β} {g : α → γ} {l : filter α} {c : β} (hc : c ≠ 0) :
is_bigo (λ x, c * f x) g l ↔ is_bigo f g l :=
begin
have cne0 : ∥c∥ ≠ 0, by rw [ne, norm_eq_zero]; exact hc,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mt norm_eq_zero.1 hc?

@@ -44,6 +45,9 @@ lemma is_linear_map.with_bound

namespace is_bounded_linear_map

def to_linear_map {f : E → F} (h : is_bounded_linear_map f) : E →ₗ[k] F :=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f should be explicit here, because h gets omitted in term printouts, so it's really confusing looking at to_linear_map _

⟨c', hc'⟩ := h₂ in
begin
use c * c',
filter_upwards [hc, hc'], dsimp,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the dsimp necessary here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kckennylau It is (and everywhere else I use it). filter_upwards leaves hypotheses x ∈ { x | ... } and rewrite doesn't do well with these. Is there a better way to contract these?

tendsto (λ x', ∥x' - x∥⁻¹ • (f x' - f x - f' (x' - x))) (nhds_within x s) (nhds 0)

def has_fderiv_at (f : E → F) (f' : E → F) (x : E) :=
has_fderiv_at_within f f' x set.univ
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the definition I was talking about yesterday. You should define

has_deriv_at f f' x :=
is_bounded_linear_map f' ∧
  tendsto (λ x', ∥x' - x∥⁻¹ • (f x' - f x - f' (x' - x))) (nhds x) (nhds 0)

and then prove this equality.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a really bad idea. The point is that all the theorems about fderiv expressed in terms of has_deriv_at_within will work right out of the box for has_deriv_at. If we do it your way, we either need two versions of every theorem or we will have to do a rewrite every time we want to apply one. Am I missing something?

In fact, I think we ought to unify continuous_at_within and continuous_at in this way. I have already chafed with the mistmatch.


def has_fderiv_at_within (f : E → F) (f' : E → F) (x : E) (s : set E) :=
is_bounded_linear_map f' ∧
tendsto (λ x', ∥x' - x∥⁻¹ • (f x' - f x - f' (x' - x))) (nhds_within x s) (nhds 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't you using the is_littleo version as the definition? It should unfold better than this one

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you think the is_littleo version is better? tendsto is central to our library and the tendsto version was convenient for most of the theorems in the file. My guess is that this is the more convenient definition.

theorem has_fderiv_neg {f : E → F} {f' : E → F} {x : E} {s : set E}
(h : has_fderiv_at_within f f' x s) :
has_fderiv_at_within (λ x, - f x) (λ x, - f' x) x s :=
(has_fderiv_smul (-1 : ℝ) h).congr (by simp) (by simp)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type ascription (-1 : ℝ) is not necessary because has_fderiv_smul only accepts real number as first argument.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing it results in an error. I think the elaborator tries to elaborate the negation before it infers the type.

end

def has_fderiv_at_within_mono {f : E → F} {f' : E → F} {x : E} {s t : set E}
(h : has_fderiv_at_within f f' x t) (hst : s ⊆ t) :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two arguments should be swapped, and it should be has_fderiv_at_within.mono and not a def

theorem has_fderiv_at_within.congr {f₀ f₁ : E → F} {f₀' f₁' : E → F}
{x : E} {s : set E} (h : has_fderiv_at_within f₀ f₀' x s)
(h₀ : ∀ x, f₀ x = f₁ x) (h₁ : ∀ x, f₀' x = f₁' x) :
has_fderiv_at_within f₁ f₁' x s :=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This theorem should end with an iff

has_fderiv_at_within (λ x, f x - g x) (λ x, f' x - g' x) x s :=
has_fderiv_add hf (has_fderiv_neg hg)

theorem continuous_of_has_fderiv {f : E → F} {f' : E → F} {x : E} {s : set E}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might this proof be shortened by using o-analysis? This seems like a reasonable second touchstone for the o-analysis library other than the chain rule below.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll give it a try.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Soon I'll update the PR with a nicer version.

has_fderiv_at_within f₁ f₁' x s :=
by rw [←(funext h₀ : f₀ = f₁), ←(funext h₁ : f₀' = f₁')]; exact h

theorem has_fderiv_id (x : E) (s : set E) : has_fderiv_at_within id id x s :=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These theorems should first be proven as just has_fderiv_at id id x, and then there is a general theorem that has_fderiv_at implies has_deriv_at_within.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that the intended general theorem has s substituted for set.univ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, but we need both versions of the theorems in any case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my point. We don't need two versions or a translation if has_fderiv_at is defined the right way.

@@ -1104,6 +1107,12 @@ lemma tendsto_cong {f₁ f₂ : α → β} {l₁ : filter α} {l₂ : filter β}
(h : tendsto f₁ l₁ l₂) (hl : {x | f₁ x = f₂ x} ∈ l₁.sets) : tendsto f₂ l₁ l₂ :=
by rwa [tendsto, ←map_cong hl]

theorem tendsto.congr {f₁ f₂ : α → β} {l₁ : filter α} {l₂ : filter β}
(h : tendsto f₁ l₁ l₂) (h' : ∀ x, f₁ x = f₂ x) :
tendsto f₂ l₁ l₂ :=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be an iff

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, is this necessary at all? This is just congr; ext

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the proofs that use this theorem should use convert instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see now how this can come up in a proof. I guess this version also has its uses, although the arguments should be flipped (it will still work with projection notation). But I think this can be one line proved by by rw <- funext h'; exact h or by convert h; ext; apply h'

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have found that this functions as a proof-term version of convert (which I have come to really enjoy).

@@ -549,6 +549,21 @@ have h₁ : ∃ (i : set α), i ∈ {t : set α | a ∈ t ∧ is_open t},
from ⟨set.univ, set.mem_univ _, is_open_univ⟩,
by { rw [nhds_within_eq, map_binfi_eq h₀ h₁], simp only [map_principal] }

theorem tendsto_nhds_within_mono_left {f : α → β} {a : α}
{s t : set α} {l : filter β} (h : tendsto f (nhds_within a t) l) (hst : s ⊆ t) :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two final arguments should be flipped here and in the next theorem

@avigad
Copy link
Collaborator Author

avigad commented Feb 23, 2019

This version addresses all the comments in the reviews. I made all the changes, except for @kckennylau's suggestion to use the [monotonicity] attribute. I'll try it at some point and add it if it works.

In addition, I improved definitions and proofs in asymptotics, added more useful properties, and wrote a nicer proof of the fact that differentiability implies continuity. The commits have been rebased and tested with the current master.

import topology.basic analysis.normed_space.bounded_linear_maps ..asymptotics tactic.abel
open filter asymptotics

variables {E : Type*} [normed_space ℝ E]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there really something specific in this file to real numbers, or would everything go through for the complex numbers or the p-adics, say?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried changing the variable declarations to this:

variables {K : Type*} [normed_field K]
variables {E : Type} [normed_space K E]
variables {F : Type} [normed_space K F]
variables {G : Type} [normed_space K G]

include K

I don't see why it shouldn't work, since ultimately norms are put on everything. But the declaration causes the elaborator to fail miserably everywhere. Tracing class instances doesn't make it clear what is going wrong. One guess is that the problem has to do with the fact that a normed_field is also an instance of a normed_space (I think).

I move to accept the PR as is, so that anyone who wants to get the generalization to work can give it a try.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it fails because normed_space etc are no longer out_param, so you have to make K explicit everywhere.

@avigad
Copy link
Collaborator Author

avigad commented Mar 1, 2019

Changes:

  • renamed is_bigo to is_O, is_littleo to is_o
  • adopted Mario's changes and additions, but added an expanded proof of the chain rule as an example
  • generalized to normed spaces over any normed field to cover e.g. the complex numbers and the p-adics.

@avigad avigad merged commit 04b5f88 into leanprover-community:master Mar 1, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants