module Numeric.Limp.Canon.Simplify.Bounder where
import Numeric.Limp.Canon.Constraint
import Numeric.Limp.Canon.Linear
import Numeric.Limp.Canon.Program
import Numeric.Limp.Rep
import Numeric.Limp.Error
import Data.Either
import qualified Data.Map as M
type Bound z r c = (Either z r, (Maybe (R c), Maybe (R c)))
bounderConstraint1 :: (Ord z, Ord r, Rep c) => Constraint1 z r c -> Either Infeasible (Maybe (Bound z r c))
bounderConstraint1 (C1 low (Linear mf) upp)
| M.size mf == 1
, [(k,c)] <- M.toList mf
, c /= 0
= let fixup = (/ c)
low' = fmap fixup low
upp' = fmap fixup upp
bounds
| c >= 0
= (low',upp')
| otherwise
= (upp',low')
valid
| (Just lo, Just hi) <- bounds
= lo <= hi
| otherwise
= True
in if valid
then Right $ Just (k, bounds)
else Left InfeasibleNotIntegral
| otherwise
= Right Nothing
bounderConstraint :: (Ord z, Ord r, Rep c) => Constraint z r c -> Either Infeasible (Constraint z r c, [Bound z r c])
bounderConstraint (Constraint cs)
= do (cs', bs) <- partitionEithers <$> mapM bounderC cs
return (Constraint cs', bs)
where
bounderC c
= do c' <- bounderConstraint1 c
return $ case c' of
Nothing -> Left c
Just b -> Right b
bounderProgram :: (Ord z, Ord r, Rep c) => Program z r c -> Either Infeasible (Program z r c)
bounderProgram p
= do (c',bs) <- bounderConstraint $ _constraints p
return $ p
{ _constraints = c'
, _bounds = foldl merge (_bounds p) bs }
where
merge m (k,v)
= case M.lookup k m of
Just v'
-> M.insert k (mergeBounds v' v) m
Nothing
-> M.insert k v m