From f56a41a88706314e002e1c5126d5962d0da7d21c Mon Sep 17 00:00:00 2001 From: Daily Perf Improver Date: Sat, 11 Oct 2025 20:43:37 +0000 Subject: [PATCH] Add comprehensive matrix operation benchmarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds extensive benchmarking coverage for matrix operations as part of Phase 1 of the performance improvement plan. Changes: - Add Matrix.fs benchmark file with 14 comprehensive benchmarks - Benchmark element-wise operations (add, subtract, multiply, divide) - Benchmark scalar operations (add, multiply) - Benchmark matrix multiplication (matmul) - Benchmark matrix-vector operations (both directions) - Benchmark transpose operation - Benchmark row/column access patterns - Benchmark broadcast operations (addRowVector, addColVector) - Test with sizes: 10x10, 50x50, 100x100 Benchmarks use BenchmarkDotNet with MemoryDiagnoser to track allocations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../FsMath.Benchmarks.fsproj | 1 + benchmarks/FsMath.Benchmarks/Matrix.fs | 107 ++++++++++++++++++ benchmarks/FsMath.Benchmarks/Program.fs | 3 +- 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 benchmarks/FsMath.Benchmarks/Matrix.fs diff --git a/benchmarks/FsMath.Benchmarks/FsMath.Benchmarks.fsproj b/benchmarks/FsMath.Benchmarks/FsMath.Benchmarks.fsproj index 6b13aa6..e32e1c0 100644 --- a/benchmarks/FsMath.Benchmarks/FsMath.Benchmarks.fsproj +++ b/benchmarks/FsMath.Benchmarks/FsMath.Benchmarks.fsproj @@ -7,6 +7,7 @@ + diff --git a/benchmarks/FsMath.Benchmarks/Matrix.fs b/benchmarks/FsMath.Benchmarks/Matrix.fs new file mode 100644 index 0000000..60d070e --- /dev/null +++ b/benchmarks/FsMath.Benchmarks/Matrix.fs @@ -0,0 +1,107 @@ +namespace FsMath.Benchmarks + +open System +open BenchmarkDotNet.Attributes +open FsMath + +[] +type MatrixBenchmarks() = + + let mutable matrixA = Unchecked.defaultof> + let mutable matrixB = Unchecked.defaultof> + let mutable vector = [||] + + // Parameterize matrix sizes: small, medium, large + [] + member val Size = 0 with get, set + + [] + member this.Setup() = + // Initialize square matrices with some values + matrixA <- Matrix.init this.Size this.Size (fun i j -> float (i + j)) + matrixB <- Matrix.init this.Size this.Size (fun i j -> float (i * 2 + j)) + vector <- Array.init this.Size (fun i -> float i) + + // Element-wise operations + + [] + member _.ElementWiseAdd() = + let result = Matrix.add matrixA matrixB + GC.KeepAlive(result) + + [] + member _.ElementWiseSubtract() = + let result = Matrix.subtract matrixA matrixB + GC.KeepAlive(result) + + [] + member _.ElementWiseMultiply() = + let result = Matrix.multiply matrixA matrixB + GC.KeepAlive(result) + + [] + member _.ElementWiseDivide() = + let result = Matrix.divide matrixA matrixB + GC.KeepAlive(result) + + // Scalar operations + + [] + member _.ScalarAdd() = + let result = Matrix.addScalar matrixA 5.0 + GC.KeepAlive(result) + + [] + member _.ScalarMultiply() = + let result = Matrix.multiplyScalar matrixA 2.5 + GC.KeepAlive(result) + + // Matrix multiplication + + [] + member _.MatrixMultiply() = + let result = Matrix.matmul matrixA matrixB + GC.KeepAlive(result) + + // Matrix-vector operations + + [] + member _.MatrixVectorMultiply() = + let result = Matrix.muliplyVector matrixA vector + GC.KeepAlive(result) + + [] + member _.VectorMatrixMultiply() = + let result = Matrix.multiplyRowVector vector matrixA + GC.KeepAlive(result) + + // Transpose + + [] + member _.Transpose() = + let result = matrixA.Transpose() + GC.KeepAlive(result) + + // Row/column access patterns + + [] + member this.GetRow() = + let result = Matrix.getRow (this.Size / 2) matrixA + GC.KeepAlive(result) + + [] + member this.GetCol() = + let result = Matrix.getCol (this.Size / 2) matrixA + GC.KeepAlive(result) + + // Broadcast operations + + [] + member _.AddRowVector() = + let result = Matrix.addRowVector matrixA vector + GC.KeepAlive(result) + + [] + member _.AddColVector() = + let result = Matrix.addColVector matrixA vector + GC.KeepAlive(result) diff --git a/benchmarks/FsMath.Benchmarks/Program.fs b/benchmarks/FsMath.Benchmarks/Program.fs index d3c9b13..3c8a441 100644 --- a/benchmarks/FsMath.Benchmarks/Program.fs +++ b/benchmarks/FsMath.Benchmarks/Program.fs @@ -5,8 +5,9 @@ open FsMath.Benchmarks [] let Main args = // Register multiple benchmark classes - let switcher = BenchmarkSwitcher [| + let switcher = BenchmarkSwitcher [| typeof + typeof |] switcher.Run args |> ignore 0