{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE UndecidableInstances #-} -- | Data and class definitions for the core math programming -- interface. module Math.Programming.Types where import Control.Monad.Trans.Class import Control.Monad.Trans.RWS import Control.Monad.Trans.Reader import Control.Monad.Trans.State import Control.Monad.Trans.Writer import qualified Data.Text as T import Math.Programming.LinExpr -- | A linear program. -- -- This is a monadic context for formulating and solving linear -- programs. The types @v@, @c@, and @o@ refer to the types of -- variables, constraints, and objectives, respectively, used by a -- particular solver backend. class Monad m => MonadLP v c o m | m -> v c o where -- | Add a new (free) variable to the model. -- -- See 'Math.Programming.Dsl.free', 'Math.Programming.Dsl.bounded', -- 'Math.Programming.Dsl.nonNeg', and 'Math.Programming.Dsl.nonPos' -- as higher-level alternatives. addVariable :: m v -- | Remove a variable from the model. deleteVariable :: v -> m () -- | Get the name of a variable. getVariableName :: v -> m T.Text -- | Set a name for a variable. setVariableName :: v -> T.Text -> m () -- | Retrieve the current bounds associated with a variable. getVariableBounds :: v -> m Bounds -- | Apply bounds to a variable. -- -- See 'Math.Programming.Dsl.within' as a higher-level alternative. setVariableBounds :: v -> Bounds -> m () -- | Get the value of a variable in the current solution. -- -- This value could be arbitrary if no solve has been completed, or -- a solve produced an infeasible or unbounded solution. getVariableValue :: v -> m Double -- | Add a constraint representing the given inequality to the model. -- -- See the 'Math.Programming.Dsl..==.', 'Math.Programming.Dsl..==#', -- 'Math.Programming.Dsl.==.', 'Math.Programming.Dsl..>=.', -- 'Math.Programming.Dsl..>=', 'Math.Programming.Dsl.>=.', -- 'Math.Programming.Dsl..<=.', 'Math.Programming.Dsl..<=', and -- 'Math.Programming.Dsl.<=.' functions as higher-level -- alternatives. addConstraint :: Inequality (Expr v) -> m c -- | Remove a constraint from the model. deleteConstraint :: c -> m () -- | Get the name of a constraint. getConstraintName :: c -> m T.Text -- | Set a name for a constraint. setConstraintName :: c -> T.Text -> m () -- | Get the dual value associated with a constraint. getConstraintValue :: c -> m Double -- | Add an objective to the problem. -- -- Depending on the solver backend, this might replace an existing objective. addObjective :: Expr v -> m o -- | Remove an objective from the model. deleteObjective :: o -> m () -- | Get the name of a objective. getObjectiveName :: o -> m T.Text -- | Set a name for a objective. setObjectiveName :: o -> T.Text -> m () -- | Get the sense of an objective. getObjectiveSense :: o -> m Sense -- | Set the sense of an objective. setObjectiveSense :: o -> Sense -> m () -- | Get the value of an objective. getObjectiveValue :: o -> m Double -- | Get the timeout associated with a problem. getTimeout :: m Double -- | Set the timeout associated with a problem. setTimeout :: Double -> m () -- | Compute an LP-optimal solution. optimizeLP :: m SolutionStatus -- | Function composition involving a 2-argument function. compose2 :: (c -> d) -> (a -> b -> c) -> (a -> b -> d) compose2 = fmap fmap fmap -- | Monadic lifting involving a 2-argument function. lift2 :: (MonadTrans t, Monad m) => (a -> b -> m c) -> (a -> b -> t m c) lift2 = compose2 lift instance (MonadLP v c o m) => MonadLP v c o (ReaderT r m) where addVariable = lift addVariable deleteVariable = lift . deleteVariable getVariableName = lift . getVariableName setVariableName = lift2 setVariableName getVariableValue = lift . getVariableValue getVariableBounds = lift . getVariableBounds setVariableBounds = lift2 setVariableBounds addConstraint = lift . addConstraint deleteConstraint = lift . deleteConstraint getConstraintName = lift . getConstraintName setConstraintName = lift2 setConstraintName getConstraintValue = lift . getConstraintValue addObjective = lift . addObjective deleteObjective = lift . deleteObjective getObjectiveName = lift . getObjectiveName setObjectiveName = lift2 setObjectiveName getObjectiveValue = lift . getObjectiveValue getObjectiveSense = lift . getObjectiveSense setObjectiveSense = lift2 setObjectiveSense getTimeout = lift getTimeout setTimeout = lift . setTimeout optimizeLP = lift optimizeLP instance (MonadLP v c o m, Monoid w) => MonadLP v c o (WriterT w m) where addVariable = lift addVariable deleteVariable = lift . deleteVariable getVariableName = lift . getVariableName setVariableName = lift2 setVariableName getVariableValue = lift . getVariableValue getVariableBounds = lift . getVariableBounds setVariableBounds = lift2 setVariableBounds addConstraint = lift . addConstraint deleteConstraint = lift . deleteConstraint getConstraintName = lift . getConstraintName setConstraintName = lift2 setConstraintName getConstraintValue = lift . getConstraintValue addObjective = lift . addObjective deleteObjective = lift . deleteObjective getObjectiveName = lift . getObjectiveName setObjectiveName = lift2 setObjectiveName getObjectiveValue = lift . getObjectiveValue getObjectiveSense = lift . getObjectiveSense setObjectiveSense = lift2 setObjectiveSense getTimeout = lift getTimeout setTimeout = lift . setTimeout optimizeLP = lift optimizeLP instance (MonadLP v c o m, Monoid w) => MonadLP v c o (RWST r w s m) where addVariable = lift addVariable deleteVariable = lift . deleteVariable getVariableName = lift . getVariableName setVariableName = lift2 setVariableName getVariableValue = lift . getVariableValue getVariableBounds = lift . getVariableBounds setVariableBounds = lift2 setVariableBounds addConstraint = lift . addConstraint deleteConstraint = lift . deleteConstraint getConstraintName = lift . getConstraintName setConstraintName = lift2 setConstraintName getConstraintValue = lift . getConstraintValue addObjective = lift . addObjective deleteObjective = lift . deleteObjective getObjectiveName = lift . getObjectiveName setObjectiveName = lift2 setObjectiveName getObjectiveValue = lift . getObjectiveValue getObjectiveSense = lift . getObjectiveSense setObjectiveSense = lift2 setObjectiveSense getTimeout = lift getTimeout setTimeout = lift . setTimeout optimizeLP = lift optimizeLP instance MonadLP v c o m => MonadLP v c o (StateT s m) where addVariable = lift addVariable deleteVariable = lift . deleteVariable getVariableValue = lift . getVariableValue getVariableName = lift . getVariableName setVariableName = lift2 setVariableName getVariableBounds = lift . getVariableBounds setVariableBounds = lift2 setVariableBounds addConstraint = lift . addConstraint deleteConstraint = lift . deleteConstraint getConstraintName = lift . getConstraintName setConstraintName = lift2 setConstraintName getConstraintValue = lift . getConstraintValue addObjective = lift . addObjective deleteObjective = lift . deleteObjective getObjectiveName = lift . getObjectiveName setObjectiveName = lift2 setObjectiveName getObjectiveValue = lift . getObjectiveValue getObjectiveSense = lift . getObjectiveSense setObjectiveSense = lift2 setObjectiveSense getTimeout = lift getTimeout setTimeout = lift . setTimeout optimizeLP = lift optimizeLP -- | A (mixed) integer program. -- -- In addition to the methods of the 'MonadLP' class, this monad -- supports constraining variables to be either continuous or -- discrete. class MonadLP v c o m => MonadIP v c o m | m -> v c o where getVariableDomain :: v -> m Domain setVariableDomain :: v -> Domain -> m () getRelativeMIPGap :: m Double setRelativeMIPGap :: Double -> m () optimizeIP :: m SolutionStatus instance MonadIP v c o m => MonadIP v c o (ReaderT r m) where getVariableDomain = lift . getVariableDomain setVariableDomain = lift2 setVariableDomain getRelativeMIPGap = lift getRelativeMIPGap setRelativeMIPGap = lift . setRelativeMIPGap optimizeIP = lift optimizeIP instance MonadIP v c o m => MonadIP v c o (StateT s m) where getVariableDomain = lift . getVariableDomain setVariableDomain = lift2 setVariableDomain getRelativeMIPGap = lift getRelativeMIPGap setRelativeMIPGap = lift . setRelativeMIPGap optimizeIP = lift optimizeIP -- | Whether a math program is minimizing or maximizing its objective. data Sense = Minimization | Maximization deriving ( Eq, Ord, Read, Show ) -- | The outcome of an optimization. data SolutionStatus = -- | An optimal solution has been found. Optimal | -- | A feasible solution has been found. The result may or may not -- be optimal. Feasible | -- | The model has been proven to be infeasible. Infeasible | -- | The model has been proven to be unbounded. Unbounded | -- | An error was encountered during the solve. Instance-specific -- methods should be used to determine what occurred. Error deriving ( Eq, Ord, Read, Show ) -- | An interval of the real numbers. data Bounds = -- | The non-negative reals. NonNegativeReals | -- | The non-positive reals. NonPositiveReals | -- | Any closed interval of the reals. Interval Double Double | -- | Any real number. Free deriving ( Read, Show ) -- | The type of values that a variable can take on. -- -- Note that the @Integer@ constructor does not interfere with the -- @Integer@ type, as the @Integer@ type does not define a constuctor -- of the same name. The ambiguity is unfortunate, but other natural -- nomenclature such as @Integral@ are similarly conflicted. data Domain = -- | The variable lies in the real numbers Continuous | -- | The variable lies in the integers Integer | -- | The variable lies in the set @{0, 1}@. Binary deriving ( Read, Show ) -- | Non-strict inequalities. data Inequality a = Inequality Ordering a a deriving ( Read, Show, Functor, Foldable, Traversable ) -- | A convient shorthand for the type of linear expressions used in -- models. type Expr = LinExpr Double