From: Greg Burri Date: Wed, 31 Mar 2021 19:02:59 +0000 (+0200) Subject: Add an ellipse benchmark + unit test (WIP) X-Git-Url: http://git.euphorik.ch/?p=master-thesis.git;a=commitdiff_plain;h=2e029053d283ce141ce9870336cb9574ea4a203a Add an ellipse benchmark + unit test (WIP) --- diff --git a/Parasitemia/ParasitemiaCore/Ellipse.fs b/Parasitemia/ParasitemiaCore/Ellipse.fs index 65264ad..5a7df2b 100644 --- a/Parasitemia/ParasitemiaCore/Ellipse.fs +++ b/Parasitemia/ParasitemiaCore/Ellipse.fs @@ -78,6 +78,11 @@ let ellipse (p1x : float) (p1y : float) (m1 : float) (p2x : float) (p2y : float) Some (Types.Ellipse (float32 cx, float32 cy, float32 majorAxis, float32 minorAxis, float32 phi')) + +// Optimized version of 'ellipse': TODO +let ellipse' (p1x : float) (p1y : float) (m1 : float) (p2x : float) (p2y : float) (m2 : float) (p3x : float) (p3y : float) : Types.Ellipse option = + ellipse p1x p1y m1 p2x p2y m2 p3x p3y + let inline private vectorRotation (px : float32) (py : float32) (vx : float32) (vy : float32) (p0x : float32) (p0y : float32) : float32 = if py > p0y then if vx > 0.f then -1.f else 1.f diff --git a/Parasitemia/ParasitemiaCore/Types.fs b/Parasitemia/ParasitemiaCore/Types.fs index 84d4548..f13043c 100644 --- a/Parasitemia/ParasitemiaCore/Types.fs +++ b/Parasitemia/ParasitemiaCore/Types.fs @@ -44,7 +44,19 @@ type Ellipse (cx : float32, cy : float32, a : float32, b : float32, alpha : floa PI * (3.f * (this.A + this.B) - sqrt ((3.f * this.A + this.B) * (this.A + 3.f * this.B))) override this.ToString () = - sprintf "{Ellipse: cx = %f, cy = %f, a = %f, b = %f, alpha = %f}" this.Cx this.Cy this.A this.B this.Alpha + $"{{Ellipse: cx = %f{this.Cx}, cy = %f{this.Cy}, a = %f{this.A}, b = %f{this.B}, alpha = %f{this.Alpha}}}" + + override this.Equals (other : obj) = + match other with + | :? Ellipse as otherEllipse -> + otherEllipse.Cx = this.Cx && + otherEllipse.Cy = this.Cy && + otherEllipse.A = this.A && + otherEllipse.B = this.B && + otherEllipse.Alpha = this.Alpha + | _ -> false + + override this.GetHashCode () = HashCode.Combine (this.Cx, this.Cy, this.A, this.B, this.Alpha) [] type CellClass = HealthyRBC | InfectedRBC | Peculiar diff --git a/Parasitemia/ParasitemiaUI/Constants.fs b/Parasitemia/ParasitemiaUI/Constants.fs new file mode 100644 index 0000000..8ad5db7 --- /dev/null +++ b/Parasitemia/ParasitemiaUI/Constants.fs @@ -0,0 +1 @@ +module ParasitemiaUI.Constants diff --git a/Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj b/Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj index 1583816..2a87c55 100644 --- a/Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj +++ b/Parasitemia/ParasitemiaUI/ParasitemiaUI.fsproj @@ -17,6 +17,7 @@ + diff --git a/Parasitemia/Tests/ParasitemiaCore.Benchmark/EllipsesBench.fs b/Parasitemia/Tests/ParasitemiaCore.Benchmark/EllipsesBench.fs new file mode 100644 index 0000000..33ce745 --- /dev/null +++ b/Parasitemia/Tests/ParasitemiaCore.Benchmark/EllipsesBench.fs @@ -0,0 +1,42 @@ +module ParasitemiaCore.EllipsesBench + +open System +open System.Diagnostics +open type System.Console + +open ParasitemiaCore.Ellipse + +let rng = System.Random (42) + +let generateParameters () : float * float * float * float * float * float * float * float = + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble () + +let benchOld () = + let sw = Stopwatch () + sw.Start () + + for i in 1 .. 500_000 do + let p1x, p1y, m1, p2x, p2y, m2, p3x, p3y = generateParameters () + ellipse p1x p1y m1 p2x p2y m2 p3x p3y |> ignore + + sw.Stop () + WriteLine (sprintf "Old: time = %A ms" sw.ElapsedMilliseconds) + + +let benchNew () = + let sw = Stopwatch () + sw.Start () + + for i in 1 .. 500_000 do + let p1x, p1y, m1, p2x, p2y, m2, p3x, p3y = generateParameters () + ellipse' p1x p1y m1 p2x p2y m2 p3x p3y |> ignore + + sw.Stop () + WriteLine (sprintf "New: time = %A ms" sw.ElapsedMilliseconds) \ No newline at end of file diff --git a/Parasitemia/Tests/ParasitemiaCore.Benchmark/KdTreeBench.fs b/Parasitemia/Tests/ParasitemiaCore.Benchmark/KdTreeBench.fs new file mode 100644 index 0000000..028939b --- /dev/null +++ b/Parasitemia/Tests/ParasitemiaCore.Benchmark/KdTreeBench.fs @@ -0,0 +1,65 @@ +module ParasitemiaCore.KdTreeBench + +open System +open type System.Console + +open ParasitemiaCore.KdTree + +type Point (x : float32, y : float32) = + interface I2DCoords with + member this.X = x + member this.Y = y + + override this.ToString () = + sprintf "(%.1f, %.1f)" x y + +let bench1 () = + let min = -1_000. + let max = +1_000. + let windowSize = 10. + let nbPoints = 1_000_000 + let n = 1_000_000 + + let rng = Random 42 + let nextNumber (min : float) (max : float) (rng : Random) = + (rng.NextDouble () * (max + abs min)) + min |> float32 + + let points = + [ + for i = 1 to nbPoints do + let x = nextNumber min max rng + let y = nextNumber min max rng + Point (x, y) + ] + + let sw = System.Diagnostics.Stopwatch () + sw.Start () + + let tree = Tree.BuildTree points + + sw.Stop () + WriteLine (sprintf "Time to build = %A ms" sw.ElapsedMilliseconds) + + let rng = Random 42 + sw.Restart () + + let mutable nbFound = 0 + for i = 1 to n do + let minX = nextNumber min (max - windowSize) rng + let minY = nextNumber min (max - windowSize) rng + nbFound <- nbFound + (tree.SearchOld { minX = minX; maxX = minX + float32 windowSize; minY = minY; maxY = minY + float32 windowSize } |> List.length) + + sw.Stop () + WriteLine (sprintf "New: nb found: %i. Time to search = %A ms" nbFound sw.ElapsedMilliseconds) + + let rng = Random 42 + sw.Restart () + + let mutable nbFound = 0 + for i = 1 to n do + let minX = nextNumber min (max - windowSize) rng + let minY = nextNumber min (max - windowSize) rng + nbFound <- nbFound + (tree.Search { minX = minX; maxX = minX + float32 windowSize; minY = minY; maxY = minY + float32 windowSize }).Count + + sw.Stop () + WriteLine (sprintf "New: nb found: %i. Time to search = %A ms" nbFound sw.ElapsedMilliseconds) \ No newline at end of file diff --git a/Parasitemia/Tests/ParasitemiaCore.Benchmark/ParasitemiaCore.Benchmark.fsproj b/Parasitemia/Tests/ParasitemiaCore.Benchmark/ParasitemiaCore.Benchmark.fsproj index ea4034b..5db4d12 100644 --- a/Parasitemia/Tests/ParasitemiaCore.Benchmark/ParasitemiaCore.Benchmark.fsproj +++ b/Parasitemia/Tests/ParasitemiaCore.Benchmark/ParasitemiaCore.Benchmark.fsproj @@ -6,6 +6,8 @@ + + diff --git a/Parasitemia/Tests/ParasitemiaCore.Benchmark/Program.fs b/Parasitemia/Tests/ParasitemiaCore.Benchmark/Program.fs index 5022108..6057f7f 100644 --- a/Parasitemia/Tests/ParasitemiaCore.Benchmark/Program.fs +++ b/Parasitemia/Tests/ParasitemiaCore.Benchmark/Program.fs @@ -1,70 +1,10 @@ // Learn more about F# at http://docs.microsoft.com/dotnet/fsharp -open System -open type System.Console - -open ParasitemiaCore.KdTree - -type Point (x : float32, y : float32) = - interface I2DCoords with - member this.X = x - member this.Y = y - - override this.ToString () = - sprintf "(%.1f, %.1f)" x y - -let kdTree () = - let min = -1_000. - let max = +1_000. - let windowSize = 10. - let nbPoints = 1_000_000 - let n = 1_000_000 - - let rng = Random 42 - let nextNumber (min : float) (max : float) (rng : Random) = - (rng.NextDouble () * (max + abs min)) + min |> float32 - - let points = - [ - for i = 1 to nbPoints do - let x = nextNumber min max rng - let y = nextNumber min max rng - Point (x, y) - ] - - let sw = System.Diagnostics.Stopwatch () - sw.Start () - - let tree = Tree.BuildTree points - - sw.Stop () - WriteLine (sprintf "Time to build = %A ms" sw.ElapsedMilliseconds) - - let rng = Random 42 - sw.Restart () - - let mutable nbFound = 0 - for i = 1 to n do - let minX = nextNumber min (max - windowSize) rng - let minY = nextNumber min (max - windowSize) rng - nbFound <- nbFound + (tree.SearchOld { minX = minX; maxX = minX + float32 windowSize; minY = minY; maxY = minY + float32 windowSize } |> List.length) - - sw.Stop () - WriteLine (sprintf "New: nb found: %i. Time to search = %A ms" nbFound sw.ElapsedMilliseconds) - - let rng = Random 42 - sw.Restart () - - let mutable nbFound = 0 - for i = 1 to n do - let minX = nextNumber min (max - windowSize) rng - let minY = nextNumber min (max - windowSize) rng - nbFound <- nbFound + (tree.Search { minX = minX; maxX = minX + float32 windowSize; minY = minY; maxY = minY + float32 windowSize }).Count - - sw.Stop () - WriteLine (sprintf "New: nb found: %i. Time to search = %A ms" nbFound sw.ElapsedMilliseconds) +module ParasitemiaCore.Main [] let main argv = - kdTree () + //KdTreeBench.bench1 () + EllipsesBench.benchOld () + EllipsesBench.benchNew () 0 \ No newline at end of file diff --git a/Parasitemia/Tests/ParasitemiaCore.Tests/EllipsesTests.fs b/Parasitemia/Tests/ParasitemiaCore.Tests/EllipsesTests.fs new file mode 100644 index 0000000..185c43d --- /dev/null +++ b/Parasitemia/Tests/ParasitemiaCore.Tests/EllipsesTests.fs @@ -0,0 +1,35 @@ +namespace ParasitemiaCore.Tests + +open Xunit +open Xunit.Abstractions + +open Swensen.Unquote + +open ParasitemiaCore.Ellipse + +type EllipsesTests (output : ITestOutputHelper) = + + [] + member this.``Compare the old and new ellipse construction implementations`` () = + let rng = System.Random (42) + + let generateParameters () : float * float * float * float * float * float * float * float = + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble (), + rng.NextDouble () + + for i in 1 .. 100 do + let p1x, p1y, m1, p2x, p2y, m2, p3x, p3y = generateParameters () + let e = ellipse p1x p1y m1 p2x p2y m2 p3x p3y + let e' = ellipse' p1x p1y m1 p2x p2y m2 p3x p3y + + output.WriteLine (string e) + + test <@ e = e' @> + + () \ No newline at end of file diff --git a/Parasitemia/Tests/ParasitemiaCore.Tests/ParasitemiaCore.Tests.fsproj b/Parasitemia/Tests/ParasitemiaCore.Tests/ParasitemiaCore.Tests.fsproj index 6ef1b8e..45f05bb 100644 --- a/Parasitemia/Tests/ParasitemiaCore.Tests/ParasitemiaCore.Tests.fsproj +++ b/Parasitemia/Tests/ParasitemiaCore.Tests/ParasitemiaCore.Tests.fsproj @@ -7,11 +7,13 @@ + + all