Zulip Chat Archive

Stream: lean4

Topic: Automatically generate Equiv from enum to Fin n


Jesse Slater (Apr 05 2023 at 19:17):

Is there a way that I can automatically generate an Equiv between a finite inductive enum with n elements and Fin n? For example :

inductive α where
  | a
  | b
  | c

open α

def αEquiv : α  (Fin 3) := {
  toFun :=
    λ | a => 0
      | b => 1
      | c => 2

  invFun :=
    λ | 0 => a
      | 1 => b
      | 2 => c

  left_inv := by
    unfold Function.LeftInverse
    aesop

  right_inv := by
    unfold Function.RightInverse Function.LeftInverse
    aesop
}

The goal is to be able to create any finite inductive type and then automatically generate the obvious equivalence so that I can index a vector by meaningful names.

I would also be open to some other way of indexing a vector by meaningful names, this is just the first idea I came up with to achieve that.

Kyle Miller (Apr 05 2023 at 19:25):

It's not the most efficient approach here, but mathlib4#3198 has a term elaborator named proxy_equiv% that generates an equivalence between a non-recursive inductive type (like your enum type) and some simple type. There should be enough FinEnum instances in mathlib to use this to derive a likely-not-efficient equivalence to Fin 3.

Kyle Miller (Apr 05 2023 at 19:26):

I can also point you to the DecidableEq derive handler in Lean 4, which for enum types generates the invFun for you. The toFun is already called toCtorIdx and is generated by Lean automatically.

Kyle Miller (Apr 05 2023 at 19:27):

That derive handler generates ofNat and ofNat_toCtorIdx, which you can make use of if you add deriving DecidableEq after your inductive type.

Eric Wieser (Apr 05 2023 at 22:40):

docs4#FinEnum is the class for precisely this, right? (Though you'd need to implement the instance for it)

Eric Wieser (Apr 05 2023 at 22:42):

Why do you need Fin 3 at all though if your intent is to index with meaningful names? You can just use α →ℝ directly

Jesse Slater (Apr 05 2023 at 23:52):

Thanks, FinEnum looks great. When you say use α →ℝ directly, is the idea to get rid of the vectors entirely? I might be able to do that, but I am using some vector functions which I don't know how to replace. How would I do Vector.map and Vector.toList if I was working with functions instead of vectors?

Eric Wieser (Apr 06 2023 at 00:14):

What do you mean by "vector"? I assumed you mean Fin 3 → ℝ...

Eric Wieser (Apr 06 2023 at 00:15):

Vector.map is just composition

Eric Wieser (Apr 06 2023 at 00:15):

toList requires the equivalence you asked for because you need to choose an order for your elements

Jesse Slater (Apr 07 2023 at 02:57):

By vector, I mean Mathlib.Data.Vector. I am using vectors of nats. I probably should have made that more clear. It is possible that I could just use Fin n -> Nat, or α -> Nat but this seemed more intuitive to me. The reason I am using vectors is that I am doing entry wise operations with multiple vectors, so I need to make sure they have the same number of elements.
Here are all of the operations I think I need:

Entry wise operations on multiple vectors
Appending vectors together to get longer ones, but maintaining my useful names
Iterating over the elements of a vector, as in foldl

It is not immediately obvious to me how I would do those using the α -> Nat strategy, but I am sure there is a way.

Mario Carneiro (Apr 07 2023 at 02:59):

Aren't most of those operations already implemented over Fin n -> A vectors? It is used for vectors / matrices

Mario Carneiro (Apr 07 2023 at 03:00):

Mathlib.Data.Vector is not used much in mathlib

Jesse Slater (Apr 07 2023 at 03:07):

Where should I look for the functions for Fin n -> A? My problem is that I am very new to Lean, and everything I know is from reading the books and searching mathlib, so I never know if I am missing something. Mathlib.Data.Vector is just the first thing that came up when I was searching for a vector.

Mario Carneiro (Apr 07 2023 at 03:08):

Vector3 is used more IIRC, but it is still being ported in mathlib4 (there is an open PR about it)

Mario Carneiro (Apr 07 2023 at 03:08):

it will be easier to peruse the state of things in mathlib3

Trebor Huang (Apr 07 2023 at 04:49):

As a related thing, what about automatically generating Equiv from structures to nested Sigma types?

Kyle Miller (Apr 07 2023 at 05:08):

@Trebor Huang Take a look at mathlib4#3198, which gives a term elaborator (proxy_equiv%) for exactly that.

Kyle Miller (Apr 07 2023 at 05:30):

Eric Wieser said:

docs4#FinEnum is the class for precisely this, right? (Though you'd need to implement the instance for it)

That was what I was suggesting with using proxy_equiv% and relying on FinEnum instances, since it'd be a way to implement that instance automatically.

Just to show what I meant with the other suggestion, I'll post the code here (although it looks like this might not be useful for Jesse).

import Mathlib.Logic.Equiv.Basic
import Mathlib.Tactic.IntervalCases
import Mathlib.Data.FinEnum

inductive α where
  | a
  | b
  | c
  deriving DecidableEq

open α

def αEquiv : α  Fin 3 where
  toFun x := α.toCtorIdx x, by cases x <;> simp
  invFun x := α.ofNat x
  left_inv := α.ofNat_toCtorIdx
  right_inv := by
    intro x, h
    interval_cases x <;> rfl

instance : FinEnum α where
  card := 3
  Equiv := αEquiv

Last updated: Dec 20 2023 at 11:08 UTC