diff --git a/src/Informedica.GenSolver.Lib/Scripts/MinMax.fsx b/src/Informedica.GenSolver.Lib/Scripts/MinMax.fsx index 984cc49..83bc784 100644 --- a/src/Informedica.GenSolver.Lib/Scripts/MinMax.fsx +++ b/src/Informedica.GenSolver.Lib/Scripts/MinMax.fsx @@ -23,6 +23,25 @@ open Informedica.Utils.Lib.BCL open Informedica.GenSolver.Lib +[1..10] +|> List.filter (fun x -> x % 2 = 0) + +module List = + + let filter _ (xs: 'a list) = + printfn "hello world" + + +[1..10] +|> List.filter (fun x -> x % 2 = 0) + + +module OriginalList = + + let filter = Microsoft.FSharp.Collections.List.filter + +OriginalList.filter + [|3N/20N; 3N/10N; 1N/2N; 1N; 2N; 5N; 10N|] |> Array.allPairs [|1N/10N; 1N/5N; 1N/2N; 1N; 2N; 10N/3N; 20N/3N|] |> Array.map (fun (x1, x2) -> x1 * x2) diff --git a/src/Informedica.GenSolver.Lib/Variable.fs b/src/Informedica.GenSolver.Lib/Variable.fs index 53dfcec..8360d18 100644 --- a/src/Informedica.GenSolver.Lib/Variable.fs +++ b/src/Informedica.GenSolver.Lib/Variable.fs @@ -1022,7 +1022,9 @@ module Variable = /// /// Check if the first `ValueSet` is a subset of the second `ValueSet`. /// - let isSubset (ValueSet vu1) (ValueSet vu2) = ValueUnit.isSubset vu1 vu2 + let isSubsetOf vs1 vs2 = + let ValueSet vu1, ValueSet vu2 = vs1, vs2 + ValueUnit.isSubset vu1 vu2 /// @@ -1048,8 +1050,11 @@ module Variable = /// Apply a binary operator to two `ValueSet`s. /// /// The operator to apply - let calc op (ValueSet s1) (ValueSet s2) = - s1 |> op <| s2 |> + /// The first `ValueSet` + /// The second `ValueSet` + let calc op vs1 vs2 = + let ValueSet vu1, ValueSet vu2 = vs1, vs2 + vu1 |> op <| vu2 |> create @@ -1099,15 +1104,17 @@ module Variable = /// Get a string representation of a `ValueSet`. /// /// Whether values should be printed 'exact' - let toString exact (ValueSet vs) = + /// The `ValueSet` + let toString exact vs = + let (ValueSet vu) = vs let count = ValueUnit.getValue >> Array.length - if vs |> count <= 10 then - $"""[{vs |> ValueUnit.toStr exact}]""" + if vu |> count <= 10 then + $"""[{vu |> ValueUnit.toStr exact}]""" else - let first3 = vs |> ValueUnit.takeFirst 3 - let last3 = vs |> ValueUnit.takeLast 3 + let first3 = vu |> ValueUnit.takeFirst 3 + let last3 = vu |> ValueUnit.takeLast 3 $"[{first3 |> ValueUnit.toStr exact} .. {last3 |> ValueUnit.toStr exact}]" @@ -1115,15 +1122,17 @@ module Variable = /// Get a markdown representation of a `ValueSet`. /// /// The precision to print values with - let toMarkdown prec (ValueSet vs) = + /// The `ValueSet` + let toMarkdown prec vs = + let (ValueSet vu) = vs let count = ValueUnit.getValue >> Array.length - if vs |> count <= 10 then - $"""[{vs |> ValueUnit.toDelimitedString prec}]""" + if vu |> count <= 10 then + $"""[{vu |> ValueUnit.toDelimitedString prec}]""" else - let first3 = vs |> ValueUnit.takeFirst 3 - let last3 = vs |> ValueUnit.takeLast 3 + let first3 = vu |> ValueUnit.takeFirst 3 + let last3 = vu |> ValueUnit.takeLast 3 $"[{first3 |> ValueUnit.toDelimitedString prec} .. {last3 |> ValueUnit.toDelimitedString prec}]" @@ -1184,6 +1193,21 @@ module Variable = | ValsProp vs -> vs |> ValueSet.toString exact + // === START ValueRange === + + /// + /// Map a function over a `ValueRange`. + /// + /// The function to apply to a `Minimum` + /// The function to apply to a `Maximum` + /// The function to apply to a `MinMax` + /// The function to apply to an `Increment` + /// The function to apply to a `MinIncr` + /// The function to apply to an `IncrMax` + /// The function to apply to a `MinIncrMax` + /// The function to apply to a `ValueSet` + /// The `ValueRange` + /// The mapped `ValueRange` let map fMin fMax fMinMax fIncr fMinIncr fIncrMax fMinIncrMax fValueSet vr = match vr with | Unrestricted -> vr @@ -1198,10 +1222,23 @@ module Variable = | ValSet vs -> vs |> fValueSet |> ValSet + /// + /// Prune, limit the number of values, in a `ValueRange`. + /// + /// + /// Only a `ValueSet` can be pruned. The other `ValueRange`s + /// are left untouched. + /// let prune = map id id id id id id id ValueSet.prune + /// + /// Map a function to the ValueUnit of a `ValueRange`. + /// + /// The function to apply to the `ValueUnit` + /// The `ValueRange` + /// The mapped `ValueRange` let mapValueUnit f vr = vr |> map @@ -1215,9 +1252,28 @@ module Variable = (ValueSet.map f) + /// + /// Convert the unit of a `ValueRange` to **u**. + /// + /// The unit to convert to let setUnit u = mapValueUnit (ValueUnit.convertTo u) + /// + /// Apply a function to a `ValueRange`. + /// + /// Constant for `Unrestricted` + /// Constant for `NonZeroNoneNegative` + /// The function to apply to a `Minimum` + /// The function to apply to a `Maximum` + /// The function to apply to a `MinMax` + /// The function to apply to an `Increment` + /// The function to apply to a `MinIncr` + /// The function to apply to an `IncrMax` + /// The function to apply to a `MinIncrMax` + /// The function to apply to a `ValueSet` + /// The `ValueRange` + /// The result of applying the function to the `ValueRange` let apply unr nonz fMin fMax fMinMax fIncr fMinIncr fIncrMax fMinIncrMax fValueSet = function | Unrestricted -> unr @@ -1232,8 +1288,13 @@ module Variable = | ValSet vs -> vs |> fValueSet + /// /// Count the number of values in a `ValueRange`. /// Returns 0 if no count is possible. + /// + /// + /// Only when value range is a ValueSet there can be a count. + /// let cardinality = let zero _ = 0 apply 0 0 zero zero zero zero zero zero zero ValueSet.count @@ -1323,6 +1384,7 @@ module Variable = returnFalse + /// Checks whether a `ValueRange` is `Incr` let isIncr = let returnFalse = Boolean.returnFalse @@ -1339,6 +1401,7 @@ module Variable = returnFalse + /// Checks whether a `ValueRange` is `MinIncr` let isMinIncr = let returnFalse = Boolean.returnFalse @@ -1355,6 +1418,7 @@ module Variable = returnFalse + /// Checks whether a `ValueRange` is `IncrMax` let isIncrMax = let returnFalse = Boolean.returnFalse @@ -1371,6 +1435,7 @@ module Variable = returnFalse + /// Checks whether a `ValueRange` is `MinIncrMax` let isMinIncrMax = let returnFalse = Boolean.returnFalse @@ -1387,6 +1452,7 @@ module Variable = returnFalse + /// Checks whether a `ValueRange` is `ValueSet` let isValueSet = let returnFalse = Boolean.returnFalse @@ -1403,8 +1469,26 @@ module Variable = Boolean.returnTrue + /// /// Checks whether a `BigRational` is between an optional /// **min** and an optional **max** + /// + /// The optional minimum + /// The optional maximum + /// The `BigRational` to check + /// True if **br** is between **min** and **max** + /// + /// + /// let min = Minimum.create true ( [| 3N |] |> ValueUnit.create Units.Mass.gram) |> Some + /// let max = Maximum.create true ( [| 5N |] |> ValueUnit.create Units.Mass.gram) |> Some + /// let br = 4N + /// br |> isBetweenMinMax min max // returns true + /// let br = 6N + /// br |> isBetweenMinMax min max // returns false + /// let max = None + /// br |> isBetweenMinMax min max // returns true + /// + /// let isBetweenMinMax min max br = let fMin = function @@ -1434,6 +1518,23 @@ module Variable = (fMin min) && (fMax max) + /// + /// Checks whether a `BigRational` is a multiple of an optional + /// **incr**. + /// + /// + /// + /// + /// + /// let incr = Increment.create ( [| 2N |] |> ValueUnit.create Units.Mass.gram) |> Some + /// let br = 4N + /// br |> isMultipleOfIncr incr // returns true + /// let br = 5N + /// br |> isMultipleOfIncr incr // returns false + /// let incr = None + /// br |> isMultipleOfIncr incr // returns true + /// + /// let isMultipleOfIncr incrOpt br = let isDiv i = br |> BigRational.isMultiple i @@ -1442,16 +1543,33 @@ module Variable = | Some (Increment incr) -> incr |> ValueUnit.getBaseValue |> Seq.exists isDiv - /// Filter a set of `BigRational` according + /// + /// Filter a set of `ValueSet` according /// to **min** **max** and incr constraints + /// + /// The optional minimum + /// The optional increment + /// The optional maximum + /// + /// A `ValueSet` that contains the values that are between **min** and **max** + /// and that are a multiple of **incr**. + /// + /// + /// + /// let vs = [| 1N; 2N; 3N; 4N; 5N; 6N; 7N; 8N; 9N; 10N |] |> ValueUnit.create Units.Mass.gram |> ValueSet.create + /// vs |> filter (Some (Minimum.create true ( [| 3N |] |> ValueUnit.create Units.Mass.gram))) None None + /// // returns ValueSet (ValueUnit ([|3N; 4N; 5N; 6N; 7N; 8N; 9N; 10N|], Mass (Gram 1N))) + /// vs |> filter None None None // will return the same ValueSet + /// + /// let filter minOpt incrOpt maxOpt (ValueSet vs) = try - vs - |> ValueUnit.filter (fun v -> - v |> isBetweenMinMax minOpt maxOpt - && v |> isMultipleOfIncr incrOpt - ) - |> ValueSet.create + vs + |> ValueUnit.filter (fun v -> + v |> isBetweenMinMax minOpt maxOpt + && v |> isMultipleOfIncr incrOpt + ) + |> ValueSet.create with | e -> printfn $"filter with {minOpt}, {incrOpt}, {maxOpt} and {vs} gives empty set" @@ -1477,9 +1595,41 @@ module Variable = let minSTEmax max min = min |> minGTmax max |> not + /// + /// Create a `Minimum` that is a multiple of **incr**. + /// + /// The increment + /// The minimum + /// + /// + /// let incr = Increment.create ( [| 2N |] |> ValueUnit.create Units.Mass.gram) + /// let min = Minimum.create false ( [| 3N |] |> ValueUnit.create Units.Mass.gram) + /// min |> minMultipleOf incr // returns Minimum.MinIncl (ValueUnit ([|4N|], Mass (Gram 1N))) + /// + /// + /// + /// Note that the resulting min is always inclusive and greater than + /// or equal to the original min. + /// let minMultipleOf incr min = min |> Minimum.multipleOf incr + /// + /// Create a `Maximum` that is a multiple of **incr**. + /// + /// The increment + /// The maximum + /// + /// + /// let incr = Increment.create ( [| 2N |] |> ValueUnit.create Units.Mass.gram) + /// let max = Maximum.create false ( [| 5N |] |> ValueUnit.create Units.Mass.gram) + /// max |> maxMultipleOf incr // returns Maximum.MaxIncl (ValueUnit ([|4N|], Mass (Gram 1N))) + /// + /// + /// + /// Note that the resulting max is always inclusive and smaller than + /// or equal to the original max. + /// let maxMultipleOf incr max = max |> Maximum.multipleOf incr @@ -1487,12 +1637,19 @@ module Variable = let unrestricted = Unrestricted + /// A `ValueRange` that contains only non-zero, positive values. let nonZeroOrNegative = NonZeroNoneNegative + /// /// Create a `MinMax` `ValueRange`. If **min** > **max** raises /// an `MinLargetThanMax` exception. If min equals max, a `ValueSet` with /// value min (= max). + /// + /// The minimum + /// The maximum + /// A `MinMax` `ValueRange` + /// When **min** > **max** let minMaxToValueRange min max = if min |> minGTmax max then // printfn $"min:\n{min}\nmax:\n{max}" @@ -1510,6 +1667,24 @@ module Variable = (min, max) |> MinMax + /// + /// Create a `MinIncr` `ValueRange`. + /// + /// The minimum + /// The increment + /// A `MinIncr` `ValueRange` + /// + /// + /// let min = Minimum.create false ( [| 3N |] |> ValueUnit.create Units.Mass.gram) + /// let incr = Increment.create ( [| 2N |] |> ValueUnit.create Units.Mass.gram) + /// minIncrToValueRange min incr + /// // returns MinIncr (Minimum.MinIncl (ValueUnit ([|4N|], Mass (Gram 1N))), Increment (ValueUnit ([|2N|], Mass (Gram 1N)))) + /// + /// + /// + /// Note that the resulting min is always inclusive and greater than + /// or equal to the original min and is a multiple of **incr**. + /// let minIncrToValueRange min incr = if min |> Minimum.hasZeroUnit |> not then (min |> minMultipleOf incr, incr) @@ -1522,7 +1697,24 @@ module Variable = | None -> incr |> Incr + /// /// Create an `IncrMax` `ValueRange`. + /// + /// The increment + /// The maximum + /// An `IncrMax` `ValueRange` + /// + /// + /// let incr = Increment.create ( [| 2N |] |> ValueUnit.create Units.Mass.gram) + /// let max = Maximum.create false ( [| 5N |] |> ValueUnit.create Units.Mass.gram) + /// incrMaxToValueRange incr max + /// // returns IncrMax (Increment (ValueUnit ([|2N|], Mass (Gram 1N))), Maximum.MaxIncl (ValueUnit ([|4N|], Mass (Gram 1N)))) + /// + /// + /// + /// Note that the resulting max is always inclusive and smaller than + /// or equal to the original max and is a multiple of **incr**. + /// let incrMaxToValueRange incr max = (incr, max |> maxMultipleOf incr) |> IncrMax @@ -2409,7 +2601,7 @@ module Variable = /// `ValueRange` vr2. let isSubSetOf vr2 vr1 = match vr1, vr2 with - | ValSet s1, ValSet s2 -> s2 |> ValueSet.isSubset s1 + | ValSet s1, ValSet s2 -> s2 |> ValueSet.isSubsetOf s1 | _ -> false diff --git a/src/Informedica.GenUnits.Lib/Notebooks/Examples.dib b/src/Informedica.GenUnits.Lib/Notebooks/Examples.dib index 07a267a..235f6ce 100644 --- a/src/Informedica.GenUnits.Lib/Notebooks/Examples.dib +++ b/src/Informedica.GenUnits.Lib/Notebooks/Examples.dib @@ -1,6 +1,6 @@ #!meta -{"kernelInfo":{"defaultKernelName":"csharp","items":[{"name":"csharp","aliases":["c#","C#"],"languageName":"C#"},{"name":"vscode","languageName":null,"aliases":["frontend"]}]}} +{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":["C#","c#"],"languageName":"C#","name":"csharp"},{"aliases":["frontend"],"name":"vscode"}]}} #!markdown