From cfc1dd6fd3214d8b0b32f555a6c15ff2ba2dc809 Mon Sep 17 00:00:00 2001 From: Junaid Rasheed Date: Sat, 2 Dec 2023 13:53:59 +0000 Subject: [PATCH] Update docs --- README.md | 106 ++++++++++++++++++++---------------- src/Linear/Simplex/Types.hs | 2 +- 2 files changed, 59 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index f391970..e583f35 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The `Linear.Simplex.Solver.TwoPhase` module contain both phases of the two-phase Phase one is implemented by `findFeasibleSolution`: ```haskell -findFeasibleSolution :: [PolyConstraint] -> Maybe (DictionaryForm, [Integer], [Integer], Integer) +findFeasibleSolution :: (MonadIO m, MonadLogger m) => [PolyConstraint] -> m (Maybe FeasibleSystem) ``` `findFeasibleSolution` takes a list of `PolyConstraint`s. @@ -19,50 +19,65 @@ The `PolyConstraint` type, as well as other custom types required by this librar `PolyConstraint` is defined as: ```haskell -data PolyConstraint = - LEQ Vars Rational | - GEQ Vars Rational | - EQ Vars Rational deriving (Show, Eq); +data PolyConstraint + = LEQ {lhs :: VarLitMapSum, rhs :: SimplexNum} + | GEQ {lhs :: VarLitMapSum, rhs :: SimplexNum} + | EQ {lhs :: VarLitMapSum, rhs :: SimplexNum} + deriving (Show, Read, Eq, Generic) ``` -And `Vars` is defined as: +`SimplexNum` is an alias for `Rational`, and `VarLitMapSum` is an alias for `VarLitMap`, which is an alias for `Map Var SimplexNum`. +`Var` is an alias of `Int`. -```haskell -type Vars = [(Integer, Rational)] -``` +A `VarLitMapSum` is read as `Integer` variables mapped to their `Rational` coefficients, with an implicit `+` between each entry. +For example: `Map.fromList [(1, 2), (2, (-3)), (1, 3)]` is equivalent to `(2x1 + (-3x2) + 3x1)`. -A `Vars` is treated as a list of `Integer` variables mapped to their `Rational` coefficients, with an implicit `+` between each element in the list. -For example: `[(1, 2), (2, (-3)), (1, 3)]` is equivalent to `(2x1 + (-3x2) + 3x1)`. +And a `PolyConstraint` is an inequality/equality where the LHS is a `VarLitMapSum` and the RHS is a `Rational`. +For example: `LEQ (Map.fromList [(1, 2), (2, (-3)), (1, 3)] 60)` is equivalent to `(2x1 + (-3x2) + 3x1) <= 60`. -And a `PolyConstraint` is an inequality/equality where the LHS is a `Vars` and the RHS is a `Rational`. -For example: `LEQ [(1, 2), (2, (-3)), (1, 3)] 60` is equivalent to `(2x1 + (-3x2) + 3x1) <= 60`. +Passing a `[PolyConstraint]` to `findFeasibleSolution` will return a `FeasibleSystem` if a feasible solution exists: -Passing a `[PolyConstraint]` to `findFeasibleSolution` will return a feasible solution if it exists as well as a list of slack variables, artificial variables, and a variable that can be safely used to represent the objective for phase two. -`Nothing` is returned if the given `[PolyConstraint]` is infeasible. -The feasible system is returned as the type `DictionaryForm`: +```haskell +data FeasibleSystem = FeasibleSystem + { dict :: Dict + , slackVars :: [Var] + , artificialVars :: [Var] + , objectiveVar :: Var + } + deriving (Show, Read, Eq, Generic) +``` ```haskell -type DictionaryForm = [(Integer, Vars)] +type Dict = M.Map Var DictValue + +data DictValue = DictValue + { varMapSum :: VarLitMapSum + , constant :: SimplexNum + } + deriving (Show, Read, Eq, Generic) ``` -`DictionaryForm` can be thought of as a list of equations, where the `Integer` represents a basic variable on the LHS that is equal to the RHS represented as a `Vars`. In this `Vars`, the `Integer` -1 is used internally to represent a `Rational` number. +`Dict` can be thought of as a set of equations, where the key represents a basic variable on the LHS of the equation +that is equal to the RHS represented as a `DictValue` value. ### Phase Two `optimizeFeasibleSystem` performs phase two of the simplex method, and has the type: ```haskell -data ObjectiveFunction = Max Vars | Min Vars deriving (Show, Eq) -optimizeFeasibleSystem :: ObjectiveFunction -> DictionaryForm -> [Integer] -> [Integer] -> Integer -> Maybe (Integer, [(Integer, Rational)]) +optimizeFeasibleSystem :: (MonadIO m, MonadLogger m) => ObjectiveFunction -> FeasibleSystem -> m (Maybe Result) + +data ObjectiveFunction = Max {objective :: VarLitMapSum} | Min {objective :: VarLitMapSum} + +data Result = Result + { objectiveVar :: Var + , varValMap :: VarLitMap + } + deriving (Show, Read, Eq, Generic) ``` -We first pass an `ObjectiveFunction`. -Then we give a feasible system in `DictionaryForm`, a list of slack variables, a list of artificial variables, and a variable to represent the objective. -`optimizeFeasibleSystem` Maximizes/Minimizes the linear equation represented as a `Vars` in the given `ObjectiveFunction`. -The first item of the returned pair is the `Integer` variable representing the objective. -The second item is a list of `Integer` variables mapped to their optimized values. -If a variable is not in this list, the variable is equal to 0. +We give `optimizeFeasibleSystem` an `ObjectiveFunction` along with a `FeasibleSystem`. ### Two-Phase Simplex @@ -70,38 +85,31 @@ If a variable is not in this list, the variable is equal to 0. It has the type: ```haskell -twoPhaseSimplex :: ObjectiveFunction -> [PolyConstraint] -> Maybe (Integer, [(Integer, Rational)]) +twoPhaseSimplex :: (MonadIO m, MonadLogger m) => ObjectiveFunction -> [PolyConstraint] -> m (Maybe Result) ``` -The return type is the same as that of `optimizeFeasibleSystem` - ### Extracting Results -The result of the objective function is present in the return type of both `twoPhaseSimplex` and `optimizeFeasibleSystem`, but this can be difficult to grok in systems with many variables, so the following function will extract the value of the objective function for you. +The result of the objective function is present in the returned `Result` type of both `twoPhaseSimplex` and `optimizeFeasibleSystem`, but this can be difficult to grok in systems with many variables, so the following function will extract the value of the objective function for you. ```haskell -extractObjectiveValue :: Maybe (Integer, [(Integer, Rational)]) -> Maybe Rational +dictionaryFormToTableau :: Dict -> Tableau ``` There are similar functions for `DictionaryForm` as well as other custom types in the module `Linear.Simplex.Util`. -## Usage notes - -You must only use positive `Integer` variables in a `Vars`. -This implementation assumes that the user only provides positive `Integer` variables; the `Integer` -1, for example, is sometimes used to represent a `Rational` number. - ## Example ```haskell exampleFunction :: (ObjectiveFunction, [PolyConstraint]) exampleFunction = ( - Max [(1, 3), (2, 5)], -- 3x1 + 5x2 + Max {objective = Map.fromList [(1, 3), (2, 5)]}, -- 3x1 + 5x2 [ - LEQ [(1, 3), (2, 1)] 15, -- 3x1 + x2 <= 15 - LEQ [(1, 1), (2, 1)] 7, -- x1 + x2 <= 7 - LEQ [(2, 1)] 4, -- x2 <= 4 - LEQ [(1, -1), (2, 2)] 6 -- -x1 + 2x2 <= 6 + LEQ {lhs = Map.fromList [(1, 3), (2, 1)], rhs = 15}, -- 3x1 + x2 <= 15 + LEQ {lhs = Map.fromList [(1, 1), (2, 1)], rhs = 7}, -- x1 + x2 <= 7 + LEQ {lhs = Map.fromList [(2, 1)], rhs = 4}, -- x2 <= 4 + LEQ {lhs = Map.fromList [(1, -1), (2, 2)], rhs = 6} -- -x1 + 2x2 <= 6 ] ) @@ -111,13 +119,15 @@ twoPhaseSimplex (fst exampleFunction) (snd exampleFunction) The result of the call above is: ```haskell -Just - (7, -- Integer representing objective function - [ - (7,29 % 1), -- Value for variable 7, so max(3x1 + 5x2) = 29. - (1,3 % 1), -- Value for variable 1, so x1 = 3 - (2,4 % 1) -- Value for variable 2, so x2 = 4 - ] +Just + (Result + { objectiveVar = 7 -- Integer representing objective function + , varValMap = M.fromList + [ (7, 29) -- Value for variable 7, so max(3x1 + 5x2) = 29. + , (1, 3) -- Value for variable 1, so x1 = 3 + , (2, 4) -- Value for variable 2, so x2 = 4 + ] + } ) ``` diff --git a/src/Linear/Simplex/Types.hs b/src/Linear/Simplex/Types.hs index 5ea9019..15e5d1f 100644 --- a/src/Linear/Simplex/Types.hs +++ b/src/Linear/Simplex/Types.hs @@ -98,7 +98,7 @@ data TableauRow = TableauRow -- Each entry in the map is a row. type Tableau = M.Map Var TableauRow --- | Values for a 'DictEntry'. +-- | Values for a 'Dict'. data DictValue = DictValue { varMapSum :: VarLitMapSum , constant :: SimplexNum