module G2.Execution.NewPC ( NewPC (..)
                          , newPCEmpty
                          , reduceNewPC ) where

import G2.Language
import qualified G2.Language.PathConds as PC
import G2.Solver

import qualified Data.List as L

data NewPC t = NewPC { state :: State t
                     , new_pcs :: [PathCond]
                     , concretized :: [Id] }

newPCEmpty :: State t -> NewPC t
newPCEmpty s = NewPC { state = s, new_pcs = [], concretized = []}

reduceNewPC :: (Solver solver, Simplifier simplifier) => solver -> simplifier -> NewPC t -> IO (Maybe (State t))
reduceNewPC solver simplifier
            (NewPC { state = s@(State { path_conds = spc })
                   , new_pcs = pc
                   , concretized = concIds })
    | not (null pc) || not (null concIds) = do
        let (s', pc') = L.mapAccumL (simplifyPC simplifier) s pc
            pc'' = concat pc'


        -- Optimization
        -- We replace the path_conds with only those that are directly
        -- affected by the new path constraints
        -- This allows for more efficient solving, and in some cases may
  change an Unknown into a SAT or UNSAT
        let new_pc = foldr PC.insert spc $ pc''
            new_pc' = foldr (simplifyPCs simplifier s') new_pc pc''

            s'' = s' {path_conds = new_pc'}

        let ns = (concatMap PC.varNamesInPC pc) ++ namesList concIds
            rel_pc = case ns of
                [] -> PC.fromList pc''
                _ -> PC.scc ns new_pc'

        res <- check solver s' rel_pc

        if res == SAT () then
            return $ Just s''
        else
            return Nothing
    | otherwise = return $ Just s

 Optimization
 We replace the path_conds with only those that are directly
 affected by the new path constraints
 This allows for more efficient solving, and in some cases may
module G2.Execution.NewPC ( NewPC (..)
                          , newPCEmpty
                          , reduceNewPC ) where

import G2.Language
import qualified G2.Language.PathConds as PC
import G2.Solver

import qualified Data.List as L

data NewPC t = NewPC { state :: State t
                     , new_pcs :: [PathCond]
                     , concretized :: [Id] }

newPCEmpty :: State t -> NewPC t
newPCEmpty s = NewPC { state = s, new_pcs = [], concretized = []}

reduceNewPC :: (Solver solver, Simplifier simplifier) => solver -> simplifier -> NewPC t -> IO (Maybe (State t))
reduceNewPC solver simplifier
            (NewPC { state = s@(State { path_conds = spc })
                   , new_pcs = pc
                   , concretized = concIds })
    | not (null pc) || not (null concIds) = do
        let (s', pc') = L.mapAccumL (simplifyPC simplifier) s pc
            pc'' = concat pc'


  change an Unknown into a SAT or UNSAT
        let new_pc = foldr PC.insert spc $ pc''
            new_pc' = foldr (simplifyPCs simplifier s') new_pc pc''

            s'' = s' {path_conds = new_pc'}

        let ns = (concatMap PC.varNamesInPC pc) ++ namesList concIds
            rel_pc = case ns of
                [] -> PC.fromList pc''
                _ -> PC.scc ns new_pc'

        res <- check solver s' rel_pc

        if res == SAT () then
            return $ Just s''
        else
            return Nothing
    | otherwise = return $ Just s
