Zulip Chat Archive

Stream: general

Topic: Structure defined for Desarguesian proj plane


Quinn Culver (Feb 17 2023 at 17:47):

Here is the beginning of my attempt to define a structure associated to every Desarguesian projective plane. Why is my attempt instance : has_zero proj_plane_div_ring P L := proj_plane_div_ring.a₁ to define the zero element causing an error?

import basic combinatorics.configuration

open configuration

universe u

variables {P L : Type u} [has_mem P L] [configuration.projective_plane P L]

variables (P L)
structure proj_plane_div_ring :=
(hdesarg : is_desarguesian P L)
(a₁ a₂ c₁₃ c₂₃ : P)
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)

instance : has_zero proj_plane_div_ring P L := proj_plane_div_ring.a₁

The error is

  has_zero proj_plane_div_ring
term
  proj_plane_div_ring
has type
  Π (P L : Type ?) [_inst_1 : has_mem P L] [_inst_2 : projective_plane P L], Type ? : Type (?+1)
but is expected to have type
  Type ? : Type (?+1)

Any other comments, critiques, etc. would be most welcome.

Alex J. Best (Feb 17 2023 at 17:50):

The error message is trying to tell you that you need brackets

instance : has_zero (proj_plane_div_ring P L)

Quinn Culver (Feb 17 2023 at 18:16):

Thanks that worked. But now proj_plane_div_ring.a₁ is yielding the error

type mismatch, term
  proj_plane_div_ring.a₁
has type
  proj_plane_div_ring ?m_1 ?m_2  ?m_1 : Type ?
but is expected to have type
  has_zero (proj_plane_div_ring P L) : Type u

Alex J. Best (Feb 17 2023 at 18:20):

