{-# LANGUAGE CPP #-}
module Numeric.Limp.Canon.Simplify where
import Numeric.Limp.Canon.Program
import Numeric.Limp.Rep
import Numeric.Limp.Error
import Numeric.Limp.Canon.Analyse.Constants
import Numeric.Limp.Canon.Simplify.Bounder
import Numeric.Limp.Canon.Simplify.Crunch
import Numeric.Limp.Canon.Simplify.Subst
#if MIN_VERSION_base(4,9,0) && !MIN_VERSION_base(4,11,0)
import Data.Semigroup
#endif
simplify :: (Ord z, Ord r, Rep c) => Program z r c -> Either Infeasible (Assignment z r c, Program z r c)
simplify p
= simplify' mempty p
simplify' :: (Ord z, Ord r, Rep c) => Assignment z r c -> Program z r c -> Either Infeasible (Assignment z r c, Program z r c)
simplify' sub1 p
= do let p' = crunchProgram p
p'' <- bounderProgram p'
sub2 <- constantsProgram p''
if assSize sub2 == 0
then return (sub1, p'')
else simplify' (sub1 <> sub2) (substProgram sub2 p'')