Zulip Chat Archive

Stream: new members

Topic: FinVec Option to Option FinVec


Jesse Slater (Oct 02 2023 at 22:50):

I am using Fin n -> A as my vector type. I want to write a function to convert from FinVec Option A, and I want to convert it into a FinVec A, with a default FinVec if any of the indices are none.

I have working code that does it by converting to a vector using Vector.mOfFn, which gives Option Vector Nat, and then converting back to a function. I was wondering if there was some way I could do it without converting to a Vector.

Here is the MWE which converts to Vector:

import Mathlib.Data.Fin.VecNotation
import Mathlib.Data.Vector.Basic

def f1 : Fin 2  Option Nat
  | 0 => some 2
  | 1 => none

def f2 : Fin 2  Option Nat
  | 0 => some 2
  | 1 => some 3

def default : Fin 2  Nat
  | 0 => 0
  | 1 => 0

def optfn_or_default
  (f : Fin 2  Option Nat) : Fin 2  Nat :=
  Vector.mOfFn f
  |>.getD default
  |>.get

#eval optfn_or_default f1

#eval optfn_or_default f2

Chris Wong (Oct 03 2023 at 05:19):

That function looks a lot like docs#Traversable. I wonder if such an instance is viable in Lean (functions cannot be Traversable in general, as the argument may be infinite, but that doesn't apply to Fin _ -> .).

Yaël Dillies (Oct 03 2023 at 08:24):

I have a traversable instance for Fin-indexed functions in my computer project from last year. Let me dig it up.

Chris Wong (Oct 03 2023 at 09:42):

Is it generalizable to Fintype too? :eyes:

Yaël Dillies (Oct 03 2023 at 10:07):

Actually, it's not quite a Traversable instance that I've got, but pretty sure it's what Jesse wants:

import Mathlib.Data.Vector

namespace Vector

infixr:67 " ::ᵥ " => Vector.cons

/-- Apply a monadic function to each component of a vector, returning a vector inside the monad. -/
def mapM {m} [Monad m] {α} {β : Type _} (f : α  m β) :  {n}, Vector α n  m (Vector β n)
  | 0, _ => pure nil
  | n + 1, xs => do
    let h'  f xs.head
    let t'  @mapM m _ _ _ f n xs.tail
    pure (h' :: t')

end Vector
import Mathlib.Data.Fin.Basic
import Mathlib.Data.List.Range
import TheFileAbove

/-!
# Enumeration of types
-/

class Enum (α : Type _) where
  enum : List α
  enum_nodup : enum.Nodup
  index : α  Fin enum.length
  enum_index :  a, enum.get (index a) = a

instance {n : } : Enum (Fin n) :=
{ enum := List.finRange _,
  enum_nodup := List.nodup_finRange _,
  index := λ n  n, by rw [List.length_finRange]; exact n.2⟩,
  enum_index := λ a  by simp }

instance {α : Type _} {β : α  Type _} [Enum α] [ a, ToString (β a)] : ToString ( a, β a) :=
λ f  toString $ Enum.enum.map $ λ a  toString $ f a

instance [Enum α] [Nonempty α] : NeZero (Enum.enum : List α).length :=
λ h  by
  haveI := Nonempty α.map Enum.index
  rw [h] at this
  exact not_isEmpty_of_nonempty (Fin 0) (inferInstance : IsEmpty (Fin 0))⟩

namespace Monad
universe u v
variable {α : Type u} {β : Type (max u v)} {m : Type (max u v)  Type _}

-- TODO: Generalise to dependent types
/-- Return a random function from random results for each input. -/
def pi [Enum α] [Monad m] (r : α  m β) : m (α  β) :=
(λ l a  l.toList.get Enum.index a, by simp⟩) <$> Vector.mapM r Enum.enum, rfl

end Monad

Eric Wieser (Oct 03 2023 at 12:54):

I think I have a PR with PiFin.mapM

Eric Wieser (Oct 03 2023 at 12:55):

docs3#pi_fin.mmap


Last updated: Dec 20 2023 at 11:08 UTC