Skip to content

Commit

Permalink
perf: improved valueunit simplify performance
Browse files Browse the repository at this point in the history
  • Loading branch information
Casper Bollen authored and Casper Bollen committed Oct 23, 2023
1 parent ae6e0c7 commit 177399f
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 39 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@
# Add benchmark files
!/benchmark/
!/benchmark/run.bat
!/benchmark/run.sh
!/benchmark/.paket/
!/benchmark/.paket/Paket.Restore.targets
!/benchmark/Informedica.GenSolver.Lib_v1/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ Apple M2 Max, 1 CPU, 12 logical and 12 physical cores
```
| Method | Mean | Error | StdDev |
|------------------------ |----------:|---------:|---------:|
| BaseValue_200 | 41.12 ms | 0.661 ms | 0.618 ms |
| AllPairs_True_100 | 25.70 ms | 0.089 ms | 0.083 ms |
| AllPairs_True_200 | 129.14 ms | 0.579 ms | 0.513 ms |
| AllPairs_True_Rand_100 | 127.78 ms | 0.404 ms | 0.378 ms |
| AllPairs_False_Rand_200 | 623.85 ms | 4.947 ms | 4.627 ms |
| AllPairs_True_Rand_200 | 624.27 ms | 2.291 ms | 2.031 ms |
| Method | Mean | Error | StdDev |
|---------------------------------- |----------:|---------:|---------:|
| BaseValue_200 | 39.32 ms | 0.502 ms | 0.419 ms |
| AllPairs_True_100 | 25.08 ms | 0.117 ms | 0.104 ms |
| AllPairs_True_200 | 128.50 ms | 0.730 ms | 0.683 ms |
| AllPairs_True_Rand_100 | 133.47 ms | 0.397 ms | 0.372 ms |
| AllPairs_False_Rand_200 | 555.15 ms | 4.057 ms | 3.596 ms |
| AllPairs_True_Rand_200 | 554.77 ms | 3.653 ms | 3.051 ms |
| AllPairs_True_Rand_100_mgPerMl_ml | 114.64 ms | 2.232 ms | 2.088 ms |
14 changes: 14 additions & 0 deletions benchmark/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,12 @@ type ValueUnitBenchmarks () =
Utils.getTwoRandomLists 200 1_000
|> fun (x1, x2) -> ValueUnit.create Units.Count.times x1, ValueUnit.create Units.Count.times x2

let rand_100_a_mg_per_ml, rand_100_b_ml =
let mgPerMl = Units.Mass.milliGram |> Units.per Units.Volume.milliLiter
let ml = Units.Volume.milliLiter
Utils.getTwoRandomLists 100 1_000
|> fun (x1, x2) -> ValueUnit.create mgPerMl x1, ValueUnit.create ml x2

let calc b op x1 x2 = ValueUnit.calc b op x1 x2 //x1 |> op <| x2

let add b = calc b (+)
Expand Down Expand Up @@ -292,6 +298,14 @@ type ValueUnitBenchmarks () =
div true x1 x2 |> ignore


[<Benchmark>]
member this.AllPairs_True_Rand_100_mgPerMl_ml () =
let x1, x2 = rand_100_a_mg_per_ml, rand_100_b_ml
add true x1 x1 |> ignore // can only add with same units
sub true x1 x1 |> ignore // can only sub with same units
mul true x1 x2 |> ignore
div true x1 x2 |> ignore



type EquationBenchmarks () =
Expand Down
1 change: 1 addition & 0 deletions benchmark/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sudo dotnet run -c Release $@
68 changes: 37 additions & 31 deletions src/Informedica.GenUnits.Lib/ValueUnit.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2594,6 +2594,33 @@ module ValueUnit =
|> fun u -> build tail ds (isCount, u)


/// <summary>
/// Simplify a unit u such that units are algebraically removed or
/// transformed to count units, where applicable.
/// </summary>
/// <param name="u">The unit to simplify</param>
/// <returns>
/// The simplified unit
/// </returns>
let simplifyUnit u =
if u = NoUnit then u
else
let ns, ds = u |> numDenom true

(false, NoUnit)
|> build ns ds
|> fun (_, newU) ->
// nothing changed so just return original
if u = newU then u
else
match newU with
| CombiUnit(u1, OpPer, CombiUnit(u2, OpTimes, u3)) ->
if u2 |> Group.eqsGroup u3 then newU
else
CombiUnit(CombiUnit(u1, OpPer, u2), OpPer, u3)
| _ -> newU


/// <summary>
/// Simplify a value unit u such that units are algebraically removed or
/// transformed to count units, where applicable.
Expand All @@ -2610,40 +2637,19 @@ module ValueUnit =
/// ValueUnit ([|1N; 2N; 3N|], Count (Times 1N))
/// </code>
/// </example>
let simplify vu =
let u = vu |> getUnit
let rec simplify vu =
let v, u = vu |> get

if u = NoUnit then
vu
else
let ns, ds = u |> numDenom true

(false, NoUnit)
|> build ns ds
|> fun (_, u1) ->
// nothing changed so just return original
if u = u1 then vu
else
vu
|> toBaseValue
|> create u1
|> toUnitValue
|> create u1
// rewrite case u1/u2 * u3 -> u1/u2/u3 when group u2 <> group u3
|> fun vu ->
let v, u =
vu
|> get
let u =
match u with
| CombiUnit(u1, OpPer, CombiUnit(u2, OpTimes, u3)) ->
if u2 |> Group.eqsGroup u3 then
u
else
CombiUnit(CombiUnit(u1, OpPer, u2), OpPer, u3)
| _ -> u

v |> withUnit u
let u = simplifyUnit u
v
|> create u
// calculate to the new combiunit
|> toUnitValue
// recreate again to final value unit
|> create u


/// <summary>
Expand Down Expand Up @@ -2696,14 +2702,14 @@ module ValueUnit =
| _ ->
failwith
<| $"cannot add or subtract different units %A{u1} %A{u2}"
|> fun u -> if b then simplifyUnit u else u
// recreate valueunit with base value and combined unit
v
|> create u
// calculate to the new combiunit
|> toUnitValue
// recreate again to final value unit
|> create u
|> fun vu -> if b then vu |> simplify else vu


/// <summary>
Expand Down

0 comments on commit 177399f

Please sign in to comment.