Skip to content

Commit

Permalink
refact: removed unnecessary onlyMinIncrMax and added comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Casper Bollen authored and Casper Bollen committed Oct 29, 2023
1 parent 1ba0398 commit 385d105
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 50 deletions.
2 changes: 1 addition & 1 deletion src/Informedica.GenOrder.Lib/OrderVariable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ module OrderVariable =
else
vr
|> ValueRange.setOptVs ovar.Constraints.Values
|> Variable.setValueRange true ovar.Variable
|> Variable.setValueRange ovar.Variable
}


Expand Down
66 changes: 50 additions & 16 deletions src/Informedica.GenSolver.Lib/Api.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ module Api =
module Name = Variable.Name


/// Initialize the solver returning a set of equations
/// <summary>
/// Create a list of Equations from a list of strings
/// </summary>
/// <param name="eqs">List of strings</param>
/// <returns>List of Equations</returns>
let init eqs =
let notEmpty = String.IsNullOrWhiteSpace >> not
let prodEqs, sumEqs = eqs |> List.partition (String.contains "*")
Expand All @@ -34,48 +38,70 @@ module Api =
(parse prodEqs '*' |> createProdEqs) @ (parse sumEqs '+' |> createSumEqs)


let setVariableValues onlyMinIncrMax n p eqs =
/// <summary>
/// Apply a variable property to a list of equations
/// </summary>
/// <param name="n">Name of the variable</param>
/// <param name="p">Property of the variable</param>
/// <param name="eqs">List of equations</param>
/// <returns>The variable option where the property is applied to</returns>
/// <remarks>
/// The combination of n and p is equal to a constraint
/// </remarks>
let setVariableValues n p eqs =
eqs
|> List.collect (Equation.findName n)
|> function
| [] -> None
| var::_ ->
p
|> Property.toValueRange
|> Variable.setValueRange onlyMinIncrMax var
|> Variable.setValueRange var
|> Some


/// Solve an `Equations` list
let solveAll = Solver.solveAll


/// <summary>
/// Solve an `Equations` list with
///
/// * f: function used to process string message
/// * n: the name of the variable to be updated
/// * p: the property of the variable to be updated
/// * vs: the values to update the property of the variable
/// * eqs: the list of equations to solve
/// </summary>
/// <param name="onlyMinIncrMax">True if only min, incr and max values are to be used</param>
/// <param name="sortQue">The algorithm to sort the equations</param>
/// <param name="log">The logger to log operations</param>
/// <param name="n">Name of the variable to be updated</param>
/// <param name="p">Property of the variable to be updated</param>
/// <param name="eqs">List of equations to solve</param>
/// <returns>A result type of the solved equations</returns>
let solve onlyMinIncrMax sortQue log n p eqs =
eqs
|> setVariableValues onlyMinIncrMax n p
|> setVariableValues n p
|> function
| None -> eqs |> Ok
| Some var ->
eqs
|> Solver.solveVariable onlyMinIncrMax log sortQue var


/// Make a list of `EQD`
/// to contain only positive
/// values as solutions
/// <summary>
/// Set all variables in a list of equations to a non zero or negative value
/// </summary>
/// <param name="eqs">The list of Equations</param>
let nonZeroNegative eqs =
eqs
|> List.map Equation.nonZeroOrNegative


let applyConstraints onlyMinIncrMax log eqs cs =
let apply = Constraint.apply onlyMinIncrMax log
/// <summary>
/// Apply a list of constraints to a list of equations
/// </summary>
/// <param name="log">The logger to log operations</param>
/// <param name="eqs">A list of Equations</param>
/// <param name="cs">A list of constraints</param>
/// <returns>A list of Equations</returns>
let applyConstraints log eqs cs =
let apply = Constraint.apply log

cs
|> List.fold (fun acc c ->
Expand All @@ -87,8 +113,16 @@ module Api =
) eqs


/// <summary>
/// Solve a list of equations using a list of constraints
/// </summary>
/// <param name="onlyMinIncrMax">True if only min, incr and max values are to be used</param>
/// <param name="log">The logger to log operations</param>
/// <param name="eqs">A list of Equations</param>
/// <param name="cs">A list of constraints</param>
/// <returns>A list of Equations</returns>
let solveConstraints onlyMinIncrMax log cs eqs =
cs
|> Constraint.orderConstraints log
|> applyConstraints false log eqs
|> applyConstraints log eqs
|> Solver.solveAll onlyMinIncrMax log
39 changes: 36 additions & 3 deletions src/Informedica.GenSolver.Lib/Constraint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,23 @@ module Constraint =
module Name = Variable.Name


