Zulip Chat Archive

Stream: mathlib4

Topic: ENat is noncomputable


Geoffrey Irving (Sep 17 2025 at 20:33):

I'm doing some verified computations with power series approximations (https://github.com/girving/series). I want my Series α to have a finite list of known, explicit coefficients, followed by a zero to infinite number of known zeros. This is nicely representable if Series has an order : ℕ∞ field. For intuition, the most important application of an infinite number of known series is so that constants cleanly embed as series, without knowing the order one eventually needs them to.

Unfortunately, the ℕ∞ ordering is noncomputable:

import Mathlib.Data.ENat.Lattice

variable {α : Type}

/-- `min` on `WithTop α` and `α` produces `α` -/
def WithTop.min_coe [Min α] (x : WithTop α) (y : α) : α := match x with
  | some x => min x y
  |  => y

/--- The size of the explicit coefficient array after a binary componentwise operation like add or sub.

Fails with failed to compile definition, compiler IR check failed at `binary_n._closed_0`. Error: depends on declaration 'instCompleteLinearOrderENat', which has no executable code; consider marking definition as 'noncomputable' -/
def binary_n (a0 a1 : ) (b0 b1 : ) :  :=
  let a := min a0 a1
  max (WithTop.min_coe a b0) (WithTop.min_coe a b1)

so I am following the instructions given here:

Deprecation #
As it appears this has been unused since 2018, we are now deprecating it. If ENat does not serve your purposes, please raise this on the community Zulip.

What's the best way to proceed? For now I'll define my own computable version of min and it should be fine, just a bit clunky.

Robin Arnez (Sep 17 2025 at 21:24):

It's not that the ordering on ℕ∞ is noncomputable but that it took the wrong turn in instance synthesis, take:

import Mathlib.Data.ENat.Lattice

set_option pp.explicit true in
/--
info: @SemilatticeInf.toMin ENat
  (@Lattice.toSemilatticeInf ENat
    (@ConditionallyCompleteLattice.toLattice ENat
      (@ConditionallyCompleteLinearOrder.toConditionallyCompleteLattice ENat
        (@ConditionallyCompleteLinearOrderBot.toConditionallyCompleteLinearOrder ENat
          (@CompleteLinearOrder.toConditionallyCompleteLinearOrderBot ENat instCompleteLinearOrderENat)))))
-/
#guard_msgs in #synth Min 

attribute [-instance] instCompleteLinearOrderENat

set_option pp.explicit true in
/--
info: @SemilatticeInf.toMin ENat
  (@Lattice.toSemilatticeInf ENat
    (@DistribLattice.toLattice ENat (@instDistribLatticeOfLinearOrder ENat instLinearOrderENat)))
-/
#guard_msgs in #synth Min 

Robin Arnez (Sep 17 2025 at 21:27):

What you'd really hope to see is @LinearOrder.toMin ENat instLinearOrderENat but well, instance search takes detours quite often

Kenny Lau (Sep 17 2025 at 21:29):

maybe the solution is instead to lower the priority of ConditionallyCompleteLattice.toLattice compared to DistribLattice.toLattice?

Robin Arnez (Sep 17 2025 at 21:34):

Hmm or maybe even also reduce the priority of SemilatticeInf.toMin in comparison to LinearOrder.toMin?

Robin Arnez (Sep 17 2025 at 21:35):

Maybe we could make this a more general rule: When class A implies class B and both class A and class B provide an instance to C then B.toC should have lower priority in comparison to A.toC

Eric Wieser (Sep 17 2025 at 21:52):

Nrmally we just make a computable shortcut when this happens

Eric Wieser (Sep 17 2025 at 21:53):

So in this case, just add instance : Lattice ENat := inferInstance before the complete lattice is set up

Eric Wieser (Sep 17 2025 at 21:54):

Or without a mathlib change, if you don't want to wait

import Mathlib.Data.ENat.Lattice

variable {α : Type}

-- this should be upstreamed as a "computable shortcut instance"
instance : Lattice ENat := LinearOrder.toLattice

/-- `min` on `WithTop α` and `α` produces `α` -/
def WithTop.min_coe [Min α] (x : WithTop α) (y : α) : α := match x with
  | some x => min x y
  |  => y

/--- The size of the explicit coefficient array after a binary componentwise operation like add or sub. -/
def binary_n (a0 a1 : ) (b0 b1 : ) :  :=
  let a := min a0 a1
  max (WithTop.min_coe a b0) (WithTop.min_coe a b1)

Robin Arnez (Sep 17 2025 at 21:55):

I guess maybe we could do that but it would probably be nice to reduce the amount of detours instance search takes in general

Robin Arnez (Sep 17 2025 at 21:56):

Again, we want to use LinearOrder.toMin here, really

Eric Wieser (Sep 17 2025 at 22:10):

We do this shortcut pattern pretty extensively already

Eric Wieser (Sep 17 2025 at 22:12):

Another solution would be to do search in two stages, using one that skips noncomputable instances the first time

Eric Wieser (Sep 17 2025 at 22:13):

Robin Arnez said:

Maybe we could make this a more general rule: When class A implies class B and both class A and class B provide an instance to C then B.toC should have lower priority in comparison to A.toC

I'd make the stronger claim that A.toC should not exist at all

Robin Arnez (Sep 17 2025 at 22:13):

You mean docs#LinearOrder.toMin should not exist and we should use docs#SemilatticeInf.toMin instead..?

Eric Wieser (Sep 17 2025 at 22:14):

Or at least the former should not be an instance

Eric Wieser (Sep 17 2025 at 22:14):

I think we start to get close to import considerations here though, where we want linear orders available before lattices

Robin Arnez (Sep 17 2025 at 22:18):

Well, I quickly threw together a little

Triangle detector

which gives you this list. So those are the ones we need to consider at least.

Eric Wieser (Sep 17 2025 at 22:19):

I've tried multiple times to fix this for the normed hierarchy :)

Robin Arnez (Sep 17 2025 at 22:20):

There also some of these interesting four-sided shapes like

LinearOrder -> SemilatticeSup -> PartialOrder
LinearOrder -> SemilatticeInf -> PartialOrder

where I don't believe we can remove the A.toC connection without causing asymmetry


Last updated: Dec 20 2025 at 21:32 UTC