From c1b5d157559cfaa0eb105cf1f19c373236cf8b00 Mon Sep 17 00:00:00 2001 From: Casper Bollen Date: Mon, 2 Oct 2023 22:44:47 +0200 Subject: [PATCH] chore: sync commit working on min max tests --- .../Scripts/Tests.fsx | 832 +++++++++++------- src/Informedica.GenSolver.Lib/Variable.fs | 6 +- tests/Informedica.GenSolver.Tests/Tests.fs | 8 +- 3 files changed, 513 insertions(+), 333 deletions(-) diff --git a/src/Informedica.GenSolver.Lib/Scripts/Tests.fsx b/src/Informedica.GenSolver.Lib/Scripts/Tests.fsx index 2cf3946..6fc38a8 100644 --- a/src/Informedica.GenSolver.Lib/Scripts/Tests.fsx +++ b/src/Informedica.GenSolver.Lib/Scripts/Tests.fsx @@ -543,6 +543,7 @@ module Tests = ] + module MaximumTests = @@ -674,6 +675,7 @@ module Tests = ] + module MinMaxCalculatorTests = open Informedica.GenSolver.Lib.Variable.ValueRange @@ -687,264 +689,414 @@ module Tests = let calc = MinMaxCalculator.calc (fun b vu -> Some vu, b) let tests = testList "minmax calculator" [ - testList "Multiplication" [ - // multiplication of two values, both are None - // should return None - test "x1 = None and x2 = None" { - let x1 = None |> create true - let x2 = None |> create true - calc (*) x1 x2 - |> Expect.equal "should be None" None - } - // multiplication of two values, the first is Some 1 - // and the second is None should return None - test "x1 = Some 1 and x2 = None" { - let x1 = Some 1N |> create true - let x2 = None |> create true - calc (*) x1 x2 - |> Expect.equal "should be None" None - } - // multiplication of two values, the first is None - // and the second is Some 1 should return None - test "x1 = None and x2 = Some 1" { - let x1 = None |> create true - let x2 = Some 1N |> create true - calc (*) x1 x2 - |> Expect.equal "should be None" None - } - // multiplication of two values, the first is Some 1 - // and the second is Some 1 should return Some 1 - test "x1 = Some 1 and x2 = Some 1" { - let x1 = Some 1N |> create true - let x2 = Some 1N |> create true - calc (*) x1 x2 - |> Expect.equal "should be Some 1" (Some 1N |> create true |> Some) - } - // multiplication of two values, the first is Some 1 - // and the second is Some 2 should return Some 2. - // When the first value is exclusive, the result should be exclusive - test "x1 = Some 1, excl and x2 = Some 2, incl" { - let x1 = Some 1N |> create false - let x2 = Some 2N |> create true - calc (*) x1 x2 - |> Expect.equal "should be Some 2, exclusive" (Some 2N |> create false |> Some) - } - // multiplication of two values, the first is Some 1 - // and the second is Some 2 should return Some 2. - // When the both values are exclusive, the result should be exclusive - test "x1 = Some 1, excl and x2 = Some 2, excl" { - let x1 = Some 1N |> create false - let x2 = Some 2N |> create false - calc (*) x1 x2 - |> Expect.equal "should be Some 2, exclusive" (Some 2N |> create false |> Some) - } - // multiplication of two values and the first value is Some 0 and - // the second value is None, results in Some 0 with ZeroUnit! - test "x1 = Some 0 and x2 = None" { - let x1 = Some 0N |> create true - let x2 = None |> create true - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (*) x1 x2 - |> Expect.equal "should be Some 0" ((Some zero, true) |> Some) - } - // multiplication of two values and the first value is None and - // the second value is Some 0, results in Some 0 with ZeroUnit! - test "x1 = None and x2 = Some 0" { - let x2 = Some 0N |> create true - let x1 = None |> create true - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (*) x1 x2 - |> Expect.equal "should be Some 0" ((Some zero, true) |> Some) - } - // multiplication of two values and the first value is Some 0 excl and - // the second value is None, results in Some 0 with ZeroUnit, excl! - test "x1 = Some 0, excl and x2 = None, incl" { - let x1 = Some 0N |> create false - let x2 = None |> create true - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (*) x1 x2 - |> Expect.equal "should be Some 0, excl" ((Some zero, false) |> Some) - } - // multiplication of two values and the first value is Some 0 incl and - // the second value is None excl, results in Some 0 with ZeroUnit, incl! - test "x1 = Some 0, incl and x2 = None, excl" { - let x1 = Some 0N |> create true - let x2 = None |> create false - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (*) x1 x2 - |> Expect.equal "should be Some 0, incl" ((Some zero, true) |> Some) - } + testList "calc operator" [ + testList "Multiplication" [ + // multiplication of two values, both are None + // should return None + test "x1 = None and x2 = None" { + let x1 = None |> create true + let x2 = None |> create true + calc (*) x1 x2 + |> Expect.equal "should be None" None + } + // multiplication of two values, the first is Some 1 + // and the second is None should return None + test "x1 = Some 1 and x2 = None" { + let x1 = Some 1N |> create true + let x2 = None |> create true + calc (*) x1 x2 + |> Expect.equal "should be None" None + } + // multiplication of two values, the first is None + // and the second is Some 1 should return None + test "x1 = None and x2 = Some 1" { + let x1 = None |> create true + let x2 = Some 1N |> create true + calc (*) x1 x2 + |> Expect.equal "should be None" None + } + // multiplication of two values, the first is Some 1 + // and the second is Some 1 should return Some 1 + test "x1 = Some 1 and x2 = Some 1" { + let x1 = Some 1N |> create true + let x2 = Some 1N |> create true + calc (*) x1 x2 + |> Expect.equal "should be Some 1" (Some 1N |> create true |> Some) + } + // multiplication of two values, the first is Some 1 + // and the second is Some 2 should return Some 2. + // When the first value is exclusive, the result should be exclusive + test "x1 = Some 1, excl and x2 = Some 2, incl" { + let x1 = Some 1N |> create false + let x2 = Some 2N |> create true + calc (*) x1 x2 + |> Expect.equal "should be Some 2, exclusive" (Some 2N |> create false |> Some) + } + // multiplication of two values, the first is Some 1 + // and the second is Some 2 should return Some 2. + // When the both values are exclusive, the result should be exclusive + test "x1 = Some 1, excl and x2 = Some 2, excl" { + let x1 = Some 1N |> create false + let x2 = Some 2N |> create false + calc (*) x1 x2 + |> Expect.equal "should be Some 2, exclusive" (Some 2N |> create false |> Some) + } + // multiplication of two values and the first value is Some 0 and + // the second value is None, results in Some 0 with ZeroUnit! + test "x1 = Some 0 and x2 = None" { + let x1 = Some 0N |> create true + let x2 = None |> create true + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (*) x1 x2 + |> Expect.equal "should be Some 0" ((Some zero, true) |> Some) + } + // multiplication of two values and the first value is None and + // the second value is Some 0, results in Some 0 with ZeroUnit! + test "x1 = None and x2 = Some 0" { + let x2 = Some 0N |> create true + let x1 = None |> create true + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (*) x1 x2 + |> Expect.equal "should be Some 0" ((Some zero, true) |> Some) + } + // multiplication of two values and the first value is Some 0 excl and + // the second value is None, results in Some 0 with ZeroUnit, excl! + test "x1 = Some 0, excl and x2 = None, incl" { + let x1 = Some 0N |> create false + let x2 = None |> create true + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (*) x1 x2 + |> Expect.equal "should be Some 0, excl" ((Some zero, false) |> Some) + } + // multiplication of two values and the first value is Some 0 incl and + // the second value is None excl, results in Some 0 with ZeroUnit, incl! + test "x1 = Some 0, incl and x2 = None, excl" { + let x1 = Some 0N |> create true + let x2 = None |> create false + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (*) x1 x2 + |> Expect.equal "should be Some 0, incl" ((Some zero, true) |> Some) + } + ] + + testList "Division" [ + // division of two values, both are None + // should return None + test "x1 = None and x2 = None" { + let x1 = None |> create true + let x2 = None |> create true + calc (/) x1 x2 + |> Expect.equal "should be None" None + } + // division of two values, the first is Some 0 + // and the second is None should return Some 0 + // with zero unit + test "x1 = Some 0 and x2 = None" { + let x1 = Some 0N |> create true + let x2 = None |> create true + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (/) x1 x2 + |> Expect.equal "should be Some 0" ((Some zero, true) |> Some) + } + // division of two values, the first is Some 0, excl + // and the second is None should return Some 0 + // with zero unit, excl + test "x1 = Some 0, excl and x2 = None" { + let x1 = Some 0N |> create false + let x2 = None |> create true + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (/) x1 x2 + |> Expect.equal "should be Some 0" ((Some zero, false) |> Some) + } + // division of two values, the first is Some 1 + // and the second is None should return Some 0, excl + // with ZeroUnit + test "x1 = Some 1 and x2 = None" { + let x1 = Some 1N |> create true + let x2 = None |> create true + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (/) x1 x2 + |> Expect.equal "should be Some 0, excl" ((Some zero, false) |> Some) + + let x1 = Some 1N |> create false + let x2 = None |> create true + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (/) x1 x2 + |> Expect.equal "should be Some 0, excl" ((Some zero, false) |> Some) + + let x1 = Some 1N |> create true + let x2 = None |> create false + let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit + calc (/) x1 x2 + |> Expect.equal "should be Some 0, excl" ((Some zero, false) |> Some) + } + // division of two values, the first is Some 1 and the + // second value is Zero incl, should throw a DivideByZeroException + // whatever the first value is + test "x1 = Some 1 and x2 = Some 0, incl" { + let x1 = Some 1N |> create true + let x2 = Some 0N |> create true + Expect.throws "should throw DivideByZeroException" (fun () -> calc (/) x1 x2 |> ignore) + + let x1 = None, true + let x2 = Some 0N |> create true + Expect.throws "should throw DivideByZeroException" (fun () -> calc (/) x1 x2 |> ignore) + + let x1 = Some 0N |> create true + let x2 = Some 0N |> create true + Expect.throws "should throw DivideByZeroException" (fun () -> calc (/) x1 x2 |> ignore) + + let x1 = Some 0N |> create false + let x2 = Some 0N |> create true + Expect.throws "should throw DivideByZeroException" (fun () -> calc (/) x1 x2 |> ignore) + } + // division by a value that approaches zero, should + // return None, whatever the first value is + test "x1 = Some 1 and x2 = Some 0, excl" { + let x1 = Some 1N |> create true + let x2 = Some 0N |> create false + Expect.equal "should return None" None (calc (/) x1 x2) + + let x1 = None, false + let x2 = Some 0N |> create false + Expect.equal "should return None" None (calc (/) x1 x2) + + let x1 = Some 0N |> create true + let x2 = Some 0N |> create false + Expect.equal "should return None" None (calc (/) x1 x2) + + let x1 = Some 0N |> create false + let x2 = Some 0N |> create false + Expect.equal "should return None" None (calc (/) x1 x2) + } + ] + + testList "Addition" [ + // addition of two values, both are None + // should return None + test "x1 = None and x2 = None" { + let x1 = None |> create true + let x2 = None |> create true + calc (+) x1 x2 + |> Expect.equal "should be None" None + } + // addition of two values, the first is Some 1 + // and the second is None should return None + test "x1 = Some 1 and x2 = None" { + let x1 = Some 1N |> create true + let x2 = None |> create true + calc (+) x1 x2 + |> Expect.equal "should be None" None + } + // addition of two values, the first is None + // and the second is Some 1 should return None + test "x1 = None and x2 = Some 1" { + let x1 = None |> create true + let x2 = Some 1N |> create true + calc (+) x1 x2 + |> Expect.equal "should be None" None + } + // addition of two values, the first is Some 1 + // and the second is Some 1 should return Some 2 + test "x1 = Some 1 and x2 = Some 1" { + let x1 = Some 1N |> create true + let x2 = Some 1N |> create true + calc (+) x1 x2 + |> Expect.equal "should be Some 2" (Some 2N |> create true |> Some) + } + // addition of two values, the first is Some 1 + // and the second is Some 2 should return Some 3. + // When the first value is exclusive, the result should be exclusive + test "x1 = Some 1, excl and x2 = Some 2, incl" { + let x1 = Some 1N |> create false + let x2 = Some 2N |> create true + calc (+) x1 x2 + |> Expect.equal "should be Some 3, exclusive" (Some 3N |> create false |> Some) + } + // addition of two values, the first is Some 1, incl + // and the second is Zero incl should return Some 1, incl + test "x1 = Some 1, incl and x2 = Some 0, incl" { + let x1 = Some 1N |> create true + let x2 = Some 0N |> create true + calc (+) x1 x2 + |> Expect.equal "should be Some 1, incl" (x1 |> Some) + } + // addition of two values, the first is Some 1, excl + // and the second is Zero incl should return Some 1, excl + test "x1 = Some 1, excl and x2 = Some 0, incl" { + let x1 = Some 1N |> create false + let x2 = Some 0N |> create true + calc (+) x1 x2 + |> Expect.equal "should be Some 1, excl" (x1 |> Some) + } + // addition of two values, the first is Some 1, incl + // and the second is Zero excl should return Some 1, excl + test "x1 = Some 1, incl and x2 = Some 0, excl" { + let x1 = Some 1N |> create true + let x2 = Some 0N |> create false + calc (+) x1 x2 + |> Expect.equal "should be Some 1, incl" (Some 1N |> create false |> Some) + } + // addition of two values, the first is Some 1, excl + // and the second is Zero excl should return Some 1, excl + test "x1 = Some 1, excl and x2 = Some 0, excl" { + let x1 = Some 1N |> create false + let x2 = Some 0N |> create false + calc (+) x1 x2 + |> Expect.equal "should be Some 1, excl" (x1 |> Some) + } + ] ] - testList "Division" [ - // division of two values, both are None - // should return None - test "x1 = None and x2 = None" { - let x1 = None |> create true - let x2 = None |> create true - calc (/) x1 x2 - |> Expect.equal "should be None" None - } - // division of two values, the first is Some 0 - // and the second is None should return Some 0 - // with zero unit - test "x1 = Some 0 and x2 = None" { - let x1 = Some 0N |> create true - let x2 = None |> create true - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (/) x1 x2 - |> Expect.equal "should be Some 0" ((Some zero, true) |> Some) - } - // division of two values, the first is Some 0, excl - // and the second is None should return Some 0 - // with zero unit, excl - test "x1 = Some 0, excl and x2 = None" { - let x1 = Some 0N |> create false - let x2 = None |> create true - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (/) x1 x2 - |> Expect.equal "should be Some 0" ((Some zero, false) |> Some) - } - // division of two values, the first is Some 1 - // and the second is None should return Some 0, excl - // with ZeroUnit - test "x1 = Some 1 and x2 = None" { - let x1 = Some 1N |> create true - let x2 = None |> create true - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (/) x1 x2 - |> Expect.equal "should be Some 0, excl" ((Some zero, false) |> Some) - - let x1 = Some 1N |> create false - let x2 = None |> create true - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (/) x1 x2 - |> Expect.equal "should be Some 0, excl" ((Some zero, false) |> Some) - - let x1 = Some 1N |> create true - let x2 = None |> create false - let zero = 0N |> ValueUnit.singleWithUnit ZeroUnit - calc (/) x1 x2 - |> Expect.equal "should be Some 0, excl" ((Some zero, false) |> Some) - } - // division of two values, the first is Some 1 and the - // second value is Zero incl, should throw a DivideByZeroException - // whatever the first value is - test "x1 = Some 1 and x2 = Some 0, incl" { - let x1 = Some 1N |> create true - let x2 = Some 0N |> create true - Expect.throws "should throw DivideByZeroException" (fun () -> calc (/) x1 x2 |> ignore) - - let x1 = None, true - let x2 = Some 0N |> create true - Expect.throws "should throw DivideByZeroException" (fun () -> calc (/) x1 x2 |> ignore) - - let x1 = Some 0N |> create true - let x2 = Some 0N |> create true - Expect.throws "should throw DivideByZeroException" (fun () -> calc (/) x1 x2 |> ignore) - - let x1 = Some 0N |> create false - let x2 = Some 0N |> create true - Expect.throws "should throw DivideByZeroException" (fun () -> calc (/) x1 x2 |> ignore) - } - // division by a value that approaches zero, should - // return None, whatever the first value is - test "x1 = Some 1 and x2 = Some 0, excl" { - let x1 = Some 1N |> create true - let x2 = Some 0N |> create false - Expect.equal "should return None" None (calc (/) x1 x2) - - let x1 = None, false - let x2 = Some 0N |> create false - Expect.equal "should return None" None (calc (/) x1 x2) - - let x1 = Some 0N |> create true - let x2 = Some 0N |> create false - Expect.equal "should return None" None (calc (/) x1 x2) - - let x1 = Some 0N |> create false - let x2 = Some 0N |> create false - Expect.equal "should return None" None (calc (/) x1 x2) - } - ] - - testList "Addition" [ - // addition of two values, both are None - // should return None - test "x1 = None and x2 = None" { - let x1 = None |> create true - let x2 = None |> create true - calc (+) x1 x2 - |> Expect.equal "should be None" None - } - // addition of two values, the first is Some 1 - // and the second is None should return None - test "x1 = Some 1 and x2 = None" { - let x1 = Some 1N |> create true - let x2 = None |> create true - calc (+) x1 x2 - |> Expect.equal "should be None" None - } - // addition of two values, the first is None - // and the second is Some 1 should return None - test "x1 = None and x2 = Some 1" { - let x1 = None |> create true - let x2 = Some 1N |> create true - calc (+) x1 x2 - |> Expect.equal "should be None" None - } - // addition of two values, the first is Some 1 - // and the second is Some 1 should return Some 2 - test "x1 = Some 1 and x2 = Some 1" { - let x1 = Some 1N |> create true - let x2 = Some 1N |> create true - calc (+) x1 x2 - |> Expect.equal "should be Some 2" (Some 2N |> create true |> Some) - } - // addition of two values, the first is Some 1 - // and the second is Some 2 should return Some 3. - // When the first value is exclusive, the result should be exclusive - test "x1 = Some 1, excl and x2 = Some 2, incl" { - let x1 = Some 1N |> create false - let x2 = Some 2N |> create true - calc (+) x1 x2 - |> Expect.equal "should be Some 3, exclusive" (Some 3N |> create false |> Some) - } - // addition of two values, the first is Some 1, incl - // and the second is Zero incl should return Some 1, incl - test "x1 = Some 1, incl and x2 = Some 0, incl" { - let x1 = Some 1N |> create true - let x2 = Some 0N |> create true - calc (+) x1 x2 - |> Expect.equal "should be Some 1, incl" (x1 |> Some) - } - // addition of two values, the first is Some 1, excl - // and the second is Zero incl should return Some 1, excl - test "x1 = Some 1, excl and x2 = Some 0, incl" { - let x1 = Some 1N |> create false - let x2 = Some 0N |> create true - calc (+) x1 x2 - |> Expect.equal "should be Some 1, excl" (x1 |> Some) - } - // addition of two values, the first is Some 1, incl - // and the second is Zero excl should return Some 1, excl - test "x1 = Some 1, incl and x2 = Some 0, excl" { - let x1 = Some 1N |> create true - let x2 = Some 0N |> create false - calc (+) x1 x2 - |> Expect.equal "should be Some 1, incl" (Some 1N |> create false |> Some) - } - // addition of two values, the first is Some 1, excl - // and the second is Zero excl should return Some 1, excl - test "x1 = Some 1, excl and x2 = Some 0, excl" { - let x1 = Some 1N |> create false - let x2 = Some 0N |> create false - calc (+) x1 x2 - |> Expect.equal "should be Some 1, excl" (x1 |> Some) - } + testList "calc min max" [ + let createMin = MinimumTests.create + let createMax = MaximumTests.create + + testList "Multiplication" [ + let mult = MinMaxCalculator.multiplication + + // multiplication of two ranges with min1 and max1 + // both None and min2 and max2 both None should return None + test "min1 = None and max1 = None, min2 = None and max2 = None" { + let min1 = None |> create true + let max1 = None |> create true + let min2 = None |> create true + let max2 = None |> create true + mult min1 max1 min2 max2 + |> Expect.equal "should be None, None" (None, None) + } + + // multiplication of two ranges with min1 = Some 1 and max1 + // is None and min2 and max2 both None should return None + test "min1 = Some 1 and max1 = None, min2 = None and max2 = None" { + let min1 = Some 1N |> create true + let max1 = None |> create true + let min2 = None |> create true + let max2 = None |> create true + mult min1 max1 min2 max2 + |> Expect.equal "should be None, None" (None, None) + } + + // multiplication of two ranges with min1 = None and max1 + // is Some 1 and min2 and max2 both None should return None + test "min1 = None and max1 = Some 1, min2 = None and max2 = None" { + let min1 = None |> create true + let max1 = Some 1N |> create true + let min2 = None |> create true + let max2 = None |> create true + mult min1 max1 min2 max2 + |> Expect.equal "should be None, None" (None, None) + } + + // multiplication of two ranges with min1 = Some 1 and max1 + // is Some 1 and min2 and max2 both None should return None, None + test "min1 = Some 1 and max1 = Some 1, min2 = None and max2 = None" { + let min1 = Some 1N |> create true + let max1 = Some 1N |> create true + let min2 = None |> create true + let max2 = None |> create true + let expMin = None + let expMax = None + mult min1 max1 min2 max2 + |> Expect.equal "should be None, None" (expMin, expMax) + } + + // multiplication of two ranges with min1 = Some 1 and max1 + // is None and min2 = Some 2 and max2 = None should return Some Minimum 2, None + test "min1 = Some 1 and max1 = None, min2 = Some 2 and max2 = None" { + let min1 = Some 1N |> create true + let max1 = None |> create true + let min2 = Some 2N |> create true + let max2 = None |> create true + let expMin = 2N |> createMin true |> Some + let expMax = None + mult min1 max1 min2 max2 + |> Expect.equal "should be Some 2, None" (expMin, expMax) + } + + // multiplication of two ranges with min1 = Some 1 and max1 + // is None and min2 = None and max2 = Some 2 should return None, None + test "min1 = Some 1 and max1 = None, min2 = None and max2 = Some 2" { + let min1 = Some 1N |> create true + let max1 = None |> create true + let min2 = None |> create true + let max2 = Some 2N |> create true + let expMin = None + let expMax = None + mult min1 max1 min2 max2 + |> Expect.equal "should be None, None" (expMin, expMax) + } + + // multiplication of two ranges with min1 = Some 1 and max1 + // is None and min2 = Some 2 and max2 = Some 3 should return Some Minimum 2, None + test "min1 = Some 1 and max1 = None, min2 = Some 2 and max2 = Some 3" { + let min1 = Some 1N |> create true + let max1 = None |> create true + let min2 = Some 2N |> create true + let max2 = Some 3N |> create true + let expMin = 2N |> createMin true |> Some + let expMax = None + mult min1 max1 min2 max2 + |> Expect.equal "should be Some 2, None" (expMin, expMax) + } + + // multiplication of two ranges with min1 = None and max1 + // is Some 1 and min2 = Some 2 and max2 = None should return None, None + test "min1 = None and max1 = Some 1, min2 = Some 2 and max2 = None" { + let min1 = None |> create true + let max1 = Some 1N |> create true + let min2 = Some 2N |> create true + let max2 = None |> create true + let expMin = None + let expMax = None + mult min1 max1 min2 max2 + |> Expect.equal "should be None, None" (expMin, expMax) + } + + // multiplication of two ranges with min1 = None and max1 + // is Some 1 and min2 = None and max2 = Some 2 should return None, None + test "min1 = None and max1 = Some 1, min2 = None and max2 = Some 2" { + let min1 = None |> create true + let max1 = Some 1N |> create true + let min2 = None |> create true + let max2 = Some 2N |> create true + let expMin = None + let expMax = None + mult min1 max1 min2 max2 + |> Expect.equal "should be None, None" (expMin, expMax) + } + + // multiplication of two ranges with min1 = None and max1 + // is Some 1 and min2 = Some 2 and max2 = Some 3 should return None, Some Max 3 + test "min1 = None and max1 = Some 1, min2 = Some 2 and max2 = Some 3" { + let min1 = None |> create true + let max1 = Some 1N |> create true + let min2 = Some 2N |> create true + let max2 = Some 3N |> create true + let expMin = None + let expMax = 3N |> createMax true |> Some + mult min1 max1 min2 max2 + |> Expect.equal "should be None, None" (expMin, expMax) + } + + // multiplication of two ranges with min1 = Some 1 and max1 + // is Some 2 and min2 = Some 2 and max2 = Some 3 should return Some Min 2, Some Max 6 + test "min1 = Some 1 and max1 = Some 2, min2 = Some 2 and max2 = Some 3" { + let min1 = Some 1N |> create true + let max1 = Some 2N |> create true + let min2 = Some 2N |> create true + let max2 = Some 3N |> create true + let expMin = 2N |> createMin true |> Some + let expMax = 6N |> createMax true |> Some + mult min1 max1 min2 max2 + |> Expect.equal "should be Some 2, Some 6" (expMin, expMax) + } + ] ] ] + + module ValueRange = Variable.ValueRange @@ -966,6 +1118,7 @@ module Tests = open ValueRange.Operators + let tests = testList "valuerange" [ @@ -1016,6 +1169,36 @@ module Tests = |> Generators.testProp "is always multiple of none incr" ] + testList "calculation with ValueRange" [ + let calc = ValueRange.calc true + + test "when any operator is applied to x1 = Unrestricted and x2 = Unrestricted" { + let x1 = ValueRange.Unrestricted + let x2 = ValueRange.Unrestricted + [ + calc (+) (x1, x2) + calc (-) (x1, x2) + calc (*) (x1, x2) + calc (/) (x1, x2) + ] + |> List.forall (fun x -> x = ValueRange.Unrestricted) + |> Expect.isTrue "should all be Unrestricted" + } + + test "when any operator is applied to x1 = Zero and x2 = Unrestricted" { + let x1 = 0N |> ValueUnit.singleWithUnit Units.Count.times |> ValueRange.createValSet + let x2 = ValueRange.Unrestricted + [ + calc (+) (x1, x2) + calc (-) (x1, x2) + calc (*) (x1, x2) + calc (/) (x1, x2) + ] + |> List.forall (fun x -> x = ValueRange.Unrestricted) + |> Expect.isTrue "should all be Unrestricted" + } + ] + testList "valuerange set min incr max" [ test "smaller max can be set" { @@ -1375,77 +1558,80 @@ Tests.tests |> Expecto.run - - -open MathNet.Numerics - open Informedica.Utils.Lib.BCL open Informedica.GenUnits.Lib open Informedica.GenSolver.Lib -let mg = Units.Mass.milliGram -let day = Units.Time.day -let kg = Units.Weight.kiloGram -let mgPerDay = CombiUnit(mg, OpPer, day) -let mgPerKgPerDay = (CombiUnit (mg, OpPer, kg), OpPer, day) |> CombiUnit -let frq = Units.Count.times |> Units.per day -let mL = Units.Volume.milliLiter -let x = Units.Count.times -let min = Units.Time.minute -let hr = Units.Time.hour -let mcg = Units.Mass.microGram -let mcgPerKgPerMin = - mcg |> Units.per kg |> Units.per min -let mcgPerMin = mcg |> Units.per min -let mcgPerHour = - mcg |> Units.per hr -let piece = Units.General.general "stuk" - - -module ValueRange = Variable.ValueRange -module Minimum = Variable.ValueRange.Minimum -module Maximum = Variable.ValueRange.Maximum -module Increment = Variable.ValueRange.Increment - - -// This variable: -// [1.amikacine.injectievloeistof.amikacine]_dos_qty [170079/500 mg..267/500;25 mg..50997/100 mg] -// cannot be set with this range:[170079/500 mg..267/500 mg..50997/100 mg] - -let min1 = [| 170079N/500N |] |> ValueUnit.create Units.Mass.milliGram |> Minimum.create true -let incr1 = - [| - 267N/500N - 25N - |] |> ValueUnit.create Units.Mass.milliGram |> Increment.create -let max1 = [| 50997N/100N |] |> ValueUnit.create Units.Mass.milliGram |> Maximum.create true -let vr1 = (min1, incr1, max1) |> MinIncrMax -vr1 |> ValueRange.toString false - -let min2 = [| 170079N/500N |] |> ValueUnit.create Units.Mass.milliGram |> Minimum.create true -let incr2 = - [| - 267N/500N - |] |> ValueUnit.create Units.Mass.milliGram |> Increment.create -let max2 = [| 50997N/100N |] |> ValueUnit.create Units.Mass.milliGram |> Maximum.create true -let vr2 = (min2, incr2, max2) |> MinIncrMax -vr2 |> ValueRange.toString false - -vr1 |> ValueRange.applyExpr true (incr2 |> Types.ValueRange.Incr) - -min1 |> Minimum.multipleOf incr2 -max1 |> Maximum.multipleOf incr2 - -vr1 |> ValueRange.setIncr true incr2 - -incr1 |> Increment.restrict incr2 - - -incr2 |> Increment.toValueUnit -|> ValueUnit.filter (fun i1 -> - (incr1 |> Increment.toValueUnit) - |> ValueUnit.getBaseValue - |> Array.exists (fun i2 -> i1 |> BigRational.isMultiple i2) -) -//|> ValueUnit.toUnit - +let min1Options = [None, true; Some -2, true; Some -2, false; Some 0, true; Some 0, false; Some 2, true; Some 2, false] +let max1Options = [None, true; Some -1, true; Some -1, false; Some 0, true; Some 0, false; Some 3, true; Some 3, false] +let min2Options = [None, true; Some -2, true; Some -2, false; Some 0, true; Some 0, false; Some 3, true; Some 3, false] +let max2Options = [None, true; Some -1, true; Some -1, false; Some 0, true; Some 0, false; Some 5, true; Some 5, false] + +let validPermutations = + [ + for min1 in min1Options do + for max1 in max1Options do + for min2 in min2Options do + for max2 in max2Options do + match min1, max1, min2, max2 with + | (None, _), _, (None, _), _ + | _, (None, _), (None, _), _ + | (None, _), _, _, (None, _) + | _, (None, _), _, (None, _) -> yield min1, max1, min2, max2 + | (Some min1', _), (Some max1', _), (Some min2', _), (Some max2', _) when min1' <= max1' && min2' <= max2' -> + yield (min1, max1, min2, max2) + | (Some min1', _), (Some max1', _), (None, _), _ + | (Some min1', _), (Some max1', _), _, (None, _) when min1' <= max1' -> + yield (min1, max1, min2, max2) + | (None, _), _, (Some min2', _), (Some max2', _) + | _, (None, _), (Some min2', _), (Some max2', _) when min2' <= max2' -> + yield (min1, max1, min2, max2) + | _ -> () + ] + |> List.distinct + + +let mult = Variable.ValueRange.MinMaxCalculator.multiplication +let div = Variable.ValueRange.MinMaxCalculator.division +let add = Variable.ValueRange.MinMaxCalculator.addition +let sub = Variable.ValueRange.MinMaxCalculator.subtraction + + +let createVuOpt (intOpt, b) = + intOpt + |> Option.map BigRational.fromInt + |> Option.map (fun i -> + i + |> ValueUnit.singleWithUnit Units.Count.times), b + + +let printTests op opStr= + validPermutations + |> List.iteri (fun i (min1, max1, min2, max2) -> + let printLeft left = if left |> snd then "[" else "<" + let printRight right = if right |> snd then "]" else ">" + let printVal v = v |> fst |> Option.map string |> Option.defaultValue "" + + let result = + try + op + (min1 |> createVuOpt) + (max1 |> createVuOpt) + (min2 |> createVuOpt) + (max2 |> createVuOpt) + |> fun (min, max) -> Variable.ValueRange.create true min None max None + |> Variable.ValueRange.toString true + |> String.replace "x" "" + |> String.replace "<" "< " + |> String.replace ">" " >" + with + | _ -> "failed" + + printfn $"%i{i}, {min1 |> printLeft} {min1 |> printVal} .. {max1 |> printVal} {max1 |> printRight}, {opStr}, {min2 |> printLeft} {min2 |> printVal} .. {max2 |> printVal} {max2 |> printRight}, =, {result}" + ) + + +printTests mult "x" +printTests div "/" +printTests add "+" +printTests sub "-" diff --git a/src/Informedica.GenSolver.Lib/Variable.fs b/src/Informedica.GenSolver.Lib/Variable.fs index 261c2b7..f607022 100644 --- a/src/Informedica.GenSolver.Lib/Variable.fs +++ b/src/Informedica.GenSolver.Lib/Variable.fs @@ -2529,6 +2529,7 @@ module Variable = let calcMax = calc Maximum.create + /// get the smallest minimum let minimize min1 min2 = match min1, min2 with | None, None -> None @@ -2542,6 +2543,7 @@ module Variable = |> Some + /// get the largest maximum let maximize max1 max2 = match max1, max2 with | None, None -> None @@ -2557,7 +2559,6 @@ module Variable = /// Match a min, max tuple **min**, **max** /// to: - /// /// * `PP`: both positive /// * `NN`: both negative /// * `NP`: one negative, the other positive @@ -2743,9 +2744,8 @@ module Variable = /// Doesn't perform any calculation when both /// **x1** and **x2** are `Unrestricted`. let calc onlyMinIncrMax op (x1, x2) = - //printfn "start valuerange calc" + let calcMinMax min1 max1 min2 max2 = - //printfn "start minmax calc" let getMin m = let incl = match m with diff --git a/tests/Informedica.GenSolver.Tests/Tests.fs b/tests/Informedica.GenSolver.Tests/Tests.fs index efc3115..3edfa82 100644 --- a/tests/Informedica.GenSolver.Tests/Tests.fs +++ b/tests/Informedica.GenSolver.Tests/Tests.fs @@ -26,7 +26,7 @@ module Generators = n / d - let bigRGenOpt (n, d) = bigRGen (n, 1) |> Some + let bigRGenOpt (n, _) = bigRGen (n, 1) |> Some let bigRGenerator = @@ -94,14 +94,8 @@ module Expecto = module TestSolver = - open System - open System.IO - open Informedica.GenUnits.Lib open Informedica.GenSolver.Lib - open Informedica.Utils.Lib.BCL - open MathNet.Numerics - open Types module Api = Informedica.GenSolver.Lib.Api module Solver = Informedica.GenSolver.Lib.Solver