Zulip Chat Archive

Stream: general

Topic: typeclass problems


Kenny Lau (Jun 15 2018 at 22:05):

This loop is breaking everything

[class_instances] (25) ?x_99 : out_param (field ?x_97) := @field_extension.to_field ?x_101 ?x_102 ?x_103 ?x_104
[class_instances] (26) ?x_104 : @field_extension ?x_101 ?x_102 ?x_103 := @algebraic_field_extension.to_field_extension ?x_105 ?x_106 ?x_107 ?x_108
[class_instances] (27) ?x_108 : @algebraic_field_extension ?x_105 ?x_106 ?x_107 := @algebraic_closure.to_algebraic_field_extension ?x_109 ?x_110 ?x_111 ?x_112

Kenny Lau (Jun 15 2018 at 22:05):

class alg_closed_field (α : Type*) extends field α :=
(alg_closed :  f : polynomial α, f.deg > 1   x, f.eval α α x = 0)

class field_extension (α : out_param $ Type*) (β : Type*)
  [out_param $ field α] extends field β :=
(f : α  β) [hom : is_ring_hom f]

instance field_extension.to_is_ring_hom (α : Type*) (β : Type*)
  [field α] [field_extension α β] : is_ring_hom (field_extension.f β) :=
field_extension.hom β

instance field_extension.to_algebra (α : Type*) (β : Type*)
  [field α] [field_extension α β] : algebra α β :=
{ f := field_extension.f β }

class algebraic_field_extension (α : out_param $ Type*) (β : Type*)
  [out_param $ field α] extends field_extension α β :=
(algebraic :  x : β,  f : polynomial α, f.eval α β x = 0)

set_option old_structure_cmd true

class algebraic_closure (α : out_param $ Type*) (β : Type*)
  [out_param $ field α] extends alg_closed_field β, algebraic_field_extension α β

set_option old_structure_cmd false

Kenny Lau (Jun 15 2018 at 22:08):

I'm not very good at dealing with typeclasses

Kenny Lau (Jun 15 2018 at 22:23):

somehow the same setting with ring instead of field doesn't cause this problem:

class algebra (R : out_param Type*) (A : Type*)
  [out_param $ comm_ring R] extends comm_ring A :=
(f : R  A) [hom : is_ring_hom f]

This doesn't cause any loops

Kenny Lau (Jun 15 2018 at 22:28):

solution:

class is_alg_closed_field (α : Type*) [field α] : Prop :=
(alg_closed :  f : polynomial α, f.deg > 1   x, f.eval α α x = 0)

class field_extension (α : out_param $ Type*) (β : Type*)
  [out_param $ field α] extends field β :=
(f : α  β) [hom : is_ring_hom f]

instance field_extension.to_is_ring_hom (α : Type*) (β : Type*)
  [field α] [field_extension α β] : is_ring_hom (field_extension.f β) :=
field_extension.hom β

instance field_extension.to_algebra (α : Type*) (β : Type*)
  [field α] [field_extension α β] : algebra α β :=
{ f := field_extension.f β }

class is_algebraic_field_extension (α : out_param $ Type*) (β : Type*)
  [out_param $ field α] [field_extension α β] : Prop :=
(algebraic :  x : β,  f : polynomial α, f.eval α β x = 0)

class is_algebraic_closure (α : out_param $ Type*) (β : Type*)
  [field α] [field_extension α β]
  extends is_alg_closed_field β, is_algebraic_field_extension α β : Prop

Kenny Lau (Jun 15 2018 at 22:29):

TLDR: change algebraic_field_extension (not Prop) to is_algebraic_field_extension (Prop) etc

Kenny Lau (Jun 15 2018 at 22:30):

update: it is not true that the algebra causes no problem

Mario Carneiro (Jun 15 2018 at 22:31):

out_param (field ?x_97)

not the first time I've seen this today

Kenny Lau (Jun 15 2018 at 22:32):

but module seems to be doing fine

Mario Carneiro (Jun 15 2018 at 22:32):

What caused this typeclass search? You never want to find arbitrary fields

Kenny Lau (Jun 15 2018 at 22:32):

what stops ring.to_module and class module ... [ring _] from forming a loop?

Kenny Lau (Jun 15 2018 at 22:34):

What caused this typeclass search? You never want to find arbitrary fields

I have something involving rings and no fields at all. The searcher wants to know that it has addition. Somehow it got to fields, and then it started the loop

Mario Carneiro (Jun 15 2018 at 22:34):

I don't mean just field ?, but also ring ? and other such things

Mario Carneiro (Jun 15 2018 at 22:35):

the bad sign is a class on a metavar

Kenny Lau (Jun 15 2018 at 22:36):

[class_instances]  class-instance resolution trace
[class_instances] (0) ?x_0 : has_zero α := @pi.has_zero ?x_1 ?x_2 ?x_3
failed is_def_eq
[class_instances] (0) ?x_0 : has_zero α := cardinal.has_zero
failed is_def_eq
[class_instances] (0) ?x_0 : has_zero α := @finsupp.has_zero ?x_4 ?x_5 ?x_6
failed is_def_eq
[class_instances] (0) ?x_0 : has_zero α := @multiset.has_zero ?x_7
failed is_def_eq
[class_instances] (0) ?x_0 : has_zero α := unsigned.has_zero
failed is_def_eq
[class_instances] (0) ?x_0 : has_zero α := @fin.has_zero ?x_8
failed is_def_eq
[class_instances] (0) ?x_0 : has_zero α := int.has_zero
failed is_def_eq
[class_instances] (0) ?x_0 : has_zero α := nat.has_zero
failed is_def_eq
[class_instances] (0) ?x_0 : has_zero α := @no_zero_divisors.to_has_zero ?x_9 ?x_10
[class_instances] (1) ?x_10 : no_zero_divisors α := @domain.to_no_zero_divisors ?x_11 ?x_12
[class_instances] (2) ?x_12 : domain α := @linear_nonneg_ring.to_domain ?x_13 ?x_14
[class_instances] (2) ?x_12 : domain α := @to_domain ?x_13 ?x_14
[class_instances] (3) ?x_14 : linear_ordered_ring α := @linear_nonneg_ring.to_linear_ordered_ring ?x_15 ?x_16
[class_instances] (3) ?x_14 : linear_ordered_ring α := @linear_ordered_field.to_linear_ordered_ring ?x_15 ?x_16
[class_instances] (4) ?x_16 : linear_ordered_field α := @discrete_linear_ordered_field.to_linear_ordered_field ?x_17 ?x_18
[class_instances] (3) ?x_14 : linear_ordered_ring α := @linear_ordered_comm_ring.to_linear_ordered_ring ?x_15 ?x_16
[class_instances] (4) ?x_16 : linear_ordered_comm_ring α := @decidable_linear_ordered_comm_ring.to_linear_ordered_comm_ring ?x_17 ?x_18
[class_instances] (5) ?x_18 : decidable_linear_ordered_comm_ring α := @linear_nonneg_ring.to_decidable_linear_ordered_comm_ring ?x_19 ?x_20 ?x_21 ?x_22
[class_instances] (5) ?x_18 : decidable_linear_ordered_comm_ring α := int.decidable_linear_ordered_comm_ring
failed is_def_eq
[class_instances] (5) ?x_18 : decidable_linear_ordered_comm_ring α := @discrete_linear_ordered_field.to_decidable_linear_ordered_comm_ring ?x_19 ?x_20
[class_instances] (2) ?x_12 : domain α := @division_ring.to_domain ?x_13 ?x_14
[class_instances] (3) ?x_14 : division_ring α := @field.to_division_ring ?x_15 ?x_16
[class_instances] (4) ?x_16 : field α := @field_extension.to_field ?x_17 ?x_18 ?x_19 ?x_20
[class_instances] (5) ?x_20 : @field_extension ?x_17 α ?x_19 := @algebraic_field_extension.to_field_extension ?x_21 ?x_22 ?x_23 ?x_24
[class_instances] (6) ?x_24 : @algebraic_field_extension ?x_21 α ?x_23 := @algebraic_closure.to_algebraic_field_extension ?x_25 ?x_26 ?x_27 ?x_28
[class_instances] (7) ?x_27 : field ?x_25 := @field_extension.to_field ?x_29 ?x_30 ?x_31 ?x_32
[class_instances] (8) ?x_32 : @field_extension ?x_29 ?x_30 ?x_31 := @algebraic_field_extension.to_field_extension ?x_33 ?x_34 ?x_35 ?x_36
[class_instances] (9) ?x_36 : @algebraic_field_extension ?x_33 ?x_34 ?x_35 := @algebraic_closure.to_algebraic_field_extension ?x_37 ?x_38 ?x_39 ?x_40
[class_instances] (10) ?x_39 : field ?x_37 := @field_extension.to_field ?x_41 ?x_42 ?x_43 ?x_44

