linear-simplex-haskell: Haskell implementation of the two-phase simplex method

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Please see the README on GitHub at https://github.com/rasheedja/linear-simplex-haskell#readme


[Skip to Readme]

Properties

Versions 0.1.0.0
Change log ChangeLog.md
Dependencies base (>=4.7 && <5) [details]
License BSD-3-Clause
Copyright BSD-3
Author Junaid Rasheed
Maintainer jrasheed178@gmail.com
Category Math, Maths, Mathematics, Optimisation, Optimization, Linear Programming
Home page https://github.com/rasheedja/linaer-simplex-haskell#readme
Bug tracker https://github.com/rasheedja/linaer-simplex-haskell/issues
Source repo head: git clone https://github.com/rasheedja/linaer-simplex-haskell
Uploaded by JunaidRasheed at 2022-07-18T10:17:09Z

Modules

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for linear-simplex-haskell-0.1.0.0

[back to package description]

linear-simplex-haskell

linear-simplex-haskell is a library that implements the two-phase simplex method.

Quick Overview

The Linear.Simplex module contain both phases of the simplex method.

Phase One

Phase one is implemented by findFeasibleSolution:

findFeasibleSolution :: [PolyConstraint] -> Maybe (DictionaryForm, [Integer], [Integer], Integer)

findFeasibleSolution takes a list of PolyConstraints. The PolyConstraint type, as well as other custom types required by this library, are defined in the Linear.Type module. PolyConstraint is defined as:

data PolyConstraint =
  LEQ VarConstMap Rational      | 
  GEQ VarConstMap Rational      | 
  EQ  VarConstMap Rational       deriving (Show, Eq);

And VarConstMap is defined as:

type VarConstMap = [(Integer, Rational)]

A VarConstMap 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 VarConstMap 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 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:

type DictionaryForm = [(Integer, VarConstMap)]

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 VarConstMap. In this VarConstMap, the Integer -1 is used internally to represent a Rational number.

Phase Two

optimizeFeasibleSystem performs phase two of the simplex method, and has the type:

data ObjectiveFunction = Max VarConstMap | Min VarConstMap deriving (Show, Eq)

optimizeFeasibleSystem :: ObjectiveFunction -> DictionaryForm -> [Integer] -> [Integer] -> Integer -> Maybe (Integer, [(Integer, Rational)])

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 VarConstMap in the given ObjectiveFunction. The first item of the returned pair is the Integer variable representing the objective. Ths second item is a map of Integer variables with their optimized values. If a variable is not present in this map, the variable is equal to 0.

Two-Phase Simplex

twoPhaseSimplex performs both phases of the simplex method. It has the type:

twoPhaseSimplex :: ObjectiveFunction -> [PolyConstraint] -> Maybe (Integer, [(Integer, Rational)])

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.

extractObjectiveValue :: Maybe (Integer, [(Integer, Rational)]) -> Maybe Rational

There are similar functions for DictionaryForm as well as other custom types in the module Linear.Util.

Usage notes

You must only use positive Integer variables in a VarConstMap. 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

exampleFunction :: (ObjectiveFunction, [PolyConstraint])
exampleFunction =
  (
    Max [(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
    ]
  )

twoPhaseSimplex (fst exampleFunction) (snd exampleFunction)

The result of the call above is:

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
  ]
  )

There are many more examples in test/TestFunctions.hs. You may use prettyShowVarConstMap, prettyShowPolyConstraint, and prettyShowObjectiveFunction to convert these tests into a more human-readable format.

Issues

Please share any bugs you find here.