packages feed

glpk-hs 0.0.4 → 0.1.0

raw patch · 12 files changed

+233/−115 lines, 12 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.LinearProgram.Common: mapVals :: (Ord c', Module r c') => (c -> c') -> LP v c -> LP v c'
+ Data.LinearProgram.Common: mapVars :: (Ord v', Ord c, Module r c) => (v -> v') -> LP v c -> LP v' c
+ Data.LinearProgram.LPMonad: readLPFromFile' :: (MonadState (LP String Double) m, MonadIO m) => FilePath -> m ()
- Data.LinearProgram.LPMonad: readLPFromFile :: (MonadState (LP String Double) m, MonadIO m) => FilePath -> m ()
+ Data.LinearProgram.LPMonad: readLPFromFile :: (Ord v, Read v, Ord c, Fractional c, Module r c, MonadState (LP v c) m, MonadIO m) => FilePath -> m ()

Files

Data/LinearProgram/Common.hs view
@@ -6,3 +6,12 @@ import Data.LinearProgram.Spec import Data.LinearProgram.LinFunc import Data.LinearProgram.Types++import Data.Map+import GHC.Exts (build)++{-# RULES+	"assocs" assocs = \ m -> build (\ c n -> foldWithKey (curry c) n m);+	"elems" elems = \ m -> build (\ c n -> foldWithKey (const c) n m);+	"keys" keys = \ m -> build (\ c n -> foldWithKey (\ k _ -> c k) n m);+	#-}
Data/LinearProgram/GLPK/IO.hs view
@@ -12,8 +12,8 @@  -- | Read a linear program from a file in CPLEX LP format. readLP :: FilePath -> IO (LP String Double)-readLP = runGLPK . readGLP_LP+readLP = runGLPK . readGLPLP  -- | Write a linear program to a file in CPLEX LP format. writeLP :: (Ord v, Show v, Real c) => FilePath -> LP v c -> IO ()-writeLP file = runGLPK . writeGLP_LP file+writeLP file = runGLPK . writeGLPLP file
Data/LinearProgram/GLPK/IO/Internal.hs view
@@ -1,9 +1,9 @@ {-# LANGUAGE ForeignFunctionInterface #-} -module Data.LinearProgram.GLPK.IO.Internal (readGLP_LP, writeGLP_LP) where+module Data.LinearProgram.GLPK.IO.Internal (readGLPLP, writeGLPLP) where  import Control.Monad-import Control.Monad.Trans+import Control.Monad.Trans (liftIO, lift)  import Data.Map hiding (map, filter) @@ -13,6 +13,8 @@  foreign import ccall unsafe "c_glp_write_lp" glpWriteLP :: Ptr GlpProb -> CString -> IO () foreign import ccall unsafe "c_glp_read_lp" glpReadLP :: Ptr GlpProb -> CString -> IO ()+foreign import ccall unsafe "c_glp_set_col_name" glpSetColName :: Ptr GlpProb -> CInt -> CString -> IO ()+foreign import ccall unsafe "c_glp_set_row_name" glpSetRowName :: Ptr GlpProb -> CInt -> CString -> IO () foreign import ccall unsafe "c_glp_get_obj_dir" glpGetObjDir :: Ptr GlpProb -> IO CInt foreign import ccall unsafe "c_glp_get_num_rows" glpGetNumRows :: Ptr GlpProb -> IO CInt foreign import ccall unsafe "c_glp_get_num_cols" glpGetNumCols :: Ptr GlpProb -> IO CInt@@ -63,6 +65,12 @@ getCDouble :: (Ptr GlpProb -> CInt -> IO CDouble) -> Int -> GLPK Double getCDouble f i = GLP $ \ lp -> liftM realToFrac $ f lp (fromIntegral i) +setRowName :: Int -> String -> GLPK ()+setRowName i nam = GLP $ withCString nam . flip glpSetRowName (fromIntegral i)++setColName :: Int -> String -> GLPK ()+setColName i nam = GLP $ withCString nam . flip glpSetColName (fromIntegral i)+ loadBounds :: (Int -> GLPK Double) -> (Int -> GLPK Double) -> 	(Int -> GLPK Int) -> Int -> GLPK (Bounds Double) loadBounds lb ub tp i = do@@ -89,8 +97,8 @@ 			return (i, zip (map fromIntegral ixsL) (map realToFrac coefsL)) 			| i <- [1..n]] -readGLP_LP :: FilePath -> GLPK (LP String Double)-readGLP_LP file = execLPT $ do+readGLPLP :: FilePath -> GLPK (LP String Double)+readGLPLP file = execLPT $ do 	lift $ readLP file 	setDirection =<< lift getDir 	nCols <- lift getNumCols@@ -117,7 +125,9 @@ 	setObjective (fromList (filter ((/= 0) . snd) obj)) 		 -writeGLP_LP :: (Show v, Ord v, Real c) => FilePath -> LP v c -> GLPK ()-writeGLP_LP file lp = do-	writeProblem lp+writeGLPLP :: (Show v, Ord v, Real c) => FilePath -> LP v c -> GLPK ()+writeGLPLP file lp = do+	vars <- writeProblem lp+	sequence_ [setColName i (show v) | (v, i) <- assocs vars]+	sequence_ [setRowName i lab | (i, Constr (Just lab) _ _) <- zip [1..] (constraints lp)] 	writeLP file
Data/LinearProgram/GLPK/Internal.hs view
@@ -1,8 +1,10 @@-{-# LANGUAGE RecordWildCards, ScopedTypeVariables, EmptyDataDecls, ForeignFunctionInterface #-}-module Data.LinearProgram.GLPK.Internal (writeProblem, addCols,+{-# LANGUAGE RecordWildCards, ScopedTypeVariables, ForeignFunctionInterface #-}+module Data.LinearProgram.GLPK.Internal (writeProblem, solveSimplex, mipSolve,+	getObjVal, getRowPrim, getColPrim, mipObjVal, mipRowVal, mipColVal) where+{-(writeProblem, addCols, 	addRows, createIndex, findCol, findRow, getColPrim, getRowPrim, getObjVal, 	mipColVal, mipRowVal, mipObjVal, mipSolve, setColBounds, setColKind, setColName, setMatRow,-	setObjCoef, setObjectiveDirection, setRowBounds, setRowName, solveSimplex) where+	setObjCoef, setObjectiveDirection, setRowBounds, setRowName, solveSimplex) where-}  import Control.Monad @@ -20,15 +22,13 @@ foreign import ccall unsafe "c_glp_set_obj_dir" glpSetObjDir :: Ptr GlpProb -> CInt -> IO () foreign import ccall unsafe "c_glp_add_rows" glpAddRows :: Ptr GlpProb -> CInt -> IO CInt foreign import ccall unsafe "c_glp_add_cols" glpAddCols :: Ptr GlpProb -> CInt -> IO CInt-foreign import ccall unsafe "c_glp_set_row_name" glpSetRowName :: Ptr GlpProb -> CInt -> CString -> IO ()-foreign import ccall unsafe "c_glp_set_col_name" glpSetColName :: Ptr GlpProb -> CInt -> CString -> IO () foreign import ccall unsafe "c_glp_set_row_bnds" glpSetRowBnds :: Ptr GlpProb -> CInt -> CInt -> CDouble -> CDouble -> IO () foreign import ccall unsafe "c_glp_set_col_bnds" glpSetColBnds :: Ptr GlpProb -> CInt -> CInt -> CDouble -> CDouble -> IO () foreign import ccall unsafe "c_glp_set_obj_coef" glpSetObjCoef :: Ptr GlpProb -> CInt -> CDouble -> IO () foreign import ccall unsafe "c_glp_set_mat_row" glpSetMatRow :: Ptr GlpProb -> CInt -> CInt -> Ptr CInt -> Ptr CDouble -> IO ()-foreign import ccall unsafe "c_glp_create_index" glpCreateIndex :: Ptr GlpProb -> IO ()-foreign import ccall unsafe "c_glp_find_row" glpFindRow :: Ptr GlpProb -> CString -> IO CInt-foreign import ccall unsafe "c_glp_find_col" glpFindCol :: Ptr GlpProb -> CString -> IO CInt+-- foreign import ccall unsafe "c_glp_create_index" glpCreateIndex :: Ptr GlpProb -> IO ()+-- foreign import ccall unsafe "c_glp_find_row" glpFindRow :: Ptr GlpProb -> CString -> IO CInt+-- foreign import ccall unsafe "c_glp_find_col" glpFindCol :: Ptr GlpProb -> CString -> IO CInt foreign import ccall unsafe "c_glp_solve_simplex" glpSolveSimplex :: Ptr GlpProb -> CInt -> CInt -> CInt -> IO CInt foreign import ccall unsafe "c_glp_get_obj_val" glpGetObjVal :: Ptr GlpProb -> IO CDouble foreign import ccall unsafe "c_glp_get_row_prim" glpGetRowPrim :: Ptr GlpProb -> CInt -> IO CDouble@@ -50,12 +50,6 @@ addCols :: Int -> GLPK Int addCols n = GLP $ liftM fromIntegral . flip glpAddCols (fromIntegral n) -setRowName :: Int -> String -> GLPK ()-setRowName i nam = GLP $ withCString nam . flip glpSetRowName (fromIntegral i)--setColName :: Int -> String -> GLPK ()-setColName i nam = GLP $ withCString nam . flip glpSetColName (fromIntegral i)- setRowBounds :: Real a => Int -> Bounds a -> GLPK () setRowBounds i bds = GLP $ \ lp -> onBounds (glpSetRowBnds lp (fromIntegral i)) bds @@ -81,14 +75,14 @@ 		glpSetMatRow lp (fromIntegral i) (fromIntegral len) ixs coeffs 	where	len = length row -createIndex :: GLPK ()-createIndex = GLP glpCreateIndex+-- createIndex :: GLPK ()+-- createIndex = GLP glpCreateIndex -findRow :: String -> GLPK Int-findRow nam = GLP $ liftM fromIntegral . withCString nam . glpFindRow+-- findRow :: String -> GLPK Int+-- findRow nam = GLP $ liftM fromIntegral . withCString nam . glpFindRow -findCol :: String -> GLPK Int-findCol nam = GLP $ liftM fromIntegral . withCString nam . glpFindCol+-- findCol :: String -> GLPK Int+-- findCol nam = GLP $ liftM fromIntegral . withCString nam . glpFindCol  solveSimplex :: MsgLev -> Int -> Bool -> GLPK ReturnCode solveSimplex msglev tmLim presolve = GLP $ \ lp -> liftM (toEnum . fromIntegral) $ glpSolveSimplex lp@@ -118,29 +112,17 @@ 		liftM (toEnum . fromIntegral) $ GLP $ \ lp -> glpMipSolve lp msglev' 						brt' btt' pp' fp' tmlim' cuts' mipgap' presol' 	where	!msglev' = getMsgLev msglev-		!brt' = case brt of-			FirstFrac	-> 1-			LastFrac	-> 2-			MostFrac	-> 3-			DrTom		-> 4-			HybridP		-> 5-		!btt' = case btt of-			DepthFirst	-> 1-			BreadthFirst	-> 2-			LocBound	-> 3-			ProjHeur	-> 4-		!pp' = case pp of-			NoPre	-> 0-			RootPre	-> 1-			AllPre	-> 2-		!fp' = if fp then 1 else 0+		!brt' = 1 + fromIntegral (fromEnum brt)+		!btt' = 1 + fromIntegral (fromEnum btt)+		!pp' = fromIntegral (fromEnum pp)+		!fp' = fromIntegral (fromEnum fp) 		!cuts' = (if GMI `elem` cuts then 1 else 0) .|. 			(if MIR `elem` cuts then 2 else 0) .|. 			(if Cov `elem` cuts then 4 else 0) .|. 			(if Clq `elem` cuts then 8 else 0) 		!mipgap' = realToFrac mipgap 		!tmlim' = fromIntegral (1000 * tmlim)-		!presol' = if presol then 1 else 0+		!presol' = fromIntegral (fromEnum presol)  mipObjVal :: GLPK Double mipObjVal = liftM realToFrac $ GLP glpMIPObjVal@@ -158,18 +140,15 @@ 	let allVars' = fmap (i0 +) allVars 	sequence_ [setObjCoef i v | (i, v) <- elems $ intersectionWith (,) allVars' objective] 	j0 <- addRows (length constraints)-	sequence_ [do	case lab of-				Nothing	-> return ()-				Just n	-> setRowName j n-			setMatRow j+	sequence_ [do	setMatRow j 				[(i, v) | (i, v) <- elems (intersectionWith (,) allVars' f)] 			setRowBounds j bnds-				| (j, Constr lab f bnds) <- zip [j0..] constraints]+				| (j, Constr _ f bnds) <- zip [j0..] constraints] -- 	createIndex-	sequence_ [setColBounds (i) bnds |+	sequence_ [setColBounds i bnds | 			(i, bnds) <- elems $ intersectionWith (,) allVars' varBounds] 	sequence_ [setColBounds i Free | i <- elems $ difference allVars' varBounds]-	sequence_ [setColKind (i) knd |+	sequence_ [setColKind i knd | 			(i, knd) <- elems $ intersectionWith (,) allVars' varTypes] -- 	writeLP 	return allVars'
Data/LinearProgram/GLPK/Solver.hs view
@@ -19,20 +19,10 @@ 	Cuts(..)) where   import Control.Monad--- import Control.Monad.Trans --- import Debug.Trace- import Data.Map--- import Data.Maybe (catMaybes)-import Data.LinearProgram.Common-import Data.LinearProgram.GLPK.Internal-import Data.LinearProgram.GLPK.Types---- import Data.Time.Clock--- import System.Time--import GHC.Exts(build)+import Data.LinearProgram.Spec+import Data.LinearProgram.GLPK.Common  -- | Options available for customizing GLPK operations.  This also determines -- which kind of solving is performed -- relaxed LP, or MIP.@@ -95,7 +85,7 @@ 			val <- mipColVal i 			return (v, val) 				| (v, i) <- assocs vars]-		rows <- sequence [liftM (RowVal c) (getRowPrim i)+		rows <- sequence [liftM (RowVal c) (mipRowVal i) 					| (i, c) <- zip [1..] constraints] 		return (Just (obj, fromDistinctAscList vals, rows))) vars @@ -113,9 +103,3 @@ 	success <- mipSolve msgLev brTech btTech ppTech fpHeur cuts mipGap (fromIntegral tmLim') presolve 	return (success, guard (gaveAnswer success) >> Just vars) --(if success then Just vars else Nothing) -- 	where	getTime = liftIO getCurrentTime-		-{-# RULES-	"assocs" assocs = \ m -> build (\ c n -> foldWithKey (curry c) n m);-	"elems" elems = \ m -> build (\ c n -> foldWithKey (const c) n m);-	"keys" keys = \ m -> build (\ c n -> foldWithKey (\ k _ -> c k) n m);-	#-}
Data/LinearProgram/GLPK/Types.hs view
@@ -2,7 +2,7 @@  module Data.LinearProgram.GLPK.Types where -import Control.Monad.Trans+import Control.Monad.Trans (MonadIO (..))  import Foreign.Ptr import Foreign.ForeignPtr
Data/LinearProgram/LPMonad.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleContexts, RecordWildCards #-}+{-# LANGUAGE FlexibleContexts #-}  -- | A collection of operations that can be used to specify linear programming in a -- simple, monadic way.  It is not too difficult to construct 'LP' values explicitly,@@ -17,13 +17,14 @@ 	glpSolve', 	-- * File I/O 	writeLPToFile,-	readLPFromFile) where+	readLPFromFile,+	readLPFromFile') where -import Control.Monad.State.Strict--- import Control.Monad.Identity+import Control.Monad ((<=<))+import Control.Monad.State.Class (MonadState(..))+import Control.Monad.Trans (MonadIO (..)) -import Data.Map--- import Data.Monoid+import Data.Map (Map)  import Data.LinearProgram.Common import Data.LinearProgram.LPMonad.Internal@@ -31,7 +32,6 @@ import Data.LinearProgram.GLPK.Solver import Data.LinearProgram.GLPK.IO - {-# SPECIALIZE quickSolveLP :: (Ord v, Real c) =>  	LPT v c IO (ReturnCode, Maybe (Double, Map v Double)) #-} {-# SPECIALIZE quickSolveMIP :: (Ord v, Real c) => @@ -68,11 +68,23 @@ glpSolve' opts = get >>= liftIO . glpSolveAll opts  {-# SPECIALIZE writeLPToFile :: (Ord v, Show v, Real c) => FilePath -> LPT v c IO () #-}+-- | Writes the current linear program to the specified file in CPLEX LP format. +-- (This is a binding to GLPK, not a Haskell implementation of CPLEX.) writeLPToFile :: (Ord v, Show v, Real c, MonadState (LP v c) m, MonadIO m) => 	FilePath -> m () writeLPToFile file = get >>= liftIO . writeLP file  +{-# SPECIALIZE readLPFromFile :: (Ord v, Read v, Ord c, Fractional c, Module r c) => FilePath -> LPT v c IO () #-}+-- | Reads a linear program from the specified file in CPLEX LP format, overwriting+-- the current linear program.  Uses 'read' and 'realToFrac' to translate to the specified type.+-- (This is a binding to GLPK, not a Haskell implementation of CPLEX.)+readLPFromFile :: (Ord v, Read v, Ord c, Fractional c, Module r c, MonadState (LP v c) m, MonadIO m) =>+	FilePath -> m ()+readLPFromFile = put . mapVars read . mapVals realToFrac <=< liftIO . execLPT . readLPFromFile'+ {-# SPECIALIZE readLPFromFile :: FilePath -> LPT String Double IO () #-}-readLPFromFile :: (MonadState (LP String Double) m, MonadIO m) =>+-- | Reads a linear program from the specified file in CPLEX LP format, overwriting+-- the current linear program.  (This is a binding to GLPK, not a Haskell implementation of CPLEX.)+readLPFromFile' :: (MonadState (LP String Double) m, MonadIO m) => 	FilePath -> m ()-readLPFromFile file = put =<< liftIO (readLP file)+readLPFromFile' file = put =<< liftIO (readLP file)
Data/LinearProgram/LPMonad/Internal.hs view
@@ -11,19 +11,20 @@ 	execLPT, 	evalLPM, 	evalLPT,-	-- * Objective configuration+	-- * Constructing the LP+	-- ** Objective configuration 	setDirection, 	setObjective, 	addObjective, 	addWeightedObjective,-	-- * Two-function constraints+	-- ** Two-function constraints 	leq, 	equal, 	geq, 	leq', 	equal', 	geq',-	-- * One-function constraints+	-- ** One-function constraints 	leqTo, 	equalTo, 	geqTo,@@ -32,7 +33,7 @@ 	equalTo', 	geqTo', 	constrain',-	-- * Variable constraints+	-- ** Variable constraints 	varLeq, 	varEq, 	varGeq,@@ -121,7 +122,7 @@ 	Monad m => String -> LinFunc v c -> c -> LPT v c m () #-} {-# SPECIALIZE leqTo' :: String -> LinFunc v c -> c -> LPM v c (), 	Monad m => String -> LinFunc v c -> c -> LPT v c m () #-}--- | Sets a labelled constraint on a linear function in the variables.+-- | Sets a labeled constraint on a linear function in the variables. equalTo', leqTo', geqTo' :: MonadState (LP v c) m => String -> LinFunc v c -> c -> m () equalTo' lab f v = constrain' lab f (Equ v) leqTo' lab f v = constrain' lab f (UBound v)@@ -134,7 +135,8 @@ {-# SPECIALIZE varGeq :: (Ord v, Ord c) => v -> c -> LPM v c (), 	(Ord v, Ord c, Monad m) => v -> c -> LPT v c m () #-} -- | Sets a constraint on the value of a variable.  If you constrain a variable more than once,--- the constraints will be combined.+-- the constraints will be combined.  If the constraints are mutually contradictory,+-- an error will be generated.  This is more efficient than adding an equivalent function constraint. varEq, varLeq, varGeq :: (Ord v, Ord c, MonadState (LP v c) m) => v -> c -> m () varEq v c = setVarBounds v (Equ c) varLeq v c = setVarBounds v (UBound c)@@ -143,7 +145,8 @@ {-# SPECIALIZE varBds :: (Ord v, Ord c) => v -> c -> c -> LPM v c (), 	(Ord v, Ord c, Monad m) => v -> c -> c -> LPT v c m () #-} -- | Bounds the value of a variable on both sides.  If you constrain a variable more than once,--- the constraints will be combined.+-- the constraints will be combined.  If the constraints are mutually contradictory,+-- an error will be generated.  This is more efficient than adding an equivalent function constraint. varBds :: (Ord v, Ord c, MonadState (LP v c) m) => v -> c -> c -> m () varBds v l u = setVarBounds v (Bound l u) @@ -188,6 +191,8 @@ 	(Ord v, Ord c, Monad m) => v -> Bounds c -> LPT v c m () #-} -- | The most general way to set constraints on a variable. -- If you constrain a variable more than once, the constraints will be combined.+-- If you combine mutually contradictory constraints, an error will be generated.+-- This is more efficient than creating an equivalent function constraint. setVarBounds :: (Ord v, Ord c, MonadState (LP v c) m) => v -> Bounds c -> m () setVarBounds var bds = modify addBds where 	addBds lp@LP{..} = lp{varBounds = insertWith mappend var bds varBounds}
Data/LinearProgram/LinFunc.hs view
@@ -2,16 +2,14 @@  module Data.LinearProgram.LinFunc (LinFunc, Module(..), var, varSum, (*&), vsum, combination, linCombination) where -import Control.Monad+import Control.Applicative  import qualified Data.Map as M import qualified Data.IntMap as IM import Data.Ratio import Data.Array.Base import Data.Array.IArray--- import Data.Array.Unboxed --- import Data.LinFunc.TH import Data.LinearProgram.LinFunc.Class  -- | @'LinFunc' v c@ is a linear combination of variables of type @v@ with coefficients@@ -52,8 +50,8 @@ instance Module r m => Module r (a -> m) where 	(*^) = fmap . (*^) 	zero = const zero-	(^+^) = liftM2 (^+^)-	(^-^) = liftM2 (^-^)+	(^+^) = liftA2 (^+^)+	(^-^) = liftA2 (^-^) 	neg = fmap neg  instance (Ord k, Module r m) => Module r (M.Map k m) where
Data/LinearProgram/Spec.hs view
@@ -1,24 +1,136 @@-{-# LANGUAGE RecordWildCards #-}-module Data.LinearProgram.Spec where+{-# LANGUAGE TupleSections, RecordWildCards, DeriveFunctor #-}+module Data.LinearProgram.Spec (Constraint(..), VarTypes, ObjectiveFunc, VarBounds, LP(..),+	mapVars, mapVals) where --- import Control.DeepSeq--- import Data.Bounds+import Control.Applicative ((<$>))+import Control.Monad++import Data.Char (isSpace)+import Data.Monoid+import Data.Map hiding (map)++import Text.ParserCombinators.ReadP+ import Data.LinearProgram.LinFunc import Data.LinearProgram.Types-import Data.Map  data Constraint v c = Constr (Maybe String) 			(LinFunc v c)-			(Bounds c) deriving (Read, Show)+			(Bounds c) deriving (Functor) type VarTypes v = Map v VarKind type ObjectiveFunc = LinFunc type VarBounds v c = Map v (Bounds c) +data LP v c = LP {direction :: Direction, objective :: ObjectiveFunc v c, constraints :: [Constraint v c],+			varBounds :: VarBounds v c, varTypes :: VarTypes v} deriving (Read, Show, Functor)++showBds :: Show c => String -> Bounds c -> String+showBds expr bds = case bds of+	Free	-> expr ++ " free"+	Equ x	-> expr ++ " = " ++ show x+	LBound x -> expr ++ " >= " ++ show x+	UBound x -> expr ++ " <= " ++ show x+	Bound l u -> show l ++ " <= " ++ expr ++ " <= " ++ show u++showFunc :: (Show v, Num c, Ord c) => LinFunc v c -> String+showFunc func = case assocs func of+	[]	-> "0"+	((v,c):vcs) ->+		show c ++ " " ++ map replaceSpace (show v) ++ +			concatMap showTerm vcs+	where	showTerm (v, c) = case compare c 0 of+			EQ	-> ""+			GT	-> " + " ++ show c ++ " " ++ show v+			LT	-> " - " ++ show (negate c) ++ " " ++ show v+		+replaceSpace :: Char -> Char+replaceSpace c+	| isSpace c	= '_'+	| otherwise	= c++instance (Show v, Num c, Ord c) => Show (Constraint v c) where+	show (Constr lab func bds) = maybe "" (++ ": ") lab +++		showBds (showFunc func) bds++instance (Read v, Ord v, Read c, Ord c, Num c) => Read (Constraint v c) where+	readsPrec _= readP_to_S $ liftM toConstr (lab <++ nolab) where+		toConstr (l, f, bds) = Constr l (fromList f) bds+		lab = do	skipSpaces+				label <- manyTill get (skipSpaces >> char ':')+				(_, f, bds) <- nolab+				return (Just label, f, bds)+		nolab = liftM (\ (f, bds) -> (Nothing, f, bds)) $ readBds readConst readFunc+		readFunc = (do	c <- readCoef readConst+				v <- readVar+				liftM ((v, c):) readFunc) <++ return []+		readConst = readS_to_P reads+		readVar = readS_to_P reads++readCoef :: Num c => ReadP c -> ReadP c+readCoef readC = between skipSpaces skipSpaces $ +	(do	char '+'+		skipSpaces+		readC') <+++	(do	char '-'+		skipSpaces+		negate <$> readC') <++ readC'+	where	readC' = readC <++ return 1++optMaybe :: ReadP a -> ReadP (Maybe a)+optMaybe p = fmap Just p <++ return Nothing++readBds :: Ord c => ReadP c -> ReadP a -> ReadP (a, Bounds c)+readBds cst expr = do+	left <- optMaybe (do	lb <- cst+				skipSpaces+				rel <- readRelation+				return (lb, rel))+	skipSpaces+	f <- expr+	skipSpaces+	right <- optMaybe (do	rel <- readRelation+				skipSpaces+				ub <- cst+				return (ub, revOrd rel))+	return (f, getBd left `mappend` getBd right)+	where	revOrd :: Ordering -> Ordering+		revOrd GT = LT+		revOrd LT = GT+		revOrd EQ = EQ+		getBd :: Maybe (c, Ordering) -> Bounds c+		getBd Nothing = Free+		getBd (Just (x, cmp)) = case cmp of+			EQ	-> Equ x+			GT	-> LBound x+			LT	-> UBound x+		readRelation = choice [char '<' >> optional (char '=') >> return LT,+			char '=' >> return EQ,+			char '>' >> optional (char '=') >> return GT]++-- | Applies the specified function to the variables in the linear program.+-- If multiple variables in the original program are mapped to the same variable in the new program,+-- in general, we set those variables to all be equal, as follows.+-- * In linear functions, including the objective function and the constraints,+-- 	coefficients will be added together.  For instance, if @v1,v2@ are mapped to the same+-- 	variable @v'@, then a linear function of the form @c1 *& v1 ^+^ c2 *& v2@ will be mapped to+-- 	@(c1 ^+^ c2) *& v'@.+-- * In variable bounds, bounds will be combined.  An error will be thrown if the bounds+-- 	are mutually contradictory.+-- * In variable kinds, the most restrictive kind will be retained.+mapVars :: (Ord v', Ord c, Module r c) => (v -> v') -> LP v c -> LP v' c+mapVars f LP{..} =  +	LP{objective = mapKeysWith (^+^) f objective, +		constraints = [Constr lab (mapKeysWith (^+^) f func) bd | Constr lab func bd <- constraints],+		varBounds = mapKeysWith mappend f varBounds,+		varTypes = mapKeysWith mappend f varTypes, ..}++-- | Applies the specified function to the constants in the linear program.  This is only safe+-- for a monotonic function.+mapVals :: (Ord c', Module r c') => (c -> c') -> LP v c -> LP v c'+mapVals = fmap+ -- instance (NFData v, NFData c) => NFData (Constraint v c) where -- 	rnf (Constr lab f b) = lab `deepseq` f `deepseq` rnf b--data LP v c = LP {direction :: Direction, objective :: ObjectiveFunc v c, constraints :: [Constraint v c],-			varBounds :: VarBounds v c, varTypes :: VarTypes v} deriving (Read, Show)  -- instance (NFData v, NFData c) => NFData (LP v c) where -- 	rnf LP{..} = direction `deepseq` objective `deepseq` constraints `deepseq`
Data/LinearProgram/Types.hs view
@@ -1,4 +1,5 @@-module Data.LinearProgram.Types where+{-# LANGUAGE DeriveFunctor #-}+module Data.LinearProgram.Types (VarKind(..), Direction(..), Bounds(..)) where  -- import Control.DeepSeq @@ -17,7 +18,7 @@ -- instance NFData Direction  data Bounds a =-	Free | LBound a | UBound a | Equ a | Bound a a deriving (Eq, Show, Read)+	Free | LBound a | UBound a | Equ a | Bound a a deriving (Eq, Show, Read, Functor)  -- instance NFData (Bounds a) @@ -26,14 +27,22 @@ 	mempty = Free 	Free `mappend` bd = bd 	bd `mappend` Free = bd-	Equ a `mappend` _ = Equ a-	_ `mappend` Equ a = Equ a+	Equ a `mappend` Equ b+		| a == b	= Equ a+		| otherwise	= infeasible 	LBound a `mappend` LBound b = LBound (max a b)-	LBound l `mappend` UBound u = Bound l u-	UBound u `mappend` LBound l = Bound l u-	LBound a `mappend` Bound l u = Bound (max a l) u-	Bound l u `mappend` LBound a = Bound (max a l) u+	LBound l `mappend` UBound u = bound l u+	UBound u `mappend` LBound l = bound l u+	LBound a `mappend` Bound l u = bound (max a l) u+	Bound l u `mappend` LBound a = bound (max a l) u 	UBound a `mappend` UBound b = UBound (min a b)-	UBound a `mappend` Bound l u = Bound l (min a u)-	Bound l u `mappend` UBound a = Bound l (min a u)-	Bound l u `mappend` Bound l' u' = Bound (max l l') (min u u')+	UBound a `mappend` Bound l u = bound l (min a u)+	Bound l u `mappend` UBound a = bound l (min a u)+	Bound l u `mappend` Bound l' u' = bound (max l l') (min u u')++infeasible :: Bounds a+infeasible = error "Mutually contradictory constraints found."++bound :: Ord a => a -> a -> Bounds a+bound l u	| l <= u	= Bound l u+		| otherwise	= infeasible
glpk-hs.cabal view
@@ -1,5 +1,5 @@ Name:           glpk-hs-Version:        0.0.4+Version:        0.1.0 Author:         Louis Wasserman License:        GPL License-file:   LICENSE