Kenny Lau (Jun 15 2018 at 22:36):

loop the last 3 lines

Mario Carneiro (Jun 15 2018 at 22:36):

field_extension.to_field

Mario Carneiro (Jun 15 2018 at 22:36):

kill it

Kenny Lau (Jun 15 2018 at 22:37):

class field_extension (α : out_param $ Type*) (β : Type*)
  [out_param $ field α] extends field β :=
(f : α  β) [hom : is_ring_hom f]

Kenny Lau (Jun 15 2018 at 22:37):

class algebra (R : out_param Type*) (A : Type*)
  [out_param $ comm_ring R] extends comm_ring A :=
(f : R  A) [hom : is_ring_hom f]

Kenny Lau (Jun 15 2018 at 22:37):

class module (α : out_param $ Type u) (β : Type v) [out_param $ ring α]
  extends has_scalar α β, add_comm_group β :=
(smul_add : r (x y : β), r  (x + y) = r  x + r  y)
(add_smul : r s (x : β), (r + s)  x = r  x + s  x)
(mul_smul : r s (x : β), (r * s)  x = r  s  x)
(one_smul : x : β, (1 : α)  x = x)

Kenny Lau (Jun 15 2018 at 22:37):

(not that algebra is not causing problem)

Kenny Lau (Jun 15 2018 at 22:38):

why does module have no problem

Kenny Lau (Jun 15 2018 at 22:41):

@Mario Carneiro what should I replace it with?

Kenny Lau (Jun 15 2018 at 22:41):

I see

Kenny Lau (Jun 15 2018 at 23:29):

class subring (α : Type*) [comm_ring α] (S : set α) : Prop :=
(add_mem :  {x y}, x  S  y  S  x + y  S)
(neg_mem :  {x}, x  S  -x  S)
(mul_mem :  {x y}, x  S  y  S  x * y  S)
(one_mem : (1:α)  S)

open subring

instance subring.to_comm_ring (α : Type*) [comm_ring α] (S : set α) [subring α S] : comm_ring S :=
{ add            := λ x, hx y, hy, x + y, add_mem hx hy,
  add_assoc      := λ x, hx y, hy z, hz, subtype.eq $ add_assoc x y z,
  zero           := 0, eq.subst (add_neg_self (1:α)) $ add_mem (one_mem S) $ neg_mem $ one_mem S,
  zero_add       := λ x, hx, subtype.eq $ zero_add x,
  add_zero       := λ x, hx, subtype.eq $ add_zero x,
  neg            := λ x, hx, ⟨-x, neg_mem hx,
  add_left_neg   := λ x, hx, subtype.eq $ add_left_neg x,
  add_comm       := λ x, hx y, hy, subtype.eq $ add_comm x y,
  mul            := λ x, hx y, hy, x * y, mul_mem hx hy,
  mul_assoc      := λ x, hx y, hy z, hz, subtype.eq $ mul_assoc x y z,
  one            := 1, one_mem S,
  one_mul        := λ x, hx, subtype.eq $ one_mul x,
  mul_one        := λ x, hx, subtype.eq $ mul_one x,
  left_distrib   := λ x, hx y, hy z, hz, subtype.eq $ left_distrib x y z,
  right_distrib  := λ x, hx y, hy z, hz, subtype.eq $ right_distrib x y z,
  mul_comm       := λ x, hx y, hy, subtype.eq $ mul_comm x y }

Kenny Lau (Jun 15 2018 at 23:29):

will this instance cause problems?

Kenny Lau (Jun 15 2018 at 23:30):

if so, what should I replace it with?

Kenny Lau (Jun 16 2018 at 01:20):

adding by letI := subring.to_comm_ring _ S to every definition and theorem is not very feasible

Kenny Lau (Jun 16 2018 at 01:20):

and is wasting me a lot of time

Kenny Lau (Jun 16 2018 at 01:20):

but as soon as I make it an instance, everything crashes

Kenny Lau (Jun 16 2018 at 09:11):

what is this

Kenny Lau (Jun 16 2018 at 09:11):

def Hausdorff_abelianization (G : Type*) [t : topological_group G] : Type* :=
@left_cosets (abelianization G) _ (closure {1})
  (by apply_instance)

Kenny Lau (Jun 16 2018 at 09:12):

[class_instances] (0) ?x_60 : topological_group G := t
failed is_def_eq

Kenny Lau (Jun 16 2018 at 09:21):

Lean, they are the same

Kenny Lau (Jun 16 2018 at 11:26):

if subring.to_comm_ring causes problems then why doesn't subtype.group cause problems?

Kenny Lau (Jun 16 2018 at 13:29):

@Patrick Massot @Sebastian Ullrich @Mario Carneiro it can be avoided by using universes instead of Type*

https://leanprover.zulipchat.com/#narrow/stream/113488-general/subject/unfolding.20notation.20in.20theorem.20vs.20def.2Finstance/near/128167978

Kenny Lau (Jun 16 2018 at 13:29):

oh and of course the same trick applies to this case

Kenny Lau (Jun 16 2018 at 13:29):

there's no loop any more

Kenny Lau (Jun 16 2018 at 13:29):

once I use Type u instead of Type*

Kenny Lau (Jun 16 2018 at 13:31):

Lean, they are the same

https://leanprover.zulipchat.com/#narrow/stream/113488-general/subject/typeclass.20problems/near/128162755

Kenny Lau (Jun 16 2018 at 13:31):

ditto

Kenny Lau (Jun 16 2018 at 17:03):

Is this a good instance?

def Hausdorff_abelianization.setoid (G : Type u)
  [topological_group G] : setoid G :=
left_rel (closure (commutator_subgroup G set.univ))

Mario Carneiro (Jun 16 2018 at 17:08):

A local instance maybe

Mario Carneiro (Jun 16 2018 at 17:08):

it looks a bit domain specific

Kenny Lau (Jun 16 2018 at 17:08):

domain specific?

Mario Carneiro (Jun 16 2018 at 17:08):

is there a reason that should be the canonical equivalence on any top group?

Kenny Lau (Jun 16 2018 at 17:09):

it's the functor from TopGrp to AbelianHasudorffTopGrp

Johan Commelin (Jun 16 2018 at 17:09):

Kenny, for every topological group G, there should be at most 1 instance of setoid G.

Kenny Lau (Jun 16 2018 at 17:09):

I see

Kenny Lau (Jun 16 2018 at 17:09):

ok this isn't canonical then

Johan Commelin (Jun 16 2018 at 17:10):

So you should probably not make this an instance. But possibly define AbHausTopGrp, and make it an instance of that...

Kenny Lau (Jun 16 2018 at 17:11):

I'm glad I didn't switch the first two words of the name of the category... :D