/// <summary>
/// Check whether constraint c1 has the same name as constraint c2.
/// </summary>
let eqsName (c1 : Constraint) (c2 : Constraint) = c1.Name = c2.Name


/// <summary>
/// Print the constraint as a string
/// </summary>
let toString { Name = n; Property = p } = $"{n |> Name.toString}: {p}"


/// <summary>
/// Give a constraint a score based on the property.
/// Low scores should be solved first.
/// </summary>
/// <param name="c">The constraint</param>
let scoreConstraint c =
match c.Property with
| ValsProp vs ->
Expand All @@ -29,6 +40,11 @@ module Constraint =
| _ -> -2, c


/// <summary>
/// Order constraints based on their score.
/// </summary>
/// <param name="log">The logger to log operations</param>
/// <param name="cs">The list of constraints</param>
let orderConstraints log cs =
cs
// calc min and max from valsprop constraints
Expand Down Expand Up @@ -63,7 +79,15 @@ module Constraint =
|> List.map snd


let apply onlyMinIncrMax log (c : Constraint) eqs =
/// <summary>
/// Apply a constraint to the matching variables
/// in the list of equations.
/// </summary>
/// <param name="log">The logger</param>
/// <param name="c">The constraint</param>
/// <param name="eqs">The list of Equations</param>
/// <returns>The variable the constraint is applied to</returns>
let apply log (c : Constraint) eqs =

eqs
|> List.collect (Equation.findName c.Name)
Expand All @@ -76,7 +100,7 @@ module Constraint =
| vr::_ ->
c.Property
|> Property.toValueRange
|> Variable.setValueRange onlyMinIncrMax vr
|> Variable.setValueRange vr
|> fun var ->
c
|> Events.ConstraintApplied
Expand All @@ -85,8 +109,17 @@ module Constraint =
var


/// <summary>
/// Apply a constraint to the matching variables and solve the
/// list of equations.
/// </summary>
/// <param name="onlyMinIncrMax">Whether only min incr max should be calculated</param>
/// <param name="log">The logger</param>
/// <param name="sortQue">The algorithm to sort the equations</param>
/// <param name="c">The constraint</param>
/// <param name="eqs">The list of Equations</param>
let solve onlyMinIncrMax log sortQue (c : Constraint) eqs =
let var = apply onlyMinIncrMax log c eqs
let var = apply log c eqs

eqs
|> Solver.solveVariable onlyMinIncrMax log sortQue var
Expand Down
4 changes: 1 addition & 3 deletions src/Informedica.GenSolver.Lib/Equation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,6 @@ module Equation =
| y::xs ->
y |> op2 <| (xs |> List.reduce op1)
|> Some
// select the right application operator
let (<==) = if onlyMinIncrMax then (@<-) else (^<-)
// perform the calculations on the vars
let calcVars op1 op2 vars =
vars
Expand Down Expand Up @@ -365,7 +363,7 @@ module Equation =

None
| Some var ->
let yNew = y <== var
let yNew = y @<- var

if yNew <> y then
// log finishing the calculation
Expand Down
42 changes: 33 additions & 9 deletions src/Informedica.GenSolver.Lib/Solver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,27 @@ module Solver =
, rst


let sortQue onlyMinMax que =
if que |> List.length = 0 then que
/// <summary>
/// Sort a list of equations by the number of
/// total values in the equation.
/// </summary>
/// <param name="onlyMinMax">Whether only min incr max is calculated</param>
/// <param name="eqs">The list of Equations</param>
let sortQue onlyMinMax eqs =
if eqs |> List.length = 0 then eqs
else
que
eqs
|> List.sortBy (Equation.count onlyMinMax) //Equation.countProduct


/// Create the equation solver using a
/// product equation and a sum equation solver
/// and function to determine whether an
/// equation is solved
/// <summary>
/// Solve a set of equations.
/// </summary>
/// <param name="onlyMinIncrMax">Whether to only use min, incr and max</param>
/// <param name="log">The log function</param>
/// <param name="sortQue">The sort function for the que</param>
/// <param name="var">An option variable to solve for</param>
/// <param name="eqs">The equations to solve</param>
let solve onlyMinIncrMax log sortQue var eqs =

let solveE n eqs eq =
Expand Down Expand Up @@ -222,7 +232,14 @@ module Solver =
Error (eqs, m)


