grisette-0.1.0.0: Symbolic evaluation as a library
Copyright(c) Sirui Lu 2021-2023
LicenseBSD-3-Clause (see the LICENSE file)
Maintainersiruilu@cs.washington.edu
StabilityExperimental
PortabilityGHC only
Safe HaskellTrustworthy
LanguageHaskell2010

Grisette.Core.Control.Monad.UnionM

Description

 
Synopsis

UnionM and helpers

data UnionM a where Source #

UnionM is the Union container (hidden) enhanced with MergingStrategy knowledge propagation.

The Union models the underlying semantics evaluation semantics for unsolvable types with the nested if-then-else tree semantics, and can be viewed as the following structure:

data Union a
  = Single a
  | If bool (Union a) (Union a)

The Single constructor is for a single value with the path condition true, and the If constructor is the if operator in an if-then-else tree. For clarity, when printing a UnionM value, we will omit the Single constructor. The following two representations has the same semantics.

If      c1    (If c11 v11 (If c12 v12 v13))
  (If   c2    v2
              v3)

\[ \left\{\begin{aligned}&t_1&&\mathrm{if}&&c_1\\&v_2&&\mathrm{else if}&&c_2\\&v_3&&\mathrm{otherwise}&&\end{aligned}\right.\hspace{2em}\mathrm{where}\hspace{2em}t_1 = \left\{\begin{aligned}&v_{11}&&\mathrm{if}&&c_{11}\\&v_{12}&&\mathrm{else if}&&c_{12}\\&v_{13}&&\mathrm{otherwise}&&\end{aligned}\right. \]

To reduce the size of the if-then-else tree to reduce the number of paths to execute, Grisette would merge the branches in a Union container and maintain a representation invariant for them. To perform this merging procedure, Grisette relies on a type class called Mergeable and the merging strategy defined by it.

Union is a monad, so we can easily write code with the do-notation and monadic combinators. However, the standard monadic operators cannot resolve any extra constraints, including the Mergeable constraint (see The constrained-monad problem by Sculthorpe et al.). This prevents the standard do-notations to merge the results automatically, and would result in bad performance or very verbose code.

To reduce this boilerplate, Grisette provide another monad, UnionM that would try to cache the merging strategy. The UnionM has two data constructors (hidden intentionally), UAny and UMrg. The UAny data constructor (printed as <...>) wraps an arbitrary (probably unmerged) Union. It is constructed when no Mergeable knowledge is available (for example, when constructed with Haskell's return). The UMrg data constructor (printed as {...}) wraps a merged UnionM along with the Mergeable constraint. This constraint can be propagated to the contexts without Mergeable knowledge, and helps the system to merge the resulting Union.

Examples:

return cannot resolve the Mergeable constraint.

>>> return 1 :: UnionM Integer
<1>

mrgReturn can resolve the Mergeable constraint.

>>> import Grisette.Lib.Base
>>> mrgReturn 1 :: UnionM Integer
{1}

unionIf cannot resolve the Mergeable constraint.

>>> unionIf "a" (return 1) (unionIf "b" (return 1) (return 2)) :: UnionM Integer
<If a 1 (If b 1 2)>

But unionIf is able to merge the result if some of the branches are merged:

>>> unionIf "a" (return 1) (unionIf "b" (mrgReturn 1) (return 2)) :: UnionM Integer
{If (|| a b) 1 2}

The >>= operator uses unionIf internally. When the final statement in a do-block merges the values, the system can then merge the final result.

>>> :{
  do
    x <- unionIf (ssym "a") (return 1) (unionIf (ssym "b") (return 1) (return 2))
    mrgSingle $ x + 1 :: UnionM Integer
:}
{If (|| a b) 2 3}

Calling a function that merges a result at the last line of a do-notation will also merge the whole block. If you stick to these mrg* combinators and all the functions will merge the results, the whole program can be symbolically evaluated efficiently.

>>> f x y = mrgIf "c" x y
>>> :{
  do
    x <- unionIf (ssym "a") (return 1) (unionIf (ssym "b") (return 1) (return 2))
    f x (x + 1) :: UnionM Integer
:}
{If (&& c (|| a b)) 1 (If (|| a (|| b c)) 2 3)}

In Grisette.Lib.Base, Grisette.Lib.Mtl, we also provided more mrg* variants of other combinators. You should stick to these combinators to ensure efficient merging by Grisette.

Constructors

UAny

UnionM with no Mergeable knowledge.

Fields

UMrg

UnionM with Mergeable knowledge.

Fields

Instances

Instances details
Eq1 UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

liftEq :: (a -> b -> Bool) -> UnionM a -> UnionM b -> Bool #

Show1 UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

liftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> UnionM a -> ShowS #

liftShowList :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> [UnionM a] -> ShowS #

Applicative UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

pure :: a -> UnionM a #

(<*>) :: UnionM (a -> b) -> UnionM a -> UnionM b #

liftA2 :: (a -> b -> c) -> UnionM a -> UnionM b -> UnionM c #

(*>) :: UnionM a -> UnionM b -> UnionM b #

(<*) :: UnionM a -> UnionM b -> UnionM a #

Functor UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

fmap :: (a -> b) -> UnionM a -> UnionM b #

(<$) :: a -> UnionM b -> UnionM a #

Monad UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

(>>=) :: UnionM a -> (a -> UnionM b) -> UnionM b #

(>>) :: UnionM a -> UnionM b -> UnionM b #

return :: a -> UnionM a #

NFData1 UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

liftRnf :: (a -> ()) -> UnionM a -> () #

Mergeable1 UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

SimpleMergeable1 UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

liftMrgIte :: (SymBool -> a -> a -> a) -> SymBool -> UnionM a -> UnionM a -> UnionM a Source #

UnionLike UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

UnionPrjOp UnionM Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

(GenSym spec a, Mergeable a) => GenSym spec (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

fresh :: MonadFresh m => spec -> m (UnionM (UnionM a)) Source #

GenSym spec a => GenSymSimple spec (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

simpleFresh :: MonadFresh m => spec -> m (UnionM a) Source #

(Solvable c t, Mergeable t) => Solvable c (UnionM t) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

con :: c -> UnionM t Source #

conView :: UnionM t -> Maybe c Source #

ssym :: String -> UnionM t Source #

isym :: String -> Int -> UnionM t Source #

sinfosym :: (Typeable a, Ord a, Lift a, NFData a, Show a, Hashable a) => String -> a -> UnionM t Source #

iinfosym :: (Typeable a, Ord a, Lift a, NFData a, Show a, Hashable a) => String -> Int -> a -> UnionM t Source #

(ToSym a b, Mergeable b) => ToSym a (UnionM b) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

toSym :: a -> UnionM b Source #

Lift a => Lift (UnionM a :: Type) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

lift :: Quote m => UnionM a -> m Exp #

liftTyped :: forall (m :: Type -> Type). Quote m => UnionM a -> Code m (UnionM a) #

(IsString a, Mergeable a) => IsString (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

fromString :: String -> UnionM a #

(Num a, Mergeable a) => Num (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

(+) :: UnionM a -> UnionM a -> UnionM a #

(-) :: UnionM a -> UnionM a -> UnionM a #

(*) :: UnionM a -> UnionM a -> UnionM a #

negate :: UnionM a -> UnionM a #

abs :: UnionM a -> UnionM a #

signum :: UnionM a -> UnionM a #

fromInteger :: Integer -> UnionM a #

Show a => Show (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

showsPrec :: Int -> UnionM a -> ShowS #

show :: UnionM a -> String #

showList :: [UnionM a] -> ShowS #

NFData a => NFData (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

rnf :: UnionM a -> () #

Eq a => Eq (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

(==) :: UnionM a -> UnionM a -> Bool #

(/=) :: UnionM a -> UnionM a -> Bool #

(ITEOp a, Mergeable a) => ITEOp (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

ites :: SymBool -> UnionM a -> UnionM a -> UnionM a Source #

(LogicalOp a, Mergeable a) => LogicalOp (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

(||~) :: UnionM a -> UnionM a -> UnionM a Source #

(&&~) :: UnionM a -> UnionM a -> UnionM a Source #

nots :: UnionM a -> UnionM a Source #

xors :: UnionM a -> UnionM a -> UnionM a Source #

implies :: UnionM a -> UnionM a -> UnionM a Source #

SEq a => SEq (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

(==~) :: UnionM a -> UnionM a -> SymBool Source #

(/=~) :: UnionM a -> UnionM a -> SymBool Source #

(Mergeable a, EvaluateSym a) => EvaluateSym (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

evaluateSym :: Bool -> Model -> UnionM a -> UnionM a Source #

ExtractSymbolics a => ExtractSymbolics (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

(Function f, Mergeable f, Mergeable a, Ret f ~ a) => Function (UnionM f) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Associated Types

type Arg (UnionM f) Source #

type Ret (UnionM f) Source #

Methods

(#) :: UnionM f -> Arg (UnionM f) -> Ret (UnionM f) Source #

Mergeable a => Mergeable (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

SOrd a => SOrd (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Mergeable a => SimpleMergeable (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

mrgIte :: SymBool -> UnionM a -> UnionM a -> UnionM a Source #

(Mergeable a, SubstituteSym a) => SubstituteSym (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

substituteSym :: TypedSymbol b -> Sym b -> UnionM a -> UnionM a Source #

Hashable a => Hashable (UnionM a) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

hashWithSalt :: Int -> UnionM a -> Int #

hash :: UnionM a -> Int #

(GenSym a a, Mergeable a) => GenSym (UnionM a) a Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

fresh :: MonadFresh m => UnionM a -> m (UnionM a) Source #

ToCon a b => ToCon (UnionM a) b Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

toCon :: UnionM a -> Maybe b Source #

UnionWithExcept (UnionM (Either e v)) UnionM e v Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

UnionWithExcept (UnionM (CBMCEither e v)) UnionM e v Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

(ToCon a b, Mergeable b) => ToCon (UnionM a) (UnionM b) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

toCon :: UnionM a -> Maybe (UnionM b) Source #

(ToSym a b, Mergeable b) => ToSym (UnionM a) (UnionM b) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

toSym :: UnionM a -> UnionM b Source #

(IsConcrete k, Mergeable t) => Mergeable (HashMap k (UnionM (Maybe t))) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

(IsConcrete k, Mergeable t) => SimpleMergeable (HashMap k (UnionM (Maybe t))) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

Methods

mrgIte :: SymBool -> HashMap k (UnionM (Maybe t)) -> HashMap k (UnionM (Maybe t)) -> HashMap k (UnionM (Maybe t)) Source #

type Arg (UnionM f) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

type Arg (UnionM f) = Arg f
type Ret (UnionM f) Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

type Ret (UnionM f) = UnionM (Ret f)

liftToMonadUnion :: (Mergeable a, MonadUnion u) => UnionM a -> u a Source #

Lift the UnionM to any MonadUnion.

underlyingUnion :: UnionM a -> Union a Source #

Extract the underlying Union. May be unmerged.

isMerged :: UnionM a -> Bool Source #

Check if a UnionM is already merged.

(#~) :: (Function f, SimpleMergeable (Ret f), UnionPrjOp u, Functor u) => f -> u (Arg f) -> Ret f infixl 9 Source #

Helper for applying functions on UnionPrjOp and SimpleMergeable.

>>> let f :: Integer -> UnionM Integer = \x -> mrgIf (ssym "a") (mrgSingle $ x + 1) (mrgSingle $ x + 2)
>>> f #~ (mrgIf (ssym "b" :: SymBool) (mrgSingle 0) (mrgSingle 2) :: UnionM Integer)
{If (&& b a) 1 (If b 2 (If a 3 4))}

class (Eq t, Ord t, Hashable t) => IsConcrete t Source #

Tag for concrete types. Useful for specifying the merge strategy for some parametrized types where we should have different merge strategy for symbolic and concrete ones.

Instances

Instances details
IsConcrete Integer Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM

IsConcrete Bool Source # 
Instance details

Defined in Grisette.Core.Control.Monad.UnionM