Johan Commelin (Jun 16 2018 at 17:12):

I don't get what would be wrong with that? ... Am I overly naive, and missing a joke?

Kenny Lau (Jun 16 2018 at 17:13):

it sounds similar to a rude word in german

Johan Commelin (Jun 16 2018 at 17:14):

Ach so, ich muss noch viel Deutsch üben. Und ich kenn kein unhöfliche Worten.

Kenny Lau (Jun 16 2018 at 17:15):

"Hau ab" means "piss off"

Johan Commelin (Jun 16 2018 at 17:16):

Wunderbar

Kenny Lau (Jun 17 2018 at 22:12):

2018-06-17-2.png

Kenny Lau (Jun 17 2018 at 22:13):

when I turn trace.class_instances on, there's nothing peculiar, except the has_sizeof thing getting pretty long

Kenny Lau (Jun 17 2018 at 22:13):

that option is not really helpful in my experience

Kenny Lau (Jun 17 2018 at 22:13):

@Mario Carneiro

Kenny Lau (Jun 17 2018 at 22:48):

oh and the depth of the class instance search never went to 6

Kenny Lau (Jun 17 2018 at 22:51):

and I don't think cogroup.base_change_left is the problem, after looking at the trace

Kenny Lau (Jun 17 2018 at 22:55):

it's here: https://github.com/kckennylau/local-langlands-abelian/blob/master/src/torus.lean#L136

Simon Hudon (Jun 17 2018 at 22:56):

Why does it need an instance of has_sizeof?

Kenny Lau (Jun 17 2018 at 22:56):

no idea

Kenny Lau (Jun 17 2018 at 22:57):

to build a structure, I think?

Kenny Lau (Jun 17 2018 at 22:57):

Please help me, my deadline is in like 12 hours

Simon Hudon (Jun 17 2018 at 22:57):

Your screenshot is not telling me much. If you comment one field declaration at a time, when does it stop failing?

Kenny Lau (Jun 17 2018 at 22:57):

as soon as I remove the last field

Kenny Lau (Jun 17 2018 at 23:03):

@Simon Hudon is there other information I can provide?

Simon Hudon (Jun 17 2018 at 23:03):

I think your project needs mathlib

Simon Hudon (Jun 17 2018 at 23:03):

I'm building it on my machine to have a closer look

Kenny Lau (Jun 17 2018 at 23:03):

thank you very much

Kenny Lau (Jun 17 2018 at 23:03):

yes, it does require mathlib

Simon Hudon (Jun 17 2018 at 23:04):

