-- | Crunch together all constraints with same linear function module Numeric.Limp.Canon.Simplify.Crunch where import Numeric.Limp.Canon.Constraint import Numeric.Limp.Canon.Program import Numeric.Limp.Rep import Data.List import Data.Function import Data.Maybe -- | Crunch the constraints in some program crunchProgram :: (Ord z, Ord r, Rep c) => Program z r c -> Program z r c crunchProgram p = p { _constraints = crunchConstraint $ _constraints p } -- | Crunch some constraints. -- Constraints with the same function, for example -- -- > 2x + y < 5 -- > && 0 < 2x + y -- > && 2x + y < 10 -- -- becomes -- -- > 0 < 2x + y < 5 -- -- This should satisfy: -- -- > forall a c. check a c == check a (crunchConstraint c) -- > forall a. length (checkConstraint c) <= length c -- crunchConstraint :: (Ord z, Ord r, Rep c) => Constraint z r c -> Constraint z r c crunchConstraint (Constraint cs) = Constraint $ map crunchC $ groupBy ((==) `on` getLin) cs where getLin (C1 _ lin _ ) = lin getLow (C1 low _ _ ) = low getUpp (C1 _ _ upp) = upp crunchC grp@(c:_) = let low = compareMaybes maximum $ map getLow grp upp = compareMaybes minimum $ map getUpp grp in C1 low (getLin c) upp crunchC [] = error "Impossible - groupBy should not produce empty lists" compareMaybes f ms = case catMaybes ms of ms'@(_:_) -> Just $ f ms' [] -> Nothing