{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_HADDOCK show-extensions #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  ToySolver.Arith.Simplex.Textbook.LPSolver
-- Copyright   :  (c) Masahiro Sakai 2011
-- License     :  BSD-style
--
-- Maintainer  :  masahiro.sakai@gmail.com
-- Stability   :  provisional
-- Portability :  non-portable
--
-- Naïve implementation of Simplex method
--
-- Reference:
--
-- * <http://www.math.cuhk.edu.hk/~wei/lpch3.pdf>
--
-----------------------------------------------------------------------------

module ToySolver.Arith.Simplex.Textbook.LPSolver
  (
  -- * Solver type
    Solver
  , emptySolver

  -- * LP monad
  , LP
  , getTableau
  , putTableau

  -- * Problem specification
  , newVar
  , addConstraint
  , addConstraintWithArtificialVariable
  , tableau
  , define

  -- * Solving
  , phaseI
  , simplex
  , dualSimplex
  , OptResult (..)
  , twoPhaseSimplex
  , primalDualSimplex

  -- * Extract results
  , getModel

  -- * Utilities
  , collectNonnegVars
  ) where

import Control.Exception (assert)
import Control.Monad
import Control.Monad.State
import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import Data.OptDir
import Data.VectorSpace

import Data.Interval ((<=!), (>=!), (==!), (<!), (>!), (/=!))
import qualified Data.Interval as Interval

import ToySolver.Data.OrdRel
import qualified ToySolver.Data.LA as LA
import ToySolver.Data.IntVar
import qualified ToySolver.Arith.Simplex.Textbook as Simplex
import qualified ToySolver.Arith.BoundsInference as BI

-- ---------------------------------------------------------------------------
-- Solver type

type Solver r = (Var, Simplex.Tableau r, VarSet, VarMap (LA.Expr r))

emptySolver :: VarSet -> Solver r
emptySolver :: VarSet -> Solver r
emptySolver VarSet
vs = (Key
1 Key -> Key -> Key
forall a. Num a => a -> a -> a
+ [Key] -> Key
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ((-Key
1) Key -> [Key] -> [Key]
forall a. a -> [a] -> [a]
: VarSet -> [Key]
IS.toList VarSet
vs), Tableau r
forall r. Tableau r
Simplex.emptyTableau, VarSet
IS.empty, IntMap (Expr r)
forall a. IntMap a
IM.empty)

-- ---------------------------------------------------------------------------
-- LP Monad

type LP r = State (Solver r)

-- | Allocate a new /non-negative/ variable.
newVar :: LP r Var
newVar :: LP r Key
newVar = do
  (Key
x,Tableau r
tbl,VarSet
avs,VarMap (Expr r)
defs) <- StateT
  (Key, Tableau r, VarSet, VarMap (Expr r))
  Identity
  (Key, Tableau r, VarSet, VarMap (Expr r))
forall s (m :: * -> *). MonadState s m => m s
get
  (Key, Tableau r, VarSet, VarMap (Expr r))
-> StateT (Key, Tableau r, VarSet, VarMap (Expr r)) Identity ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (Key
xKey -> Key -> Key
forall a. Num a => a -> a -> a
+Key
1,Tableau r
tbl,VarSet
avs,VarMap (Expr r)
defs)
  Key -> LP r Key
forall (m :: * -> *) a. Monad m => a -> m a
return Key
x

getTableau :: LP r (Simplex.Tableau r)
getTableau :: LP r (Tableau r)
getTableau = do
  (Key
_,Tableau r
tbl,VarSet
_,VarMap (Expr r)
_) <- StateT
  (Key, Tableau r, VarSet, VarMap (Expr r))
  Identity
  (Key, Tableau r, VarSet, VarMap (Expr r))
forall s (m :: * -> *). MonadState s m => m s
get
  Tableau r -> LP r (Tableau r)
forall (m :: * -> *) a. Monad m => a -> m a
return Tableau r
tbl

putTableau :: Simplex.Tableau r -> LP r ()
putTableau :: Tableau r -> LP r ()
putTableau Tableau r
tbl = do
  (Key
x,Tableau r
_,VarSet
avs,VarMap (Expr r)
defs) <- StateT
  (Key, Tableau r, VarSet, VarMap (Expr r))
  Identity
  (Key, Tableau r, VarSet, VarMap (Expr r))
forall s (m :: * -> *). MonadState s m => m s
get
  (Key, Tableau r, VarSet, VarMap (Expr r)) -> LP r ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (Key
x,Tableau r
tbl,VarSet
avs,VarMap (Expr r)
defs)

addArtificialVariable :: Var -> LP r ()
addArtificialVariable :: Key -> LP r ()
addArtificialVariable Key
v = do
  (Key
x,Tableau r
tbl,VarSet
avs,VarMap (Expr r)
defs) <- StateT
  (Key, Tableau r, VarSet, VarMap (Expr r))
  Identity
  (Key, Tableau r, VarSet, VarMap (Expr r))
forall s (m :: * -> *). MonadState s m => m s
get
  (Key, Tableau r, VarSet, VarMap (Expr r)) -> LP r ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (Key
x, Tableau r
tbl, Key -> VarSet -> VarSet
IS.insert Key
v VarSet
avs, VarMap (Expr r)
defs)

getArtificialVariables :: LP r VarSet
getArtificialVariables :: LP r VarSet
getArtificialVariables = do
  (Key
_,Tableau r
_,VarSet
avs,VarMap (Expr r)
_) <- StateT
  (Key, Tableau r, VarSet, VarMap (Expr r))
  Identity
  (Key, Tableau r, VarSet, VarMap (Expr r))
forall s (m :: * -> *). MonadState s m => m s
get
  VarSet -> LP r VarSet
forall (m :: * -> *) a. Monad m => a -> m a
return VarSet
avs

clearArtificialVariables :: LP r ()
clearArtificialVariables :: LP r ()
clearArtificialVariables = do
  (Key
x,Tableau r
tbl,VarSet
_,VarMap (Expr r)
defs) <- StateT
  (Key, Tableau r, VarSet, VarMap (Expr r))
  Identity
  (Key, Tableau r, VarSet, VarMap (Expr r))
forall s (m :: * -> *). MonadState s m => m s
get
  (Key, Tableau r, VarSet, VarMap (Expr r)) -> LP r ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (Key
x, Tableau r
tbl, VarSet
IS.empty, VarMap (Expr r)
defs)

define :: Var -> LA.Expr r -> LP r ()
define :: Key -> Expr r -> LP r ()
define Key
v Expr r
e = do
  (Key
x,Tableau r
tbl,VarSet
avs,IntMap (Expr r)
defs) <- StateT
  (Key, Tableau r, VarSet, IntMap (Expr r))
  Identity
  (Key, Tableau r, VarSet, IntMap (Expr r))
forall s (m :: * -> *). MonadState s m => m s
get
  (Key, Tableau r, VarSet, IntMap (Expr r)) -> LP r ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (Key
x,Tableau r
tbl,VarSet
avs, Key -> Expr r -> IntMap (Expr r) -> IntMap (Expr r)
forall a. Key -> a -> IntMap a -> IntMap a
IM.insert Key
v Expr r
e IntMap (Expr r)
defs)

getDefs :: LP r (VarMap (LA.Expr r))
getDefs :: LP r (VarMap (Expr r))
getDefs = do
  (Key
_,Tableau r
_,VarSet
_,VarMap (Expr r)
defs) <- StateT
  (Key, Tableau r, VarSet, VarMap (Expr r))
  Identity
  (Key, Tableau r, VarSet, VarMap (Expr r))
forall s (m :: * -> *). MonadState s m => m s
get
  VarMap (Expr r) -> LP r (VarMap (Expr r))
forall (m :: * -> *) a. Monad m => a -> m a
return VarMap (Expr r)
defs

-- ---------------------------------------------------------------------------

-- | Add a contraint and maintain feasibility condition by introducing artificial variable (if necessary).
--
-- * Disequality is not supported.
--
-- * Unlike 'addConstraint', an equality contstraint becomes one row with an artificial variable.
--
addConstraintWithArtificialVariable :: Real r => LA.Atom r -> LP r ()
addConstraintWithArtificialVariable :: Atom r -> LP r ()
addConstraintWithArtificialVariable Atom r
c = do
  Atom r
c2 <- Atom r -> LP r (Atom r)
forall r. (Num r, Eq r) => Atom r -> LP r (Atom r)
expandDefs' Atom r
c
  let (Expr r
e, RelOp
rop, r
b) = Atom r -> (Expr r, RelOp, r)
forall r. Real r => Atom r -> (Expr r, RelOp, r)
normalizeConstraint Atom r
c2
  Bool -> LP r () -> LP r ()
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (r
b r -> r -> Bool
forall a. Ord a => a -> a -> Bool
>= r
0) (LP r () -> LP r ()) -> LP r () -> LP r ()
forall a b. (a -> b) -> a -> b
$ () -> LP r ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  Tableau r
tbl <- LP r (Tableau r)
forall r. LP r (Tableau r)
getTableau
  case RelOp
rop of
    -- x≥0 is trivially true, since x is non-negative.
    RelOp
Ge | r
br -> r -> Bool
forall a. Eq a => a -> a -> Bool
==r
0 Bool -> Bool -> Bool
&& Expr r -> Bool
forall r. Real r => Expr r -> Bool
isSingleVar Expr r
e -> () -> LP r ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    -- -x≤0 is trivially true, since x is non-negative.
    RelOp
Le | r
br -> r -> Bool
forall a. Eq a => a -> a -> Bool
==r
0 Bool -> Bool -> Bool
&& Expr r -> Bool
forall r. Real r => Expr r -> Bool
isSingleNegatedVar Expr r
e -> () -> LP r ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

    RelOp
Le -> do
      Key
v <- LP r Key
forall r. LP r Key
newVar -- slack variable
      Tableau r -> LP r ()
forall r. Tableau r -> LP r ()
putTableau (Tableau r -> LP r ()) -> Tableau r -> LP r ()
forall a b. (a -> b) -> a -> b
$ Tableau r -> Key -> Row r -> Tableau r
forall r. (Num r, Eq r) => Tableau r -> Key -> Row r -> Tableau r
Simplex.addRow Tableau r
tbl Key
v (Expr r -> IntMap r
forall r. Expr r -> IntMap r
LA.coeffMap Expr r
e, r
b)
    RelOp
Ge -> do
      Key
v1 <- LP r Key
forall r. LP r Key
newVar -- surplus variable
      Key
v2 <- LP r Key
forall r. LP r Key
newVar -- artificial variable
      Tableau r -> LP r ()
forall r. Tableau r -> LP r ()
putTableau (Tableau r -> LP r ()) -> Tableau r -> LP r ()
forall a b. (a -> b) -> a -> b
$ Tableau r -> Key -> Row r -> Tableau r
forall r. (Num r, Eq r) => Tableau r -> Key -> Row r -> Tableau r
Simplex.addRow Tableau r
tbl Key
v2 (Expr r -> IntMap r
forall r. Expr r -> IntMap r
LA.coeffMap (Expr r
e Expr r -> Expr r -> Expr r
forall v. AdditiveGroup v => v -> v -> v
^-^ Key -> Expr r
forall r. Num r => Key -> Expr r
LA.var Key
v1), r
b)
      Key -> LP r ()
forall r. Key -> LP r ()
addArtificialVariable Key
v2
    RelOp
Eql -> do
      Key
v <- LP r Key
forall r. LP r Key
newVar -- artificial variable
      Tableau r -> LP r ()
forall r. Tableau r -> LP r ()
putTableau (Tableau r -> LP r ()) -> Tableau r -> LP r ()
forall a b. (a -> b) -> a -> b
$ Tableau r -> Key -> Row r -> Tableau r
forall r. (Num r, Eq r) => Tableau r -> Key -> Row r -> Tableau r
Simplex.addRow Tableau r
tbl Key
v (Expr r -> IntMap r
forall r. Expr r -> IntMap r
LA.coeffMap Expr r
e, r
b)
      Key -> LP r ()
forall r. Key -> LP r ()
addArtificialVariable Key
v
    RelOp
_ -> [Char] -> LP r ()
forall a. (?callStack::CallStack) => [Char] -> a
error ([Char] -> LP r ()) -> [Char] -> LP r ()
forall a b. (a -> b) -> a -> b
$ [Char]
"ToySolver.LPSolver.addConstraintWithArtificialVariable does not support " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ RelOp -> [Char]
forall a. Show a => a -> [Char]
show RelOp
rop

-- | Add a contraint, without maintaining feasibilty condition of tableaus.
--
-- * Disequality is not supported.
--
-- * Unlike 'addConstraintWithArtificialVariable', an equality constraint becomes two rows.
--
addConstraint :: Real r => LA.Atom r -> LP r ()
addConstraint :: Atom r -> LP r ()
addConstraint Atom r
c = do
  OrdRel Expr r
lhs RelOp
rop Expr r
rhs <- Atom r -> LP r (Atom r)
forall r. (Num r, Eq r) => Atom r -> LP r (Atom r)
expandDefs' Atom r
c
  let
    (r
b', Expr r
e) = Key -> Expr r -> (r, Expr r)
forall r. Num r => Key -> Expr r -> (r, Expr r)
LA.extract Key
LA.unitVar (Expr r
lhs Expr r -> Expr r -> Expr r
forall v. AdditiveGroup v => v -> v -> v
^-^ Expr r
rhs)
    b :: r
b = - r
b'
  case RelOp
rop of
    RelOp
Le -> Expr r -> r -> LP r ()
forall r. Real r => Expr r -> r -> StateT (Solver r) Identity ()
f Expr r
e r
b
    RelOp
Ge -> Expr r -> r -> LP r ()
forall r. Real r => Expr r -> r -> StateT (Solver r) Identity ()
f (Expr r -> Expr r
forall v. AdditiveGroup v => v -> v
negateV Expr r
e) (r -> r
forall a. Num a => a -> a
negate r
b)
    RelOp
Eql -> do
      -- Unlike addConstraintWithArtificialVariable, an equality constraint becomes two rows.
      Expr r -> r -> LP r ()
forall r. Real r => Expr r -> r -> StateT (Solver r) Identity ()
f Expr r
e r
b
      Expr r -> r -> LP r ()
forall r. Real r => Expr r -> r -> StateT (Solver r) Identity ()
f (Expr r -> Expr r
forall v. AdditiveGroup v => v -> v
negateV Expr r
e) (r -> r
forall a. Num a => a -> a
negate r
b)
    RelOp
_ -> [Char] -> LP r ()
forall a. (?callStack::CallStack) => [Char] -> a
error ([Char] -> LP r ()) -> [Char] -> LP r ()
forall a b. (a -> b) -> a -> b
$ [Char]
"ToySolver.LPSolver.addConstraint does not support " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ RelOp -> [Char]
forall a. Show a => a -> [Char]
show RelOp
rop
  where
    -- -x≤b with b≥0 is trivially true.
    f :: Expr r -> r -> StateT (Solver r) Identity ()
f Expr r
e r
b | Expr r -> Bool
forall r. Real r => Expr r -> Bool
isSingleNegatedVar Expr r
e Bool -> Bool -> Bool
&& r
0 r -> r -> Bool
forall a. Ord a => a -> a -> Bool
<= r
b = () -> StateT (Solver r) Identity ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    f Expr r
e r
b = do
      Tableau r
tbl <- LP r (Tableau r)
forall r. LP r (Tableau r)
getTableau
      Key
v <- LP r Key
forall r. LP r Key
newVar -- slack variable
      Tableau r -> StateT (Solver r) Identity ()
forall r. Tableau r -> LP r ()
putTableau (Tableau r -> StateT (Solver r) Identity ())
-> Tableau r -> StateT (Solver r) Identity ()
forall a b. (a -> b) -> a -> b
$ Tableau r -> Key -> Row r -> Tableau r
forall r. (Num r, Eq r) => Tableau r -> Key -> Row r -> Tableau r
Simplex.addRow Tableau r
tbl Key
v (Expr r -> IntMap r
forall r. Expr r -> IntMap r
LA.coeffMap Expr r
e, r
b)

isSingleVar :: Real r => LA.Expr r -> Bool
isSingleVar :: Expr r -> Bool
isSingleVar Expr r
e =
  case Expr r -> [(r, Key)]
forall r. Expr r -> [(r, Key)]
LA.terms Expr r
e of
    [(r
1,Key
_)] -> Bool
True
    [(r, Key)]
_ -> Bool
False

isSingleNegatedVar :: Real r => LA.Expr r -> Bool
isSingleNegatedVar :: Expr r -> Bool
isSingleNegatedVar Expr r
e =
  case Expr r -> [(r, Key)]
forall r. Expr r -> [(r, Key)]
LA.terms Expr r
e of
    [(-1,Key
_)] -> Bool
True
    [(r, Key)]
_ -> Bool
False

expandDefs :: (Num r, Eq r) => LA.Expr r -> LP r (LA.Expr r)
expandDefs :: Expr r -> LP r (Expr r)
expandDefs Expr r
e = do
  VarMap (Expr r)
defs <- LP r (VarMap (Expr r))
forall r. LP r (VarMap (Expr r))
getDefs
  Expr r -> LP r (Expr r)
forall (m :: * -> *) a. Monad m => a -> m a
return (Expr r -> LP r (Expr r)) -> Expr r -> LP r (Expr r)
forall a b. (a -> b) -> a -> b
$ VarMap (Expr r) -> Expr r -> Expr r
forall r. (Num r, Eq r) => VarMap (Expr r) -> Expr r -> Expr r
LA.applySubst VarMap (Expr r)
defs Expr r
e

expandDefs' :: (Num r, Eq r) => LA.Atom r -> LP r (LA.Atom r)
expandDefs' :: Atom r -> LP r (Atom r)
expandDefs' (OrdRel Expr r
lhs RelOp
op Expr r
rhs) = do
  Expr r
