Zulip Chat Archive

Stream: lean4

Topic: HAdd (Fin n) Nat (Fin n)?


James Gallicchio (Jun 01 2023 at 03:18):

is there any discussion of an hadd instance between fin and nat? just doing the usual Z/n behavior.

it is one of those things that makes sense on a type for Z/n but not a type for [n], so I'm not sure if it is there.

Mario Carneiro (Jun 01 2023 at 03:32):

I think it would be preferable to just use coercions here, same as how we don't have a HAdd Int Nat Int instance

James Gallicchio (Jun 01 2023 at 04:02):

But having a coercion Nat -> Fin n is admittedly deeply confusing (you could get inadvertent % where you don't want them).

James Gallicchio (Jun 01 2023 at 04:04):

I thought there was a discussion at one point about separating the type with wrapping ring arithmetic from the type with non-wrapping arithmetic where overflow must be accounted for.

Mario Carneiro (Jun 01 2023 at 04:08):

keep in mind that 4 : Fin 2 already typechecks

James Gallicchio (Jun 01 2023 at 04:12):

which always peeved me, since 4 : Fin n with a hypothesis in context like n = 2 or n > 0 or anything along those lines does not typecheck :joy:

Mario Carneiro (Jun 01 2023 at 04:13):

how is the hypothesis supposed to be used?

Mario Carneiro (Jun 01 2023 at 04:13):

do you want it to by assumption or something?

Mario Carneiro (Jun 01 2023 at 04:14):

4 : Fin (n+1) does typecheck

Mario Carneiro (Jun 01 2023 at 04:14):

and mathlib also has a version where 4 : Fin n typechecks given Fact (0 < n)

James Gallicchio (Jun 01 2023 at 04:16):

I think for a type like Mod n the current mathlib behavior for Fin makes sense, trying to do whatever it can do show n > 0 so that the ring operations just work (in fact, it might even make sense for Mod n to require n > 0 for simplicity's sake, since Z/0 is degenerate...)

Mario Carneiro (Jun 01 2023 at 04:18):

you mean docs4#ZMod ?

James Gallicchio (Jun 01 2023 at 04:20):

yes, that is exactly what i'm looking for :)

James Gallicchio (Jun 01 2023 at 04:21):

now the question is why the wrapping Fin.add exists!

Mario Carneiro (Jun 01 2023 at 04:22):

what do you expect it to be?

Mario Carneiro (Jun 01 2023 at 04:23):

whatever you are thinking, it is much worse to work with

Mario Carneiro (Jun 01 2023 at 04:24):

one pragmatic reason for Fin.add is that it is used to define UInt32.add and UInt64.add

James Gallicchio (Jun 01 2023 at 04:24):

yeah. but you could see ZMod being moved to core and used as the backing for UIntX

James Gallicchio (Jun 01 2023 at 04:25):

Idk. I don't really ever want to add Fins (?). Speaking as someone who only interacts with Fin in Array contexts.

Mario Carneiro (Jun 01 2023 at 04:26):

then maybe don't

Mario Carneiro (Jun 01 2023 at 04:28):

ZMod is a conditional type, it is defined as Fin n for n > 0 and Int for n = 0

Mario Carneiro (Jun 01 2023 at 04:30):

array indices don't even really want Fin n, they would be better off with { i : UInt64 // i < n }

Yaël Dillies (Jun 01 2023 at 05:46):

Your original question sounds more like vadd. I still believe we should never use HAdd because the only heterogeneous cases that matter are covered by vadd.

Eric Wieser (Jun 01 2023 at 11:10):

I'd make the stronger claim that it's not just that vadd and smul are the only cases that matter, butHAdd and HMul are massive footguns as there is no sane composition strategy to avoid non-propeq diamonds

Eric Wieser (Jun 01 2023 at 11:11):

Arguably we could add a nvadd field to AddMonoidWithOne which would give the behavior that @Yaël Dillies suggests

Eric Rodriguez (Jun 01 2023 at 11:56):

i think HAdd is more useful for programmers

Notification Bot (Jun 01 2023 at 15:01):

Marc Huisinga has marked this topic as resolved.

Notification Bot (Jun 01 2023 at 15:01):

Marc Huisinga has marked this topic as unresolved.

Mac Malone (Jun 02 2023 at 01:32):

Mario Carneiro said:

array indices don't even really want Fin n, they would be better off with { i : UInt64 // i < n }

Or, more precisely, USize.

Eric Wieser (Nov 23 2023 at 15:32):

Eric Wieser said:

I'd make the stronger claim that [...]HAdd and HMul are massive footguns as there is no sane composition strategy to avoid non-propeq diamonds

Just to give a concrete example of this:

import Mathlib.Logic.Nontrivial.Defs
import Mathlib.Data.Pi.Algebra

variable {ι α β γ : Type _}

-- HMul generalizes to families on the right
instance hmulRight [inst : HMul α β γ] : HMul α (ι  β) (ι  γ) where
  hMul a b := fun i => a * b i

-- HMul generalizes to families on the left
instance hmulLeft [inst : HMul α β γ] : HMul (ι  α) β (ι  γ) where
  hMul a b := fun i => a i * b

-- both of these are valid instance searches, lets give them short names
variable (ι)
abbrev lr : HMul (ι  Nat) (ι  Nat) (ι  ι  Nat) := hmulLeft (inst := hmulRight)
abbrev rl : HMul (ι  Nat) (ι  Nat) (ι  ι  Nat) := hmulRight (inst := hmulLeft)

-- holy diamonds batman
example (a b : ι  Nat) (i j : ι) : let _ := lr ι; (a * b) i j = a i * b j := rfl
example (a b : ι  Nat) (i j : ι) : let _ := rl ι; (a * b) i j = a j * b i := rfl

-- propositional diamonds!
example [Nontrivial ι] : lr ι  rl ι := by
  classical
  obtain i, j, hij := exists_pair_ne ι
  dsimp [lr, rl, hmulLeft, hmulRight]
  intro h
  injection h with h
  replace h := congr_fun₂ (congr_fun₂ h (Pi.mulSingle i 2) (Pi.mulSingle i 3)) i j
  rw [Pi.mulSingle_eq_same, Pi.mulSingle_eq_same, Pi.mulSingle_eq_of_ne' hij, Pi.mulSingle_eq_of_ne' hij] at h
  cases h

Last updated: Dec 20 2023 at 11:08 UTC