Zulip Chat Archive
Stream: general
Topic: Optimizing the computation of `Fin` / `ZMod`
Yuyang Zhao (Dec 21 2023 at 08:11):
I'm trying to optimize the computation for large Fin
. But @[csimp]
doesn't seem to work here. I realized that I need to redefine instance. Is there any way to make @[csimp]
work automatically for all functions (I know there may be a lot) that use Fin.add
? Also this implementation is slower for small numbers, is this because if-then-else in lean is slower?
import Std.Data.Fin.Basic
namespace Fin
def addImpl : Fin n → Fin n → Fin n
| ⟨a, ha⟩, ⟨b, hb⟩ =>
let x := a + b
if hx : x < n then
⟨x, hx⟩
else
⟨x - n, Nat.sub_lt_left_of_lt_add (Nat.not_lt.mp hx) (Nat.add_lt_add ha hb)⟩
@[csimp]
theorem add_eq_addImpl : @Fin.add = @addImpl :=
funext fun n ↦ funext fun ⟨a, ha⟩ ↦ funext fun ⟨b, hb⟩ ↦ by
dsimp [addImpl, Fin.add]
split <;> (rename_i hx; congr)
· exact Nat.mod_eq_of_lt hx
· rw [Nat.not_lt] at hx
rw [Nat.mod_eq, if_pos ⟨Nat.lt_of_le_of_lt (Nat.zero_le a) ha, hx⟩]
exact Nat.mod_eq_of_lt (Nat.sub_lt_left_of_lt_add hx (Nat.add_lt_add ha hb))
-- instance (priority := default + 1) : Add (Fin n) where add := Fin.add
def run (n : Nat) (x : Nat) : IO Unit := do
let mut t : Fin (n + 1) := 0
for _ in [0 : x] do
t := ⟨n, n.lt_succ_self⟩ + ⟨n, n.lt_succ_self⟩
def runAdd (n : Nat) (x : Nat) : IO Unit := do
let mut t : Fin (n + 1) := 0
for _ in [0 : x] do
t := Fin.add ⟨n, n.lt_succ_self⟩ ⟨n, n.lt_succ_self⟩
def runImpl (n : Nat) (x : Nat) : IO Unit := do
let mut t : Fin (n + 1) := 0
for _ in [0 : x] do
t := addImpl ⟨n, n.lt_succ_self⟩ ⟨n, n.lt_succ_self⟩
def n := 10^100000
def x := 100000
#eval timeit "run" (run n x)
#eval timeit "runAdd" (runAdd n x)
#eval timeit "runImpl" (runImpl n x)
Eric Wieser (Dec 21 2023 at 09:47):
I think the csimp
needs to be defined before anything else uses the function
Eric Wieser (Dec 21 2023 at 09:47):
Otherwise it's too late because Fin.instAdd
has already been compiled, and future csimp
s won't force it to be recompiled
Last updated: May 02 2025 at 03:31 UTC