has_zero is a structure with a single field, not just a bare term of that type, so you need to use a syntax to construct an element of that type, i.e. {zero := blah} (or anonymous constructor syntax with \<blah\>

Quinn Culver (Feb 17 2023 at 18:42):

I tried the anonymous constructor syntax, instance : has_zero (proj_plane_div_ring P L) := ⟨proj_plane_div_ring.a₁⟩, but got the same error.

Reid Barton (Feb 17 2023 at 18:44):

You would need to give six arguments since your structure has six fields.

Reid Barton (Feb 17 2023 at 18:45):

So I assume you haven't said what you meant to say

Eric Wieser (Feb 17 2023 at 18:52):

instance : has_zero (proj_plane_div_ring P L) means "there is a proj_plane_div_ring (aka a choice of four points in the P and L projective plane) we will call 0"

Eric Wieser (Feb 17 2023 at 18:53):

proj_plane_div_ring.a₁ means "given an existing choice of those four points, give me the first one"

Eric Wieser (Feb 17 2023 at 18:55):

I suspect you meant

instance [proj_plane_div_ring P L] : has_zero P := {zero := proj_plane_div_ring.a₁}

but that won't actualy help you because lean won't find L

Quinn Culver (Feb 17 2023 at 19:11):

Which part is looking for L?

Quinn Culver (Feb 17 2023 at 19:48):

Oh are you saying that there's a problem with the L in [proj_plane_div_ring P L]?

Eric Wieser (Feb 17 2023 at 19:52):

Yes, exactly; lean won't know which L to try since it only knows P from the goal

Eric Wieser (Feb 17 2023 at 19:53):

I get the feeling your question might be an #xy problem; what do you want the 0 for?

Quinn Culver (Feb 17 2023 at 20:05):

I'm trying ultimately to formalize the fundamental theorem of projective geometry, which requires defining a division ring that coordinatizes a Desarguesian Projective plane.

Quinn Culver (Feb 17 2023 at 20:06):

In the proof I'm following it starts with four points, no three of which are colinear, and uses one of them a₁ as the zero element.

Quinn Culver (Feb 17 2023 at 20:06):

Does that clear it up?

Quinn Culver (Feb 17 2023 at 20:07):

To define the zero element, I tried following Mathematics in Lean's construction of the Guassian integers (section 6.3).

Reid Barton (Feb 17 2023 at 20:18):

But what is the division ring? I mean its underlying set/type.

Quinn Culver (Feb 17 2023 at 20:19):

It's the set of points on the line from a₁ to a₂ excluding a₂.

Reid Barton (Feb 17 2023 at 20:20):

So then that is the thing that you need to define has_zero etc. instances for

Quinn Culver (Feb 17 2023 at 20:20):

Okay thanks. I'll think about that.

Quinn Culver (Feb 17 2023 at 21:52):

Cwould (←intentional portmanteau) someone please recommend an example of a structure definition that might be useful for me to learn how to go about this the correct way? :thanks:

Eric Wieser (Feb 17 2023 at 22:28):

def the_div_ring : Type* := { x : P // is_between x a1 a2 }

Quinn Culver (Feb 17 2023 at 22:33):

Does that mean a structure isn't appropriate here?

Eric Wieser (Feb 17 2023 at 23:44):

I think it's overkill

Eric Wieser (Feb 17 2023 at 23:57):

The code above uses docs#subtype which is a structure that already exists

Kevin Buzzard (Feb 18 2023 at 18:35):

A division ring is a structure on a type (the "underlying set") so you need to first make the type and then make the division ring structure on top

Quinn Culver (Feb 19 2023 at 03:34):

(deleted)

Quinn Culver (Feb 19 2023 at 04:09):

(deleted)

Quinn Culver (Feb 19 2023 at 16:32):

The subtype example, def the_div_ring : Type* := { x : P // is_between x a1 a2 } above refers to a1 and a2. How to do this properly? Here a1 and a2 are points that are i) not equal and ii) two of a set of four points no three of which are colinear that I'm using as my alternative configuration axiom. I've already proven that mathlib's configuration axiom,exists_config, implies this alternative one.

My only idea is to use variables and constants as below, but that feels wrong.

variables a₁ a₂ c₁₃ c₂₃ : P
constant axiom3_alt : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃
constant ha₁a₂ : a₁  a₂

def the_div_ring : Type* := { x : P // (x  mk_line ha₁a₂)  x  a₂}

Eric Wieser (Feb 19 2023 at 16:46):

You definitely do not want to use constants here

Eric Wieser (Feb 19 2023 at 16:47):

I was assuming you would keep your existing structure, or something similar to it:

/-- A choice of four points in a desarguesian plane, which define a division ring -/
structure proj_plane_div_config [is_desarguesian P L] :=
(a₁ a₂ c₁₃ c₂₃ : P)
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)

def the_div_ring (c : proj_plane_div_config P L) : Type* := { x : P // is_between x c.a₁ c.a₂ }

-- optional; this lets you write `x : c` instead of `x : c.the_div_ring`
instance : has_coe_to_sort (proj_plane_div_config P L) := { coe_sort := the_div_ring }

(untested, but should be easy to make that work after fiddling with implicit / explicit arguments)

Eric Wieser (Feb 19 2023 at 16:50):

Note that this:

variables a₁ a₂ c₁₃ c₂₃ : P
constant axiom3_alt : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃

says "any four points have no three collinear", which I assume is false. This is one reason to avoid constant and axiom; it is very easy to add a false axiom by accident, especially if you're new to Lean.

Quinn Culver (Feb 19 2023 at 16:59):

I thought that since you said a structure is overkill, your suggestion was intended to supplant it, @Eric Wieser . What would you recommend be used instead of structure here?

Eric Wieser (Feb 19 2023 at 17:01):

structure is overkill for the_div_ring (that's what I intepreted "here" as in your question)

Eric Wieser (Feb 19 2023 at 17:01):

The thing I was implying you should not write is

structure the_div_ring (c : proj_plane_div_config P L) : Type* :=
(val : P)
(property : is_between x c.a₁ c.a₂)

Eric Wieser (Feb 19 2023 at 17:05):

Quinn Culver said:

My only idea is to use variables and constants as below, but that feels wrong.

variables a₁ a₂ c₁₃ c₂₃ : P
constant axiom3_alt : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃
constant ha₁a₂ : a₁  a₂

def the_div_ring : Type* := { x : P // (x  mk_line ha₁a₂)  x  a₂}

Just to be clear, this approach would be fine if you used variables intead of constant; but you'd have to write x : the_div_ring a₁ a₂ c₁₃ c₂₃ axiom3_alt ha₁a₂ instead of x : the_div_ring c or x : coe_sort c. structure lets you take a bunch of variables and combine them into a single variable.

Quinn Culver (Feb 19 2023 at 17:06):

My god, people in this forum are so helpful. Thanks!

Quinn Culver (Feb 24 2023 at 15:54):

Following the suggestion above, I have

structure proj_plane_div_config [is_desarguesian P L] :=
(a₁ a₂ c₁₃ c₂₃ : P)
(ha₁a₂ : a₁  a₂)
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)


def the_div_ring (c : proj_plane_div_config P L) : Type* := {x : P //  x  (mk_line c.ha₁a₂)}

right now the is_desarguesian is throwing the an 'unknown identifier' error, even though it's in a file, basic.lean, that is imported.

The mk_lineis throwing an error too, saying that Lean doesn't know how to synthesize placeholder.

Kevin Buzzard (Feb 24 2023 at 16:06):

Maybe some spelling mistake? Can you post a #mwe ? (perhaps append the copy of one file to another?)

Kevin Buzzard (Feb 24 2023 at 16:07):

This is not going to be some deep problem, it's far more likely to be a typo.

Quinn Culver (Feb 24 2023 at 16:40):

You were right about a typo, is_desarguesian needed to be configuration.is_desarguesian. Fixed, thanks!

Now the proj_plane_div_config in def the_div_ring (c : proj_plane_div_config P L) : Type* := {x : P // x ∈ (mk_line c.ha₁a₂)} is throwing a 'failed to synthesize typeclass instance' error. The mk_line is still throwing an error too, but first things first; once the previous sentence's error is dealt with that error might go away.

Here's my attempt at a MWE.

import combinatorics.configuration

open configuration.has_lines
open configuration.has_points
open configuration.nondegenerate
open classical
open set

universe u

variables {P L : Type u} [has_mem P L] [configuration.has_lines P L] [configuration.has_points P L] [nontrivial P] [nontrivial L]

variables (P L)
structure triangle :=
(p₀ p₁ p₂ : P)
(l₀ l₁ l₂ : L)
(i₀₁ : p₀  l₁)
(i₀₂ : p₀  l₂)
(i₁₀ : p₁  l₀)
(i₁₂ : p₁  l₂)
(i₂₀ : p₂  l₀)
(i₂₁ : p₂  l₁)

variables {P}
def collinear (p₀ p₁ p₂ : P) : Prop :=  l : L, p₀  l  p₁  l  p₂  l


variables (P) {L}
def concurrent (l₀ l₁ l₂ : L) : Prop :=  p : P, p  l₀  p  l₁  p  l₂

variables {P}
def centrally_perspective (T₁ T₂ : triangle P L) : Prop :=
 p : P, collinear L p T₁.p₀ T₂.p₀  collinear L p T₁.p₁ T₂.p₁  collinear L p T₁.p₂ T₂.p₂

def axially_perspective (T₁ T₂ : triangle P L) : Prop :=
 l : L, concurrent P l T₁.l₀ T₂.l₀  concurrent P l T₁.l₁ T₂.l₁  concurrent P l T₁.l₂ T₂.l₂



variables (P L)
def configuration.is_desarguesian : Prop :=
 T₁ T₂ : triangle P L, centrally_perspective T₁ T₂  axially_perspective T₁ T₂

variables {P}
def four_points_no_three_collinear (p₀ p₁ p₂ p₃ : P) : Prop := ¬ collinear L p₀ p₁ p₂  ¬ collinear L p₀ p₁ p₃  ¬ collinear L p₀ p₂ p₃  ¬ collinear L p₁ p₂ p₃

/-- A choice of four points in a desarguesian plane, which define a division ring -/
structure proj_plane_div_config [configuration.is_desarguesian P L] :=
(a₁ a₂ c₁₃ c₂₃ : P)
(ha₁a₂ : a₁  a₂)
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)


def the_div_ring (c : proj_plane_div_config P L) : Type* := {x : P //  x  (mk_line c.ha₁a₂)}

Thomas Browning (Feb 24 2023 at 19:12):

Here you go:

variables (P L)
@[class] def configuration.is_desarguesian : Prop :=
 T₁ T₂ : triangle P L, centrally_perspective T₁ T₂  axially_perspective T₁ T₂

variables {P}
def four_points_no_three_collinear (p₀ p₁ p₂ p₃ : P) : Prop := ¬ collinear L p₀ p₁ p₂  ¬ collinear L p₀ p₁ p₃  ¬ collinear L p₀ p₂ p₃  ¬ collinear L p₁ p₂ p₃

variables (P L)
/-- A choice of four points in a desarguesian plane, which define a division ring -/
structure proj_plane_div_config [configuration.is_desarguesian P L] :=
(a₁ a₂ c₁₃ c₂₃ : P)
(ha₁a₂ : a₁  a₂)
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)


def the_div_ring [configuration.is_desarguesian P L] (c : proj_plane_div_config P L) : Type* := {x : P //  x  (mk_line c.ha₁a₂ : L)}

Thomas Browning (Feb 24 2023 at 19:14):

You need @[class] to be able to use the square bracket instance notation.
You need variables (P L) to make both P and L explicit for proj_plane_div_config P L.
You need to add [configuration.is_desarguesian P L] to the_div_ring because it's needed for proj_plane_div_config.
You need to write (mk_line c.ha₁a₂ : L) because L cannot be inferred.

Thomas Browning (Feb 24 2023 at 19:15):

But really there's no reason to make proj_plane_div_config require [configuration.is_desarguesian P L], right?

Quinn Culver (Feb 26 2023 at 18:21):

I'm unclear on how & where to define the division ring operations (which are rather complicated). I guess I need to define their types as data in the structure, like

structure proj_plane_div_config :=
(a₁ a₂ c₁₃ c₂₃ : P)
(ha₁a₂ : a₁  a₂) --TODO: figure out how to remove this since hnoncol below implies it. mk_line should get the proof from hnoncol
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)
(addition : P  P  P)  --IS THIS CORRECT?

Then, once the carrier set is defined as

def the_div_ring (c : proj_plane_div_config P L) : Type* := {x : P //  x  (mk_line c.ha₁a₂ : L)  x  c.a₂}

How and where do I define the addition of elements on that carrier set? I tried def addition (r s : the_div_ring) : the_div_ring := r, (which I intended to mean r+s = r, just as a test) but that didn't work. Thoughts?

Eric Wieser (Feb 26 2023 at 18:56):

You at some point need to say

def my_config : proj_plane_div_ring P L :=
{ a₁ := sorry,
  addition := sorry }
-- lean will ask you to add the other fields too

What's the maths here? Is the addition derived solely from the relation between P and L, or is the idea that it is already the natural one on P?

Reid Barton (Feb 26 2023 at 21:41):

Quinn Culver said:

I tried def addition (r s : the_div_ring) : the_div_ring := r, (which I intended to mean r+s = r, just as a test) but that didn't work. Thoughts?

In what sense did it not work? Was there an error?
You probably need to give c (the proj_plane_div_config P L) as an argument to the_div_ring.

Reid Barton (Feb 26 2023 at 21:42):

Quinn Culver said:

I'm unclear on how & where to define the division ring operations (which are rather complicated). I guess I need to define their types as data in the structure, like

structure proj_plane_div_config :=
(a₁ a₂ c₁₃ c₂₃ : P)
(ha₁a₂ : a₁  a₂) --TODO: figure out how to remove this since hnoncol below implies it. mk_line should get the proof from hnoncol
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)
(addition : P  P  P)  --IS THIS CORRECT?

No, you shouldn't try to put addition here.

Quinn Culver (Feb 27 2023 at 15:53):

@Eric Wieser Given four points, a₁ a₂ c₁₃ c₂₃, no three of which are colinear, addition of two points, r and s, on the line connecting a₁ and a₂ is

r+s=[[(rc13)(a2a3)]([(sa3)(a2c13)]](a1a2),r + s = [[(r \vee c_{13}) \wedge (a_2 \vee a_3)] \vee ([(s \vee a_3) \wedge (a_2 \vee c_{13})]] \wedge (a_1 \vee a_2),

where the join of two points is their line and the meet of two lines is their point.

Eric Wieser (Feb 27 2023 at 15:54):

Great, then you definitely do not want to be adding to proj_plane_div_config

Quinn Culver (Feb 27 2023 at 15:55):

So I guess after defining the structure and then the carrier set, the operations come separately?

Quinn Culver (Feb 28 2023 at 15:03):

@Reid Barton How would you go about it?

Reid Barton (Feb 28 2023 at 15:04):

I think what you had above was good

Notification Bot (Feb 28 2023 at 15:14):

35 messages were moved here from #general > Structure defined for Desarguesian proj plane by Eric Wieser.

Eric Wieser (Feb 28 2023 at 15:16):

Apologies for the has_coe_to_sort notational distraction, I've moved that all to a new thread

Eric Wieser (Feb 28 2023 at 15:17):

Reid Barton said:

Quinn Culver said:

I tried def addition (r s : the_div_ring) : the_div_ring := r, (which I intended to mean r+s = r, just as a test) but that didn't work. Thoughts?

In what sense did it not work? Was there an error?
You probably need to give c (the proj_plane_div_config P L) as an argument to the_div_ring.

I don't think you ever answered this question @Quinn Culver

Quinn Culver (Feb 28 2023 at 15:34):

I think I got it to work; at least there're no errors: def addition (c : proj_plane_div_config P L) (r s : the_div_ring P L c) : the_div_ring P L c:= r

Quinn Culver (Feb 28 2023 at 15:35):

should I be using a namespace? namespace proj_plane_div_config?

Eric Wieser (Feb 28 2023 at 15:47):

I would skip the def entirely and just write a has_add instance

Eric Wieser (Feb 28 2023 at 15:47):

instance (c : proj_plane_div_config P L) : has_add (the_div_ring P L c) :=
{ add := λ r s, sorry }

Eric Wieser (Feb 28 2023 at 15:49):

Also you should change the argument explicitness on the_div_ring so that P and L are implicit, as they're obvious from c; then you can write c.the_div_ring instead of the_div_ring P L c

Quinn Culver (Mar 01 2023 at 18:41):

(deleted)

Eric Wieser (Mar 01 2023 at 18:46):

I recommend you write

structure proj_plane_div_config :=
(a₁ a₂ c₁₃ c₂₃ : P)
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)

lemma proj_plane_div_config.ha₁a₂ (c : proj_plane_div_config  P L) : c.a₁  c.a₂ := sorry

so that you don't have to prove it inline

Quinn Culver (Mar 01 2023 at 18:47):

Just did that!

Quinn Culver (Mar 01 2023 at 18:47):

But now...

Quinn Culver (Mar 01 2023 at 18:48):

The is displaying the error

35:75: invalid type ascription, term has type
  Prop : Type
but is expected to have type
  L : Type u

Here's the code:

/-- A choice of four points in a desarguesian plane, which define a division ring -/
structure proj_plane_div_config :=
(a₁ a₂ c₁₃ c₂₃ : P)
(hnoncol : four_points_no_three_collinear L a₁ a₂ c₁₃ c₂₃)

namespace proj_plane_div_config

variables {P L}
lemma neq_a₁a₂ (c: proj_plane_div_config P L): c.a₁  c.a₂ := sorry


def the_div_ring (c : proj_plane_div_config P L) : Type* := {x : P //  (x  mk_line (neq_a₁a₂ c) : L)  x  c.a₂}

Eric Wieser (Mar 01 2023 at 18:51):

That comma is illegal after the sorry

Quinn Culver (Mar 01 2023 at 18:51):

Corrected that, thanks.

Eric Wieser (Mar 01 2023 at 18:51):

And (x ∈ mk_line (neq_a₁a₂ c) : L) means ((x ∈ mk_line (neq_a₁a₂ c)) : L), you meant x ∈ (mk_line (neq_a₁a₂ c) : L).

Quinn Culver (Mar 01 2023 at 18:52):

Nice! That worked. Thanks again.

Quinn Culver (Mar 01 2023 at 18:53):

Why did you suggest putting proj_plane_div_config. at the beginning of the lemma's name?

Quinn Culver (Mar 01 2023 at 18:55):

Wait I guess it's so I can just write c.neq_a₁a₂. Is that the reason?

Eric Wieser (Mar 01 2023 at 18:55):

Quinn Culver said:

Why did you suggest putting proj_plane_div_config. at the beginning of the lemma's name?

It does the same thing as the namespace command that I didn't know you had

Eric Wieser (Mar 01 2023 at 18:56):

So yes, you can write it as x ∈ (mk_line c.neq_a₁a₂ : L) too

Quinn Culver (Mar 01 2023 at 21:06):

For notational convenience, I'm considering defining the meet and join of points and lines as in ftpg.pdf. Any reason this is unwise? For example might it be more work than it's worth?

That way instead of always invokingmk_line I can just use the meet symbol.

Eric Wieser (Mar 01 2023 at 22:24):

If you do that you'll need to define meet a b as something like if h : a \ne b then mk_line h else classical.choice sorry

Reid Barton (Mar 02 2023 at 17:54):

If you define it on flats as described in those notes then it is always defined and well-behaved, and I expect it would save a large amount of case analysis.

Quinn Culver (Mar 03 2023 at 18:34):

I'm unsure how to even start implementing the meet & join. I'd need to add a 0 and 1 element (\emptyset and the whole plane, I think). Any advice?

Reid Barton (Mar 03 2023 at 18:42):

I would make an inductive type with 4 constructors

Quinn Culver (Mar 08 2023 at 18:21):

Is an inductive type more appropriate than a structure here? Is that because there's no single carrier set?

Are the 4 constructors you had in mind, @Reid Barton, 1. the minimum (zero), 2. the maximum (one), 3. the points, and 4. the lines? If so, why not also include constructors for the meet & join? Is it better to define those separately?

Eric Wieser (Mar 08 2023 at 19:15):

You should define those separately

Eric Wieser (Mar 08 2023 at 19:16):

If you include them, then meet zero zero = zero is false

Quinn Culver (Mar 08 2023 at 23:25):

(deleted)


Last updated: Dec 20 2023 at 11:08 UTC