lhs' <- Expr r -> LP r (Expr r)
forall r. (Num r, Eq r) => Expr r -> LP r (Expr r)
expandDefs Expr r
lhs
  Expr r
rhs' <- Expr r -> LP r (Expr r)
forall r. (Num r, Eq r) => Expr r -> LP r (Expr r)
expandDefs Expr r
rhs
  Atom r -> LP r (Atom r)
forall (m :: * -> *) a. Monad m => a -> m a
return (Atom r -> LP r (Atom r)) -> Atom r -> LP r (Atom r)
forall a b. (a -> b) -> a -> b
$ Expr r -> RelOp -> Expr r -> Atom r
forall e. e -> RelOp -> e -> OrdRel e
OrdRel Expr r
lhs' RelOp
op Expr r
rhs'

tableau :: (RealFrac r) => [LA.Atom r] -> LP r ()
tableau :: [Atom r] -> LP r ()
tableau [Atom r]
cs = do
  let (VarSet
nonnegVars, [Atom r]
cs') = [Atom r] -> VarSet -> (VarSet, [Atom r])
forall r. RealFrac r => [Atom r] -> VarSet -> (VarSet, [Atom r])
collectNonnegVars [Atom r]
cs VarSet
IS.empty
      fvs :: VarSet
fvs = [Atom r] -> VarSet
forall a. Variables a => a -> VarSet
vars [Atom r]
cs VarSet -> VarSet -> VarSet
`IS.difference` VarSet
nonnegVars
  [Key] -> (Key -> LP r ()) -> LP r ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ (VarSet -> [Key]
IS.toList VarSet
fvs) ((Key -> LP r ()) -> LP r ()) -> (Key -> LP r ()) -> LP r ()
forall a b. (a -> b) -> a -> b
$ \Key
v -> do
    Key
v1 <- LP r Key
forall r. LP r Key
newVar
    Key
v2 <- LP r Key
forall r. LP r Key
newVar
    Key -> Expr r -> LP r ()
forall r. Key -> Expr r -> LP r ()
define Key
v (Key -> Expr r
forall r. Num r => Key -> Expr r
LA.var Key
v1 Expr r -> Expr r -> Expr r
forall v. AdditiveGroup v => v -> v -> v
^-^ Key -> Expr r
forall r. Num r => Key -> Expr r
LA.var Key
v2)
  (Atom r -> LP r ()) -> [Atom r] -> LP r ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ Atom r -> LP r ()
forall r. Real r => Atom r -> LP r ()
addConstraint [Atom r]
cs'

getModel :: Fractional r => VarSet -> LP r (Model r)
getModel :: VarSet -> LP r (Model r)
getModel VarSet
vs = do
  Tableau r
tbl <- LP r (Tableau r)
forall r. LP r (Tableau r)
getTableau
  VarMap (Expr r)
defs <- LP r (VarMap (Expr r))
forall r. LP r (VarMap (Expr r))
getDefs
  let vs' :: VarSet
vs' = (VarSet
vs VarSet -> VarSet -> VarSet
`IS.difference` VarMap (Expr r) -> VarSet
forall a. IntMap a -> VarSet
IM.keysSet VarMap (Expr r)
defs) VarSet -> VarSet -> VarSet
`IS.union` [VarSet] -> VarSet
forall (f :: * -> *). Foldable f => f VarSet -> VarSet
IS.unions [Expr r -> VarSet
forall a. Variables a => a -> VarSet
vars Expr r
e | Expr r
e <- VarMap (Expr r) -> [Expr r]
forall a. IntMap a -> [a]
IM.elems VarMap (Expr r)
defs]
      m0 :: Model r