Is it possible you did not commit the latest version of leanpkg.toml? (I don't need it, I can fix it but in general, that makes things smoother for people trying your project)

Kenny Lau (Jun 17 2018 at 23:05):

oh I didn't really set it up

Simon Hudon (Jun 17 2018 at 23:05):

Ah ok. Just to be sure, do you use Lean 3.4.1 and the latest mathlib?

Kenny Lau (Jun 17 2018 at 23:06):

yes

Kenny Lau (Jun 17 2018 at 23:08):

ok not exactly the latest

Kenny Lau (Jun 17 2018 at 23:08):

i'm on mathlib commit fe590ca272a41bb321a13be505964e78cad1e731

Kenny Lau (Jun 17 2018 at 23:09):

third from latest

Simon Hudon (Jun 17 2018 at 23:43):

In this expression (tensor_a F split.S T) you get into trouble because split.S is a set but a type is expected. If you replace it with subtype split.S, type is required to have a comm_ring instance which you only have for T

Kenny Lau (Jun 17 2018 at 23:43):

:o

Kenny Lau (Jun 17 2018 at 23:43):

thanks

Kenny Lau (Jun 17 2018 at 23:43):

do you have a fix?

Simon Hudon (Jun 17 2018 at 23:46):

No, it really depends on what you're trying to do. If you actually want subtype split.S, you'd need to add [comm_ring (subtype split.S)] to the local instances which would get hairy because split is a field. Maybe replacing split.S with T would suit your purpose, in which case, the fit is perfect because you already have a comm_ring T instance

Kenny Lau (Jun 17 2018 at 23:46):

I can't just change my deifnition like that?

Simon Hudon (Jun 17 2018 at 23:46):

Which one?

Kenny Lau (Jun 17 2018 at 23:47):

replacing split.S with T?

Simon Hudon (Jun 17 2018 at 23:47):

That might work. I haven't tried it but that would fix that particular problem

Kenny Lau (Jun 17 2018 at 23:47):

I mean, it would be a wrong definition

Simon Hudon (Jun 17 2018 at 23:48):

What would be the right definition?

Kenny Lau (Jun 17 2018 at 23:48):

split.S as it is

Simon Hudon (Jun 17 2018 at 23:48):

That would be nonsense: that's not type correct.

Simon Hudon (Jun 17 2018 at 23:49):

Unless your tensor_a definition is wrong and it should take a set there, not a type

Kenny Lau (Jun 17 2018 at 23:49):

I'm coercing a set to a type

Kenny Lau (Jun 17 2018 at 23:49):

it's done automatically

Kenny Lau (Jun 17 2018 at 23:49):

I do it every time

Simon Hudon (Jun 17 2018 at 23:51):

Right but that type is then expected to be a commutative ring. I'm not sure how that can be proved automatically

Kenny Lau (Jun 17 2018 at 23:51):

I have a working version above it, one can trace class instance

Kenny Lau (Jun 17 2018 at 23:52):

I think it will go through subfield -> field -> comm_ring

Simon Hudon (Jun 17 2018 at 23:52):

How do you prove that it's a subfield?

Kenny Lau (Jun 17 2018 at 23:52):

instance finite_Galois_intermediate_extension.to_subfield

Kenny Lau (Jun 17 2018 at 23:52):

L132 of field_extensions.lean

Kenny Lau (Jun 17 2018 at 23:53):

right, I just realized, there should be no problem, because there's a working version right above it!

Simon Hudon (Jun 17 2018 at 23:54):

Which line?

Kenny Lau (Jun 17 2018 at 23:54):

The #check one

Kenny Lau (Jun 17 2018 at 23:54):

L139

Kenny Lau (Jun 17 2018 at 23:55):

oops

Kenny Lau (Jun 17 2018 at 23:55):

L123

Kenny Lau (Jun 17 2018 at 23:55):

https://github.com/kckennylau/local-langlands-abelian/blob/master/src/torus.lean#L123

Kenny Lau (Jun 17 2018 at 23:55):

#check λ (F : Type u) [field F]
  (AC : Type v) [field AC] [is_alg_closed_field AC]
  [field_extension F AC] [is_algebraic_closure F AC]
  (T : Type w) [comm_ring T] [algebra F T] [cogroup F T]
(split : finite_Galois_intermediate_extension F AC)
(rank : ),
@cogroup_iso split.S _ (tensor_a F split.S T)
  (tensor_a.comm_ring _ _ _)
  (base_change_left F split.S T)
  (GL₁ⁿ split.S rank) _ _
  (cogroup.base_change_left F split.S T)
  (GL₁ⁿ.cogroup _ _)

Simon Hudon (Jun 17 2018 at 23:56):

If I change that check into a def:

def foo := λ (F : Type u) [field F]
  (AC : Type v) [field AC] [is_alg_closed_field AC]
  [field_extension F AC] [is_algebraic_closure F AC]
  (T : Type w) [comm_ring T] [algebra F T] [cogroup F T]
(split : finite_Galois_intermediate_extension F AC)
(rank : ),
@cogroup_iso split.S _ (tensor_a F split.S T)
  (tensor_a.comm_ring _ _ _)
  (base_change_left F split.S T)
  (GL₁ⁿ split.S rank) _ _
  (cogroup.base_change_left F split.S T)
  (GL₁ⁿ.cogroup _ _)

Simon Hudon (Jun 17 2018 at 23:56):

I get I lot of errors

Kenny Lau (Jun 17 2018 at 23:57):

curious

Simon Hudon (Jun 17 2018 at 23:57):

Screen-Shot-2018-06-17-at-7.57.01-PM.png

Simon Hudon (Jun 17 2018 at 23:57):

I think you're asking a lot of type class inference

Kenny Lau (Jun 17 2018 at 23:58):

heh...

Kenny Lau (Jun 17 2018 at 23:58):

how about I move them before the colon

Kenny Lau (Jun 17 2018 at 23:58):

def foo (F : Type u) [field F]
  (AC : Type v) [field AC] [is_alg_closed_field AC]
  [field_extension F AC] [is_algebraic_closure F AC]
  (T : Type w) [comm_ring T] [algebra F T] [cogroup F T]
(split : finite_Galois_intermediate_extension F AC)
(rank : ) :=
@cogroup_iso split.S _ (tensor_a F split.S T)
  (tensor_a.comm_ring _ _ _)
  (base_change_left F split.S T)
  (GL₁ⁿ split.S rank) _ _
  (cogroup.base_change_left F split.S T)
  (GL₁ⁿ.cogroup _ _)

Kenny Lau (Jun 17 2018 at 23:58):

no errors!

Kenny Lau (Jun 17 2018 at 23:59):

also I looked at the trace as I said before

Simon Hudon (Jun 17 2018 at 23:59):

You're right, I didn't do it well

Kenny Lau (Jun 17 2018 at 23:59):

there is no issue with the typeclass inferences

Kenny Lau (Jun 17 2018 at 23:59):

and the max depth is 5

Kenny Lau (Jun 17 2018 at 23:59):

there should not be any error

Simon Hudon (Jun 18 2018 at 00:00):

Try:

structure torus (F : Type u) [field F]
  (AC : Type v) [field AC] [is_alg_closed_field AC]
  [field_extension F AC] [is_algebraic_closure F AC]
  (T : Type w) [comm_ring T] [algebra F T] [cogroup F T] :=
(split : finite_Galois_intermediate_extension F AC)
(rank : )
(splits : foo F AC T split rank)

Kenny Lau (Jun 18 2018 at 00:01):

what the actual

Kenny Lau (Jun 18 2018 at 00:01):

@Mario Carneiro you need to see this

Kenny Lau (Jun 18 2018 at 00:02):

@Simon Hudon what do you think

Simon Hudon (Jun 18 2018 at 00:03):

I'm not actually sure why the other one wouldn't work. In general, there's nothing wrong with breaking down your definitions into smaller pieces though

Kenny Lau (Jun 18 2018 at 00:04):

I see

Kenny Lau (Jun 18 2018 at 00:12):

@Simon Hudon how should I break this loop?

Kenny Lau (Jun 18 2018 at 00:12):

[class_instances] (5) ?x_31 : field AC := _inst_6
failed is_def_eq
[class_instances] (5) ?x_31 : field AC := @subfield.to_field ?x_34 ?x_35 ?x_36 ?x_37
failed is_def_eq
[class_instances] (5) ?x_31 : field AC := @topological_field.to_field ?x_38 ?x_39
[class_instances] (5) ?x_31 : field AC := @linear_ordered_field.to_field ?x_34 ?x_35
[class_instances] (6) ?x_35 : linear_ordered_field AC := @discrete_linear_ordered_field.to_linear_ordered_field ?x_36 ?x_37
[class_instances] (7) ?x_37 : discrete_linear_ordered_field AC := rat.discrete_linear_ordered_field
failed is_def_eq
[class_instances] (5) ?x_31 : field AC := @discrete_field.to_field ?x_34 ?x_35
[class_instances] (6) ?x_35 : discrete_field AC := rat.field_rat
failed is_def_eq
[class_instances] (6) ?x_35 : discrete_field AC := @discrete_linear_ordered_field.to_discrete_field ?x_36 ?x_37
[class_instances] (7) ?x_37 : discrete_linear_ordered_field AC := rat.discrete_linear_ordered_field
failed is_def_eq
[class_instances] (5) ?x_30 : field ?x_28 := @subfield.to_field ?x_34 ?x_35 ?x_36 ?x_37
[class_instances] (6) ?x_35 : field ?x_34 := _inst_7
[class_instances] (6) ?x_37 : @subfield AC _inst_7 ?x_36 := @finite_Galois_intermediate_extension.to_subfield ?x_38 ?x_39 ?x_40 ?x_41 ?x_42 ?x_43 ?x_44 ?x_45
[class_instances] (7) ?x_39 : field ?x_38 := _inst_7
[class_instances] (7) ?x_41 : field AC := _inst_7
[class_instances] (7) ?x_42 : @is_alg_closed_field AC _inst_7 := _inst_8
[class_instances] (7) ?x_43 : @field_extension AC AC _inst_7 _inst_7 := _inst_9
failed is_def_eq
[class_instances] (7) ?x_43 : @field_extension AC AC _inst_7 _inst_7 := @is_intermediate_field.to_field_extension' ?x_46 ?x_47 ?x_48 ?x_49 ?x_50 ?x_51 ?x_52
failed is_def_eq
[class_instances] (7) ?x_43 : @field_extension AC AC _inst_7 _inst_7 := @is_intermediate_field.to_field_extension ?x_53 ?x_54 ?x_55 ?x_56 ?x_57 ?x_58 ?x_59
failed is_def_eq
[class_instances] (7) ?x_42 : @is_alg_closed_field AC _inst_7 := @is_algebraic_closure.to_is_alg_closed_field ?x_46 ?x_47 ?x_48 ?x_49 ?x_50 ?x_51
[class_instances] (8) ?x_48 : field ?x_46 := _inst_7
[class_instances] (8) ?x_49 : field AC := _inst_7
[class_instances] (8) ?x_50 : @field_extension AC AC _inst_7 _inst_7 := _inst_9
failed is_def_eq
[class_instances] (8) ?x_50 : @field_extension AC AC _inst_7 _inst_7 := @is_intermediate_field.to_field_extension' ?x_52 ?x_53 ?x_54 ?x_55 ?x_56 ?x_57 ?x_58
failed is_def_eq
[class_instances] (8) ?x_50 : @field_extension AC AC _inst_7 _inst_7 := @is_intermediate_field.to_field_extension ?x_59 ?x_60 ?x_61 ?x_62 ?x_63 ?x_64 ?x_65
failed is_def_eq

Simon Hudon (Jun 18 2018 at 00:15):

There seems to be a circular dependency between your instances. You should try to guarantee that something decreases (syntactically) whenever you apply an instance. For example, instance [decidable_eq a] : decidable_eq (list a) := ... is such an instance. It is about list a and all the instances it relies on involve simpler expressions.

Kenny Lau (Jun 18 2018 at 00:16):

sorry but could you explain what you mean by decreasing?

Simon Hudon (Jun 18 2018 at 00:19):

If you compare a and list a (one is a type in an assumed instance, the other, in the head of the instance) list a is a more complex expression than a. That means that if I look for an instance of decidable_eq (list a) and I apply the above instance, I'm decreasing the size of my problem so I'm getting closer to a solution. If every instance decreases the size of the problem, you can't search forever. (just like with structural recursion)

Kenny Lau (Jun 18 2018 at 00:20):

hmm... but there are times at which I would need to infer simpler instances from complex instances?

Simon Hudon (Jun 18 2018 at 00:21):

like field from discrete_linear_ordered_field?

Kenny Lau (Jun 18 2018 at 00:21):

sure

Kenny Lau (Jun 18 2018 at 00:21):

or sometimes I need to infer a single instance from like 10 instances

Kenny Lau (Jun 18 2018 at 00:21):

do you have general workarounds?

Simon Hudon (Jun 18 2018 at 00:23):

A single instance from 10 instances is not a problem as long as each instance is smaller than the initial one

Kenny Lau (Jun 18 2018 at 00:23):

hmm I still don't know how to judge whether two instances are smaller

Simon Hudon (Jun 18 2018 at 00:23):

In the case of discrete_linear_ordered_field, does it not extend field?

Kenny Lau (Jun 18 2018 at 00:23):

I mean, your examples are quite obvious

Kenny Lau (Jun 18 2018 at 00:24):

yes it does

Kenny Lau (Jun 18 2018 at 00:24):

I think

Simon Hudon (Jun 18 2018 at 00:24):

That should be enough, no? You don't need an instance on top of that

Kenny Lau (Jun 18 2018 at 00:24):

this is a bad instance then?

instance subring.to_comm_ring (α : Type u) [comm_ring α] (S : set α) [subring α S] : comm_ring S :=

Simon Hudon (Jun 18 2018 at 00:24):

You can compare by counting the number of symbols and operators in each types.

Kenny Lau (Jun 18 2018 at 00:25):

that instance doesn't seem to be causing much problem though

Kenny Lau (Jun 18 2018 at 00:25):

I guess it's because it requires subring

Kenny Lau (Jun 18 2018 at 00:26):

This seems to be the problem:

instance finite_Galois_intermediate_extension.to_subfield
  (F : Type u) [field F]
  (AC : Type v) [field AC] [is_alg_closed_field AC]
  [field_extension F AC] [is_algebraic_closure F AC]
  (E : finite_Galois_intermediate_extension F AC) :
  subfield _ E.S :=
by apply_instance

Simon Hudon (Jun 18 2018 at 00:26):

subring is actually what I find problematic in it

Kenny Lau (Jun 18 2018 at 00:27):

because I have an instance from subfield to field

Kenny Lau (Jun 18 2018 at 00:27):

subring is actually what I find problematic in it

how so?

Simon Hudon (Jun 18 2018 at 00:28):

there are invisible operators: comm_ring S is actually comm_ring (subtype S) which is more complex than comm_ring a. However subring a (subtype S) is more complex than comm_ring (subtype S)

Kenny Lau (Jun 18 2018 at 00:28):

nah it's subring a S

Kenny Lau (Jun 18 2018 at 00:28):

there is no coercion there

Simon Hudon (Jun 18 2018 at 00:29):

It might actually fly then

Simon Hudon (Jun 18 2018 at 00:29):

Lean is actually more tolerant than what I'm used to and I'm not sure if that's a good thing or if it's just handing you enough rope to hang yourself with

Kenny Lau (Jun 18 2018 at 00:31):

this should be the problem

Kenny Lau (Jun 18 2018 at 00:31):

[class_instances] (5) ?x_30 : field ?x_28 := @subfield.to_field ?x_34 ?x_35 ?x_36 ?x_37
[class_instances] (6) ?x_35 : field ?x_34 := _inst_7
[class_instances] (6) ?x_37 : @subfield AC _inst_7 ?x_36 := @finite_Galois_intermediate_extension.to_subfield ?x_38 ?x_39 ?x_40 ?x_41 ?x_42 ?x_43 ?x_44 ?x_45
[class_instances] (7) ?x_39 : field ?x_38 := _inst_7
[class_instances] (7) ?x_41 : field AC := _inst_7
[class_instances] (7) ?x_42 : @is_alg_closed_field AC _inst_7 := _inst_8

Kenny Lau (Jun 18 2018 at 00:32):

right, subfield.to_field is the problem

Simon Hudon (Jun 18 2018 at 00:32):

You can try commenting one instance at a time until the problem disappears

Simon Hudon (Jun 18 2018 at 00:32):

cool

Kenny Lau (Jun 18 2018 at 00:32):

that isn't how it works

Kenny Lau (Jun 18 2018 at 00:32):

if I comment one instance out, a million lines of code will break

Kenny Lau (Jun 18 2018 at 00:34):

@Simon Hudon a million things depend on subfield.to_field though...

Kenny Lau (Jun 18 2018 at 00:34):

this is a huge abyss

Simon Hudon (Jun 18 2018 at 00:34):

does subfield extend field?

Kenny Lau (Jun 18 2018 at 00:34):

no

Simon Hudon (Jun 18 2018 at 00:34):

Why not?

Kenny Lau (Jun 18 2018 at 00:35):

just as is_subgroup does not extend group

Kenny Lau (Jun 18 2018 at 00:35):

and as I say this sentence

Kenny Lau (Jun 18 2018 at 00:35):

why doesn't that cause problems?

Simon Hudon (Jun 18 2018 at 00:35):

I'm not intimate enough with the algebraic hierarchy to know

Kenny Lau (Jun 18 2018 at 00:36):

#check @subtype.group
/-
subtype.group : Π {α : Type u_1} [_inst_1 : group α] {s : set α} [_inst_2 : is_subgroup s], group ↥s
-/

Simon Hudon (Jun 18 2018 at 00:37):

Actually, because there's no coercion, that's not that big of a deal. A different instance must be worse

Kenny Lau (Jun 18 2018 at 00:37):

hmm

Kenny Lau (Jun 18 2018 at 00:38):

this is a huge mess

Simon Hudon (Jun 18 2018 at 00:39):

Yeah, that's a problem with this way of doing type classes. You can't understand each instance in isolation

Kenny Lau (Jun 18 2018 at 00:42):

I think depth first search is not very good

Kevin Buzzard (Jun 18 2018 at 07:52):

Kenny remember as a last resort you can just override the type class system and give it the instances yourself. I used to do this all the time when I got stuck on (much easier) stuff.

Alex J. Best (Dec 22 2019 at 21:42):

I just made the PR #1822 where I did something bad and broke multiplication, but I'm not sure how to fix it. I'm not sure how to minify it but you can look at line 154 in https://github.com/leanprover-community/mathlib/blob/6764734114a5e07eddc0409e485eb0bab6aea161/src/ring_theory/dedekind_finite.lean#L154 compared to 115 where somehow the intervening instance instance dedekind_finite_of_noetherian [is_noetherian_ring R] : dedekind_finite R := breaks monoid.has_mul.

Kevin Buzzard (Dec 22 2019 at 22:50):

You should ask permission to make new branches on leanprover-community; that way I could use cache-olean to make checking out your issue less of a hassle.

Alex J. Best (Dec 22 2019 at 22:55):

I hereby ask for permission! Sorry, I also just added a new better version, but the question /relevant part is still the same.

Kevin Buzzard (Dec 22 2019 at 22:58):

Here's the instance trace. I think you might have created a loop. For example I see

[class_instances] (17) ?x_59 : field G := real.field
failed is_def_eq
[class_instances] (17) ?x_59 : field G := rat.field
failed is_def_eq
...
[class_instances] (17) ?x_59 : field G := real.field
failed is_def_eq
[class_instances] (17) ?x_59 : field G := rat.field
failed is_def_eq
...
[class_instances] (20) ?x_124 : field G := real.field
failed is_def_eq
[class_instances] (20) ?x_124 : field G := rat.field
failed is_def_eq
...
[class_instances] (18) ?x_65 : field G := real.field
failed is_def_eq
[class_instances] (18) ?x_65 : field G := rat.field
failed is_def_eq
...
[class_instances] (19) ?x_67 : field G := real.field
failed is_def_eq
[class_instances] (19) ?x_67 : field G := rat.field
failed is_def_eq
...
[class_instances] (19) ?x_67 : field G := real.field
failed is_def_eq
[class_instances] (19) ?x_67 : field G := rat.field
failed is_def_eq
...
[class_instances] (19) ?x_67 : field G := real.field
failed is_def_eq
[class_instances] (19) ?x_67 : field G := rat.field
failed is_def_eq
...

but actually that just looks weird (to me), usually the numbers just creep up by one.

Kevin Buzzard (Dec 22 2019 at 23:17):

[class_instances] (3) ?x_11 : ring G := @dedekind_finite.to_ring ?x_12 ?x_13
[class_instances] (4) ?x_13 : dedekind_finite G := @ @_root_.dedekind_finite_of_noetherian ?x_17 ?x_18 ?x_19
[class_instances] (5) ?x_18 : ring G := @dedekind_finite.to_ring ?x_20 ?x_21
[class_instances] (6) ?x_21 : dedekind_finite G := @ @_root_.dedekind_finite_of_noetherian ?x_25 ?x_26 ?x_27
...

I think that's your problem.

Kevin Buzzard (Dec 22 2019 at 23:17):

To prove G is a ring it suffices to prove it's Dedekind finite, to prove it's Dedekind finite it suffices to prove it's a Noetherian ring and...oh.. also a ring! And to check that it's a ring, it suffices to prove it's Dedekind finite, and off we go again.

Kevin Buzzard (Dec 22 2019 at 23:24):

You wrote

variables (R : Type*)

class dedekind_finite extends ring R :=
( inv_comm :  a b : R, a * b = 1  b * a = 1 )

and I am wondering whether this should be

class dedekind_finite (R : Type*) [ring R] :=
( inv_comm :  a b : R, a * b = 1  b * a = 1 )

but unfortunately I am guessing here. I don't really understand how these things work -- I don't really understand the difference between the two in practice.

Kevin Buzzard (Dec 22 2019 at 23:27):

The thing I know for sure is that I am quoting the last (3), the last (4), the last (5)...in the instance trace, which means for sure that things are spiralling out of control.

Kevin Buzzard (Dec 22 2019 at 23:31):

OK so I can't guarantee that my fix is what you should be doing, but it does seem to fix the problem. You have to add the extra ring instances

variables (x y : Π i, f i) (i : I) [ i, ring (f i)]

on line 27 but then the monoid error goes away. (I also have an error in dedekind_finite_of_noetherian but that was before I started fiddling and it might be because I just cut and pasted the file instead of forking your clone)

Kevin Buzzard (Dec 22 2019 at 23:36):

I hereby ask for permission! Sorry, I also just added a new better version, but the question /relevant part is still the same.

@Simon Hudon -- who can add people to the "can push to mathlib non-master branch" list? Is it you? Alex is alexjbest on github

Simon Hudon (Dec 23 2019 at 00:55):

The invite is in the mail. @Alex J. Best let me know if you encounter any issues

Alex J. Best (Dec 23 2019 at 16:40):

Thanks @Kevin Buzzard and @Johan Commelin for the very helpful comments! It looks like it works well with classes taking ring as a parameter instead of extending (I should have copied the way is_noetherian_ring is set up, rather than integral_domain!) I'll do some more tidy up and push it (unfortunately I can't see a way to change the PR branch but for the next one I should be able to push to mathlib instead (ty @Simon Hudon ))