//TODO: need to clean up the number check
/// <summary>
/// Solve a set of equations for a specific variable.
/// </summary>
/// <param name="onlyMinIncrMax">Whether to only use min, incr and max</param>
/// <param name="log">The log function</param>
/// <param name="sortQue">The sort function for the que</param>
/// <param name="vr">The variable to solve for</param>
/// <param name="eqs">The equations to solve</param>
let solveVariable onlyMinIncrMax log sortQue vr eqs =
let n1 = eqs |> List.length
let solve =
Expand All @@ -231,12 +248,18 @@ module Solver =
match solve eqs with
| Error (eqs, errs) -> Error (eqs, errs)
| Ok eqs ->
//TODO: need to clean up the number check
let n2 = eqs |> List.length
if n2 <> n1 then failwith $"not the same number of eqs, was: {n1}, now {n2}"
else Ok eqs


//TODO: need to clean up the number check
/// <summary>
/// Solve a set of equations for all variables.
/// </summary>
/// <param name="onlyMinIncrMax">Whether to only use min, incr and max</param>
/// <param name="log">The log function</param>
/// <param name="eqs">The equations to solve</param>
let solveAll onlyMinIncrMax log eqs =
let n1 = eqs |> List.length
let solve =
Expand All @@ -245,6 +268,7 @@ module Solver =
match solve eqs with
| Error (eqs, errs) -> Error (eqs, errs)
| Ok eqs ->
//TODO: need to clean up the number check
let n2 = eqs |> List.length
if n2 <> n1 then failwith $"not the same number of eqs, was: {n1}, now {n2}"
else Ok eqs
4 changes: 2 additions & 2 deletions src/Informedica.GenSolver.Lib/Types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ module rec Types =

/// <summary>
/// Represents a constraint on a `Variable`.
/// I.e. either a set of values, or an increment
/// or a minimum of maximum.
/// I.e. either a set of values, or an increment,
/// minimum or maximum.
/// </summary>
type Constraint =
{
Expand Down
22 changes: 7 additions & 15 deletions src/Informedica.GenSolver.Lib/Variable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2989,8 +2989,7 @@ module Variable =
/// </code>
/// </example>
let applyExpr y expr =
let appl _ get set vr =
//printfn $"{s}"
let appl get set vr =
match expr |> get with
| Some m -> vr |> set m
| None -> vr
Expand All @@ -3000,9 +2999,9 @@ module Variable =
| ValSet vs -> y |> setValueSet vs
| _ ->
y
|> appl "incr" getIncr setIncr
|> appl "min" getMin setMin
|> appl "max" getMax setMax
|> appl getIncr setIncr
|> appl getMin setMin
|> appl getMax setMax


module Operators =
Expand All @@ -3015,8 +3014,6 @@ module Variable =

let inline (^-) vr1 vr2 = calc false (-) (vr1, vr2)

let inline (^<-) vr1 vr2 = applyExpr vr1 vr2


let inline (@*) vr1 vr2 = calc true (*) (vr1, vr2)

Expand Down Expand Up @@ -3093,14 +3090,11 @@ module Variable =

/// Apply a `ValueRange` **vr** to
/// `Variable` **v**.
let setValueRange onlyMinIncrMax var vr =
let op =
if onlyMinIncrMax then (@<-) else (^<-)

let setValueRange var vr =
try
{ var with
Values =
(var |> get).Values |> op <| vr
(var |> get).Values @<- vr
}

with
Expand Down Expand Up @@ -3239,8 +3233,6 @@ module Variable =

let inline (^-) vr1 vr2 = calc (^-) (vr1, vr2)

let inline (^<-) vr1 vr2 = vr2 |> getValueRange |> setValueRange false vr1


let inline (@*) vr1 vr2 = calc (@*) (vr1, vr2)

Expand All @@ -3250,7 +3242,7 @@ module Variable =

let inline (@-) vr1 vr2 = calc (@-) (vr1, vr2)

let inline (@<-) vr1 vr2 = vr2 |> getValueRange |> setValueRange true vr1
let inline (@<-) vr1 vr2 = vr2 |> getValueRange |> setValueRange vr1


/// Constant 1
Expand Down
2 changes: 1 addition & 1 deletion tests/Informedica.GenSolver.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ module TestSolver =

let setProp n p eqs =
let n = n |> Name.createExc
match eqs |> Api.setVariableValues true n p with
match eqs |> Api.setVariableValues n p with
| Some var ->
eqs
|> List.map (fun e ->
Expand Down

0 comments on commit 385d105

Please sign in to comment.