diff --git a/benchmark/BenchmarkDotNet.Artifacts/results/Program.Benchmarks-report-github.md b/benchmark/BenchmarkDotNet.Artifacts/results/Program.Benchmarks-report-github.md
index f247d2d..1bcb8f7 100644
--- a/benchmark/BenchmarkDotNet.Artifacts/results/Program.Benchmarks-report-github.md
+++ b/benchmark/BenchmarkDotNet.Artifacts/results/Program.Benchmarks-report-github.md
@@ -1,27 +1,27 @@
```
-BenchmarkDotNet v0.13.9+228a464e8be6c580ad9408e98f18813f6407fb5a, macOS Monterey 12.6.9 (21G726) [Darwin 21.6.0]
-Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
-.NET SDK 6.0.403
- [Host] : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2 DEBUG
- DefaultJob : .NET 6.0.11 (6.0.1122.52304), X64 RyuJIT AVX2
+BenchmarkDotNet v0.13.9+228a464e8be6c580ad9408e98f18813f6407fb5a, macOS Ventura 13.5 (22G74) [Darwin 22.6.0]
+Apple M2 Max, 1 CPU, 12 logical and 12 physical cores
+.NET SDK 6.0.415
+ [Host] : .NET 6.0.23 (6.0.2323.48002), Arm64 RyuJIT AdvSIMD DEBUG
+ DefaultJob : .NET 6.0.23 (6.0.2323.48002), Arm64 RyuJIT AdvSIMD
```
-| Method | Mean | Error | StdDev |
-|-------------------- |-------------:|------------:|------------:|
-| AllPairesInt_100 | 200.5 μs | 2.35 μs | 1.96 μs |
-| AllPairsInt_200 | 1,351.2 μs | 13.08 μs | 10.92 μs |
-| AllPairsBR_100 | 994.5 μs | 4.76 μs | 4.22 μs |
-| AllPairsBR_200 | 5,406.7 μs | 22.60 μs | 18.87 μs |
-| AllPairsBR_Rand_100 | 3,571.2 μs | 15.51 μs | 13.75 μs |
-| AllPairsBR_Rand_200 | 16,147.1 μs | 158.76 μs | 140.73 μs |
-| SolveCountMinIncl | 281.5 μs | 1.07 μs | 0.89 μs |
-| Solve_1_Eqs_100 | 44,174.2 μs | 870.02 μs | 854.48 μs |
-| Solve_1_Eqs_200 | 177,626.8 μs | 3,524.22 μs | 4,582.48 μs |
-| Solve_3_Eqs_100 | 45,644.5 μs | 724.51 μs | 642.26 μs |
-| Solve_3_Eqs_200 | 179,394.1 μs | 3,491.76 μs | 4,779.56 μs |
-| Solve_1_Eqs_Rand_10 | 24,787.3 μs | 93.87 μs | 78.39 μs |
-| Solve_1_Eqs_Rand_20 | 271,758.6 μs | 3,096.51 μs | 2,896.48 μs |
-| Solve_3_Eqs_Rand_10 | 25,649.5 μs | 89.37 μs | 69.78 μs |
-| Solve_3_Eqs_Rand_20 | 269,382.4 μs | 1,385.37 μs | 1,295.88 μs |
+| Method | Mean | Error | StdDev | Median |
+|-------------------- |-------------:|------------:|------------:|-------------:|
+| AllPairesInt_100 | 126.3 μs | 1.33 μs | 1.24 μs | 126.3 μs |
+| AllPairsInt_200 | 1,076.4 μs | 6.78 μs | 6.01 μs | 1,074.6 μs |
+| AllPairsBR_100 | 639.7 μs | 12.69 μs | 33.89 μs | 628.6 μs |
+| AllPairsBR_200 | 3,585.7 μs | 7.39 μs | 6.91 μs | 3,583.7 μs |
+| AllPairsBR_Rand_100 | 2,068.7 μs | 5.88 μs | 5.50 μs | 2,071.2 μs |
+| AllPairsBR_Rand_200 | 10,738.3 μs | 95.29 μs | 74.40 μs | 10,724.1 μs |
+| SolveCountMinIncl | 153.3 μs | 2.28 μs | 2.13 μs | 153.8 μs |
+| Solve_1_Eqs_100 | 28,284.4 μs | 255.51 μs | 239.01 μs | 28,372.7 μs |
+| Solve_1_Eqs_200 | 105,200.0 μs | 1,523.82 μs | 1,425.38 μs | 105,116.0 μs |
+| Solve_3_Eqs_100 | 29,274.8 μs | 585.01 μs | 518.60 μs | 29,154.9 μs |
+| Solve_3_Eqs_200 | 107,030.6 μs | 1,688.19 μs | 1,579.14 μs | 107,266.9 μs |
+| Solve_1_Eqs_Rand_10 | 16,717.6 μs | 183.67 μs | 171.81 μs | 16,639.5 μs |
+| Solve_1_Eqs_Rand_20 | 177,293.1 μs | 1,016.90 μs | 901.46 μs | 177,328.1 μs |
+| Solve_3_Eqs_Rand_10 | 16,968.0 μs | 60.90 μs | 53.99 μs | 16,959.7 μs |
+| Solve_3_Eqs_Rand_20 | 177,484.6 μs | 828.61 μs | 775.08 μs | 177,584.3 μs |
diff --git a/src/Informedica.GenSolver.Lib/Equation.fs b/src/Informedica.GenSolver.Lib/Equation.fs
index 7cadc72..b6706f1 100644
--- a/src/Informedica.GenSolver.Lib/Equation.fs
+++ b/src/Informedica.GenSolver.Lib/Equation.fs
@@ -22,6 +22,9 @@ module Equation =
module Property = Variable.ValueRange.Property
+ ///
+ /// Get the string representation of a SolveResult
+ ///
let toString = function
| Unchanged -> "Unchanged"
| Changed cs ->
@@ -38,11 +41,13 @@ module Equation =
|> String.concat ", "
+ ///
/// Create an `Equation` with an **y** and
/// **xs**. Fails if a variable is added more
/// than one time using the **fail** function.
/// The type of Equation product or sum
/// is determined by the constructor **c**.
+ ///
let create c succ fail (y, xs) =
y::xs
|> List.filter (fun v ->
@@ -55,44 +60,73 @@ module Equation =
|> Exceptions.EquationDuplicateVariables
|> fail
+
+ ///
/// Create an `ProductEquation` with an **y** and
/// **xs**. Fails if a variable is added more
/// than one time using the **fail** function.
+ ///
let createProductEq = create ProductEquation
+
+ ///
/// Create an `SumEquation` with an **y** and
/// **xs**. Fails if a variable is added more
/// than one time using the **fail** function.
+ ///
let createSumEq = create SumEquation
+
+ ///
/// Create an `ProductEquation` with an **y** and
/// **xs**. Fails if a variable is added more
/// than one time raising an exception.
+ ///
let createProductEqExc = createProductEq id (Exceptions.raiseExc None [])
+
+ ///
/// Create an `SumEquation` with an **y** and
/// **xs**. Fails if a variable is added more
/// than one time raising an exception.
+ ///
let createSumEqExc = createSumEq id (Exceptions.raiseExc None [])
+
+ ///
/// Apply **fp** to a `ProductEquation` and
/// **fs** to a `SumEquation`.
+ ///
let apply fp fs = function
| ProductEquation (y,xs) -> fp y xs
| SumEquation (y, xs) -> fs y xs
+
+ ///
/// Check whether an `Equation` is a product equation
+ ///
let isProduct = apply (fun _ _ -> true) (fun _ _ -> false)
+
+ ///
/// Check whether an `Equation` is a sum equation
+ ///
let isSum = apply (fun _ _ -> true) (fun _ _ -> false)
+
+ ///
/// Turn an `Equation` into a list of `Variable`
+ ///
let toVars =
let f y xs = y::xs
apply f f
+ ///
+ /// Get the count of `Variable`s in an `Equation`
+ ///
+ /// Whether only min max is used
+ /// The equation
let count onlyMinMax eq =
let vars = eq |> toVars
let b =
@@ -119,6 +153,9 @@ module Equation =
) 0
+ ///
+ /// Get product of the `Variable`s in an `Equation`
+ ///
let countProduct eq =
//match eq with
//| SumEquation _ -> -1
@@ -131,6 +168,9 @@ module Equation =
) 1
+ ///
+ /// Get the string representation of an `Equation`
+ ///
let toString exact eq =
let op = if eq |> isProduct then " * " else " + "
let varToString = Variable.toString exact
@@ -142,9 +182,11 @@ module Equation =
$"""{y |> varToString} = {xs |> List.map varToString |> String.concat op}"""
+ ///
/// Make sure that the `Variables` in the
/// `Equation` can only contain positive
/// non zero values.
+ ///
let nonZeroOrNegative eq =
let set c y xs =
let y = y |> Variable.setNonZeroOrNegative
@@ -154,12 +196,18 @@ module Equation =
let fs = set SumEquation
eq |> apply fp fs
+
+ ///
/// Check whether an `Equation` contains
/// a `Variable` **v**
+ ///
let contains v = toVars >> (List.exists (Variable.eqName v))
+
+ ///
/// Check whether `Equation`s
/// **eq1** and **eq2** are equal
+ ///
let equals eq1 eq2 =
let vrs1 = eq1 |> toVars
let vrs2 = eq2 |> toVars
@@ -168,24 +216,33 @@ module Equation =
((eq1 |> isProduct) && (eq2 |> isProduct) ||
(eq1 |> isSum) && (eq2 |> isSum))
+
+ ///
/// Find a `Variable` **vr** in
/// an `Equation` **eq** and return
/// the result in a list
+ ///
let find var eq =
eq
|> toVars
|> List.filter (fun v -> v |> Variable.getName = (var |> Variable.getName))
+
+ ///
/// Find a `Variable` with `Name`
/// **n** in an `Equation` **eq**
/// and return the result as a list
+ ///
let findName n eq =
eq
|> toVars
|> List.filter (fun vr -> vr |> Variable.getName = n)
+
+ ///
/// Replace a `Variable` **v** in the
/// `Equation` **e**.
+ ///
let replace var eq =
let r c v vs =
let vs = vs |> List.replace (Variable.eqName v) v
@@ -195,17 +252,22 @@ module Equation =
eq |> apply fp fs
- // Check whether an equation is solved
+
+ ///
+ /// Check whether an equation is solved
+ ///
let isSolved = function
| ProductEquation (y, xs)
| SumEquation (y, xs) ->
y::xs |> List.forall Variable.isSolved
- // Check whether an equation will change by calc
- // This is not the same as `isSolved`!! If all
- // the variables are unrestricted than the equation
- // is not solvable but is also not solved.
+ ///
+ /// Check whether an equation will change by calc
+ /// This is not the same as `isSolved`!! If all
+ /// the variables are unrestricted than the equation
+ /// is not solvable but is also not solved.
+ ///
let isSolvable = function
| ProductEquation (y, xs)
| SumEquation (y, xs) ->
@@ -216,6 +278,10 @@ module Equation =
|> not
+ ///
+ /// Check whether an equation is valid
+ ///
+ /// The equation
let check eq =
let isSub op (y : Variable) (xs : Variable list) =
match xs with
@@ -241,6 +307,9 @@ module Equation =
else true
+ ///
+ /// Get the string representation of a calculation
+ ///
let calculationToString b op1 op2 y xs =
let varToStr = Variable.toString b
let opToStr op = $" {op |> Variable.Operators.toString} "
@@ -251,8 +320,10 @@ module Equation =
$"""{y |> varToStr} = {x1 |> varToStr}{op2 |> opToStr}{xs |> List.map varToStr |> String.concat (op1 |> opToStr)} (cost: {cost})"""
+ ///
/// Solve an equation **e**, return a list of
/// changed `Variable`s.
+ ///
let solve onlyMinIncrMax log eq =
// helper functions
let without x xs = xs |> List.filter (Variable.eqName x >> not)