limp-0.3.1.0: src/Numeric/Limp/Canon/Simplify/Subst.hs
-- | Substitute an assignment into functions, constraints and programs
module Numeric.Limp.Canon.Simplify.Subst where
import Numeric.Limp.Canon.Constraint
import Numeric.Limp.Canon.Linear
import Numeric.Limp.Canon.Program
import Numeric.Limp.Rep
import qualified Data.Map as M
-- | Substitute assignment into linear function.
-- However, 'Linear' isn't quite a linear function! That is, it doesn't have a constant summand.
-- So we must return the constant summand we lose.
--
-- Satisfies:
--
-- > forall a b f.
-- > let (f', c') = substLinear a f
-- > in eval (a <> b) f == eval b f' + c'
--
-- > subst (x := 5) in 2x + y
-- > (y, 10)
--
substLinear :: (Ord z, Ord r, Rep c) => Assignment z r c -> Linear z r c -> (Linear z r c, R c)
substLinear (Assignment mz mr) (Linear mf)
= ( Linear $ M.fromList $ concatMap update mf'
, sum $ map getC mf' )
where
mf' = M.toList mf
get (v,co)
| Left z <- v
, Just zv <- M.lookup z mz
= Just $ fromZ zv * co
| Right r <- v
, Just rv <- M.lookup r mr
= Just $ rv * co
| otherwise
= Nothing
update vc
| Just _ <- get vc
= []
| otherwise
= [vc]
getC vc
| Just n <- get vc
= n
| otherwise
= 0
-- | Substitute assignment into a single linear constraint.
-- See 'substConstraint'.
--
-- > 5 <= 2x + y <= 10
-- > subst (y := 3)
-- > 2 <= 2x <= 7
--
substConstraint1 :: (Ord z, Ord r, Rep c) => Assignment z r c -> Constraint1 z r c -> Constraint1 z r c
substConstraint1 ass (C1 low lin upp)
= let (lin', const') = substLinear ass lin
fixup bound = bound - const'
in C1 (fmap fixup low) lin' (fmap fixup upp)
-- | Substitute assignment into a set of linear constraints.
-- Satisfies:
--
-- > forall a b f.
-- > let c' = substConstraint a c
-- > in check (a <> b) c == check b c'
--
-- > subst (x := 5) in 15 <= 2x + y <= 20
-- > 5 <= y <= 10
--
substConstraint :: (Ord z, Ord r, Rep c) => Assignment z r c -> Constraint z r c -> Constraint z r c
substConstraint ass (Constraint cs)
= Constraint
$ map (substConstraint1 ass) cs
-- | Substitute assignment into a program.
-- What does this satisfy? Hm.
substProgram :: (Ord z, Ord r, Rep c) => Assignment z r c -> Program z r c -> Program z r c
substProgram ass@(Assignment mz mr) p
= p
{ _objective = fst $ substLinear ass $ _objective p
, _constraints = substConstraint ass $ _constraints p
, _bounds = cullBounds $ _bounds p
}
where
cullBounds
= M.mapMaybeWithKey cullB
cullB k v
| Left z <- k
, Just _ <- M.lookup z mz
= Nothing
| Right r <- k
, Just _ <- M.lookup r mr
= Nothing
| otherwise
= Just v