Zulip Chat Archive

Stream: general

Topic: treacherous sorry


Patrick Massot (Jun 28 2018 at 10:01):

I'm slowing beginning to understand why trying to formalize math in a top to down way is very dangerous, even if this is very appealing to mathematicians. Today's lesson is about sorried properties. In the minimized version below, say we are trying to build of stub of continuous functions theory.

variables {α β γ : Type}

-- function f is continuous at point x
def continuous_at (x : α) (f : α  β) : Prop := sorry

def continuous (f : α  β) : Prop :=  x, continuous_at x f

lemma continuous_at_comp {f : α  β} {g : β  γ} {x : α} :
continuous_at x f  continuous_at (f x) g  continuous_at x (g  f) := sorry

lemma continuous_comp (f : α  β) (g : β  γ) :
  continuous f  continuous g  continuous (g  f) :=
assume cont_f cont_g x, continuous_at_comp (cont_f x) (cont_g (f x))

Looks good to me. It tells the story of continuity being a property of a function that can be checked near each point, and the composition property of this local thing implies composition for the global thing.

Patrick Massot (Jun 28 2018 at 10:02):

Now let's look at the following "simplified" version:

Patrick Massot (Jun 28 2018 at 10:02):

variables {α β γ : Type}

-- function f is continuous at point x
def continuous_at (x : α) (f : α  β) : Prop := sorry

def continuous (f : α  β) : Prop :=  x, continuous_at x f

lemma continuous_comp (f : α  β) (g : β  γ) :
  continuous f  continuous g  continuous (g  f) :=
assume cont_f cont_g x, cont_g (f x)

:scream:

Patrick Massot (Jun 28 2018 at 10:03):

It reminds me of traps of unit testing using mocks.

Mario Carneiro (Jun 28 2018 at 10:31):

The problem is that continuous_at has been defined as a constant wrt x and f, since sorry : Prop has no stated dependence on x and f. One solution is to sorry at the function level:

def continuous_at : α → (α → β) → Prop := sorry

(you can also write ∀ (x : α) (f : α → β), Prop if you prefer to name the variables)

Mario Carneiro (Jun 28 2018 at 10:34):

That said, I completely agree with you about the dangers of axiomatizing things without a cross-check. I did not notice the issue in the first code block until you pointed it out

Patrick Massot (Jun 28 2018 at 10:35):

Indeed this fixes this problem. But my point remains: one needs to be extremely careful with this kind of sorries

Patrick Massot (Jun 28 2018 at 10:35):

I'd like to understand better what you call "cross-check".

Mario Carneiro (Jun 28 2018 at 10:36):

It is hard to check an axiom or a definition for correctness, since lean can't help you

Mario Carneiro (Jun 28 2018 at 10:38):

In a sense, proving theorems about a definition or theorems that follow from axioms form a kind of testing on the definition, since they can (but not necessarily will) expose issues and edge cases that were not originally considered

Patrick Massot (Jun 28 2018 at 10:38):

Something else mysterious to me: replacing def continuous_at (x : α) (f : α → β) : Prop := sorry by constant continuous_at (x : α) (f : α → β) : Prop also allows to uncover the issue

Mario Carneiro (Jun 28 2018 at 10:39):

That's because in axiom and constant it is always defined as a single global constant abstracted over any variables

Mario Carneiro (Jun 28 2018 at 10:40):

so it's exactly the same as constant continuous_at : α → (α → β) → Prop

Mario Carneiro (Jun 28 2018 at 10:41):

You should think of sorry as providing a term of the specified type, without necessarily pulling in all the assumptions in the context but only the ones needed to typecheck the type of the sorry

Mario Carneiro (Jun 28 2018 at 10:42):

while axiom / constant only produces terms in the empty context so it gets all the variables

Patrick Massot (Jun 28 2018 at 10:42):

Indeed that clearly explains the flaw: x and f are not needed to construct a term with type Prop

Patrick Massot (Jun 28 2018 at 10:43):

I mean: it explains why sorry is dangerous here, it doesn't quite explain why constant works

Mario Carneiro (Jun 28 2018 at 10:43):

another option would be to write sorry x f, but this doesn't typecheck so you have to annotate the type, which kind of defeats the point

Mario Carneiro (Jun 28 2018 at 10:44):

i.e.

def continuous_at (x : α) (f : α → β) : Prop :=
(sorry : α → (α → β) → Prop) x f

Mario Carneiro (Jun 28 2018 at 10:46):

constant continuous_at (x : α) (f : α → β) : Prop
#print continuous_at
-- constant continuous_at : Π {α β : Type}, α → (α → β) → Prop

what else would it do? A def doesn't randomly drop variables that are given in its statement, so it would be weird for constant to do so

Patrick Massot (Jun 28 2018 at 10:46):

Ok, thanks

Mario Carneiro (Jun 28 2018 at 10:46):

note that even with def continuous_at (x : α) (f : α → β) : Prop := sorry, continuous_at has exactly that same type

Mario Carneiro (Jun 28 2018 at 10:47):

the only difference is that constant continuous_at can't be unfolded

Patrick Massot (Jun 28 2018 at 10:47):

My train ride is almost finished, I'll disappear from here (I love trains with WIFI).

Patrick Massot (Jun 28 2018 at 10:47):

You can answer emails in the meantime :wink:

Sebastien Gouezel (Jun 28 2018 at 16:28):

Instead of sorrying stuff, you could work in an axiomatic kind of way, just putting as assumptions all the stuff you need and starting from there. If you want to work with general pseudo-groups, maybe this is the way to go. For instance, if you define a smoothness class as follows, then I guess this is enough to define manifolds based on the smoothness class. And then you will just need to show that your favorite class (say symplectomorphisms, but maybe it is better to work with homeos to start with) satisfies your axioms, to get symplectic manifolds or C^0 manifolds.

import analysis.real data.set.function

noncomputable theory
local attribute [instance] classical.decidable_inhabited classical.prop_decidable

universes u v
variables {α : Type u} [inhabited α] {β : Type v}

open set

def inverse_on (U : set α) (f : α  β) : β  α :=
λ b, if h : b  f '' U then classical.some h else default α

def homeomorphism_on (U : set α) (f : α  β) := inj_on f U -- agreed, this definition is not optimal

structure smoothness_class (α : Type u) [topological_space α] [inhabited α] :=
(smooth_on : (set α)  (α  α)  Prop)
(open_domain: U f, smooth_on U f  is_open U)
(homeo: U f, smooth_on U f  homeomorphism_on U f)
(restriction: U V f, smooth_on U f  is_open V  V  U  smooth_on V f)
(composition: U V f g, smooth_on U f  smooth_on V g  f ''(U)  V  smooth_on U (g  f))
(inversion: U f, smooth_on U f  smooth_on (f ''(U)) (inverse_on U f))

variables [topological_space α] (S: smoothness_class α)
-- and now I want to define manifolds based on the class of maps S...

Maybe I forgot some important axiom, but you see the idea.

And I also enjoy the wifi on trains :)

Kevin Buzzard (Jun 28 2018 at 16:52):

This is very interesting to me because we started at the top with perfectoid spaces: https://github.com/kbuzzard/lean-perfectoid-spaces/blob/master/src/perfectoid_space.lean ; and I had no idea that this could cause any problems at all. The perfectoid space link is what looks like a fully written definition of a perfectoid space, but the import contains a gazillion sorries.

Simon Hudon (Jun 28 2018 at 17:14):

Is gazillion defined as def gazillion : nat := sorry?


Last updated: Dec 20 2023 at 11:08 UTC