m0 = [(Key, r)] -> Model r
forall a. [(Key, a)] -> IntMap a
IM.fromAscList [(Key
v, Tableau r -> Key -> r
forall r. Num r => Tableau r -> Key -> r
Simplex.currentValue Tableau r
tbl Key
v) | Key
v <- VarSet -> [Key]
IS.toAscList VarSet
vs']
  Model r -> LP r (Model r)
forall (m :: * -> *) a. Monad m => a -> m a
return (Model r -> LP r (Model r)) -> Model r -> LP r (Model r)
forall a b. (a -> b) -> a -> b
$ (Key -> r -> Bool) -> Model r -> Model r
forall a. (Key -> a -> Bool) -> IntMap a -> IntMap a
IM.filterWithKey (\Key
k r
_ -> Key
k Key -> VarSet -> Bool
`IS.member` VarSet
vs) (Model r -> Model r) -> Model r -> Model r
forall a b. (a -> b) -> a -> b
$ (Expr r -> r) -> VarMap (Expr r) -> Model r
forall a b. (a -> b) -> IntMap a -> IntMap b
IM.map (Model r -> Expr r -> r
forall m e v. Eval m e v => m -> e -> v
LA.eval Model r
m0) VarMap (Expr r)
defs Model r -> Model r -> Model r
forall a. IntMap a -> IntMap a -> IntMap a
`IM.union` Model r
m0

phaseI :: (Fractional r, Real r) => LP r Bool
phaseI :: LP r Bool
phaseI = do
  LP r ()
forall r. Real r => LP r ()
introduceArtificialVariables
  Tableau r
tbl <- LP r (Tableau r)
forall r. LP r (Tableau r)
getTableau
  VarSet
avs <- LP r VarSet
forall r. LP r VarSet
getArtificialVariables
  let (Bool
ret, Tableau r
tbl') = Tableau r -> VarSet -> (Bool, Tableau r)
forall r.
(Real r, Fractional r) =>
Tableau r -> VarSet -> (Bool, Tableau r)
Simplex.phaseI Tableau r
tbl VarSet
avs
  Tableau r -> LP r ()
forall r. Tableau r -> LP r ()
putTableau Tableau r
tbl'
  Bool -> LP r () -> LP r ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
ret LP r ()
forall r. LP r ()
clearArtificialVariables
  Bool -> LP r Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
ret

introduceArtificialVariables :: (Real r) => LP r ()
introduceArtificialVariables :: LP r ()
introduceArtificialVariables = do
  Tableau r
tbl <- LP r (Tableau r)
forall r. LP r (Tableau r)
getTableau
  Tableau r
tbl' <- ([(Key, (VarMap r, r))] -> Tableau r)
-> StateT (Solver r) Identity [(Key, (VarMap r, r))]
-> LP r (Tableau r)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [(Key, (VarMap r, r))] -> Tableau r
forall a. [(Key, a)] -> IntMap a
IM.fromList (StateT (Solver r) Identity [(Key, (VarMap r, r))]
 -> LP r (Tableau r))
-> StateT (Solver r) Identity [(Key, (VarMap r, r))]
-> LP r (Tableau r)
forall a b. (a -> b) -> a -> b
$ [(Key, (VarMap r, r))]
-> ((Key, (VarMap r, r))
    -> StateT (Solver r) Identity (Key, (VarMap r, r)))
-> StateT (Solver r) Identity [(Key, (VarMap r, r))]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM (Tableau r -> [(Key, (VarMap r, r))]
forall a. IntMap a -> [(Key, a)]
IM.toList Tableau r
tbl) (((Key, (VarMap r, r))
  -> StateT (Solver r) Identity (Key, (VarMap r, r)))
 -> StateT (Solver r) Identity [(Key, (VarMap r, r))])
-> ((Key, (VarMap r, r))
    -> StateT (Solver r) Identity (Key, (VarMap r, r)))
-> StateT (Solver r) Identity [(Key, (VarMap r, r))]
forall a b. (a -> b) -> a -> b
$ \(Key
v,(VarMap r
e,r
rhs)) -> do
    if r
rhs r -> r -> Bool
forall a. Ord a => a -> a -> Bool
>= r
0 then do
      (Key, (VarMap r, r))
-> StateT (Solver r) Identity (Key, (VarMap r, r))
forall (m :: * -> *) a. Monad m => a -> m a
return (Key
v,(VarMap r
e,r
rhs)) -- v + e == rhs
    else do
      Key
a <- LP r Key
forall r. LP r Key
newVar
      Key -> LP r ()
forall r. Key -> LP r ()
addArtificialVariable Key
a
      (Key, (VarMap r, r))
-> StateT (Solver r) Identity (Key, (VarMap r, r))
forall (m :: * -> *) a. Monad m => a -> m a
return (Key
a, (Key -> r -> VarMap r -> VarMap r
forall a. Key -> a -> IntMap a -> IntMap a
IM.insert Key
v (-r
1) ((r -> r) -> VarMap r -> VarMap r
forall a b. (a -> b) -> IntMap a -> IntMap b
IM.map r -> r
forall a. Num a => a -> a
negate VarMap r
e), -r
rhs)) -- a - (v + e) == -rhs
  Tableau r -> LP r ()
forall r. Tableau r -> LP r ()
putTableau Tableau r
tbl'

simplex :: (Fractional r, Real r) => OptDir -> LA.Expr r -> LP r Bool
simplex :: OptDir -> Expr r -> LP r Bool
simplex OptDir
optdir Expr r
obj = do
  Tableau r
tbl <- LP r (Tableau r)
forall r. LP r (Tableau r)
getTableau
  VarMap (Expr r)
defs <- LP r (VarMap (Expr r))
forall r. LP r (VarMap (Expr r))
getDefs
  let (Bool
ret, Tableau r
tbl') = OptDir -> Tableau r -> (Bool, Tableau r)
forall r.
(Real r, Fractional r) =>
OptDir -> Tableau r -> (Bool, Tableau r)
Simplex.simplex OptDir
optdir (Tableau r -> Expr r -> Tableau r
forall r. (Num r, Eq r) => Tableau r -> Expr r -> Tableau r
Simplex.setObjFun Tableau r
tbl (VarMap (Expr r) -> Expr r -> Expr r
forall r. (Num r, Eq r) => VarMap (Expr r) -> Expr r -> Expr r
LA.applySubst VarMap (Expr r)
defs Expr r
obj))
  Tableau r -> LP r ()
forall r. Tableau r -> LP r ()
putTableau Tableau r
tbl'
  Bool -> LP r Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
ret

dualSimplex :: (Fractional r, Real r) => OptDir -> LA.Expr r -> LP r Bool
dualSimplex :: OptDir -> Expr r -> LP r Bool
dualSimplex OptDir
optdir Expr r
obj = do
  Tableau r
tbl <- LP r (Tableau r)
forall r. LP r (Tableau r)
getTableau
  VarMap (Expr r)
defs <- LP r (VarMap (Expr r))
forall r. LP r (VarMap (Expr r))
getDefs
  let (Bool
ret, Tableau r
tbl') = OptDir -> Tableau r -> (Bool, Tableau r)
forall r.
(Real r, Fractional r) =>
OptDir -> Tableau r -> (Bool, Tableau r)
Simplex.dualSimplex OptDir
optdir (Tableau r -> Expr r -> Tableau r
forall r. (Num r, Eq r) => Tableau r -> Expr r -> Tableau r
Simplex.setObjFun Tableau r
tbl (VarMap (Expr r) -> Expr r -> Expr r
forall r. (Num r, Eq r) => VarMap (Expr r) -> Expr r -> Expr r
LA.applySubst VarMap (Expr r)
defs Expr r
obj))
  Tableau r -> LP r ()
forall r. Tableau r -> LP r ()
putTableau Tableau r
tbl'
  Bool -> LP r Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
ret

-- | results of optimization
data OptResult = Optimum | Unsat | Unbounded
  deriving (Key -> OptResult -> [Char] -> [Char]
[OptResult] -> [Char] -> [Char]
OptResult -> [Char]
(Key -> OptResult -> [Char] -> [Char])
-> (OptResult -> [Char])
-> ([OptResult] -> [Char] -> [Char])
-> Show OptResult
forall a.
(Key -> a -> [Char] -> [Char])
-> (a -> [Char]) -> ([a] -> [Char] -> [Char]) -> Show a
showList :: [OptResult] -> [Char] -> [Char]
$cshowList :: [OptResult] -> [Char] -> [Char]
show :: OptResult -> [Char]
$cshow :: OptResult -> [Char]
showsPrec :: Key -> OptResult -> [Char] -> [Char]
$cshowsPrec :: Key -> OptResult -> [Char] -> [Char]
Show, OptResult -> OptResult -> Bool
(OptResult -> OptResult -> Bool)
-> (OptResult -> OptResult -> Bool) -> Eq OptResult
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OptResult -> OptResult -> Bool
$c/= :: OptResult -> OptResult -> Bool
== :: OptResult -> OptResult -> Bool
$c== :: OptResult -> OptResult -> Bool
Eq, Eq OptResult
Eq OptResult
-> (OptResult -> OptResult -> Ordering)
-> (OptResult -> OptResult -> Bool)
-> (OptResult -> OptResult -> Bool)
-> (OptResult -> OptResult -> Bool)
-> (OptResult -> OptResult -> Bool)
-> (OptResult -> OptResult -> OptResult)
-> (OptResult -> OptResult -> OptResult)
-> Ord OptResult
OptResult -> OptResult -> Bool
OptResult -> OptResult -> Ordering
OptResult -> OptResult -> OptResult
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: OptResult -> OptResult -> OptResult
$cmin :: OptResult -> OptResult -> OptResult
max :: OptResult -> OptResult -> OptResult
$cmax :: OptResult -> OptResult -> OptResult
>= :: OptResult -> OptResult -> Bool
$c>= :: OptResult -> OptResult -> Bool
> :: OptResult -> OptResult -> Bool
$c> :: OptResult -> OptResult -> Bool
<= :: OptResult -> OptResult -> Bool
$c<= :: OptResult -> OptResult -> Bool
< :: OptResult -> OptResult -> Bool
$c< :: OptResult -> OptResult -> Bool
compare :: OptResult -> OptResult -> Ordering
$ccompare :: OptResult -> OptResult -> Ordering
$cp1Ord :: Eq OptResult
Ord)

twoPhaseSimplex :: (Fractional r, Real r) => OptDir -> LA.Expr r -> LP r OptResult
twoPhaseSimplex :: OptDir -> Expr r -> LP r OptResult
twoPhaseSimplex OptDir
optdir Expr r
obj = do
  Bool
ret <- LP r Bool
forall r. (Fractional r, Real r) => LP r Bool
phaseI
  if Bool -> Bool
not Bool
ret then
    OptResult -> LP r OptResult
forall (m :: * -> *) a. Monad m => a -> m a
return OptResult
Unsat
  else do
    Bool
ret <- OptDir -> Expr r -> LP r Bool
forall r. (Fractional r, Real r) => OptDir -> Expr r -> LP r Bool
simplex OptDir
optdir Expr r
obj
    if Bool
ret then
      OptResult -> LP r OptResult
forall (m :: * -> *) a. Monad m => a -> m a
return OptResult
Optimum
    else
      OptResult -> LP r OptResult
forall (m :: * -> *) a. Monad m => a -> m a
return OptResult
Unbounded

primalDualSimplex :: (Fractional r, Real r) => OptDir -> LA.Expr r -> LP r OptResult
primalDualSimplex :: OptDir -> Expr r -> LP r OptResult
primalDualSimplex OptDir
optdir Expr r
obj = do
  Tableau r
tbl <- LP r (Tableau r)
forall r. LP r (Tableau r)
getTableau
  VarMap (Expr r)
defs <- LP r (VarMap (Expr r))
forall r. LP r (VarMap (Expr r))
getDefs
  let (Bool
ret, Tableau r
tbl') = OptDir -> Tableau r -> (Bool, Tableau r)
forall r.
(Real r, Fractional r) =>
OptDir -> Tableau r -> (Bool, Tableau r)
Simplex.primalDualSimplex OptDir
optdir (Tableau r -> Expr r -> Tableau r
forall r. (Num r, Eq r) => Tableau r -> Expr r -> Tableau r
Simplex.setObjFun Tableau r
tbl (VarMap (Expr r) -> Expr r -> Expr r
forall r. (Num r, Eq r) => VarMap (Expr r) -> Expr r -> Expr r
LA.applySubst VarMap (Expr r)
defs Expr r
obj))
  Tableau r -> LP r ()
forall r. Tableau r -> LP r ()
putTableau Tableau r
tbl'
  if Bool
ret then
    OptResult -> LP r OptResult
forall (m :: * -> *) a. Monad m => a -> m a
return OptResult
Optimum
  else if Bool -> Bool
not (Tableau r -> Bool
forall r. Real r => Tableau r -> Bool
Simplex.isFeasible Tableau r
tbl') then
    OptResult -> LP r OptResult
forall (m :: * -> *) a. Monad m => a -> m a
return OptResult
Unsat
  else
    OptResult -> LP r OptResult
forall (m :: * -> *) a. Monad m => a -> m a
return OptResult
Unbounded

-- ---------------------------------------------------------------------------

-- convert right hand side to be non-negative
normalizeConstraint :: forall r. Real r => LA.Atom r -> (LA.Expr r, RelOp, r)
normalizeConstraint :: Atom r -> (Expr r, RelOp, r)
normalizeConstraint (OrdRel Expr r
a RelOp
op Expr r
b)
  | r
rhs r -> r -> Bool
forall a. Ord a => a -> a -> Bool
< r
0   = (Expr r -> Expr r
forall v. AdditiveGroup v => v -> v
negateV Expr r
lhs, RelOp -> RelOp
flipOp RelOp
op, r -> r
forall a. Num a => a -> a
negate r
rhs)
  | Bool
otherwise = (Expr r
lhs, RelOp
op, r
rhs)
  where
    (r
c, Expr r
lhs) = Key -> Expr r -> (r, Expr r)
forall r. Num r => Key -> Expr r -> (r, Expr r)
LA.extract Key
LA.unitVar (Expr r
a Expr r -> Expr r -> Expr r
forall v. AdditiveGroup v => v -> v -> v
^-^ Expr r
b)
    rhs :: r
rhs = - r
c

collectNonnegVars :: forall r. (RealFrac r) => [LA.Atom r] -> VarSet -> (VarSet, [LA.Atom r])
collectNonnegVars :: [Atom r] -> VarSet -> (VarSet, [Atom r])
collectNonnegVars [Atom r]
cs VarSet
ivs = (VarSet
nonnegVars, [Atom r]
cs)
  where
    vs :: VarSet
vs = [Atom r] -> VarSet
forall a. Variables a => a -> VarSet
vars [Atom r]
cs
    bounds :: BoundsEnv r
bounds = BoundsEnv r -> [Atom r] -> VarSet -> Key -> BoundsEnv r
forall r.
RealFrac r =>
BoundsEnv r -> [Atom r] -> VarSet -> Key -> BoundsEnv r
BI.inferBounds BoundsEnv r
initialBounds [Atom r]
cs VarSet
ivs Key
1000
      where
        initialBounds :: BoundsEnv r
initialBounds = [(Key, Interval r)] -> BoundsEnv r
forall a. [(Key, a)] -> IntMap a
IM.fromAscList [(Key
v, Interval r
forall r. Ord r => Interval r
Interval.whole) | Key
v <- VarSet -> [Key]
IS.toAscList VarSet
vs]
    nonnegVars :: VarSet
nonnegVars = (Key -> Bool) -> VarSet -> VarSet
IS.filter (\Key
v -> Interval r
0 Interval r -> Interval r -> Bool
forall r. Ord r => Interval r -> Interval r -> Bool
<=! (BoundsEnv r
bounds BoundsEnv r -> Key -> Interval r
forall a. IntMap a -> Key -> a
IM.! Key
v)) VarSet
vs

    isTriviallyTrue :: LA.Atom r -> Bool
    isTriviallyTrue :: Atom r -> Bool
isTriviallyTrue (OrdRel Expr r
a RelOp
op Expr r
b) =
      case RelOp
op of
        RelOp
Le -> Interval r
i Interval r -> Interval r -> Bool
forall r. Ord r => Interval r -> Interval r -> Bool
<=! Interval r
0
        RelOp
Ge -> Interval r
i Interval r -> Interval r -> Bool
forall r. Ord r => Interval r -> Interval r -> Bool
>=! Interval r
0
        RelOp
Lt -> Interval r
i Interval r -> Interval r -> Bool
forall r. Ord r => Interval r -> Interval r -> Bool
<! Interval r
0
        RelOp
Gt -> Interval r
i Interval r -> Interval r -> Bool
forall r. Ord r => Interval r -> Interval r -> Bool
>! Interval r
0
        RelOp
Eql -> Interval r
i Interval r -> Interval r -> Bool
forall r. Ord r => Interval r -> Interval r -> Bool
==! Interval r
0
        RelOp
NEq -> Interval r
i Interval r -> Interval r -> Bool
forall r. Ord r => Interval r -> Interval r -> Bool
/=! Interval r
0
      where
        i :: Interval r
i = BoundsEnv r -> Expr r -> Interval r
forall r.
(Real r, Fractional r) =>
BoundsEnv r -> Expr r -> Interval r
LA.computeInterval BoundsEnv r
bounds (Expr r
a Expr r -> Expr r -> Expr r
forall v. AdditiveGroup v => v -> v -> v
^-^ Expr r
b)

-- ---------------------------------------------------------------------------