math-programming 0.4.0 → 0.5.0
raw patch · 13 files changed
+705/−786 lines, 13 filesdep +QuickCheckdep +exceptionsdep +hspecdep −tastydep −tasty-discoverdep −tasty-hunitdep ~basedep ~containersdep ~mtlPVP ok
version bump matches the API change (PVP)
Dependencies added: QuickCheck, exceptions, hspec, transformers
Dependencies removed: tasty, tasty-discover, tasty-hunit, tasty-quickcheck
Dependency ranges changed: base, containers, mtl, text
API changes (from Hackage documentation)
- Math.Programming: (#*.) :: Num a => a -> LinearExpression a b -> LinearExpression a b
- Math.Programming: (#*@) :: Num a => a -> b -> LinearExpression a b
- Math.Programming: (#+.) :: Num a => a -> LinearExpression a b -> LinearExpression a b
- Math.Programming: (#+@) :: Num a => a -> b -> LinearExpression a b
- Math.Programming: (#-.) :: Num a => a -> LinearExpression a b -> LinearExpression a b
- Math.Programming: (#-@) :: Num a => a -> b -> LinearExpression a b
- Math.Programming: (#<=.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)
- Math.Programming: (#<=@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)
- Math.Programming: (#==.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)
- Math.Programming: (#==@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)
- Math.Programming: (#>=.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)
- Math.Programming: (#>=@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)
- Math.Programming: (.*#) :: Num a => LinearExpression a b -> a -> LinearExpression a b
- Math.Programming: (.+#) :: Num a => LinearExpression a b -> a -> LinearExpression a b
- Math.Programming: (.+@) :: Num a => LinearExpression a b -> b -> LinearExpression a b
- Math.Programming: (.-#) :: Num a => LinearExpression a b -> a -> LinearExpression a b
- Math.Programming: (.-@) :: Num a => LinearExpression a b -> b -> LinearExpression a b
- Math.Programming: (./#) :: Fractional a => LinearExpression a b -> a -> LinearExpression a b
- Math.Programming: (.<=#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)
- Math.Programming: (.<=@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)
- Math.Programming: (.==#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)
- Math.Programming: (.==@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)
- Math.Programming: (.>=#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)
- Math.Programming: (.>=@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)
- Math.Programming: (@*#) :: Num a => b -> a -> LinearExpression a b
- Math.Programming: (@+#) :: Num a => b -> a -> LinearExpression a b
- Math.Programming: (@+.) :: Num a => b -> LinearExpression a b -> LinearExpression a b
- Math.Programming: (@+@) :: Num a => b -> b -> LinearExpression a b
- Math.Programming: (@-#) :: Num a => b -> a -> LinearExpression a b
- Math.Programming: (@-.) :: Num a => b -> LinearExpression a b -> LinearExpression a b
- Math.Programming: (@-@) :: Num a => b -> b -> LinearExpression a b
- Math.Programming: (@/#) :: Fractional a => b -> a -> LinearExpression a b
- Math.Programming: (@<=#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)
- Math.Programming: (@<=.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)
- Math.Programming: (@<=@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)
- Math.Programming: (@==#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)
- Math.Programming: (@==.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)
- Math.Programming: (@==@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)
- Math.Programming: (@>=#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)
- Math.Programming: (@>=.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)
- Math.Programming: (@>=@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)
- Math.Programming: -- opaque values, but instances may expose more details.
- Math.Programming: -- | The type of objectives in the model. <a>LPMonad</a> treats these as
- Math.Programming: LinearExpression :: [(a, b)] -> a -> LinearExpression a b
- Math.Programming: class (LPMonad m) => IPMonad m
- Math.Programming: class (Monad m, Show (Numeric m), RealFrac (Numeric m)) => LPMonad m where {
- Math.Programming: data LinearExpression a b
- Math.Programming: data family Objective m :: *;
- Math.Programming: exprSum :: Num a => [LinearExpression a b] -> LinearExpression a b
- Math.Programming: getDualValue :: LPMonad m => Constraint m -> m (Numeric m)
- Math.Programming: nameOf :: (Monad m, Nameable m a) => a -> m String
- Math.Programming: named :: (Monad m, Nameable m a) => m a -> String -> m a
- Math.Programming: removeConstraint :: LPMonad m => Constraint m -> m ()
- Math.Programming: removeVariable :: LPMonad m => Variable m -> m ()
- Math.Programming: type family Numeric m :: *;
- Math.Programming: varSum :: Num a => [b] -> LinearExpression a b
- Math.Programming: }
- Math.Programming.Dsl: (#*.) :: Num a => a -> LinearExpression a b -> LinearExpression a b
- Math.Programming.Dsl: (#*@) :: Num a => a -> b -> LinearExpression a b
- Math.Programming.Dsl: (#+.) :: Num a => a -> LinearExpression a b -> LinearExpression a b
- Math.Programming.Dsl: (#+@) :: Num a => a -> b -> LinearExpression a b
- Math.Programming.Dsl: (#-.) :: Num a => a -> LinearExpression a b -> LinearExpression a b
- Math.Programming.Dsl: (#-@) :: Num a => a -> b -> LinearExpression a b
- Math.Programming.Dsl: (#<=.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)
- Math.Programming.Dsl: (#<=@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: (#==.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)
- Math.Programming.Dsl: (#==@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: (#>=.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)
- Math.Programming.Dsl: (#>=@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: (.*#) :: Num a => LinearExpression a b -> a -> LinearExpression a b
- Math.Programming.Dsl: (.+#) :: Num a => LinearExpression a b -> a -> LinearExpression a b
- Math.Programming.Dsl: (.+.) :: Num a => LinearExpression a b -> LinearExpression a b -> LinearExpression a b
- Math.Programming.Dsl: (.+@) :: Num a => LinearExpression a b -> b -> LinearExpression a b
- Math.Programming.Dsl: (.-#) :: Num a => LinearExpression a b -> a -> LinearExpression a b
- Math.Programming.Dsl: (.-.) :: Num a => LinearExpression a b -> LinearExpression a b -> LinearExpression a b
- Math.Programming.Dsl: (.-@) :: Num a => LinearExpression a b -> b -> LinearExpression a b
- Math.Programming.Dsl: (./#) :: Fractional a => LinearExpression a b -> a -> LinearExpression a b
- Math.Programming.Dsl: (.<=#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)
- Math.Programming.Dsl: (.<=@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: (.==#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)
- Math.Programming.Dsl: (.==@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: (.>=#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)
- Math.Programming.Dsl: (.>=@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: (@*#) :: Num a => b -> a -> LinearExpression a b
- Math.Programming.Dsl: (@+#) :: Num a => b -> a -> LinearExpression a b
- Math.Programming.Dsl: (@+.) :: Num a => b -> LinearExpression a b -> LinearExpression a b
- Math.Programming.Dsl: (@+@) :: Num a => b -> b -> LinearExpression a b
- Math.Programming.Dsl: (@-#) :: Num a => b -> a -> LinearExpression a b
- Math.Programming.Dsl: (@-.) :: Num a => b -> LinearExpression a b -> LinearExpression a b
- Math.Programming.Dsl: (@-@) :: Num a => b -> b -> LinearExpression a b
- Math.Programming.Dsl: (@/#) :: Fractional a => b -> a -> LinearExpression a b
- Math.Programming.Dsl: (@<=#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)
- Math.Programming.Dsl: (@<=.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)
- Math.Programming.Dsl: (@<=@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: (@==#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)
- Math.Programming.Dsl: (@==.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)
- Math.Programming.Dsl: (@==@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: (@>=#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)
- Math.Programming.Dsl: (@>=.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)
- Math.Programming.Dsl: (@>=@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)
- Math.Programming.Dsl: con :: Num a => a -> LinearExpression a b
- Math.Programming.Dsl: eval :: Num a => LinearExpression a a -> a
- Math.Programming.Dsl: exprSum :: Num a => [LinearExpression a b] -> LinearExpression a b
- Math.Programming.Dsl: infixl 6 .-.
- Math.Programming.Dsl: infixl 7 ./#
- Math.Programming.Dsl: nameOf :: (Monad m, Nameable m a) => a -> m String
- Math.Programming.Dsl: named :: (Monad m, Nameable m a) => m a -> String -> m a
- Math.Programming.Dsl: simplify :: (Ord b, Num a) => LinearExpression a b -> LinearExpression a b
- Math.Programming.Dsl: var :: Num a => b -> LinearExpression a b
- Math.Programming.Dsl: varSum :: Num a => [b] -> LinearExpression a b
- Math.Programming.Types: -- opaque values, but instances may expose more details.
- Math.Programming.Types: -- | The type of objectives in the model. <a>LPMonad</a> treats these as
- Math.Programming.Types: LinearExpression :: [(a, b)] -> a -> LinearExpression a b
- Math.Programming.Types: class (LPMonad m) => IPMonad m
- Math.Programming.Types: class (Monad m, Show (Numeric m), RealFrac (Numeric m)) => LPMonad m where {
- Math.Programming.Types: class Nameable m a
- Math.Programming.Types: data LinearExpression a b
- Math.Programming.Types: data family Objective m :: *;
- Math.Programming.Types: getDualValue :: LPMonad m => Constraint m -> m (Numeric m)
- Math.Programming.Types: getName :: Nameable m a => a -> m String
- Math.Programming.Types: instance (GHC.Read.Read a, GHC.Read.Read b) => GHC.Read.Read (Math.Programming.Types.LinearExpression a b)
- Math.Programming.Types: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Math.Programming.Types.LinearExpression a b)
- Math.Programming.Types: instance Data.Bifunctor.Bifunctor Math.Programming.Types.LinearExpression
- Math.Programming.Types: instance Data.Foldable.Foldable (Math.Programming.Types.LinearExpression a)
- Math.Programming.Types: instance Data.Traversable.Traversable (Math.Programming.Types.LinearExpression a)
- Math.Programming.Types: instance GHC.Base.Functor (Math.Programming.Types.LinearExpression a)
- Math.Programming.Types: instance GHC.Num.Num a => GHC.Base.Monoid (Math.Programming.Types.LinearExpression a b)
- Math.Programming.Types: instance GHC.Num.Num a => GHC.Base.Semigroup (Math.Programming.Types.LinearExpression a b)
- Math.Programming.Types: instance GHC.Read.Read b => GHC.Read.Read (Math.Programming.Types.Bounds b)
- Math.Programming.Types: instance GHC.Show.Show b => GHC.Show.Show (Math.Programming.Types.Bounds b)
- Math.Programming.Types: instance Math.Programming.Types.LPMonad m => Math.Programming.Types.Nameable m (Math.Programming.Types.Constraint m)
- Math.Programming.Types: instance Math.Programming.Types.LPMonad m => Math.Programming.Types.Nameable m (Math.Programming.Types.Objective m)
- Math.Programming.Types: instance Math.Programming.Types.LPMonad m => Math.Programming.Types.Nameable m (Math.Programming.Types.Variable m)
- Math.Programming.Types: removeConstraint :: LPMonad m => Constraint m -> m ()
- Math.Programming.Types: removeVariable :: LPMonad m => Variable m -> m ()
- Math.Programming.Types: setName :: Nameable m a => a -> String -> m ()
- Math.Programming.Types: type family Numeric m :: *;
- Math.Programming.Types: }
+ Math.Programming: (*.) :: Num a => a -> b -> LinExpr a b
+ Math.Programming: (.*) :: Num a => b -> a -> LinExpr a b
+ Math.Programming: (./) :: Fractional a => b -> a -> LinExpr a b
+ Math.Programming: (.<=) :: MonadLP v c o m => Expr v -> Double -> m c
+ Math.Programming: (.==) :: MonadLP v c o m => Expr v -> Double -> m c
+ Math.Programming: (.>=) :: MonadLP v c o m => Expr v -> Double -> m c
+ Math.Programming: (<=.) :: MonadLP v c o m => Double -> Expr v -> m c
+ Math.Programming: (==.) :: MonadLP v c o m => Double -> Expr v -> m c
+ Math.Programming: (>=.) :: MonadLP v c o m => Double -> Expr v -> m c
+ Math.Programming: LinExpr :: ![(a, b)] -> !a -> LinExpr a b
+ Math.Programming: class MonadLP v c o m => MonadIP v c o m | m -> v c o
+ Math.Programming: class Monad m => MonadLP v c o m | m -> v c o
+ Math.Programming: data LinExpr a b
+ Math.Programming: deleteConstraint :: MonadLP v c o m => c -> m ()
+ Math.Programming: deleteObjective :: MonadLP v c o m => o -> m ()
+ Math.Programming: deleteVariable :: MonadLP v c o m => v -> m ()
+ Math.Programming: esum :: Num a => Foldable t => t (LinExpr a b) -> LinExpr a b
+ Math.Programming: formatExpr :: MonadLP v c o m => Expr v -> m Text
+ Math.Programming: getConstraintValue :: MonadLP v c o m => c -> m Double
+ Math.Programming: scale :: Num a => a -> LinExpr a b -> LinExpr a b
+ Math.Programming: vsum :: Num a => [b] -> LinExpr a b
+ Math.Programming: withConstraintName :: MonadLP v c o m => m c -> Text -> m c
+ Math.Programming: withObjectiveName :: MonadLP v c o m => m o -> Text -> m o
+ Math.Programming: withVariableName :: MonadLP v c o m => m v -> Text -> m v
+ Math.Programming.Dsl: (.<=) :: MonadLP v c o m => Expr v -> Double -> m c
+ Math.Programming.Dsl: (.==) :: MonadLP v c o m => Expr v -> Double -> m c
+ Math.Programming.Dsl: (.>=) :: MonadLP v c o m => Expr v -> Double -> m c
+ Math.Programming.Dsl: (<=.) :: MonadLP v c o m => Double -> Expr v -> m c
+ Math.Programming.Dsl: (==.) :: MonadLP v c o m => Double -> Expr v -> m c
+ Math.Programming.Dsl: (>=.) :: MonadLP v c o m => Double -> Expr v -> m c
+ Math.Programming.Dsl: formatExpr :: MonadLP v c o m => Expr v -> m Text
+ Math.Programming.Dsl: formatExpr' :: Monad m => (v -> m Text) -> Expr v -> m Text
+ Math.Programming.Dsl: withConstraintName :: MonadLP v c o m => m c -> Text -> m c
+ Math.Programming.Dsl: withObjectiveName :: MonadLP v c o m => m o -> Text -> m o
+ Math.Programming.Dsl: withVariableName :: MonadLP v c o m => m v -> Text -> m v
+ Math.Programming.LinExpr: (*.) :: Num a => a -> b -> LinExpr a b
+ Math.Programming.LinExpr: (.*) :: Num a => b -> a -> LinExpr a b
+ Math.Programming.LinExpr: (.+.) :: Num a => LinExpr a b -> LinExpr a b -> LinExpr a b
+ Math.Programming.LinExpr: (.-.) :: Num a => LinExpr a b -> LinExpr a b -> LinExpr a b
+ Math.Programming.LinExpr: (./) :: Fractional a => b -> a -> LinExpr a b
+ Math.Programming.LinExpr: LinExpr :: ![(a, b)] -> !a -> LinExpr a b
+ Math.Programming.LinExpr: con :: a -> LinExpr a b
+ Math.Programming.LinExpr: data LinExpr a b
+ Math.Programming.LinExpr: esum :: Num a => Foldable t => t (LinExpr a b) -> LinExpr a b
+ Math.Programming.LinExpr: eval :: Num a => LinExpr a a -> a
+ Math.Programming.LinExpr: infixl 6 .-.
+ Math.Programming.LinExpr: infixl 7 ./
+ Math.Programming.LinExpr: instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (Math.Programming.LinExpr.LinExpr a b)
+ Math.Programming.LinExpr: instance (GHC.Read.Read a, GHC.Read.Read b) => GHC.Read.Read (Math.Programming.LinExpr.LinExpr a b)
+ Math.Programming.LinExpr: instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (Math.Programming.LinExpr.LinExpr a b)
+ Math.Programming.LinExpr: instance Data.Foldable.Foldable (Math.Programming.LinExpr.LinExpr a)
+ Math.Programming.LinExpr: instance Data.Traversable.Traversable (Math.Programming.LinExpr.LinExpr a)
+ Math.Programming.LinExpr: instance GHC.Base.Functor (Math.Programming.LinExpr.LinExpr a)
+ Math.Programming.LinExpr: instance GHC.Num.Num a => GHC.Base.Monoid (Math.Programming.LinExpr.LinExpr a b)
+ Math.Programming.LinExpr: instance GHC.Num.Num a => GHC.Base.Semigroup (Math.Programming.LinExpr.LinExpr a b)
+ Math.Programming.LinExpr: scale :: Num a => a -> LinExpr a b -> LinExpr a b
+ Math.Programming.LinExpr: simplify :: (Num a, Ord b) => LinExpr a b -> LinExpr a b
+ Math.Programming.LinExpr: var :: Num a => b -> LinExpr a b
+ Math.Programming.LinExpr: vsum :: Num a => [b] -> LinExpr a b
+ Math.Programming.Types: class MonadLP v c o m => MonadIP v c o m | m -> v c o
+ Math.Programming.Types: class Monad m => MonadLP v c o m | m -> v c o
+ Math.Programming.Types: compose2 :: (c -> d) -> (a -> b -> c) -> a -> b -> d
+ Math.Programming.Types: deleteConstraint :: MonadLP v c o m => c -> m ()
+ Math.Programming.Types: deleteObjective :: MonadLP v c o m => o -> m ()
+ Math.Programming.Types: deleteVariable :: MonadLP v c o m => v -> m ()
+ Math.Programming.Types: getConstraintValue :: MonadLP v c o m => c -> m Double
+ Math.Programming.Types: instance (Math.Programming.Types.MonadLP v c o m, GHC.Base.Monoid w) => Math.Programming.Types.MonadLP v c o (Control.Monad.Trans.RWS.Lazy.RWST r w s m)
+ Math.Programming.Types: instance (Math.Programming.Types.MonadLP v c o m, GHC.Base.Monoid w) => Math.Programming.Types.MonadLP v c o (Control.Monad.Trans.Writer.Lazy.WriterT w m)
+ Math.Programming.Types: instance GHC.Read.Read Math.Programming.Types.Bounds
+ Math.Programming.Types: instance GHC.Show.Show Math.Programming.Types.Bounds
+ Math.Programming.Types: instance Math.Programming.Types.MonadIP v c o m => Math.Programming.Types.MonadIP v c o (Control.Monad.Trans.Reader.ReaderT r m)
+ Math.Programming.Types: instance Math.Programming.Types.MonadIP v c o m => Math.Programming.Types.MonadIP v c o (Control.Monad.Trans.State.Lazy.StateT s m)
+ Math.Programming.Types: instance Math.Programming.Types.MonadLP v c o m => Math.Programming.Types.MonadLP v c o (Control.Monad.Trans.Reader.ReaderT r m)
+ Math.Programming.Types: instance Math.Programming.Types.MonadLP v c o m => Math.Programming.Types.MonadLP v c o (Control.Monad.Trans.State.Lazy.StateT s m)
+ Math.Programming.Types: lift2 :: (MonadTrans t, Monad m) => (a -> b -> m c) -> a -> b -> t m c
- Math.Programming: (.+.) :: Num a => LinearExpression a b -> LinearExpression a b -> LinearExpression a b
+ Math.Programming: (.+.) :: Num a => LinExpr a b -> LinExpr a b -> LinExpr a b
- Math.Programming: (.-.) :: Num a => LinearExpression a b -> LinearExpression a b -> LinearExpression a b
+ Math.Programming: (.-.) :: Num a => LinExpr a b -> LinExpr a b -> LinExpr a b
- Math.Programming: (.<=.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)
+ Math.Programming: (.<=.) :: MonadLP v c o m => Expr v -> Expr v -> m c
- Math.Programming: (.==.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)
+ Math.Programming: (.==.) :: MonadLP v c o m => Expr v -> Expr v -> m c
- Math.Programming: (.>=.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)
+ Math.Programming: (.>=.) :: MonadLP v c o m => Expr v -> Expr v -> m c
- Math.Programming: Free :: Bounds b
+ Math.Programming: Free :: Bounds
- Math.Programming: Interval :: b -> b -> Bounds b
+ Math.Programming: Interval :: Double -> Double -> Bounds
- Math.Programming: NonNegativeReals :: Bounds b
+ Math.Programming: NonNegativeReals :: Bounds
- Math.Programming: NonPositiveReals :: Bounds b
+ Math.Programming: NonPositiveReals :: Bounds
- Math.Programming: addConstraint :: LPMonad m => Inequality (LinearExpression (Numeric m) (Variable m)) -> m (Constraint m)
+ Math.Programming: addConstraint :: MonadLP v c o m => Inequality (Expr v) -> m c
- Math.Programming: addObjective :: LPMonad m => LinearExpression (Numeric m) (Variable m) -> m (Objective m)
+ Math.Programming: addObjective :: MonadLP v c o m => Expr v -> m o
- Math.Programming: addVariable :: LPMonad m => m (Variable m)
+ Math.Programming: addVariable :: MonadLP v c o m => m v
- Math.Programming: asKind :: IPMonad m => m (Variable m) -> Domain -> m (Variable m)
+ Math.Programming: asKind :: MonadIP v c o m => m v -> Domain -> m v
- Math.Programming: binary :: IPMonad m => m (Variable m)
+ Math.Programming: binary :: MonadIP v c o m => m v
- Math.Programming: bounded :: LPMonad m => Numeric m -> Numeric m -> m (Variable m)
+ Math.Programming: bounded :: MonadLP v c o m => Double -> Double -> m v
- Math.Programming: con :: Num a => a -> LinearExpression a b
+ Math.Programming: con :: a -> LinExpr a b
- Math.Programming: data Bounds b
+ Math.Programming: data Bounds
- Math.Programming: eval :: Num a => LinearExpression a a -> a
+ Math.Programming: eval :: Num a => LinExpr a a -> a
- Math.Programming: evalExpr :: LPMonad m => Expr m -> m (Numeric m)
+ Math.Programming: evalExpr :: MonadLP v c o m => Expr v -> m Double
- Math.Programming: free :: LPMonad m => m (Variable m)
+ Math.Programming: free :: MonadLP v c o m => m v
- Math.Programming: getConstraintName :: LPMonad m => Constraint m -> m String
+ Math.Programming: getConstraintName :: MonadLP v c o m => c -> m Text
- Math.Programming: getObjectiveName :: LPMonad m => Objective m -> m String
+ Math.Programming: getObjectiveName :: MonadLP v c o m => o -> m Text
- Math.Programming: getObjectiveSense :: LPMonad m => Objective m -> m Sense
+ Math.Programming: getObjectiveSense :: MonadLP v c o m => o -> m Sense
- Math.Programming: getObjectiveValue :: LPMonad m => Objective m -> m (Numeric m)
+ Math.Programming: getObjectiveValue :: MonadLP v c o m => o -> m Double
- Math.Programming: getRelativeMIPGap :: IPMonad m => m Double
+ Math.Programming: getRelativeMIPGap :: MonadIP v c o m => m Double
- Math.Programming: getTimeout :: LPMonad m => m Double
+ Math.Programming: getTimeout :: MonadLP v c o m => m Double
- Math.Programming: getVariableBounds :: LPMonad m => Variable m -> m (Bounds (Numeric m))
+ Math.Programming: getVariableBounds :: MonadLP v c o m => v -> m Bounds
- Math.Programming: getVariableDomain :: IPMonad m => Variable m -> m Domain
+ Math.Programming: getVariableDomain :: MonadIP v c o m => v -> m Domain
- Math.Programming: getVariableName :: LPMonad m => Variable m -> m String
+ Math.Programming: getVariableName :: MonadLP v c o m => v -> m Text
- Math.Programming: getVariableValue :: LPMonad m => Variable m -> m (Numeric m)
+ Math.Programming: getVariableValue :: MonadLP v c o m => v -> m Double
- Math.Programming: infix 4 .==.
+ Math.Programming: infix 4 .>=
- Math.Programming: infixl 6 .-#
+ Math.Programming: infixl 6 .-.
- Math.Programming: infixl 7 ./#
+ Math.Programming: infixl 7 ./
- Math.Programming: integer :: IPMonad m => m (Variable m)
+ Math.Programming: integer :: MonadIP v c o m => m v
- Math.Programming: maximize :: LPMonad m => Expr m -> m (Objective m)
+ Math.Programming: maximize :: MonadLP v c o m => Expr v -> m o
- Math.Programming: minimize :: LPMonad m => Expr m -> m (Objective m)
+ Math.Programming: minimize :: MonadLP v c o m => Expr v -> m o
- Math.Programming: nonNeg :: LPMonad m => m (Variable m)
+ Math.Programming: nonNeg :: MonadLP v c o m => m v
- Math.Programming: nonNegInteger :: IPMonad m => m (Variable m)
+ Math.Programming: nonNegInteger :: MonadIP v c o m => m v
- Math.Programming: nonPos :: LPMonad m => m (Variable m)
+ Math.Programming: nonPos :: MonadLP v c o m => m v
- Math.Programming: nonPosInteger :: IPMonad m => m (Variable m)
+ Math.Programming: nonPosInteger :: MonadIP v c o m => m v
- Math.Programming: optimizeIP :: IPMonad m => m SolutionStatus
+ Math.Programming: optimizeIP :: MonadIP v c o m => m SolutionStatus
- Math.Programming: optimizeLP :: LPMonad m => m SolutionStatus
+ Math.Programming: optimizeLP :: MonadLP v c o m => m SolutionStatus
- Math.Programming: setConstraintName :: LPMonad m => Constraint m -> String -> m ()
+ Math.Programming: setConstraintName :: MonadLP v c o m => c -> Text -> m ()
- Math.Programming: setObjectiveName :: LPMonad m => Objective m -> String -> m ()
+ Math.Programming: setObjectiveName :: MonadLP v c o m => o -> Text -> m ()
- Math.Programming: setObjectiveSense :: LPMonad m => Objective m -> Sense -> m ()
+ Math.Programming: setObjectiveSense :: MonadLP v c o m => o -> Sense -> m ()
- Math.Programming: setRelativeMIPGap :: IPMonad m => Double -> m ()
+ Math.Programming: setRelativeMIPGap :: MonadIP v c o m => Double -> m ()
- Math.Programming: setTimeout :: LPMonad m => Double -> m ()
+ Math.Programming: setTimeout :: MonadLP v c o m => Double -> m ()
- Math.Programming: setVariableBounds :: LPMonad m => Variable m -> Bounds (Numeric m) -> m ()
+ Math.Programming: setVariableBounds :: MonadLP v c o m => v -> Bounds -> m ()
- Math.Programming: setVariableDomain :: IPMonad m => Variable m -> Domain -> m ()
+ Math.Programming: setVariableDomain :: MonadIP v c o m => v -> Domain -> m ()
- Math.Programming: setVariableName :: LPMonad m => Variable m -> String -> m ()
+ Math.Programming: setVariableName :: MonadLP v c o m => v -> Text -> m ()
- Math.Programming: simplify :: (Ord b, Num a) => LinearExpression a b -> LinearExpression a b
+ Math.Programming: simplify :: (Num a, Ord b) => LinExpr a b -> LinExpr a b
- Math.Programming: type Expr m = LinearExpression (Numeric m) (Variable m)
+ Math.Programming: type Expr = LinExpr Double
- Math.Programming: var :: Num a => b -> LinearExpression a b
+ Math.Programming: var :: Num a => b -> LinExpr a b
- Math.Programming: within :: LPMonad m => m (Variable m) -> Bounds (Numeric m) -> m (Variable m)
+ Math.Programming: within :: MonadLP v c o m => m v -> Bounds -> m v
- Math.Programming.Dsl: (.<=.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)
+ Math.Programming.Dsl: (.<=.) :: MonadLP v c o m => Expr v -> Expr v -> m c
- Math.Programming.Dsl: (.==.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)
+ Math.Programming.Dsl: (.==.) :: MonadLP v c o m => Expr v -> Expr v -> m c
- Math.Programming.Dsl: (.>=.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)
+ Math.Programming.Dsl: (.>=.) :: MonadLP v c o m => Expr v -> Expr v -> m c
- Math.Programming.Dsl: asKind :: IPMonad m => m (Variable m) -> Domain -> m (Variable m)
+ Math.Programming.Dsl: asKind :: MonadIP v c o m => m v -> Domain -> m v
- Math.Programming.Dsl: binary :: IPMonad m => m (Variable m)
+ Math.Programming.Dsl: binary :: MonadIP v c o m => m v
- Math.Programming.Dsl: bounded :: LPMonad m => Numeric m -> Numeric m -> m (Variable m)
+ Math.Programming.Dsl: bounded :: MonadLP v c o m => Double -> Double -> m v
- Math.Programming.Dsl: evalExpr :: LPMonad m => Expr m -> m (Numeric m)
+ Math.Programming.Dsl: evalExpr :: MonadLP v c o m => Expr v -> m Double
- Math.Programming.Dsl: free :: LPMonad m => m (Variable m)
+ Math.Programming.Dsl: free :: MonadLP v c o m => m v
- Math.Programming.Dsl: infix 4 .==.
+ Math.Programming.Dsl: infix 4 .==
- Math.Programming.Dsl: integer :: IPMonad m => m (Variable m)
+ Math.Programming.Dsl: integer :: MonadIP v c o m => m v
- Math.Programming.Dsl: maximize :: LPMonad m => Expr m -> m (Objective m)
+ Math.Programming.Dsl: maximize :: MonadLP v c o m => Expr v -> m o
- Math.Programming.Dsl: minimize :: LPMonad m => Expr m -> m (Objective m)
+ Math.Programming.Dsl: minimize :: MonadLP v c o m => Expr v -> m o
- Math.Programming.Dsl: nonNeg :: LPMonad m => m (Variable m)
+ Math.Programming.Dsl: nonNeg :: MonadLP v c o m => m v
- Math.Programming.Dsl: nonNegInteger :: IPMonad m => m (Variable m)
+ Math.Programming.Dsl: nonNegInteger :: MonadIP v c o m => m v
- Math.Programming.Dsl: nonPos :: LPMonad m => m (Variable m)
+ Math.Programming.Dsl: nonPos :: MonadLP v c o m => m v
- Math.Programming.Dsl: nonPosInteger :: IPMonad m => m (Variable m)
+ Math.Programming.Dsl: nonPosInteger :: MonadIP v c o m => m v
- Math.Programming.Dsl: within :: LPMonad m => m (Variable m) -> Bounds (Numeric m) -> m (Variable m)
+ Math.Programming.Dsl: within :: MonadLP v c o m => m v -> Bounds -> m v
- Math.Programming.Types: Free :: Bounds b
+ Math.Programming.Types: Free :: Bounds
- Math.Programming.Types: Interval :: b -> b -> Bounds b
+ Math.Programming.Types: Interval :: Double -> Double -> Bounds
- Math.Programming.Types: NonNegativeReals :: Bounds b
+ Math.Programming.Types: NonNegativeReals :: Bounds
- Math.Programming.Types: NonPositiveReals :: Bounds b
+ Math.Programming.Types: NonPositiveReals :: Bounds
- Math.Programming.Types: addConstraint :: LPMonad m => Inequality (LinearExpression (Numeric m) (Variable m)) -> m (Constraint m)
+ Math.Programming.Types: addConstraint :: MonadLP v c o m => Inequality (Expr v) -> m c
- Math.Programming.Types: addObjective :: LPMonad m => LinearExpression (Numeric m) (Variable m) -> m (Objective m)
+ Math.Programming.Types: addObjective :: MonadLP v c o m => Expr v -> m o
- Math.Programming.Types: addVariable :: LPMonad m => m (Variable m)
+ Math.Programming.Types: addVariable :: MonadLP v c o m => m v
- Math.Programming.Types: data Bounds b
+ Math.Programming.Types: data Bounds
- Math.Programming.Types: getConstraintName :: LPMonad m => Constraint m -> m String
+ Math.Programming.Types: getConstraintName :: MonadLP v c o m => c -> m Text
- Math.Programming.Types: getObjectiveName :: LPMonad m => Objective m -> m String
+ Math.Programming.Types: getObjectiveName :: MonadLP v c o m => o -> m Text
- Math.Programming.Types: getObjectiveSense :: LPMonad m => Objective m -> m Sense
+ Math.Programming.Types: getObjectiveSense :: MonadLP v c o m => o -> m Sense
- Math.Programming.Types: getObjectiveValue :: LPMonad m => Objective m -> m (Numeric m)
+ Math.Programming.Types: getObjectiveValue :: MonadLP v c o m => o -> m Double
- Math.Programming.Types: getRelativeMIPGap :: IPMonad m => m Double
+ Math.Programming.Types: getRelativeMIPGap :: MonadIP v c o m => m Double
- Math.Programming.Types: getTimeout :: LPMonad m => m Double
+ Math.Programming.Types: getTimeout :: MonadLP v c o m => m Double
- Math.Programming.Types: getVariableBounds :: LPMonad m => Variable m -> m (Bounds (Numeric m))
+ Math.Programming.Types: getVariableBounds :: MonadLP v c o m => v -> m Bounds
- Math.Programming.Types: getVariableDomain :: IPMonad m => Variable m -> m Domain
+ Math.Programming.Types: getVariableDomain :: MonadIP v c o m => v -> m Domain
- Math.Programming.Types: getVariableName :: LPMonad m => Variable m -> m String
+ Math.Programming.Types: getVariableName :: MonadLP v c o m => v -> m Text
- Math.Programming.Types: getVariableValue :: LPMonad m => Variable m -> m (Numeric m)
+ Math.Programming.Types: getVariableValue :: MonadLP v c o m => v -> m Double
- Math.Programming.Types: optimizeIP :: IPMonad m => m SolutionStatus
+ Math.Programming.Types: optimizeIP :: MonadIP v c o m => m SolutionStatus
- Math.Programming.Types: optimizeLP :: LPMonad m => m SolutionStatus
+ Math.Programming.Types: optimizeLP :: MonadLP v c o m => m SolutionStatus
- Math.Programming.Types: setConstraintName :: LPMonad m => Constraint m -> String -> m ()
+ Math.Programming.Types: setConstraintName :: MonadLP v c o m => c -> Text -> m ()
- Math.Programming.Types: setObjectiveName :: LPMonad m => Objective m -> String -> m ()
+ Math.Programming.Types: setObjectiveName :: MonadLP v c o m => o -> Text -> m ()
- Math.Programming.Types: setObjectiveSense :: LPMonad m => Objective m -> Sense -> m ()
+ Math.Programming.Types: setObjectiveSense :: MonadLP v c o m => o -> Sense -> m ()
- Math.Programming.Types: setRelativeMIPGap :: IPMonad m => Double -> m ()
+ Math.Programming.Types: setRelativeMIPGap :: MonadIP v c o m => Double -> m ()
- Math.Programming.Types: setTimeout :: LPMonad m => Double -> m ()
+ Math.Programming.Types: setTimeout :: MonadLP v c o m => Double -> m ()
- Math.Programming.Types: setVariableBounds :: LPMonad m => Variable m -> Bounds (Numeric m) -> m ()
+ Math.Programming.Types: setVariableBounds :: MonadLP v c o m => v -> Bounds -> m ()
- Math.Programming.Types: setVariableDomain :: IPMonad m => Variable m -> Domain -> m ()
+ Math.Programming.Types: setVariableDomain :: MonadIP v c o m => v -> Domain -> m ()
- Math.Programming.Types: setVariableName :: LPMonad m => Variable m -> String -> m ()
+ Math.Programming.Types: setVariableName :: MonadLP v c o m => v -> Text -> m ()
- Math.Programming.Types: type Expr m = LinearExpression (Numeric m) (Variable m)
+ Math.Programming.Types: type Expr = LinExpr Double
Files
- ChangeLog.md +5/−0
- LICENSE +1/−1
- README.md +0/−11
- math-programming.cabal +45/−55
- src/Math/Programming.hs +105/−238
- src/Math/Programming/Dsl.hs +96/−199
- src/Math/Programming/LinExpr.hs +96/−0
- src/Math/Programming/Types.hs +246/−198
- test/Driver.hs +0/−10
- test/Math/Programming/DslSpec.hs +21/−0
- test/Math/Programming/LinExprSpec.hs +87/−0
- test/Math/Programming/TestLinearExpression.hs +0/−74
- test/Spec.hs +3/−0
ChangeLog.md view
@@ -1,5 +1,10 @@ # Changelog for math-programming +## [0.5.0] -- 18 January 2023+### Changed++- The API has been made more consistent.+ ## [0.4.0] -- 5 July 2020 ### Added
LICENSE view
@@ -1,4 +1,4 @@-Copyright Patrick Steele (c) 2018+Copyright (c) 2018-2023, Patrick Steele All rights reserved.
− README.md
@@ -1,11 +0,0 @@-# math-programming--A math programming library.--This library is designed to formulate and solve math programs, in-particular linear programs and mixed-integer linear programs.--This library alone is not sufficient to solve math programs; to do so,-a solver backend implementing the `LPMonad` or `IPMonad` classes is-required, such as the [GLPK-backend](https://github.com/prsteele/math-programming-glpk).
math-programming.cabal view
@@ -1,60 +1,50 @@-cabal-version: 1.12-name: math-programming-version: 0.4.0-license: BSD3-license-file: LICENSE-copyright: 2018 Patrick Steele-maintainer: steele.pat@gmail.com-author: Patrick Steele-homepage: https://github.com/prsteele/math-programming#readme-bug-reports: https://github.com/prsteele/math-programming/issues-synopsis: A library for formulating and solving math programs.-description:- Please see the README on GitHub at <https://github.com/prsteele/math-programming#readme>--category: Math-build-type: Simple-extra-source-files:- README.md- ChangeLog.md+cabal-version: 2.4+name: math-programming+version: 0.5.0+synopsis: A library for formulating and solving math programs.+description: Please see the <https://github.com/prsteele/math-programming/blob/main/README.md README on GitHub>.+bug-reports: https://github.com/prsteele/math-programming/issues+license: BSD-3-Clause+license-file: LICENSE+author: Patrick Steele+maintainer: steele.pat@gmail.com+copyright: 2018-2023, Patrick Steele+category: Math+build-type: Simple+extra-source-files: ChangeLog.md source-repository head- type: git- location: https://github.com/prsteele/math-programming+ type: git+ location: https://github.com/prsteele/math-programming library- exposed-modules:- Math.Programming- Math.Programming.Dsl- Math.Programming.Types-- hs-source-dirs: src- other-modules: Paths_math_programming- default-language: Haskell2010- ghc-options: -Wall- build-depends:- base >=4.7 && <5,- containers >=0.6.0.1 && <0.7,- mtl >=2.2.2 && <2.3,- text >=1.2.3.1 && <1.3--test-suite math-programming-test- type: exitcode-stdio-1.0- main-is: Driver.hs- hs-source-dirs: test- other-modules:- Math.Programming.TestLinearExpression- Paths_math_programming+ default-language: Haskell2010+ hs-source-dirs: src+ exposed-modules: Math.Programming+ , Math.Programming.Types+ , Math.Programming.Dsl+ , Math.Programming.LinExpr+ other-modules:+ ghc-options: -Wall+ -- Restrictions on transformers due to https://hub.darcs.net/ross/transformers/issue/90+ build-depends: base <5+ , containers ^>=0.6+ , exceptions ^>=0.10+ , mtl ^>=2.2+ , text ^>=1.2+ , transformers ^>=0.5 - default-language: Haskell2010- ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall- build-depends:- base >=4.7 && <5,- containers >=0.6.0.1 && <0.7,- math-programming -any,- mtl >=2.2.2 && <2.3,- tasty >=1.2.3 && <1.3,- tasty-discover >=4.2.1 && <4.3,- tasty-hunit >=0.10.0.2 && <0.11,- tasty-quickcheck >=0.10.1.1 && <0.11,- text >=1.2.3.1 && <1.3+test-suite math-programming-test-suite+ default-language: Haskell2010+ type: exitcode-stdio-1.0+ main-is: Spec.hs+ hs-source-dirs: test+ ghc-options: -threaded -with-rtsopts=-N -Wall+ other-modules: Math.Programming.LinExprSpec+ , Math.Programming.DslSpec+ build-depends: math-programming+ , base <5+ , hspec ^>=2.8+ , mtl ^>=2.2+ , QuickCheck ^>=2.14+ , text ^>=1.2
src/Math/Programming.hs view
@@ -1,273 +1,140 @@-{-| A library for modeling and solving linear and integer programs.--This library is merely a frontend to various solver backends. At the-time this was written, the only known supported backend is-<https://github.com/prsteele/math-programming-glpk GLPK>.--}+-- | A library for modeling and solving linear and integer programs.+--+-- This library is merely a frontend to various solver backends. At+-- the time this was written, the only known supported backend is+-- <https://github.com/prsteele/math-programming/blob/main/math-programming-glpk/README.md GLPK>.+--+-- This page includes a high-level overview of the model building DSL,+-- as well as a deeper dive into the core monadic interface. module Math.Programming- ( -- * Math programs- -- $mathprograms-- -- ** Linear programs- LPMonad (..)- , Expr- , Bounds (..)- , SolutionStatus (..)- , Sense (..)-- -- ** Integer programs- , IPMonad (..)- , Domain (..)-- -- * Model-building DSL+ ( -- * Model-building DSL -- $models -- ** Creating variables- -- $variables -- *** Continuous variables- , free- , nonNeg- , nonPos- , bounded- , within-- -- *** Integer variables- , integer- , binary- , nonNegInteger- , nonPosInteger- , asKind-- -- ** Linear expressions- -- $expressions- , LinearExpression (..)- , eval- , simplify- , var- , con- , exprSum- , varSum-- -- *** Addition- -- $addition- , (.+.)- , (@+@)- , (.+@)- , (@+.)- , (@+#)- , (#+@)- , (#+.)- , (.+#)-- -- *** Subtraction- -- $subtraction- , (.-.)- , (@-@)- , (.-@)- , (@-.)- , (@-#)- , (#-@)- , (#-.)- , (.-#)+ free,+ bounded,+ nonNeg,+ nonPos, - -- *** Multiplication- -- $multiplication- , (#*@)- , (@*#)- , (#*.)- , (.*#)+ -- *** Discrete variables+ integer,+ binary,+ nonNegInteger,+ nonPosInteger, - -- *** Division- -- $division- , (@/#)- , (./#)+ -- *** Modifying variables+ -- $modifiers+ within,+ asKind, - -- ** Constraints+ -- ** Creating constraints -- $constraints- , Inequality (..) + -- *** Equality constraints+ (.==.),+ (==.),+ (.==),+ -- *** Less-than constraints- -- $lt- , (#<=@)- , (#<=.)- , (@<=#)- , (@<=@)- , (@<=.)- , (.<=#)- , (.<=@)- , (.<=.)+ (.<=.),+ (<=.),+ (.<=), -- *** Greater-than constraints- -- $gt- , (#>=@)- , (#>=.)- , (@>=#)- , (@>=@)- , (@>=.)- , (.>=#)- , (.>=@)- , (.>=.)+ (.>=.),+ (>=.),+ (.>=), - -- *** Equality constraints- -- $eq- , (#==@)- , (#==.)- , (@==#)- , (@==@)- , (@==.)- , (.==#)- , (.==@)- , (.==.)+ -- ** Creating objectives+ minimize,+ maximize, - -- ** Specifying objectives- , minimize- , maximize+ -- ** Creating linear expressions+ -- $expressions+ var,+ con,+ (.*),+ (*.),+ (.+.),+ (.-.),+ (./),+ eval,+ simplify,+ vsum,+ esum,+ scale, - -- ** Utilities- , evalExpr- , named- , nameOf- ) where+ -- * Math programs+ -- $mathprograms -import Math.Programming.Dsl-import Math.Programming.Types+ -- ** Linear programs+ MonadLP (..), --- $mathprograms------ The 'LPMonad' provides all the primitives necessary to formulate--- and solve linear programs; the 'IPMonad' provides the same for--- integer programs. However, you should not often need to use these--- APIs directly, as we provide more user-friendly functions wrapping--- these low-level functions below.+ -- ** Integer programs+ MonadIP (..),+ Domain (..), --- $models------ The functions in the 'LPMonad' and 'IPMonad' typeclasses are--- designed to interface with low-level solver backends. We provide a--- cleaner interface in the following sections.+ -- * Other types and functions+ evalExpr,+ formatExpr,+ Expr,+ Bounds (..),+ SolutionStatus (..),+ Sense (..),+ Inequality (..),+ LinExpr (..), --- $variables------ 'LPMonad' provides 'addVariable' and 'setVariableBounds', and--- 'IPMonad' additionally provides 'setVariableDomain'. While--- sufficient to create your programs, you are encouraged to use the--- more natural functions below.+ -- * Naming model attributes+ withVariableName,+ withConstraintName,+ withObjectiveName,+ )+where --- $expressions------ The module 'Math.Programming.LinearExpression' provides operators--- to build up 'LinearExpression' objects using declared variables.+import Math.Programming.Dsl+import Math.Programming.LinExpr+import Math.Programming.Types --- $addition------ We can summarize the addition operators with the table+-- $introduction ----- +-----------------+--------+--------+------------------+--- | |Constant|Variable| Expression |--- +-----------------+--------+--------+------------------+--- |Constant | '+' | '#+@' | '#+.' |--- +-----------------+--------+--------+------------------+--- |Variable | '@+#' | '@+@' | '@+.' |--- +-----------------+--------+--------+------------------+--- |Expression | '.+#' | '.+@' | '.+.' |--- +-----------------+--------+--------+------------------++-- This library provides a monadic interface for building and solving+-- linear and integer programs. --- $subtraction------ We can summarize the subtraction operators with the table+-- $models ----- +-----------------+--------+--------+------------------+--- | |Constant|Variable| Expression |--- +-----------------+--------+--------+------------------+--- |Constant | '-' | '#-@' | '#-.' |--- +-----------------+--------+--------+------------------+--- |Variable | '@-#' | '@-@' | '@-.' |--- +-----------------+--------+--------+------------------+--- |Expression | '.-#' | '.-@' | '.-.' |--- +-----------------+--------+--------+------------------++-- We provide a monadic DSL for specifying math programs. This DSL+-- builds up programs statefully, rather than building some pure,+-- abstract representation of a math program. --- $multiplication------ We can summarize the multiplication operators with the table------ +-----------------+--------+--------+------------------+--- | |Constant|Variable| Expression |--- +-----------------+--------+--------+------------------+--- |Constant | '*' | '#*@' | '#*.' |--- +-----------------+--------+--------+------------------+--- |Variable | '@*#' | | |--- +-----------------+--------+--------+------------------+--- |Expression | '.*#' | | |--- +-----------------+--------+--------+------------------+------ As there are few possibilities for valid multiplication, it can be--- convenient to define e.g. @.*@ or some other short operator as an--- alias for '#*@'.+-- $modifiers+-- Regardless of the helper functions used above to create a+-- variable, you can modify its behavior using the following+-- modifiers. --- $division------ We can summarize the multiplication operators with the table------ +-----------------+--------+--------+------------------+--- | |Constant|Variable| Expression |--- +-----------------+--------+--------+------------------+--- |Constant | '/' | | |--- +-----------------+--------+--------+------------------+--- |Variable | '@/#' | | |--- +-----------------+--------+--------+------------------+--- |Expression | './#' | | |--- +-----------------+--------+--------+------------------++-- $expressions ----- As there are few possibilities for valid division, it--- can be convenient to define e.g. @./@ or some other short operator--- as an alias for '@/#'.+-- A @'LinExpr' a b@ is a linear expression over variables of type @b@+-- with coefficients of type @a@ (typically 'Double'.) We provide a+-- number of operators to build up linear expressions naturally. The+-- mnemonic is that @.@ characters point to expressions. -- $constraints ----- The 'LPMonad' provides the 'addConstraint' function. However, you--- will typically use the operators below to directly apply--- constraints to the model. We follow the same conventions as with--- our arithmetic operators.---- $lt------ We can summarize the various inquality operators in the following table.------ +-----------------+--------+--------+------------------+--- | |Constant|Variable| Expression |--- +-----------------+--------+--------+------------------+--- |Constant | | '#<=@' | '#<=.' |--- +-----------------+--------+--------+------------------+--- |Variable | '@<=#' | '@<=@' | '@<=.' |--- +-----------------+--------+--------+------------------+--- |Expression | '.<=#' | '.<=@' | '.<=.' |--- +-----------------+--------+--------+------------------+---- $gt------ We can summarize the various inquality operators in the following table.+-- An @'Inequality' a@ is an inequality over the type @a@, which in+-- turn is typically an @'Expr' v@ for some variable type @v@. Despite+-- the name, 'Inequality' can also represent equality constraints+-- directly. ----- +-----------------+--------+--------+------------------+--- | |Constant|Variable| Expression |--- +-----------------+--------+--------+------------------+--- |Constant | | '#>=@' | '#>=.' |--- +-----------------+--------+--------+------------------+--- |Variable | '@>=#' | '@>=@' | '@>=.' |--- +-----------------+--------+--------+------------------+--- |Expression | '.>=#' | '.>=@' | '.>=.' |--- +-----------------+--------+--------+------------------++-- As an alternative to constructing an inequality and passing it to+-- 'addConstraint', we can use the convenience operators below. Since+-- linear programming constraints often involve constant bounds, we+-- offer operators specialized for both expressions and constants. The+-- mnemonic is that @.@ characters point to expressions --- $eq------ We can summarize the various inquality operators in the following table.+-- $mathprograms ----- +-----------------+--------+--------+------------------+--- | |Constant|Variable| Expression |--- +-----------------+--------+--------+------------------+--- |Constant | | '#==@' | '#==.' |--- +-----------------+--------+--------+------------------+--- |Variable | '@==#' | '@==@' | '@==.' |--- +-----------------+--------+--------+------------------+--- |Expression | '.==#' | '.==@' | '.==.' |--- +-----------------+--------+--------+------------------++-- The 'MonadLP' and 'MonadIP' classes provide low-level APIs for+-- defining linear and integer programs, respectively, although the+-- high-level DSL will typically be easier to work with.
src/Math/Programming/Dsl.hs view
@@ -1,42 +1,47 @@-module Math.Programming.Dsl where+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-} -import Data.Bifunctor-import Data.List (sortOn)+module Math.Programming.Dsl where -import Math.Programming.Types+import Data.Functor+import qualified Data.Text as T+import Math.Programming.LinExpr+import Math.Programming.Types+import Text.Printf -- | Create an objective to be minimized.-minimize :: LPMonad m => Expr m -> m (Objective m)+minimize :: MonadLP v c o m => Expr v -> m o minimize objectiveExpr = do objective <- addObjective objectiveExpr setObjectiveSense objective Minimization pure objective -- | Create an objective to be maximized.-maximize :: LPMonad m => Expr m -> m (Objective m)+maximize :: MonadLP v c o m => Expr v -> m o maximize objectiveExpr = do objective <- addObjective objectiveExpr setObjectiveSense objective Maximization pure objective -- | Get the value of a linear expression in the current solution.-evalExpr :: LPMonad m => Expr m -> m (Numeric m)-evalExpr expr = traverse getVariableValue expr >>= return . eval+evalExpr :: MonadLP v c o m => Expr v -> m Double+evalExpr expr = traverse getVariableValue expr <&> eval -- | Create a new free variable.-free :: LPMonad m => m (Variable m)+free :: MonadLP v c o m => m v free = addVariable `within` Free -- | Create a new non-negative variable.-nonNeg :: LPMonad m => m (Variable m)+nonNeg :: MonadLP v c o m => m v nonNeg = addVariable `within` NonNegativeReals -- | Create a new non-positive variable.-nonPos :: LPMonad m => m (Variable m)+nonPos :: MonadLP v c o m => m v nonPos = addVariable `within` NonPositiveReals -- | Create a new variable bounded between two values.-bounded :: LPMonad m => Numeric m -> Numeric m -> m (Variable m)+bounded :: MonadLP v c o m => Double -> Double -> m v bounded lo hi = within addVariable (Interval lo hi) -- | Constrain a variable to take on certain values.@@ -44,28 +49,31 @@ -- This function is designed to be used as an infix operator, e.g. -- -- @--- 'addVariable' \``within`\` 'NonNegativeReals'+-- 'integer' \``within`\` 'Interval 3 7' -- @-within :: LPMonad m => m (Variable m) -> Bounds (Numeric m) -> m (Variable m)+--+-- creates an integer variable that can take on values 3, 4, 5, 6, or+-- 7.+within :: MonadLP v c o m => m v -> Bounds -> m v within makeVar bounds = do variable <- makeVar setVariableBounds variable bounds pure variable -- | Create an integer-valued variable.-integer :: IPMonad m => m (Variable m)-integer = addVariable `asKind` Integer+integer :: MonadIP v c o m => m v+integer = addVariable `asKind` Integer `within` Free -- | Create a binary variable.-binary :: IPMonad m => m (Variable m)+binary :: MonadIP v c o m => m v binary = addVariable `asKind` Binary -- | Create an integer-value variable that takes on non-negative values.-nonNegInteger :: IPMonad m => m (Variable m)+nonNegInteger :: MonadIP v c o m => m v nonNegInteger = addVariable `asKind` Integer `within` NonNegativeReals -- | Create an integer-value variable that takes on non-positive values.-nonPosInteger :: IPMonad m => m (Variable m)+nonPosInteger :: MonadIP v c o m => m v nonPosInteger = addVariable `asKind` Integer `within` NonPositiveReals -- | Set the type of a variable.@@ -73,202 +81,91 @@ -- This function is designed to be used as an infix operator, e.g. -- -- @--- 'addVariable' \``asKind`\` 'Binary'+-- 'free' \``asKind`\` 'Binary' -- @-asKind :: IPMonad m => m (Variable m) -> Domain -> m (Variable m)-asKind make domain = do+asKind :: MonadIP v c o m => m v -> Domain -> m v+asKind make dom = do variable <- make- setVariableDomain variable domain+ setVariableDomain variable dom pure variable --- | Name a variable, constraint, or objective.------ This function is designed to be used as an infix operator, e.g.------ @--- 'free' \``named`\` "X_1"--- @-named :: (Monad m, Nameable m a) => m a -> String -> m a-named make name = do- x <- make- setName x name- pure x+-- | A less-than or equal-to constraint+(.<=.) :: MonadLP v c o m => Expr v -> Expr v -> m c+(.<=.) x y = addConstraint $ Inequality LT x y --- | Retrieve the name of a variable, constraint, or objective.-nameOf :: (Monad m, Nameable m a) => a -> m String-nameOf = getName+-- | A less-than or equal-to constraint with a numeric left-hand side+(<=.) :: MonadLP v c o m => Double -> Expr v -> m c+(<=.) x y = con x .<=. y -(#+@) :: Num a => a -> b -> LinearExpression a b-(#+.) :: Num a => a -> LinearExpression a b -> LinearExpression a b-(@+#) :: Num a => b -> a -> LinearExpression a b-(@+@) :: Num a => b -> b -> LinearExpression a b-(@+.) :: Num a => b -> LinearExpression a b -> LinearExpression a b-(.+#) :: Num a => LinearExpression a b -> a -> LinearExpression a b-(.+@) :: Num a => LinearExpression a b -> b -> LinearExpression a b-(.+.) :: Num a => LinearExpression a b -> LinearExpression a b -> LinearExpression a b-(#-@) :: Num a => a -> b -> LinearExpression a b-(#-.) :: Num a => a -> LinearExpression a b -> LinearExpression a b-(@-#) :: Num a => b -> a -> LinearExpression a b-(@-@) :: Num a => b -> b -> LinearExpression a b-(@-.) :: Num a => b -> LinearExpression a b -> LinearExpression a b-(.-#) :: Num a => LinearExpression a b -> a -> LinearExpression a b-(.-@) :: Num a => LinearExpression a b -> b -> LinearExpression a b-(.-.) :: Num a => LinearExpression a b -> LinearExpression a b -> LinearExpression a b-(#*.) :: Num a => a -> LinearExpression a b -> LinearExpression a b-(.*#) :: Num a => LinearExpression a b -> a -> LinearExpression a b-(#*@) :: Num a => a -> b -> LinearExpression a b-(@*#) :: Num a => b -> a -> LinearExpression a b-(@/#) :: Fractional a => b -> a -> LinearExpression a b-(./#) :: Fractional a => LinearExpression a b -> a -> LinearExpression a b+-- | A less-than or equal-to constraint with a numeric right-hand side+(.<=) :: MonadLP v c o m => Expr v -> Double -> m c+(.<=) x y = x .<=. con y -x #+@ y = con x .+. var y-x #+. y = con x .+. y-x @+# y = var x .+. con y-x @+@ y = var x .+. var y-x @+. y = var x .+. y-x .+@ y = x .+. var y-x .+# y = x .+. con y-x .+. y = x <> y-x #-@ y = con x .-. var y-x #-. y = con x .-. y-x @-# y = var x .-. con y-x @-@ y = var x .-. var y-x @-. y = var x .-. y-x .-# y = x .-. con y-x .-@ y = x .-. var y-x .-. y = x .+. (-1) #*. y-x #*@ y = var y .*# x-x #*. y = y .*# x-x @*# y = var x .*# y-x .*# y = first (* y) x-x @/# y = var x ./# y-x ./# y = first (/ y) x+-- | A greater-than or equal-to constraint+(.>=.) :: MonadLP v c o m => Expr v -> Expr v -> m c+(.>=.) x y = addConstraint $ Inequality GT x y -infixl 6 #+@-infixl 6 #+.-infixl 6 @+#-infixl 6 @+@-infixl 6 @+.-infixl 6 .+#-infixl 6 .+@-infixl 6 .+.-infixl 6 #-@-infixl 6 #-.-infixl 6 @-#-infixl 6 @-@-infixl 6 @-.-infixl 6 .-#-infixl 6 .-@-infixl 6 .-.-infixl 7 #*@-infixl 7 #*.-infixl 7 @*#-infixl 7 .*#-infixl 7 @/#-infixl 7 ./#+-- | A greater-than or equal-to constraint with a numeric left-hand side+(>=.) :: MonadLP v c o m => Double -> Expr v -> m c+(>=.) x y = con x .>=. y --- | Combine equivalent terms by summing their coefficients.-simplify :: (Ord b, Num a) => LinearExpression a b -> LinearExpression a b-simplify (LinearExpression terms constant)- = LinearExpression (reduce (sortOn snd terms)) constant- where- reduce [] = []- reduce ((c, x): []) = [(c, x)]- reduce ((c, x): (c', x'): xs)- | x == x' = (c + c', x) : reduce xs- | otherwise = (c, x) : reduce ((c', x'): xs)+-- | A greater-than or equal-to constraint with a numeric right-hand side+(.>=) :: MonadLP v c o m => Expr v -> Double -> m c+(.>=) x y = x .>=. con y --- | Reduce an expression to its value.-eval :: Num a => LinearExpression a a -> a-eval (LinearExpression terms constant) = constant + sum (map (uncurry (*)) terms)+-- | An equality constraint+(.==.) :: MonadLP v c o m => Expr v -> Expr v -> m c+(.==.) x y = addConstraint $ Inequality EQ x y --- | Construct an expression representing a variable.-var :: Num a => b -> LinearExpression a b-var x = LinearExpression [(1, x)] 0+-- | An equality constraint with a numeric left-hand side+(==.) :: MonadLP v c o m => Double -> Expr v -> m c+(==.) x y = con x .==. y --- | Construct an expression representing a constant.-con :: Num a => a -> LinearExpression a b-con x = LinearExpression [] x+-- | An equality constraint with a numeric right-hand side+(.==) :: MonadLP v c o m => Expr v -> Double -> m c+(.==) x y = x .==. con y --- | Construct an expression by summing expressions.-exprSum :: Num a => [LinearExpression a b] -> LinearExpression a b-exprSum = mconcat+infix 4 <=. --- | Construct an expression by summing variables.-varSum :: Num a => [b] -> LinearExpression a b-varSum = mconcat . fmap var+infix 4 .<= -(#<=@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)-(#<=.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)-(@<=#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)-(@<=@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)-(@<=.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)-(.<=#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)-(.<=@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)-(.<=.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)-(#>=@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)-(#>=.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)-(@>=#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)-(@>=@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)-(@>=.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)-(.>=#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)-(.>=@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)-(.>=.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)-(#==@) :: LPMonad m => Numeric m -> Variable m -> m (Constraint m)-(#==.) :: LPMonad m => Numeric m -> Expr m -> m (Constraint m)-(@==#) :: LPMonad m => Variable m -> Numeric m -> m (Constraint m)-(@==@) :: LPMonad m => Variable m -> Variable m -> m (Constraint m)-(@==.) :: LPMonad m => Variable m -> Expr m -> m (Constraint m)-(.==#) :: LPMonad m => Expr m -> Numeric m -> m (Constraint m)-(.==@) :: LPMonad m => Expr m -> Variable m -> m (Constraint m)-(.==.) :: LPMonad m => Expr m -> Expr m -> m (Constraint m)+infix 4 .<=. -x #<=@ y = addConstraint $ Inequality LT (con x) (var y)-x #<=. y = addConstraint $ Inequality LT (con x) y-x @<=# y = addConstraint $ Inequality LT (var x) (con y)-x @<=@ y = addConstraint $ Inequality LT (var x) (var y)-x @<=. y = addConstraint $ Inequality LT (var x) y-x .<=# y = addConstraint $ Inequality LT x (con y)-x .<=@ y = addConstraint $ Inequality LT x (var y)-x .<=. y = addConstraint $ Inequality LT x y-x #>=@ y = addConstraint $ Inequality GT (con x) (var y)-x #>=. y = addConstraint $ Inequality GT (con x) y-x @>=# y = addConstraint $ Inequality GT (var x) (con y)-x @>=@ y = addConstraint $ Inequality GT (var x) (var y)-x @>=. y = addConstraint $ Inequality GT (var x) y-x .>=# y = addConstraint $ Inequality GT x (con y)-x .>=@ y = addConstraint $ Inequality GT x (var y)-x .>=. y = addConstraint $ Inequality GT x y-x #==@ y = addConstraint $ Inequality EQ (con x) (var y)-x #==. y = addConstraint $ Inequality EQ (con x) y-x @==# y = addConstraint $ Inequality EQ (var x) (con y)-x @==@ y = addConstraint $ Inequality EQ (var x) (var y)-x @==. y = addConstraint $ Inequality EQ (var x) y-x .==# y = addConstraint $ Inequality EQ x (con y)-x .==@ y = addConstraint $ Inequality EQ x (var y)-x .==. y = addConstraint $ Inequality EQ x y+infix 4 >=. -infix 4 #<=@-infix 4 #<=.-infix 4 @<=#-infix 4 @<=@-infix 4 @<=.-infix 4 .<=#-infix 4 .<=@-infix 4 .<=.-infix 4 #>=@-infix 4 #>=.-infix 4 @>=#-infix 4 @>=@-infix 4 @>=.-infix 4 .>=#-infix 4 .>=@+infix 4 .>=+ infix 4 .>=.-infix 4 #==@-infix 4 #==.-infix 4 @==#-infix 4 @==@-infix 4 @==.-infix 4 .==#-infix 4 .==@++infix 4 ==.++infix 4 .==+ infix 4 .==.++formatExpr :: MonadLP v c o m => Expr v -> m T.Text+formatExpr = formatExpr' getVariableName++formatExpr' :: Monad m => (v -> m T.Text) -> Expr v -> m T.Text+formatExpr' nameOf (LinExpr terms coef) = do+ names <- mapM (traverse nameOf) terms+ let strTerms = fmap (T.pack . uncurry (printf "%f * %s")) names+ pure $ T.intercalate " + " (strTerms <> [T.pack (show coef)])++withVariableName :: MonadLP v c o m => m v -> T.Text -> m v+withVariableName mv name = do+ v <- mv+ setVariableName v name+ pure v++withConstraintName :: MonadLP v c o m => m c -> T.Text -> m c+withConstraintName mc name = do+ c <- mc+ setConstraintName c name+ pure c++withObjectiveName :: MonadLP v c o m => m o -> T.Text -> m o+withObjectiveName mo name = do+ o <- mo+ setObjectiveName o name+ pure o
+ src/Math/Programming/LinExpr.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE TupleSections #-}++-- | Linear expressions of variables.+module Math.Programming.LinExpr where++import Data.List (foldl', sortOn)++-- | A linear expression.+--+-- Linear expressions contain symbolic variables of type @b@ and+-- numeric coefficients of type @a@. Often @a@ will be 'Double', and+-- @b@ will be whatever variable type your linear program uses.+data LinExpr a b+ = LinExpr ![(a, b)] !a+ deriving (Eq, Read, Show, Functor, Foldable, Traversable)++instance Num a => Semigroup (LinExpr a b) where+ (<>) = (.+.)++instance Num a => Monoid (LinExpr a b) where+ mempty = con 0++-- | Construct a term in a linear expression by multiplying a constant+-- by a variable.+(*.) :: Num a => a -> b -> LinExpr a b+(*.) x y = LinExpr [(x, y)] 0++infixl 7 .*++-- | Construct a term in a linear expression by multiplying a variable+-- by a constant.+(.*) :: Num a => b -> a -> LinExpr a b+(.*) = flip (*.)++infixl 7 *.++-- | Construct a term in a linear expression by dividing a variable by+-- a constant.+(./) :: Fractional a => b -> a -> LinExpr a b+(./) x y = x .* (1 / y)++infixl 7 ./++-- | Multiplication of linear expressions by a constant.+scale :: Num a => a -> LinExpr a b -> LinExpr a b+scale coef (LinExpr terms constant) = LinExpr terms' constant'+ where+ terms' = [(c * coef, x) | (c, x) <- terms]+ constant' = constant * coef++-- | Addition of linear expressions.+(.+.) :: Num a => LinExpr a b -> LinExpr a b -> LinExpr a b+(.+.) (LinExpr terms constant) (LinExpr terms' constant') =+ LinExpr (terms <> terms') (constant + constant')++infixl 6 .+.++-- | The difference of linear expressions.+(.-.) :: Num a => LinExpr a b -> LinExpr a b -> LinExpr a b+(.-.) x y = x .+. scale (-1) y++infixl 6 .-.++-- | A linear expression with a single variable term.+var :: Num a => b -> LinExpr a b+var x = LinExpr [(1, x)] 0++-- | A linear expression with only a constant term.+con :: a -> LinExpr a b+con = LinExpr []++-- | The sum of variable terms with coefficients of unity.+vsum :: Num a => [b] -> LinExpr a b+vsum = flip LinExpr 0 . fmap (1,)++-- | The sum of linear expressions.+esum :: Num a => Foldable t => t (LinExpr a b) -> LinExpr a b+esum = foldl' (.+.) mempty++-- | Reduce an expression to its value.+eval :: Num a => LinExpr a a -> a+eval (LinExpr terms constant) = constant + sum' (map (uncurry (*)) terms)+ where+ sum' = foldl' (+) 0++-- | Simplify an expression by grouping like terms.+simplify :: (Num a, Ord b) => LinExpr a b -> LinExpr a b+simplify (LinExpr terms constant) =+ LinExpr (foldr f [] (sortOn snd terms)) constant+ where+ f (c, x) [] = [(c, x)]+ f (c, x) ((c', x') : xs) =+ if x == x'+ then (c + c', x) : xs+ else (c, x) : (c', x') : xs
src/Math/Programming/Types.hs view
@@ -1,178 +1,287 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies #-}-module Math.Programming.Types where+{-# LANGUAGE UndecidableInstances #-} -import Data.Bifunctor-import Data.Traversable (fmapDefault, foldMapDefault)+-- | Data and class definitions for the core math programming+-- interface.+module Math.Programming.Types where --- | A convient shorthand for the type of linear expressions used in a--- given model.-type Expr m = LinearExpression (Numeric m) (Variable m)+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 monad for formulating and solving linear programs.+-- | A linear program. ----- We manipulate linear programs and their settings using the--- 'Mutable' typeclass.-class (Monad m, Show (Numeric m), RealFrac (Numeric m)) => LPMonad m where- -- | The numeric type used in the model.- type Numeric m :: *-- -- | The type of variables in the model. 'LPMonad' treats these as- -- opaque values, but instances may expose more details.- data Variable m :: *-- -- | The type of constraints in the model. 'LPMonad' treats these- -- as opaque values, but instances may expose more details.- data Constraint m :: *-- -- | The type of objectives in the model. 'LPMonad' treats these- -- as opaque values, but instances may expose more details.- data Objective m :: *-- -- | Create a new decision variable in the model.+-- 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. --- -- This variable will be initialized to be a non-negative continuous- -- variable.- addVariable :: m (Variable m)+ -- 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 decision variable from the model.- --- -- The variable cannot be used after being deleted.- removeVariable :: Variable m -> m ()+ -- | Remove a variable from the model.+ deleteVariable :: v -> m () - -- | Get the name of the variable.- getVariableName :: Variable m -> m String+ -- | Get the name of a variable.+ getVariableName :: v -> m T.Text - -- | Set the name of the variable.- setVariableName :: Variable m -> String -> m ()+ -- | Set a name for a variable.+ setVariableName :: v -> T.Text -> m () - -- | Get the allowed values of a variable.- getVariableBounds :: Variable m -> m (Bounds (Numeric m))+ -- | Retrieve the current bounds associated with a variable.+ getVariableBounds :: v -> m Bounds - -- | Constrain a variable to take on certain values.- setVariableBounds :: Variable m -> Bounds (Numeric m) -> m ()+ -- | 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.- getVariableValue :: Variable m -> m (Numeric m)+ --+ -- 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 to the model represented by an inequality.- addConstraint :: Inequality (LinearExpression (Numeric m) (Variable m)) -> m (Constraint m)+ -- | 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.- --- -- The constraint cannot used after being deleted.- removeConstraint :: Constraint m -> m ()+ deleteConstraint :: c -> m () - -- | Get the name of the constraint.- getConstraintName :: Constraint m -> m String+ -- | Get the name of a constraint.+ getConstraintName :: c -> m T.Text - -- | Set the name of the constraint.- setConstraintName :: Constraint m -> String -> m ()+ -- | Set a name for a constraint.+ setConstraintName :: c -> T.Text -> m () - -- | Get the value of the dual variable associated with the- -- constraint in the current solution.+ -- | Get the dual value associated with a constraint.+ getConstraintValue :: c -> m Double++ -- | Add an objective to the problem. --- -- This value has no meaning if the current solution is not an LP- -- solution.- getDualValue :: Constraint m -> m (Numeric m)+ -- Depending on the solver backend, this might replace an existing objective.+ addObjective :: Expr v -> m o - -- | Add a constraint to the model represented by an inequality.- addObjective :: LinearExpression (Numeric m) (Variable m) -> m (Objective m)+ -- | Remove an objective from the model.+ deleteObjective :: o -> m () - -- | Get the name of the objective.- getObjectiveName :: Objective m -> m String+ -- | Get the name of a objective.+ getObjectiveName :: o -> m T.Text - -- | Set the name of the objective.- setObjectiveName :: Objective m -> String -> m ()+ -- | Set a name for a objective.+ setObjectiveName :: o -> T.Text -> m () - -- | Whether the objective is to be minimized or maximized.- getObjectiveSense :: Objective m -> m Sense+ -- | Get the sense of an objective.+ getObjectiveSense :: o -> m Sense - -- | Set whether the objective is to be minimized or maximized.- setObjectiveSense :: Objective m -> Sense -> m ()+ -- | Set the sense of an objective.+ setObjectiveSense :: o -> Sense -> m () - -- | Get the value of the objective in the current solution.- getObjectiveValue :: Objective m -> m (Numeric m)+ -- | Get the value of an objective.+ getObjectiveValue :: o -> m Double - -- | Get the number of seconds the solver is allowed to run before- -- halting.+ -- | Get the timeout associated with a problem. getTimeout :: m Double - -- | Set the number of seconds the solver is allowed to run before- -- halting.+ -- | Set the timeout associated with a problem. setTimeout :: Double -> m () - -- | Optimize the continuous relaxation of the model.+ -- | 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 'LPMonad' class, this monad+-- In addition to the methods of the 'MonadLP' class, this monad -- supports constraining variables to be either continuous or -- discrete.-class ( LPMonad m- ) => IPMonad m where- -- | Optimize the mixed-integer program.- optimizeIP :: m SolutionStatus+class MonadLP v c o m => MonadIP v c o m | m -> v c o where+ getVariableDomain :: v -> m Domain+ setVariableDomain :: v -> Domain -> m () - -- | Get the domain of a variable.- getVariableDomain :: Variable m -> m Domain+ getRelativeMIPGap :: m Double+ setRelativeMIPGap :: Double -> m () - -- | Set the domain of a variable.- setVariableDomain :: Variable m -> Domain -> m ()+ optimizeIP :: m SolutionStatus - -- | Get the allowed relative gap between LP and IP solutions.- getRelativeMIPGap :: m Double+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 - -- | Set the allowed relative gap between LP and IP solutions.- setRelativeMIPGap :: Double -> m ()+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+ ( Eq,+ Ord,+ Read,+ Show ) -- | The outcome of an optimization. data SolutionStatus- = Optimal- -- ^ An optimal solution has been found.- | Feasible- -- ^ A feasible solution has been found. The result may or may not- -- be optimal.- | Infeasible- -- ^ The model has been proven to be infeasible.- | Unbounded- -- ^ The model has been proven to be unbounded.- | Error- -- ^ An error was encountered during the solve. Instance-specific- -- methods should be used to determine what occurred.+ = -- | 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+ ( Eq,+ Ord,+ Read,+ Show ) -- | An interval of the real numbers.-data Bounds b- = NonNegativeReals- -- ^ The non-negative reals.- | NonPositiveReals- -- ^ The non-positive reals.- | Interval b b- -- ^ Any closed interval of the reals.- | Free- -- ^ Any real number.+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+ ( Read,+ Show ) -- | The type of values that a variable can take on.@@ -182,89 +291,28 @@ -- of the same name. The ambiguity is unfortunate, but other natural -- nomenclature such as @Integral@ are similarly conflicted. data Domain- = Continuous- -- ^ The variable lies in the real numbers- | Integer- -- ^ The variable lies in the integers- | Binary- -- ^ The variable lies in the set @{0, 1}@.- deriving- ( Read- , Show- )--class Nameable m a where- getName :: a -> m String- setName :: a -> String -> m ()--instance LPMonad m => Nameable m (Variable m) where- getName = getVariableName- setName = setVariableName--instance LPMonad m => Nameable m (Constraint m) where- getName = getConstraintName- setName = setConstraintName--instance LPMonad m => Nameable m (Objective m) where- getName = getObjectiveName- setName = setObjectiveName---- | A linear expression containing symbolic variables of type @b@ and--- numeric coefficients of type @a@.------ Using 'String's to denote variables and 'Double's as our numeric--- type, we could express /3 x + 2 y + 1/ as------ @--- LinearExpression [(3, "x"), (2, "y")] 1--- @-data LinearExpression a b- = LinearExpression [(a, b)] a+ = -- | 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+ ( Read,+ Show ) --- | Implements addition of 'LinearExpression a b' terms-instance Num a => Semigroup (LinearExpression a b) where- (LinearExpression termsLhs constantLhs) <> (LinearExpression termsRhs constantRhs)- = LinearExpression (termsLhs <> termsRhs) (constantLhs + constantRhs)---- | Using '0' as the identity element-instance Num a => Monoid (LinearExpression a b) where- mempty = LinearExpression [] 0--instance Functor (LinearExpression a) where- fmap = fmapDefault--instance Bifunctor LinearExpression where- first f (LinearExpression terms constant)- = LinearExpression (fmap (first f) terms) (f constant)- second f (LinearExpression terms constant)- = LinearExpression (fmap (fmap f) terms) constant--instance Foldable (LinearExpression a) where- foldMap = foldMapDefault---- | Useful for substituting values in a monadic/applicative context-instance Traversable (LinearExpression a) where- traverse f (LinearExpression terms constant)- = LinearExpression <$> traverse (traverse f) terms <*> pure constant- -- | Non-strict inequalities. data Inequality a = Inequality Ordering a a deriving- ( Read- , Show+ ( Read,+ Show,+ Functor,+ Foldable,+ Traversable ) -instance Functor Inequality where- fmap = fmapDefault--instance Foldable Inequality where- foldMap = foldMapDefault--instance Traversable Inequality where- traverse f (Inequality sense lhs rhs)- = Inequality sense <$> f lhs <*> f rhs+-- | A convient shorthand for the type of linear expressions used in+-- models.+type Expr = LinExpr Double
− test/Driver.hs
@@ -1,10 +0,0 @@-{-# OPTIONS_GHC -F -pgmF tasty-discover -optF --ignores="*~" #-}-{-|-Module : Main--The entry point for tests. We use tasty-discover to automatically-discover test functions in this directory, so simply preface tasty-tests with test_ for tasty TestTrees, or prop_ for QuickCheck-properties.--}-module Main where
+ test/Math/Programming/DslSpec.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE OverloadedStrings #-}++module Math.Programming.DslSpec where++import Control.Monad.Identity+import qualified Data.Text as T+import Math.Programming+import Math.Programming.Dsl+import Test.Hspec++spec :: Spec+spec = do+ describe "formatExpr" $ do+ it "formats expressions correctly" $ do+ let ex :: Expr T.Text+ ex = 2 *. "x" .+. 3 *. "y" .+. con 1+ formatExpr' pure ex `shouldBe` Identity "2.0 * x + 3.0 * y + 1.0"++ let ex2 :: Expr T.Text+ ex2 = con 0+ formatExpr' pure ex2 `shouldBe` Identity "0.0"
+ test/Math/Programming/LinExprSpec.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE FlexibleInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Math.Programming.LinExprSpec where++import Control.Monad+import Data.Ratio+import Math.Programming+import Test.Hspec+import Test.Hspec.QuickCheck+import Test.QuickCheck++spec :: Spec+spec = do+ describe "algebraic properties" $ do+ prop "satisfies addititive commutivity" commutativityProp+ prop "satisfies addititive associativity" additiveAssociativityProp+ prop "satisfies coefficient commutativity" coefficientCommutativityProp+ describe "simplification" $ do+ simplifyRegressions+ prop "simplification preserves value" simplifyProp++type ExactExpr = LinExpr (Ratio Integer) (Ratio Integer)++instance Arbitrary ExactExpr where+ arbitrary = LinExpr <$> arbitrary <*> arbitrary++-- | A pair of linear expressions, differing only by the ordering of+-- the summands.+newtype ShuffledAndUnshuffled+ = ShuffledAndUnshuffled (ExactExpr, ExactExpr)+ deriving+ ( Show+ )++instance Arbitrary ShuffledAndUnshuffled where+ arbitrary = do+ unshuffled@(LinExpr terms constant) <- arbitrary+ shuffledTerms <- shuffle terms+ let shuffled = LinExpr shuffledTerms constant+ return $ ShuffledAndUnshuffled (unshuffled, shuffled)++-- | Addition should be commutative.+commutativityProp :: ShuffledAndUnshuffled -> Bool+commutativityProp (ShuffledAndUnshuffled (shuffled, unshuffled)) =+ eval shuffled == eval unshuffled++-- | A pair of linear expressions, differing only by the ordering of+-- the coefficients of the summands.+newtype ShuffledCoefficients+ = ShuffledCoefficients (ExactExpr, ExactExpr)+ deriving+ ( Show+ )++instance Arbitrary ShuffledCoefficients where+ arbitrary = do+ unshuffled@(LinExpr terms constant) <- arbitrary+ terms' <- forM terms $ \(x, y) -> do+ flipped <- arbitrary+ return $+ if flipped+ then (y, x)+ else (x, y)+ let shuffled = LinExpr terms' constant+ return $ ShuffledCoefficients (shuffled, unshuffled)++coefficientCommutativityProp :: ShuffledCoefficients -> Bool+coefficientCommutativityProp (ShuffledCoefficients (shuffled, unshuffled)) =+ eval shuffled == eval unshuffled++additiveAssociativityProp :: ExactExpr -> ExactExpr -> ExactExpr -> Bool+additiveAssociativityProp x y z =+ eval ((x .+. y) .+. z) == eval (x .+. (y .+. z))++simplifyProp :: ExactExpr -> Bool+simplifyProp x = eval x == eval (simplify x)++simplifyRegressions :: Spec+simplifyRegressions = do+ it "simplifies x + x - x" $+ let terms :: [(Int, Int)]+ coef :: Int+ (LinExpr terms coef) = simplify $ LinExpr [(1, 0), (1, 0), (-1, 0)] 0+ in do+ coef `shouldBe` 0+ terms `shouldBe` [(1, 0)]
− test/Math/Programming/TestLinearExpression.hs
@@ -1,74 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-# LANGUAGE FlexibleInstances #-}-module Math.Programming.TestLinearExpression where--import Control.Monad-import Data.Ratio--import Test.Tasty-import Test.Tasty.QuickCheck--import Math.Programming--test_tree :: TestTree-test_tree = testGroup "LinearExpression tests"- [ testProperty "Additive commutativity" commutativityProp- , testProperty "Additive associativity" additiveAssociativityProp- , testProperty "Coefficient commutativity" coefficientCommutativityProp- , testProperty "Simplification" simplifyProp- ]--type ExactExpr = LinearExpression (Ratio Integer) (Ratio Integer)--instance Arbitrary ExactExpr where- arbitrary = LinearExpression <$> arbitrary <*> arbitrary---- | A pair of linear expressions, differing only by the ordering of--- the summands.-newtype ShuffledAndUnshuffled- = ShuffledAndUnshuffled (ExactExpr, ExactExpr)- deriving- ( Show- )--instance Arbitrary ShuffledAndUnshuffled where- arbitrary = do- unshuffled@(LinearExpression terms constant) <- arbitrary- shuffledTerms <- shuffle terms- let shuffled = LinearExpression shuffledTerms constant- return $ ShuffledAndUnshuffled (unshuffled, shuffled)---- | Addition should be commutative.-commutativityProp :: ShuffledAndUnshuffled -> Bool-commutativityProp (ShuffledAndUnshuffled (shuffled, unshuffled))- = eval shuffled == eval unshuffled---- | A pair of linear expressions, differing only by the ordering of--- the coefficients of the summands.-newtype ShuffledCoefficients- = ShuffledCoefficients (ExactExpr, ExactExpr)- deriving- ( Show- )--instance Arbitrary ShuffledCoefficients where- arbitrary = do- unshuffled@(LinearExpression terms constant) <- arbitrary- terms' <- forM terms $ \(x, y) -> do- flipped <- arbitrary- return $ if flipped- then (y, x)- else (x, y)- let shuffled = LinearExpression terms' constant- return $ ShuffledCoefficients (shuffled, unshuffled)--coefficientCommutativityProp :: ShuffledCoefficients -> Bool-coefficientCommutativityProp (ShuffledCoefficients (shuffled, unshuffled))- = eval shuffled == eval unshuffled--additiveAssociativityProp :: ExactExpr -> ExactExpr -> ExactExpr -> Bool-additiveAssociativityProp x y z- = eval ((x .+. y) .+. z) == eval (x .+. (y .+. z))--simplifyProp :: ExactExpr -> Bool-simplifyProp x = eval x == eval (simplify x)
+ test/Spec.hs view
@@ -0,0 +1,3 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}++module Spec where