Oliver Nash (Dec 24 2019 at 19:33):

I've been suffering with some typeclass problems which I've managed to reduce to the following:

import ring_theory.algebra

universes u v

section prio
set_option default_priority 200 -- No problem if priority 199 or lower, evidently because algebra.to_module has priority 200
class foo (R : Type u) (M M'  : Type v)
  [comm_ring R] [add_comm_group M] [add_comm_group M'] [module R M] extends module R M' :=
(f : M [R] M')
end prio

set_option class.instance_max_depth 100
set_option trace.class_instances true

instance bar (R : Type u) (A : Type v)
  [comm_ring R] [ring A] [algebra R A] : module R A := infer_instance

Oliver Nash (Dec 24 2019 at 19:35):

The above will report that maximum class-instance resolution depth has been reached when elaborating bar but it will work if we lower the priority of the instances created by the declaration of foo, as indicated in my comment.

Oliver Nash (Dec 24 2019 at 19:38):

I do not understand the "Prolog-like search" that is performed as part of typeclass inference well at all but I am surprised because my fuzzy understanding had lead me to believe that changing priorities like this should merely affect performance, rather than the actual results. Evidently I am in error. Can anyone shed any light?

Kevin Buzzard (Dec 24 2019 at 19:39):

Typeclass loops can cause the max class-instance error and changing priorities can avoid the loops because a solution might be found before the loop is found

Oliver Nash (Dec 24 2019 at 19:39):

Furthermore, in debugging this, I attempted to read my first "class-instance resolution trace", and I note that my definition foo appears to introduce a looping behaviour, based on the following output from lean foobar.lean 2>&1 | grep foo.to_module:

Oliver Nash (Dec 24 2019 at 19:40):

[class_instances] (0) ?x_0 : @module R A (@comm_ring.to_ring R _inst_1) (@ring.to_add_comm_group A _inst_2) := @foo.to_module ?x_98 ?x_99 ?x_100 ?x_101 ?x_102 ?x_103 ?x_104 ?x_105
[class_instances] (1) ?x_104 : @module R (free_abelian_group ?x_122) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_122) := @foo.to_module ?x_222 ?x_223 ?x_224 ?x_225 ?x_226 ?x_227
[class_instances] (2) ?x_228 : @module R (free_abelian_group ?x_246) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_246) := @foo.to_module ?x_360 ?x_361 ?x_362 ?x_363 ?x_364 ?x_365
[class_instances] (3) ?x_366 : @module R (free_abelian_group ?x_384) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_384) := @foo.to_module ?x_498 ?x_499 ?x_500 ?x_501 ?x_502 ?x_503
[class_instances] (4) ?x_504 : @module R (free_abelian_group ?x_522) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_522) := @foo.to_module ?x_636 ?x_637 ?x_638 ?x_639 ?x_640 ?x_641
[class_instances] (5) ?x_642 : @module R (free_abelian_group ?x_660) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_660) := @foo.to_module ?x_774 ?x_775 ?x_776 ?x_777 ?x_778 ?x_779
[class_instances] (6) ?x_780 : @module R (free_abelian_group ?x_798) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_798) := @foo.to_module ?x_912 ?x_913 ?x_914 ?x_915 ?x_916 ?x_917
[class_instances] (7) ?x_918 : @module R (free_abelian_group ?x_936) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_936) := @foo.to_module ?x_1050 ?x_1051 ?x_1052 ?x_1053 ?x_1054 ?
[class_instances] (8) ?x_1056 : @module R (free_abelian_group ?x_1074) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_1074) := @foo.to_module ?x_1188 ?x_1189 ?x_1190 ?x_1191 ?x_119
[class_instances] (9) ?x_1194 : @module R (free_abelian_group ?x_1212) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_1212) := @foo.to_module ?x_1326 ?x_1327 ?x_1328 ?x_1329 ?x_133
[class_instances] (10) ?x_1332 : @module R (free_abelian_group ?x_1350) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_1350) := @foo.to_module ?x_1464 ?x_1465 ?x_1466 ?x_1467 ?x_14
[class_instances] (11) ?x_1470 : @module R (free_abelian_group ?x_1488) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_1488) := @foo.to_module ?x_1602 ?x_1603 ?x_1604 ?x_1605 ?x_16
[class_instances] (12) ?x_1608 : @module R (free_abelian_group ?x_1626) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_1626) := @foo.to_module ?x_1740 ?x_1741 ?x_1742 ?x_1743 ?x_17
[class_instances] (13) ?x_1746 : @module R (free_abelian_group ?x_1764) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_1764) := @foo.to_module ?x_1878 ?x_1879 ?x_1880 ?x_1881 ?x_18
[class_instances] (14) ?x_1884 : @module R (free_abelian_group ?x_1902) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_1902) := @foo.to_module ?x_2016 ?x_2017 ?x_2018 ?x_2019 ?x_20
[class_instances] (15) ?x_2022 : @module R (free_abelian_group ?x_2040) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_2040) := @foo.to_module ?x_2154 ?x_2155 ?x_2156 ?x_2157 ?x_21
[class_instances] (16) ?x_2160 : @module R (free_abelian_group ?x_2178) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_2178) := @foo.to_module ?x_2292 ?x_2293 ?x_2294 ?x_2295 ?x_22
[class_instances] (17) ?x_2298 : @module R (free_abelian_group ?x_2316) (@comm_ring.to_ring R _inst_1) (free_abelian_group.add_comm_group ?x_2316) := @foo.to_module ?x_2430 ?x_2431 ?x_2432 ?x_2433 ?x_24
[class_instances] (18) ?x_2436 : @module R (free_abelian_group

Oliver Nash (Dec 24 2019 at 19:41):

@Kevin Buzzard Thank you, that is consistent with my fuzzy understanding.

Oliver Nash (Dec 24 2019 at 19:42):

So what is the take-home message here? Is it:

1. I need to be more careful about instance priorities?, or
2. Priorities aside, the definition of foo is faulty / unidiomatic in some way?, or
3. I should give up on extends and just make module R M' a parameter in the definition of foo?, or
4. Something else?

Oliver Nash (Dec 24 2019 at 19:47):

(deleted)

Oliver Nash (Dec 24 2019 at 19:51):

My guess is that there is no unconditional answer to the above, and the best one can say is "sometimes option 1, sometimes option 3", depending on the situation.

Kevin Buzzard (Dec 24 2019 at 20:58):

You're not allowed to make instance loops, that's the take home message I think. I'm certainly not an expert at this stuff but we saw the other day how extending a typeclass as opposed to asking for it can cause trouble sometimes

Kevin Buzzard (Dec 24 2019 at 21:01):

I think foo.to_module exists because you're extending. I'd love to point you to some docs explaining the basic do's and don'ts in this area but there aren't any and I can't write them

Oliver Nash (Dec 24 2019 at 22:23):

Thanks. Yes, I believe one of the things that extending does is to create foo.to_module; I too would love to read such docs, but I’ll happily plough ahead for now and wait till they are written (perhaps after Lean 4 arrives).

Oliver Nash (Dec 24 2019 at 22:28):

I think I more or less understand the no loops prohibition (a tree-like search can't search a general graph) but I need to sharpen my understanding a little. I still have various questions but I'm unblocked so I think I'll just put them aside for now and see how I go when I pick this up, in a few days. Thanks again.

Mario Carneiro (Dec 24 2019 at 22:55):

The general rule being violated here is that foo has three explicit (type) args, but it has a parent that has only two

Mario Carneiro (Dec 24 2019 at 22:55):

which means that during instance search M gets invented, leading to the instance loop

Kevin Buzzard (Dec 25 2019 at 00:22):

What's a parent? Something it extends?

Kevin Buzzard (Dec 25 2019 at 00:23):

This can be avoided by just using [module R M'] right?

Mario Carneiro (Dec 25 2019 at 03:04):

yes

Oliver Nash (Dec 25 2019 at 06:38):

@Mario Carneiro Thank you, that is extremely helpful!

Daniel Selsam (Jan 06 2020 at 13:36):

Can anyone come up with a simple, mathematically-motivated version of the reduced problem @Oliver Nash introduced in https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/typeclass.20problems/near/184185635 ? Specifically, I am looking for any simple example of a "natural" collection of "action-like" instances that cannot be used in Lean3 because they would induce a cycle. Here by cycle I mean literally a cycle where the same exact subgoal repeats, and not just any infinite loop such as in https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/Cute.20instance.20loop/near/180140798 . Thanks!

Daniel Selsam (Jan 06 2020 at 13:38):

Fun fact: tangent_space.topological_space would induce a cycle on its own, if only tangent_space and topological_fiber_bundle_core.fiber were not considered opaque inside typeclass resolution. The following loops in current mathlib:

local attribute [reducible] tangent_space topological_fiber_bundle_core.fiber
example {𝕜 E : Type} [nondiscrete_normed_field 𝕜] [normed_group E] [normed_space 𝕜 E] : topological_space E :=
by apply_instance

Floris van Doorn (Jan 06 2020 at 14:14):

Do you mean something like this?

import ring_theory.algebra
universe variables u v w

instance foo {k : Type u} {A : Type v} {M : Type w}
  [comm_ring k] [ring A] [add_comm_group M] [algebra k A] [module A M] :
  module k M :=
by sorry

set_option trace.class_instances true

attribute [instance, priority 2000] ring.to_add_comm_group
example {k : Type u} {A : Type v} {M : Type w}
  [comm_ring k] [comm_ring A] [ring M] [algebra k A] [algebra A M] :
  module k M :=
by apply_instance

Here type-class inference is trying to find ring ?M but doesn't know that ?M should be A, and therefore goes in an infinite loop.

Daniel Selsam (Jan 06 2020 at 15:20):

@Floris van Doorn Thank you. I apologize that I was not precise enough in my request, and unfortunately this is not quite what I am looking for. First, this problem seems to be dependent on the order in which the instance subgoals are solved. The [ring A] argument of foo appears in the downstream instance, and it is a separate and easily fixable problem to simply postpone the search for such instances, e.g. by searching for the instances from right-to-left instead of left-to-right (which is what we do in Lean4). It would be great to find a small collection of desirable instances that would loop even under the right-to-left policy. Also, by "mathematically-motivated" I meant instances with real names and meanings, as opposed to (presumably) artificial instances like foo.

Kevin Buzzard (Jan 06 2020 at 19:39):

foo has a real mathematical meaning. An example of foo is the statement that a complex vector space can be considered as a real vector space (of twice the dimension, in this setting).

Daniel Selsam (Jan 06 2020 at 20:19):

@Kevin Buzzard Thanks. What would be a good name for this instance then? Also, I suppose this instance is problematic no matter which direction we solve the subgoals in. If we go right-to-left, we immediately cycle. However, it does seems to work when algebra k A is tried before module A M:

import ring_theory.algebra

universe variables u v w

instance foo {k : Type u} {A : Type v} {M : Type w}
  (_ : comm_ring k) (_ : ring A) (_ : add_comm_group M) [algebra k A] [module A M] :
  module k M :=
by sorry

attribute [instance, priority 2000] ring.to_add_comm_group
example {k : Type u} {A : Type v} {M : Type w}
  [comm_ring k] [comm_ring A] [ring M] [algebra k A] [algebra A M] :
  module k M :=
by apply_instance -- works

Yury G. Kudryashov (Jan 06 2020 at 20:26):

In this particular case a possible solution is to have a tag "don't try this instance if k = A".

Johan Commelin (Jan 06 2020 at 20:33):

@Daniel Selsam It could be called restrict_scalars

Daniel Selsam (Jan 06 2020 at 20:59):

Is there a reasonable "sister" instance that would make it loop even if algebra k A were tried first, before module A M?

Yury G. Kudryashov (Jan 06 2020 at 21:12):

There is instance algebra.id [comm_ring R] : algebra R R.

Yury G. Kudryashov (Jan 06 2020 at 21:24):

BTW, if we define algebra.trans similarly to restrict_scalars, then algebra.id + algebra.trans will create a loop too.

Daniel Selsam (Jan 06 2020 at 21:34):

BTW, if we define algebra.trans similarly to restrict_scalars, then algebra.id + algebra.trans will create a loop too.

Could you please post code for the algebra.trans you envision?

Yury G. Kudryashov (Jan 06 2020 at 21:47):

Look at algebra.comap in ring_theory/algebra.lean. This is what I meant but it has a type tag to avoid loops.

Yury G. Kudryashov (Jan 06 2020 at 21:48):

I don't know if we would want to have algebra.trans as an instance (without a type tag) if it was possible.

Yury G. Kudryashov (Jan 06 2020 at 21:51):

instance algebra.trans [comm_ring R] [comm_ring S] [ring A] [algebra R S] [algebra S A] : algebra R A :=
{ smul := λ r x, (algebra_map S r  x : A),
  to_fun := (algebra_map A : S  A)  algebra_map S,
  hom := by apply_instance,
  commutes' := λ r x, algebra.commutes _ _,
  smul_def' := λ _ _, algebra.smul_def _ _ }

Yury G. Kudryashov (Jan 06 2020 at 21:51):

(untested)

Yury G. Kudryashov (Jan 06 2020 at 22:03):

(tested, works, needs some defs from ring_theory/algebra.lean)

Chris Hughes (Jan 06 2020 at 22:10):

algebra.comap is a nightmare. If you prove a theorem using algebra.comap, you won't be able to apply it easily to three rings where the canonical homomorphisms don't commute by definition. For example the Q\mathbb{Q}-algebra structure on C\mathbb{C}, is not defeq to (coe : ℝ → ℂ) ∘ (coe : ℚ → ℝ). algebra.trans shouldn't be an instance because of these diamonds, and we also shouldn't prove theorems with algebra.trans in the statement. That does lead to ugly statements however.

Yury G. Kudryashov (Jan 06 2020 at 22:12):

@Chris Hughes Thank you for the explanation.

Johan Commelin (Jan 07 2020 at 09:22):

I think that Chris raises a very important problem. Without a good way to deal with commutative diagrams, advancing in commutative algebra will be nasty

Johan Commelin (Jan 07 2020 at 09:23):

Of course we can just add proof obligations. But if it isn't done carefully, it makes everything hard to read and hard to write.

Johan Commelin (Jan 07 2020 at 09:24):

In an ideal world, you just "bless" a diagram as being commutative, and don't need to mention it again. Some system (not type class inference, but maybe similar) should just solve these issues in the background.

Johan Commelin (Jan 07 2020 at 09:24):

Finding paths through a graph is something that computers are better at than humans. So this part of proving should certainly not be kicked back into the users lap.

Daniel Selsam (Jan 07 2020 at 11:51):

@Chris Hughes I am not sure if I understand. Are you saying that even in Lean4, where typeclass resolution will handle cycles and diamonds correctly, algebra.trans would still be a bad instance because the path that typeclass resolution takes through the algebra.trans graph will affect whether some highly desirable definitional equalities hold or not?

According to the comment in algebra.lean, algebra.comap is a workaround for not being able to use algebra.trans. When you say it is a nightmare, are you saying it is a nightmare for the same reason that algebra.trans would be a nightmare? Can you please give an example of an "ugly" statement that avoids both?

Thanks very much.

Johan Commelin (Jan 07 2020 at 12:01):

As far as I understand, the problem that Chris mentions affects both algebra.comap and algebra.trans. Suppose that A → B → C are ring homs. Then C is an algebra over B, and B over A. By transitivity, C is also an algebra over A. But this fixes a particular (i.e., the transitive one) algebra structure for C over A. In practice, if one wants to apply a lemma, (e.g. to ℚ → ℝ → ℂ) then there is another algebra structure floating around which is not defeq to the transitive one.

Daniel Selsam (Jan 07 2020 at 12:17):

Thanks.

Daniel Selsam (Jan 07 2020 at 12:22):

I have not been able to get the restrict_scalars example to loop when it could have succeeded, once I controlled the subgoal ordering more carefully. So, I am still looking for a more compelling example of no-cycle-support being annoying in Lean3, or for a new cycle that you will want to introduce in Lean4.

Johan Commelin (Jan 07 2020 at 12:31):

https://cloud.commelin.net/s/C8PrCLoxe7995Nk is a picture of a type class graph that algebraic geometers have in their head, and use all the time.

Johan Commelin (Jan 07 2020 at 12:31):

@Daniel Selsam We currently cannot state this graph yet, because we haven't built enough algebraic geometry yet.

Johan Commelin (Jan 07 2020 at 12:32):

But all the info in this graph is used implicitly on almost every page of algebraic geometry (after introductory lecture notes)

Johan Commelin (Jan 07 2020 at 12:34):

So, this is not really a Lean 3 example. But being able to support dependencies like those in this graph would be really cool. As far as I understand, Lean 3 wouldn't be able to do that.

Daniel Selsam (Jan 07 2020 at 12:38):

Interesting, thank you. What is the difference between the dotted edges, the regular edges, and the dark edges?

Johan Commelin (Jan 07 2020 at 12:39):

The bold edges seem to "merge" two dependencies

Johan Commelin (Jan 07 2020 at 12:39):

The dotted edges are considered "trivial" (either because the definition extends the other) or because, well... it's trivial (i.e., doesn't require proof in Hartshorne – one of the main introductory texts in AG).

Johan Commelin (Jan 07 2020 at 12:40):

I found this graph on the wall of my office, when I arrived here in Freiburg. I think it's from an appendix in a book on AG by Goertz and Wedhorn.

Johan Commelin (Jan 07 2020 at 12:40):

I left it on the wall :grinning_face_with_smiling_eyes:

Daniel Selsam (Jan 07 2020 at 12:42):

Thanks.

Yury G. Kudryashov (Jan 15 2020 at 03:03):

@Daniel Selsam One more typeclass related problem, see #1875 https://github.com/leanprover-community/mathlib/pull/1875#discussion_r366674829 for a context, or below for a minimal example.

noncomputable theory
open_locale classical

variables {α : Type*} {β : Type*}
def indicator [has_zero β] (s : set α) (f : α  β) : α  β := λ x, if x  s then f x else 0

@[instance] axiom is_add_monoid_hom.indicator (β : Type*) [add_monoid β] (s : set α) :
  is_add_monoid_hom (λf:α  β, indicator s f)

lemma indicator_sum [add_comm_monoid β] {ι : Type*} (I : finset ι) (s : set α) (f : ι  α  β) :
  indicator s (I.sum f) = I.sum (λ i, indicator s (f i)) :=
begin
  convert (finset.sum_hom _ _).symm,
  convert is_add_monoid_hom.indicator β s
end

lemma indicator_sum' [add_comm_monoid β] {ι : Type*} (I : finset ι) (s : set α) (f : ι  α  β) :
  indicator s (I.sum f) = I.sum (λ i, indicator s (f i)) :=
(finset.sum_hom _ _).symm

The begin ... end proof works while the last line fails to unify add_monoid (α → β) from add_comm_monoid.to_add_monoid (pi.add_comm_monoid ...) with pi.add_monoid .... I have no idea how hard is to improve the situation here.

Mario Carneiro (Jan 15 2020 at 03:13):

I think this is missing MWE stuff

Yury G. Kudryashov (Jan 15 2020 at 03:28):

@Mario Carneiro What do you mean?

Mario Carneiro (Jan 15 2020 at 03:28):

what are the imports? I'm pretty sure is_add_monoid_hom is not in core

Mario Carneiro (Jan 15 2020 at 03:29):

ideally this should not have any imports, so it can be a standalone example that ports to lean 4

Yury G. Kudryashov (Jan 15 2020 at 03:31):

I'll try to post a version with no imports.

Yury G. Kudryashov (Jan 15 2020 at 04:17):

When I try to create a version with no imports and most def / lemma replaced by constant / axiom, it works... I'll try again tomorrow.

Yury G. Kudryashov (Jan 15 2020 at 04:54):

Probably this is a bug in pi_instance. It generates strange add_monoid.zero and add_monoid.add. I'll see if I can make it reuse pi.has_zero.


Last updated: Dec 20 2023 at 11:08 UTC