    {-|
    Module           : What4.Interface
    Description      : Main interface for constructing What4 formulae
    Copyright        : (c) Galois, Inc 2014-2020
    License          : BSD3
    Maintainer       : Joe Hendrix <jhendrix@galois.com>

    Defines interface between the simulator and terms that are sent to the
    SAT or SMT solver.  The simulator can use a richer set of types, but the
    symbolic values must be representable by types supported by this interface.

    A solver backend is defined in terms of a type parameter @sym@, which
    is the type that tracks whatever state or context is needed by that
    particular backend. To instantiate the solver interface, one must
    provide several type family definitions and class instances for @sym@:

      [@type 'SymExpr' sym :: 'BaseType' -> *@]
      Type of symbolic expressions.

      [@type 'BoundVar' sym :: 'BaseType' -> *@]
      Representation of bound variables in symbolic expressions.

      [@type 'SymFn' sym :: Ctx BaseType -> BaseType -> *@]
      Representation of symbolic functions.

      [@instance 'IsExprBuilder' sym@]
      Functions for building expressions of various types.

      [@instance 'IsSymExprBuilder' sym@]
      Functions for building expressions with bound variables and quantifiers.

      [@instance 'IsExpr' ('SymExpr' sym)@]
      Recognizers for various kinds of literal expressions.

      [@instance 'OrdF' ('SymExpr' sym)@]

      [@instance 'TestEquality' ('SymExpr' sym)@]

      [@instance 'HashableF' ('SymExpr' sym)@]

      [@instance 'OrdF' ('BoundVar' sym)@]

      [@instance 'TestEquality' ('BoundVar' sym)@]

      [@instance 'HashableF' ('BoundVar' sym)@]

    The canonical implementation of these interface classes is found in "What4.Expr.Builder".
    -}
    {-# LANGUAGE CPP #-}
    {-# LANGUAGE ConstraintKinds #-}
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE DeriveGeneric #-}
    {-# LANGUAGE DoAndIfThenElse #-}
    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE GADTs #-}
    {-# LANGUAGE LambdaCase #-}
    {-# LANGUAGE LiberalTypeSynonyms #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE PatternGuards #-}
    {-# LANGUAGE PolyKinds #-}
    {-# LANGUAGE RankNTypes #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE TypeApplications #-}
    {-# LANGUAGE TypeFamilies #-}
    {-# LANGUAGE TypeOperators #-}

    {-# LANGUAGE UndecidableInstances #-}

    module What4.Interface
      ( -- * Interface classes
        -- ** Type Families
        SymExpr
      , BoundVar
      , SymFn
      , SymAnnotation

        -- ** Expression recognizers
      , IsExpr(..)
      , IsSymFn(..)
      , SomeSymFn(..)
      , SymFnWrapper(..)
      , UnfoldPolicy(..)
      , shouldUnfold

        -- ** IsExprBuilder
      , IsExprBuilder(..)
      , IsSymExprBuilder(..)
      , SolverEvent(..)
      , SolverStartSATQuery(..)
      , SolverEndSATQuery(..)

        -- ** Bitvector operations
      , bvJoinVector
      , bvSplitVector
      , bvSwap
      , bvBitreverse

        -- ** Floating-point rounding modes
      , RoundingMode(..)

        -- ** Run-time statistics
      , Statistics(..)
      , zeroStatistics

        -- * Type Aliases
      , Pred
      , SymInteger
      , SymReal
      , SymFloat
      , SymString
      , SymCplx
      , SymStruct
      , SymBV
      , SymArray

        -- * Natural numbers
      , SymNat
      , asNat
      , natLit
      , natAdd
      , natSub
      , natMul
      , natDiv
      , natMod
      , natIte
      , natEq
      , natLe
      , natLt
      , natToInteger
      , natToIntegerPure
      , bvToNat
      , natToReal
      , integerToNat
      , realToNat
      , freshBoundedNat
      , freshNat
      , printSymNat

        -- * Array utility types
      , IndexLit(..)
      , indexLit
      , ArrayResultWrapper(..)

        -- * Concrete values
      , asConcrete
      , concreteToSym
      , baseIsConcrete
      , baseDefaultValue
      , realExprAsInteger
      , rationalAsInteger
      , cplxExprAsRational
      , cplxExprAsInteger

        -- * SymEncoder
      , SymEncoder(..)

        -- * Utility combinators
        -- ** Boolean operations
      , backendPred
      , andAllOf
      , orOneOf
      , itePredM
      , iteM
      , iteList
      , predToReal

        -- ** Complex number operations
      , cplxDiv
      , cplxLog
      , cplxLogBase
      , mkRational
      , mkReal
      , isNonZero
      , isReal

        -- ** Indexing
      , muxRange

        -- * Exceptions
      , InvalidRange(..)

        -- * Reexports
      , module Data.Parameterized.NatRepr
      , module What4.BaseTypes
      , HasAbsValue
      , What4.Symbol.SolverSymbol
      , What4.Symbol.emptySymbol
      , What4.Symbol.userSymbol
      , What4.Symbol.safeSymbol
      , ValueRange(..)
      , StringLiteral(..)
      , stringLiteralInfo
      ) where

    #if !MIN_VERSION_base(4,13,0)
    import Control.Monad.Fail( MonadFail )
    #endif

    import           Control.Exception (assert, Exception)
    import           Control.Lens
    import           Control.Monad
    import           Control.Monad.IO.Class
    import qualified Data.BitVector.Sized as BV
    import           Data.Coerce (coerce)
    import           Data.Foldable
    import           Data.Kind ( Type )
    import qualified Data.Map as Map
    import           Data.Parameterized.Classes
    import qualified Data.Parameterized.Context as Ctx
    import           Data.Parameterized.Ctx
    import           Data.Parameterized.Utils.Endian (Endian(..))
    import           Data.Parameterized.Map (MapF)
    import           Data.Parameterized.NatRepr
    import           Data.Parameterized.TraversableFC
    import qualified Data.Parameterized.Vector as Vector
    import           Data.Ratio
    import           Data.Scientific (Scientific)
    import           Data.Set (Set)
    import           GHC.Generics (Generic)
    import           Numeric.Natural
    import           LibBF (BigFloat)
    import           Prettyprinter (Doc)

    import           What4.BaseTypes
    import           What4.Config
    import qualified What4.Expr.ArrayUpdateMap as AUM
    import           What4.IndexLit
    import           What4.ProgramLoc
    import           What4.Concrete
    import           What4.SatResult
    import           What4.SpecialFunctions
    import           What4.Symbol
    import           What4.Utils.AbstractDomains
    import           What4.Utils.Arithmetic
    import           What4.Utils.Complex
    import           What4.Utils.FloatHelpers (RoundingMode(..))
    import           What4.Utils.StringLiteral

    ------------------------------------------------------------------------
    -- SymExpr names

    -- | Symbolic boolean values, AKA predicates.
    type Pred sym = SymExpr sym BaseBoolType

    -- | Symbolic integers.
    type SymInteger sym = SymExpr sym BaseIntegerType

    -- | Symbolic real numbers.
    type SymReal sym = SymExpr sym BaseRealType

    -- | Symbolic floating point numbers.
    type SymFloat sym fpp = SymExpr sym (BaseFloatType fpp)

    -- | Symbolic complex numbers.
    type SymCplx sym = SymExpr sym BaseComplexType

    -- | Symbolic structures.
    type SymStruct sym flds = SymExpr sym (BaseStructType flds)

    -- | Symbolic arrays.
    type SymArray sym idx b = SymExpr sym (BaseArrayType idx b)

    -- | Symbolic bitvectors.
    type SymBV sym n = SymExpr sym (BaseBVType n)

    -- | Symbolic strings.
    type SymString sym si = SymExpr sym (BaseStringType si)

    ------------------------------------------------------------------------
    -- Type families for the interface.

    -- | The class for expressions.
    type family SymExpr (sym :: Type) :: BaseType -> Type

    ------------------------------------------------------------------------
    -- | Type of bound variable associated with symbolic state.
    --
    -- This type is used by some methods in class 'IsSymExprBuilder'.
    type family BoundVar (sym :: Type) :: BaseType -> Type

    ------------------------------------------------------------------------
    -- | Type used to uniquely identify expressions that have been annotated.
    type family SymAnnotation (sym :: Type) :: BaseType -> Type

    ------------------------------------------------------------------------
    -- IsBoolSolver

    -- | Perform an ite on a predicate lazily.
    itePredM :: (IsExpr (SymExpr sym), IsExprBuilder sym, MonadIO m)
             => sym
             -> Pred sym
             -> m (Pred sym)
             -> m (Pred sym)
             -> m (Pred sym)
    itePredM :: forall sym (m :: Type -> Type).
    (IsExpr (SymExpr sym), IsExprBuilder sym, MonadIO m) =>
    sym -> Pred sym -> m (Pred sym) -> m (Pred sym) -> m (Pred sym)
    itePredM sym
    sym Pred sym
    c m (Pred sym)
    mx m (Pred sym)
    my =
      case Pred sym -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred Pred sym
    c of
        Just Bool
    True -> m (Pred sym)
    mx
        Just Bool
    False -> m (Pred sym)
    my
        Maybe Bool
    Nothing -> do
          Pred sym
    x <- m (Pred sym)
    mx
          Pred sym
    y <- m (Pred sym)
    my
          IO (Pred sym) -> m (Pred sym)
    forall a. IO a -> m a
    forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
    liftIO (IO (Pred sym) -> m (Pred sym)) -> IO (Pred sym) -> m (Pred sym)
    forall a b. (a -> b) -> a -> b
    $ sym -> Pred sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> Pred sym -> IO (Pred sym)
    itePred sym
    sym Pred sym
    c Pred sym
    x Pred sym
    y

    ------------------------------------------------------------------------
    -- IsExpr

    -- | This class provides operations for recognizing when symbolic expressions
    --   represent concrete values, extracting the type from an expression,
    --   and for providing pretty-printed representations of an expression.
    class HasAbsValue e => IsExpr e where
      -- | Evaluate if predicate is constant.
      asConstantPred :: e BaseBoolType -> Maybe Bool
      asConstantPred e BaseBoolType
    _ = Maybe Bool
    forall a. Maybe a
    Nothing

      -- | Return integer if this is a constant integer.
      asInteger :: e BaseIntegerType -> Maybe Integer
      asInteger e BaseIntegerType
    _ = Maybe Integer
    forall a. Maybe a
    Nothing

      -- | Return any bounding information we have about the term
      integerBounds :: e BaseIntegerType -> ValueRange Integer

      -- | Return rational if this is a constant value.
      asRational :: e BaseRealType -> Maybe Rational
      asRational e BaseRealType
    _ = Maybe Rational
    forall a. Maybe a
    Nothing

      -- | Return floating-point value if this is a constant
      asFloat :: e (BaseFloatType fpp) -> Maybe BigFloat

      -- | Return any bounding information we have about the term
      rationalBounds :: e BaseRealType -> ValueRange Rational

      -- | Return complex if this is a constant value.
      asComplex :: e BaseComplexType -> Maybe (Complex Rational)
      asComplex e BaseComplexType
    _ = Maybe (Complex Rational)
    forall a. Maybe a
    Nothing

      -- | Return a bitvector if this is a constant bitvector.
      asBV :: e (BaseBVType w) -> Maybe (BV.BV w)
      asBV e (BaseBVType w)
    _ = Maybe (BV w)
    forall a. Maybe a
    Nothing

      -- | If we have bounds information about the term, return unsigned
      -- upper and lower bounds as integers
      unsignedBVBounds :: (1 <= w) => e (BaseBVType w) -> Maybe (Integer, Integer)

      -- | If we have bounds information about the term, return signed
      -- upper and lower bounds as integers
      signedBVBounds :: (1 <= w) => e (BaseBVType w) -> Maybe (Integer, Integer)

      -- | If this expression syntactically represents an "affine" form, return its components.
      --   When @asAffineVar x = Just (c,r,o)@, then we have @x == c*r + o@.
      asAffineVar :: e tp -> Maybe (ConcreteVal tp, e tp, ConcreteVal tp)

      -- | Return the string value if this is a constant string
      asString :: e (BaseStringType si) -> Maybe (StringLiteral si)
      asString e (BaseStringType si)
    _ = Maybe (StringLiteral si)
    forall a. Maybe a
    Nothing

      -- | Return the representation of the string info for a string-typed term.
      stringInfo :: e (BaseStringType si) -> StringInfoRepr si
      stringInfo e (BaseStringType si)
    e =
        case e (BaseStringType si) -> BaseTypeRepr (BaseStringType si)
    forall (tp :: BaseType). e tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType e (BaseStringType si)
    e of
          BaseStringRepr StringInfoRepr si
    si -> StringInfoRepr si
    StringInfoRepr si
    si

      -- | Return the unique element value if this is a constant array,
      --   such as one made with 'constantArray'.
      asConstantArray :: e (BaseArrayType idx bt) -> Maybe (e bt)
      asConstantArray e (BaseArrayType idx bt)
    _ = Maybe (e bt)
    forall a. Maybe a
    Nothing

      -- | Return the struct fields if this is a concrete struct.
      asStruct :: e (BaseStructType flds) -> Maybe (Ctx.Assignment e flds)
      asStruct e (BaseStructType flds)
    _ = Maybe (Assignment e flds)
    forall a. Maybe a
    Nothing

      -- | Get type of expression.
      exprType :: e tp -> BaseTypeRepr tp

      -- | Get the width of a bitvector
      bvWidth      :: e (BaseBVType w) -> NatRepr w
      bvWidth e (BaseBVType w)
    e =
        case e (BaseBVType w) -> BaseTypeRepr (BaseBVType w)
    forall (tp :: BaseType). e tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType e (BaseBVType w)
    e of
          BaseBVRepr NatRepr w
    w -> NatRepr w
    NatRepr w
    w

      -- | Get the precision of a floating-point expression
      floatPrecision :: e (BaseFloatType fpp) -> FloatPrecisionRepr fpp
      floatPrecision e (BaseFloatType fpp)
    e =
        case e (BaseFloatType fpp) -> BaseTypeRepr (BaseFloatType fpp)
    forall (tp :: BaseType). e tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType e (BaseFloatType fpp)
    e of
          BaseFloatRepr FloatPrecisionRepr fpp
    fpp -> FloatPrecisionRepr fpp
    FloatPrecisionRepr fpp
    fpp

      -- | Print a sym expression for debugging or display purposes.
      printSymExpr :: e tp -> Doc ann

      -- | Set the abstract value of an expression. This is primarily useful for
      -- symbolic expressions where the domain is known to be narrower than what
      -- is contained in the expression. Setting the abstract value to use the
      -- narrower domain can, in some cases, allow the expression to be further
      -- simplified.
      --
      -- This is prefixed with @unsafe-@ because it has the potential to
      -- introduce unsoundness if the new abstract value does not accurately
      -- represent the domain of the expression. As such, the burden is on users
      -- of this function to ensure that the new abstract value is used soundly.
      --
      -- Note that composing expressions together can sometimes widen the abstract
      -- domains involved, so if you use this function to change an abstract value,
      -- be careful than subsequent operations do not widen away the value. As a
      -- potential safeguard, one can use 'annotateTerm' on the new expression to
      -- inhibit transformations that could change the abstract value.
      unsafeSetAbstractValue :: AbstractValue tp -> e tp -> e tp

    newtype ArrayResultWrapper f idx tp =
      ArrayResultWrapper { forall (f :: BaseType -> Type) (idx :: Ctx BaseType)
           (tp :: BaseType).
    ArrayResultWrapper f idx tp -> f (BaseArrayType idx tp)
    unwrapArrayResult :: f (BaseArrayType idx tp) }

    instance TestEquality f => TestEquality (ArrayResultWrapper f idx) where
      testEquality :: forall (a :: BaseType) (b :: BaseType).
    ArrayResultWrapper f idx a
    -> ArrayResultWrapper f idx b -> Maybe (a :~: b)
    testEquality (ArrayResultWrapper f (BaseArrayType idx a)
    x) (ArrayResultWrapper f (BaseArrayType idx b)
    y) = do
        BaseArrayType idx a :~: BaseArrayType idx b
    Refl <- f (BaseArrayType idx a)
    -> f (BaseArrayType idx b)
    -> Maybe (BaseArrayType idx a :~: BaseArrayType idx b)
    forall {k} (f :: k -> Type) (a :: k) (b :: k).
    TestEquality f =>
    f a -> f b -> Maybe (a :~: b)
    forall (a :: BaseType) (b :: BaseType).
    f a -> f b -> Maybe (a :~: b)
    testEquality f (BaseArrayType idx a)
    x f (BaseArrayType idx b)
    y
        (a :~: b) -> Maybe (a :~: b)
    forall a. a -> Maybe a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return a :~: a
    a :~: b
    forall {k} (a :: k). a :~: a
    Refl

    instance HashableF e => HashableF (ArrayResultWrapper e idx) where
      hashWithSaltF :: forall (tp :: BaseType). Int -> ArrayResultWrapper e idx tp -> Int
    hashWithSaltF Int
    s (ArrayResultWrapper e (BaseArrayType idx tp)
    v) = Int -> e (BaseArrayType idx tp) -> Int
    forall k (f :: k -> Type) (tp :: k).
    HashableF f =>
    Int -> f tp -> Int
    forall (tp :: BaseType). Int -> e tp -> Int
    hashWithSaltF Int
    s e (BaseArrayType idx tp)
    v

    -- | This datatype describes events that involve interacting with
    --   solvers.  A @SolverEvent@ will be provided to the action
    --   installed via @setSolverLogListener@ whenever an interesting
    --   event occurs.
    data SolverEvent
      = SolverStartSATQuery SolverStartSATQuery
      | SolverEndSATQuery SolverEndSATQuery
     deriving (Int -> SolverEvent -> ShowS
    [SolverEvent] -> ShowS
    SolverEvent -> String
    (Int -> SolverEvent -> ShowS)
    -> (SolverEvent -> String)
    -> ([SolverEvent] -> ShowS)
    -> Show SolverEvent
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> SolverEvent -> ShowS
    showsPrec :: Int -> SolverEvent -> ShowS
    $cshow :: SolverEvent -> String
    show :: SolverEvent -> String
    $cshowList :: [SolverEvent] -> ShowS
    showList :: [SolverEvent] -> ShowS
    Show, (forall x. SolverEvent -> Rep SolverEvent x)
    -> (forall x. Rep SolverEvent x -> SolverEvent)
    -> Generic SolverEvent
    forall x. Rep SolverEvent x -> SolverEvent
    forall x. SolverEvent -> Rep SolverEvent x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. SolverEvent -> Rep SolverEvent x
    from :: forall x. SolverEvent -> Rep SolverEvent x
    $cto :: forall x. Rep SolverEvent x -> SolverEvent
    to :: forall x. Rep SolverEvent x -> SolverEvent
    Generic)

    data SolverStartSATQuery = SolverStartSATQueryRec
        { SolverStartSATQuery -> String
    satQuerySolverName :: !String
        , SolverStartSATQuery -> String
    satQueryReason     :: !String
        }
     deriving (Int -> SolverStartSATQuery -> ShowS
    [SolverStartSATQuery] -> ShowS
    SolverStartSATQuery -> String
    (Int -> SolverStartSATQuery -> ShowS)
    -> (SolverStartSATQuery -> String)
    -> ([SolverStartSATQuery] -> ShowS)
    -> Show SolverStartSATQuery
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> SolverStartSATQuery -> ShowS
    showsPrec :: Int -> SolverStartSATQuery -> ShowS
    $cshow :: SolverStartSATQuery -> String
    show :: SolverStartSATQuery -> String
    $cshowList :: [SolverStartSATQuery] -> ShowS
    showList :: [SolverStartSATQuery] -> ShowS
    Show, (forall x. SolverStartSATQuery -> Rep SolverStartSATQuery x)
    -> (forall x. Rep SolverStartSATQuery x -> SolverStartSATQuery)
    -> Generic SolverStartSATQuery
    forall x. Rep SolverStartSATQuery x -> SolverStartSATQuery
    forall x. SolverStartSATQuery -> Rep SolverStartSATQuery x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. SolverStartSATQuery -> Rep SolverStartSATQuery x
    from :: forall x. SolverStartSATQuery -> Rep SolverStartSATQuery x
    $cto :: forall x. Rep SolverStartSATQuery x -> SolverStartSATQuery
    to :: forall x. Rep SolverStartSATQuery x -> SolverStartSATQuery
    Generic)

    data SolverEndSATQuery = SolverEndSATQueryRec
        { SolverEndSATQuery -> SatResult () ()
    satQueryResult     :: !(SatResult () ())
        , SolverEndSATQuery -> Maybe String
    satQueryError      :: !(Maybe String)
        }
     deriving (Int -> SolverEndSATQuery -> ShowS
    [SolverEndSATQuery] -> ShowS
    SolverEndSATQuery -> String
    (Int -> SolverEndSATQuery -> ShowS)
    -> (SolverEndSATQuery -> String)
    -> ([SolverEndSATQuery] -> ShowS)
    -> Show SolverEndSATQuery
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> SolverEndSATQuery -> ShowS
    showsPrec :: Int -> SolverEndSATQuery -> ShowS
    $cshow :: SolverEndSATQuery -> String
    show :: SolverEndSATQuery -> String
    $cshowList :: [SolverEndSATQuery] -> ShowS
    showList :: [SolverEndSATQuery] -> ShowS
    Show, (forall x. SolverEndSATQuery -> Rep SolverEndSATQuery x)
    -> (forall x. Rep SolverEndSATQuery x -> SolverEndSATQuery)
    -> Generic SolverEndSATQuery
    forall x. Rep SolverEndSATQuery x -> SolverEndSATQuery
    forall x. SolverEndSATQuery -> Rep SolverEndSATQuery x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cfrom :: forall x. SolverEndSATQuery -> Rep SolverEndSATQuery x
    from :: forall x. SolverEndSATQuery -> Rep SolverEndSATQuery x
    $cto :: forall x. Rep SolverEndSATQuery x -> SolverEndSATQuery
    to :: forall x. Rep SolverEndSATQuery x -> SolverEndSATQuery
    Generic)

    ------------------------------------------------------------------------
    -- SymNat

    -- | Symbolic natural numbers.
    newtype SymNat sym =
      SymNat
      { -- Internal Invariant: the value in a SymNat is always nonnegative
        forall sym. SymNat sym -> SymExpr sym BaseIntegerType
    _symNat :: SymExpr sym BaseIntegerType
      }

    -- | Return nat if this is a constant natural number.
    asNat :: IsExpr (SymExpr sym) => SymNat sym -> Maybe Natural
    asNat :: forall sym. IsExpr (SymExpr sym) => SymNat sym -> Maybe Nat
    asNat (SymNat SymExpr sym BaseIntegerType
    x) = Integer -> Nat
    forall a. Num a => Integer -> a
    fromInteger (Integer -> Nat) -> (Integer -> Integer) -> Integer -> Nat
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Integer -> Integer -> Integer
    forall a. Ord a => a -> a -> a
    max Integer
    0 (Integer -> Nat) -> Maybe Integer -> Maybe Nat
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> SymExpr sym BaseIntegerType -> Maybe Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> Maybe Integer
    asInteger SymExpr sym BaseIntegerType
    x

    -- | A natural number literal.
    natLit :: IsExprBuilder sym => sym -> Natural -> IO (SymNat sym)
    -- @Natural@ input is necessarily nonnegative
    natLit :: forall sym. IsExprBuilder sym => sym -> Nat -> IO (SymNat sym)
    natLit sym
    sym Nat
    x = SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym -> Integer -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym (Nat -> Integer
    forall a. Integral a => a -> Integer
    toInteger Nat
    x)

    -- | Add two natural numbers.
    natAdd :: IsExprBuilder sym => sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    -- Integer addition preserves nonnegative values
    natAdd :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    natAdd sym
    sym (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) = SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    intAdd sym
    sym SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y

    -- | Subtract one number from another.
    --
    -- The result is 0 if the subtraction would otherwise be negative.
    natSub :: IsExprBuilder sym => sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    natSub :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    natSub sym
    sym (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) =
      do SymExpr sym BaseIntegerType
    z <- sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    intSub sym
    sym SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y
         SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> (sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    intMax sym
    sym SymExpr sym BaseIntegerType
    z (SymExpr sym BaseIntegerType -> IO (SymExpr sym BaseIntegerType))
    -> IO (SymExpr sym BaseIntegerType)
    -> IO (SymExpr sym BaseIntegerType)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Integer -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    0)

    -- | Multiply one number by another.
    natMul :: IsExprBuilder sym => sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    -- Integer multiplication preserves nonnegative values
    natMul :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    natMul sym
    sym (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) = SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    intMul sym
    sym SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y

    -- | @'natDiv' sym x y@ performs division on naturals.
    --
    -- The result is undefined if @y@ equals @0@.
    --
    -- 'natDiv' and 'natMod' satisfy the property that given
    --
    -- @
    --   d <- natDiv sym x y
    --   m <- natMod sym x y
    -- @
    --
    --  and @y > 0@, we have that @y * d + m = x@ and @m < y@.
    natDiv :: IsExprBuilder sym => sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    -- Integer division preserves nonnegative values.
    natDiv :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    natDiv sym
    sym (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) = SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    intDiv sym
    sym SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y

    -- | @'natMod' sym x y@ returns @x@ mod @y@.
    --
    -- See 'natDiv' for a description of the properties the return
    -- value is expected to satisfy.
    natMod :: IsExprBuilder sym => sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    -- Integer modulus preserves nonnegative values.
    natMod :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    natMod sym
    sym (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) = SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    intMod sym
    sym SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y

    -- | If-then-else applied to natural numbers.
    natIte :: IsExprBuilder sym => sym -> Pred sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    -- ITE preserves nonnegative values.
    natIte :: forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymNat sym -> SymNat sym -> IO (SymNat sym)
    natIte sym
    sym Pred sym
    p (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) = SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> Pred sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    intIte sym
    sym Pred sym
    p SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y

    -- | Equality predicate for natural numbers.
    natEq :: IsExprBuilder sym => sym -> SymNat sym -> SymNat sym -> IO (Pred sym)
    natEq :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (Pred sym)
    natEq sym
    sym (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) = sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseBoolType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intEq sym
    sym SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y

    -- | @'natLe' sym x y@ returns @true@ if @x <= y@.
    natLe :: IsExprBuilder sym => sym -> SymNat sym -> SymNat sym -> IO (Pred sym)
    natLe :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (Pred sym)
    natLe sym
    sym (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) = sym
    -> SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> IO (SymExpr sym BaseBoolType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLe sym
    sym SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y

    -- | @'natLt' sym x y@ returns @true@ if @x < y@.
    natLt :: IsExprBuilder sym => sym -> SymNat sym -> SymNat sym -> IO (Pred sym)
    natLt :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (Pred sym)
    natLt sym
    sym SymNat sym
    x SymNat sym
    y = sym -> SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym (SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType))
    -> IO (SymExpr sym BaseBoolType) -> IO (SymExpr sym BaseBoolType)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymNat sym -> SymNat sym -> IO (SymExpr sym BaseBoolType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> SymNat sym -> IO (Pred sym)
    natLe sym
    sym SymNat sym
    y SymNat sym
    x

    -- | Convert a natural number to an integer.
    natToInteger :: IsExprBuilder sym => sym -> SymNat sym -> IO (SymInteger sym)
    natToInteger :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> IO (SymInteger sym)
    natToInteger sym
    _sym (SymNat SymExpr sym BaseIntegerType
    x) = SymExpr sym BaseIntegerType -> IO (SymExpr sym BaseIntegerType)
    forall a. a -> IO a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure SymExpr sym BaseIntegerType
    x

    -- | Convert a natural number to an integer.
    --   `natToInteger` is just this operation lifted into IO.
    natToIntegerPure :: SymNat sym -> SymInteger sym
    natToIntegerPure :: forall sym. SymNat sym -> SymExpr sym BaseIntegerType
    natToIntegerPure (SymNat SymExpr sym BaseIntegerType
    x) = SymExpr sym BaseIntegerType
    x

    -- | Convert the unsigned value of a bitvector to a natural.
    bvToNat :: (IsExprBuilder sym, 1 <= w) => sym -> SymBV sym w -> IO (SymNat sym)
    -- The unsigned value of a bitvector is always nonnegative
    bvToNat :: forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (SymNat sym)
    bvToNat sym
    sym SymBV sym w
    x = SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym -> SymBV sym w -> IO (SymExpr sym BaseIntegerType)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> IO (SymExpr sym BaseIntegerType)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (SymInteger sym)
    bvToInteger sym
    sym SymBV sym w
    x

    -- | Convert a natural number to a real number.
    natToReal :: IsExprBuilder sym => sym -> SymNat sym -> IO (SymReal sym)
    natToReal :: forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> IO (SymReal sym)
    natToReal sym
    sym = sym -> SymNat sym -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymNat sym -> IO (SymInteger sym)
    natToInteger sym
    sym (SymNat sym -> IO (SymExpr sym BaseIntegerType))
    -> (SymExpr sym BaseIntegerType -> IO (SymExpr sym BaseRealType))
    -> SymNat sym
    -> IO (SymExpr sym BaseRealType)
    forall (m :: Type -> Type) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> sym -> SymExpr sym BaseIntegerType -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymReal sym)
    integerToReal sym
    sym

    -- | Convert an integer to a natural number.
    --
    -- For negative integers, the result is clamped to 0.
    integerToNat :: IsExprBuilder sym => sym -> SymInteger sym -> IO (SymNat sym)
    integerToNat :: forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymNat sym)
    integerToNat sym
    sym SymInteger sym
    x = SymInteger sym -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymInteger sym -> SymNat sym)
    -> IO (SymInteger sym) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> (sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    intMax sym
    sym SymInteger sym
    x (SymInteger sym -> IO (SymInteger sym))
    -> IO (SymInteger sym) -> IO (SymInteger sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Integer -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    0)

    -- | Convert a real number to a natural number.
    --
    -- The result is undefined if the given real number does not represent a natural number.
    realToNat :: IsExprBuilder sym => sym -> SymReal sym -> IO (SymNat sym)
    realToNat :: forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymNat sym)
    realToNat sym
    sym SymReal sym
    r = sym -> SymReal sym -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realToInteger sym
    sym SymReal sym
    r IO (SymExpr sym BaseIntegerType)
    -> (SymExpr sym BaseIntegerType -> IO (SymNat sym))
    -> IO (SymNat sym)
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
    >>= sym -> SymExpr sym BaseIntegerType -> IO (SymNat sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymNat sym)
    integerToNat sym
    sym

    -- | Create a fresh natural number constant with optional lower and upper bounds.
    --   If provided, the bounds are inclusive.
    --   If inconsistent bounds are given, an InvalidRange exception will be thrown.
    freshBoundedNat ::
      IsSymExprBuilder sym =>
      sym ->
      SolverSymbol ->
      Maybe Natural {- ^ lower bound -} ->
      Maybe Natural {- ^ upper bound -} ->
      IO (SymNat sym)
    freshBoundedNat :: forall sym.
    IsSymExprBuilder sym =>
    sym -> SolverSymbol -> Maybe Nat -> Maybe Nat -> IO (SymNat sym)
    freshBoundedNat sym
    sym SolverSymbol
    s Maybe Nat
    lo Maybe Nat
    hi = SymExpr sym BaseIntegerType -> SymNat sym
    forall sym. SymExpr sym BaseIntegerType -> SymNat sym
    SymNat (SymExpr sym BaseIntegerType -> SymNat sym)
    -> IO (SymExpr sym BaseIntegerType) -> IO (SymNat sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> (sym
    -> SolverSymbol
    -> Maybe Integer
    -> Maybe Integer
    -> IO (SymExpr sym BaseIntegerType)
    forall sym.
    IsSymExprBuilder sym =>
    sym
    -> SolverSymbol
    -> Maybe Integer
    -> Maybe Integer
    -> IO (SymInteger sym)
    freshBoundedInt sym
    sym SolverSymbol
    s Maybe Integer
    lo' Maybe Integer
    hi')
     where
       lo' :: Maybe Integer
    lo' = Integer -> Maybe Integer
    forall a. a -> Maybe a
    Just (Integer -> (Nat -> Integer) -> Maybe Nat -> Integer
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe Integer
    0 Nat -> Integer
    forall a. Integral a => a -> Integer
    toInteger Maybe Nat
    lo)
       hi' :: Maybe Integer
    hi' = Nat -> Integer
    forall a. Integral a => a -> Integer
    toInteger (Nat -> Integer) -> Maybe Nat -> Maybe Integer
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Maybe Nat
    hi

    -- | Create a fresh natural number constant.
    freshNat :: IsSymExprBuilder sym => sym -> SolverSymbol -> IO (SymNat sym)
    freshNat :: forall sym.
    IsSymExprBuilder sym =>
    sym -> SolverSymbol -> IO (SymNat sym)
    freshNat sym
    sym SolverSymbol
    s = sym -> SolverSymbol -> Maybe Nat -> Maybe Nat -> IO (SymNat sym)
    forall sym.
    IsSymExprBuilder sym =>
    sym -> SolverSymbol -> Maybe Nat -> Maybe Nat -> IO (SymNat sym)
    freshBoundedNat sym
    sym SolverSymbol
    s (Nat -> Maybe Nat
    forall a. a -> Maybe a
    Just Nat
    0) Maybe Nat
    forall a. Maybe a
    Nothing

    printSymNat :: IsExpr (SymExpr sym) => SymNat sym -> Doc ann
    printSymNat :: forall sym ann. IsExpr (SymExpr sym) => SymNat sym -> Doc ann
    printSymNat (SymNat SymExpr sym BaseIntegerType
    x) = SymExpr sym BaseIntegerType -> Doc ann
    forall (tp :: BaseType) ann. SymExpr sym tp -> Doc ann
    forall (e :: BaseType -> Type) (tp :: BaseType) ann.
    IsExpr e =>
    e tp -> Doc ann
    printSymExpr SymExpr sym BaseIntegerType
    x

    instance TestEquality (SymExpr sym) => Eq (SymNat sym) where
      SymNat SymExpr sym BaseIntegerType
    x == :: SymNat sym -> SymNat sym -> Bool
    == SymNat SymExpr sym BaseIntegerType
    y = Maybe (BaseIntegerType :~: BaseIntegerType) -> Bool
    forall a. Maybe a -> Bool
    isJust (SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> Maybe (BaseIntegerType :~: BaseIntegerType)
    forall {k} (f :: k -> Type) (a :: k) (b :: k).
    TestEquality f =>
    f a -> f b -> Maybe (a :~: b)
    forall (a :: BaseType) (b :: BaseType).
    SymExpr sym a -> SymExpr sym b -> Maybe (a :~: b)
    testEquality SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y)

    instance OrdF (SymExpr sym) => Ord (SymNat sym) where
      compare :: SymNat sym -> SymNat sym -> Ordering
    compare (SymNat SymExpr sym BaseIntegerType
    x) (SymNat SymExpr sym BaseIntegerType
    y) = OrderingF BaseIntegerType BaseIntegerType -> Ordering
    forall {k} (x :: k) (y :: k). OrderingF x y -> Ordering
    toOrdering (SymExpr sym BaseIntegerType
    -> SymExpr sym BaseIntegerType
    -> OrderingF BaseIntegerType BaseIntegerType
    forall k (ktp :: k -> Type) (x :: k) (y :: k).
    OrdF ktp =>
    ktp x -> ktp y -> OrderingF x y
    forall (x :: BaseType) (y :: BaseType).
    SymExpr sym x -> SymExpr sym y -> OrderingF x y
    compareF SymExpr sym BaseIntegerType
    x SymExpr sym BaseIntegerType
    y)

    instance (HashableF (SymExpr sym), TestEquality (SymExpr sym)) => Hashable (SymNat sym) where
      hashWithSalt :: Int -> SymNat sym -> Int
    hashWithSalt Int
    s (SymNat SymExpr sym BaseIntegerType
    x) = Int -> SymExpr sym BaseIntegerType -> Int
    forall k (f :: k -> Type) (tp :: k).
    HashableF f =>
    Int -> f tp -> Int
    forall (tp :: BaseType). Int -> SymExpr sym tp -> Int
    hashWithSaltF Int
    s SymExpr sym BaseIntegerType
    x

    ------------------------------------------------------------------------
    -- IsExprBuilder

    -- | This class allows the simulator to build symbolic expressions.
    --
    -- Methods of this class refer to type families @'SymExpr' sym@
    -- and @'SymFn' sym@.
    --
    -- Note: Some methods in this class represent operations that are
    -- partial functions on their domain (e.g., division by 0).
    -- Such functions will have documentation strings indicating that they
    -- are undefined under some conditions.  When partial functions are applied
    -- outside their defined domains, they will silently produce an unspecified
    -- value of the expected type.  The unspecified value returned as the result
    -- of an undefined function is _not_ guaranteed to be equivalant to a free
    -- constant, and no guarantees are made about what properties such values
    -- will satisfy.
    class ( IsExpr (SymExpr sym), HashableF (SymExpr sym), HashableF (BoundVar sym)
          , TestEquality (SymAnnotation sym), OrdF (SymAnnotation sym)
          , HashableF (SymAnnotation sym)
          ) => IsExprBuilder sym where

      -- | Retrieve the configuration object corresponding to this solver interface.
      getConfiguration :: sym -> Config

      -- | Install an action that will be invoked before and after calls to
      --   backend solvers.  This action is primarily intended to be used for
      --   logging\/profiling\/debugging purposes.  Passing 'Nothing' to this
      --   function disables logging.
      setSolverLogListener :: sym -> Maybe (SolverEvent -> IO ()) -> IO ()

      -- | Get the currently-installed solver log listener, if one has been installed.
      getSolverLogListener :: sym -> IO (Maybe (SolverEvent -> IO ()))

      -- | Provide the given event to the currently installed
      --   solver log listener, if any.
      logSolverEvent :: sym -> SolverEvent -> IO ()

      -- | Get statistics on execution from the initialization of the
      -- symbolic interface to this point.  May return zeros if gathering
      -- statistics isn't supported.
      getStatistics :: sym -> IO Statistics
      getStatistics sym
    _ = Statistics -> IO Statistics
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return Statistics
    zeroStatistics

      ----------------------------------------------------------------------
      -- Program location operations

      -- | Get current location of program for term creation purposes.
      getCurrentProgramLoc :: sym -> IO ProgramLoc

      -- | Set current location of program for term creation purposes.
      setCurrentProgramLoc :: sym -> ProgramLoc -> IO ()

      -- | Return true if two expressions are equal. The default
      -- implementation dispatches 'eqPred', 'bvEq', 'natEq', 'intEq',
      -- 'realEq', 'cplxEq', 'structEq', or 'arrayEq', depending on the
      -- type.
      isEq :: sym -> SymExpr sym tp -> SymExpr sym tp -> IO (Pred sym)
      isEq sym
    sym SymExpr sym tp
    x SymExpr sym tp
    y =
        case SymExpr sym tp -> BaseTypeRepr tp
    forall (tp :: BaseType). SymExpr sym tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType SymExpr sym tp
    x of
          BaseTypeRepr tp
    BaseBoolRepr     -> sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    eqPred sym
    sym SymExpr sym tp
    Pred sym
    x SymExpr sym tp
    Pred sym
    y
          BaseBVRepr{}     -> sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvEq sym
    sym SymExpr sym tp
    SymBV sym w
    x SymExpr sym tp
    SymBV sym w
    y
          BaseTypeRepr tp
    BaseIntegerRepr  -> sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intEq sym
    sym SymExpr sym tp
    SymInteger sym
    x SymExpr sym tp
    SymInteger sym
    y
          BaseTypeRepr tp
    BaseRealRepr     -> sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realEq sym
    sym SymExpr sym tp
    SymReal sym
    x SymExpr sym tp
    SymReal sym
    y
          BaseFloatRepr{}  -> sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    forall (fpp :: FloatPrecision).
    sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    floatEq sym
    sym SymExpr sym tp
    SymFloat sym fpp
    x SymExpr sym tp
    SymFloat sym fpp
    y
          BaseTypeRepr tp
    BaseComplexRepr  -> sym -> SymCplx sym -> SymCplx sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> SymCplx sym -> IO (Pred sym)
    cplxEq sym
    sym SymExpr sym tp
    SymCplx sym
    x SymExpr sym tp
    SymCplx sym
    y
          BaseStringRepr{} -> sym -> SymString sym si -> SymString sym si -> IO (Pred sym)
    forall sym (si :: StringInfo).
    IsExprBuilder sym =>
    sym -> SymString sym si -> SymString sym si -> IO (Pred sym)
    forall (si :: StringInfo).
    sym -> SymString sym si -> SymString sym si -> IO (Pred sym)
    stringEq sym
    sym SymExpr sym tp
    SymString sym si
    x SymExpr sym tp
    SymString sym si
    y
          BaseStructRepr{} -> sym -> SymStruct sym ctx -> SymStruct sym ctx -> IO (Pred sym)
    forall sym (flds :: Ctx BaseType).
    IsExprBuilder sym =>
    sym -> SymStruct sym flds -> SymStruct sym flds -> IO (Pred sym)
    forall (flds :: Ctx BaseType).
    sym -> SymStruct sym flds -> SymStruct sym flds -> IO (Pred sym)
    structEq sym
    sym SymExpr sym tp
    SymStruct sym ctx
    x SymExpr sym tp
    SymStruct sym ctx
    y
          BaseArrayRepr{}  -> sym
    -> SymArray sym (idx ::> tp) xs
    -> SymArray sym (idx ::> tp) xs
    -> IO (Pred sym)
    forall sym (idx :: Ctx BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym -> SymArray sym idx b -> SymArray sym idx b -> IO (Pred sym)
    forall (idx :: Ctx BaseType) (b :: BaseType).
    sym -> SymArray sym idx b -> SymArray sym idx b -> IO (Pred sym)
    arrayEq sym
    sym SymExpr sym tp
    SymArray sym (idx ::> tp) xs
    x SymExpr sym tp
    SymArray sym (idx ::> tp) xs
    y

      -- | Take the if-then-else of two expressions. The default
      -- implementation dispatches 'itePred', 'bvIte', 'natIte', 'intIte',
      -- 'realIte', 'cplxIte', 'structIte', or 'arrayIte', depending on
      -- the type.
      baseTypeIte :: sym
                  -> Pred sym
                  -> SymExpr sym tp
                  -> SymExpr sym tp
                  -> IO (SymExpr sym tp)
      baseTypeIte sym
    sym Pred sym
    c SymExpr sym tp
    x SymExpr sym tp
    y =
        case SymExpr sym tp -> BaseTypeRepr tp
    forall (tp :: BaseType). SymExpr sym tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType SymExpr sym tp
    x of
          BaseTypeRepr tp
    BaseBoolRepr     -> sym -> Pred sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> Pred sym -> IO (Pred sym)
    itePred   sym
    sym Pred sym
    c SymExpr sym tp
    Pred sym
    x SymExpr sym tp
    Pred sym
    y
          BaseBVRepr{}     -> sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte     sym
    sym Pred sym
    c SymExpr sym tp
    SymBV sym w
    x SymExpr sym tp
    SymBV sym w
    y
          BaseTypeRepr tp
    BaseIntegerRepr  -> sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    intIte    sym
    sym Pred sym
    c SymExpr sym tp
    SymInteger sym
    x SymExpr sym tp
    SymInteger sym
    y
          BaseTypeRepr tp
    BaseRealRepr     -> sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte   sym
    sym Pred sym
    c SymExpr sym tp
    SymReal sym
    x SymExpr sym tp
    SymReal sym
    y
          BaseFloatRepr{}  -> sym
    -> Pred sym
    -> SymFloat sym fpp
    -> SymFloat sym fpp
    -> IO (SymFloat sym fpp)
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymFloat sym fpp
    -> SymFloat sym fpp
    -> IO (SymFloat sym fpp)
    forall (fpp :: FloatPrecision).
    sym
    -> Pred sym
    -> SymFloat sym fpp
    -> SymFloat sym fpp
    -> IO (SymFloat sym fpp)
    floatIte  sym
    sym Pred sym
    c SymExpr sym tp
    SymFloat sym fpp
    x SymExpr sym tp
    SymFloat sym fpp
    y
          BaseStringRepr{} -> sym
    -> Pred sym
    -> SymString sym si
    -> SymString sym si
    -> IO (SymString sym si)
    forall sym (si :: StringInfo).
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymString sym si
    -> SymString sym si
    -> IO (SymString sym si)
    forall (si :: StringInfo).
    sym
    -> Pred sym
    -> SymString sym si
    -> SymString sym si
    -> IO (SymString sym si)
    stringIte sym
    sym Pred sym
    c SymExpr sym tp
    SymString sym si
    x SymExpr sym tp
    SymString sym si
    y
          BaseTypeRepr tp
    BaseComplexRepr  -> sym -> Pred sym -> SymCplx sym -> SymCplx sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymCplx sym -> SymCplx sym -> IO (SymCplx sym)
    cplxIte   sym
    sym Pred sym
    c SymExpr sym tp
    SymCplx sym
    x SymExpr sym tp
    SymCplx sym
    y
          BaseStructRepr{} -> sym
    -> Pred sym
    -> SymStruct sym ctx
    -> SymStruct sym ctx
    -> IO (SymStruct sym ctx)
    forall sym (flds :: Ctx BaseType).
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymStruct sym flds
    -> SymStruct sym flds
    -> IO (SymStruct sym flds)
    forall (flds :: Ctx BaseType).
    sym
    -> Pred sym
    -> SymStruct sym flds
    -> SymStruct sym flds
    -> IO (SymStruct sym flds)
    structIte sym
    sym Pred sym
    c SymExpr sym tp
    SymStruct sym ctx
    x SymExpr sym tp
    SymStruct sym ctx
    y
          BaseArrayRepr{}  -> sym
    -> Pred sym
    -> SymArray sym (idx ::> tp) xs
    -> SymArray sym (idx ::> tp) xs
    -> IO (SymArray sym (idx ::> tp) xs)
    forall sym (idx :: Ctx BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymArray sym idx b
    -> SymArray sym idx b
    -> IO (SymArray sym idx b)
    forall (idx :: Ctx BaseType) (b :: BaseType).
    sym
    -> Pred sym
    -> SymArray sym idx b
    -> SymArray sym idx b
    -> IO (SymArray sym idx b)
    arrayIte  sym
    sym Pred sym
    c SymExpr sym tp
    SymArray sym (idx ::> tp) xs
    x SymExpr sym tp
    SymArray sym (idx ::> tp) xs
    y

      -- | Given a symbolic expression, annotate it with a unique identifier
      --   that can be used to maintain a connection with the given term.
      --   The 'SymAnnotation' is intended to be used as the key in a hash
      --   table or map to additional data can be maintained alongside the terms.
      --   The returned 'SymExpr' has the same semantics as the argument, but
      --   has embedded in it the 'SymAnnotation' value so that it can be used
      --   later during term traversals.
      --
      --   Note, the returned annotation is not necessarily fresh; if an
      --   already-annotated term is passed in, the same annotation value will be
      --   returned.
      annotateTerm :: sym -> SymExpr sym tp -> IO (SymAnnotation sym tp, SymExpr sym tp)

      -- | Project an annotation from an expression
      --
      -- It should be the case that using 'getAnnotation' on a term returned by
      -- 'annotateTerm' returns the same annotation that 'annotateTerm' did.
      getAnnotation :: sym -> SymExpr sym tp -> Maybe (SymAnnotation sym tp)

      -- | Project the original, unannotated term from an annotated term.
      --   This returns 'Nothing' for terms that do not have annotations.
      getUnannotatedTerm :: sym -> SymExpr sym tp -> Maybe (SymExpr sym tp)

      ----------------------------------------------------------------------
      -- Boolean operations.

      -- | Constant true predicate
      truePred  :: sym -> Pred sym

      -- | Constant false predicate
      falsePred :: sym -> Pred sym

      -- | Boolean negation
      notPred :: sym -> Pred sym -> IO (Pred sym)

      -- | Boolean conjunction
      andPred :: sym -> Pred sym -> Pred sym -> IO (Pred sym)

      -- | Boolean disjunction
      orPred  :: sym -> Pred sym -> Pred sym -> IO (Pred sym)

      -- | Boolean implication
      impliesPred :: sym -> Pred sym -> Pred sym -> IO (Pred sym)
      impliesPred sym
    sym Pred sym
    x Pred sym
    y = do
        Pred sym
    nx <- sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym Pred sym
    x
        sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    orPred sym
    sym Pred sym
    y Pred sym
    nx

      -- | Exclusive-or operation
      xorPred :: sym -> Pred sym -> Pred sym -> IO (Pred sym)

      -- | Equality of boolean values
      eqPred  :: sym -> Pred sym -> Pred sym -> IO (Pred sym)

      -- | If-then-else on a predicate.
      itePred :: sym -> Pred sym -> Pred sym -> Pred sym -> IO (Pred sym)

      ----------------------------------------------------------------------
      -- Integer operations

      -- | Create an integer literal.
      intLit :: sym -> Integer -> IO (SymInteger sym)

      -- | Negate an integer.
      intNeg :: sym -> SymInteger sym -> IO (SymInteger sym)

      -- | Add two integers.
      intAdd :: sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)

      -- | Subtract one integer from another.
      intSub :: sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
      intSub sym
    sym SymInteger sym
    x SymInteger sym
    y = sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
    intAdd sym
    sym SymInteger sym
    x (SymInteger sym -> IO (SymInteger sym))
    -> IO (SymInteger sym) -> IO (SymInteger sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymInteger sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymInteger sym)
    intNeg sym
    sym SymInteger sym
    y

      -- | Multiply one integer by another.
      intMul :: sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)

      -- | Return the minimum value of two integers.
      intMin :: sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
      intMin sym
    sym SymInteger sym
    x SymInteger sym
    y =
        do Pred sym
    x_le_y <- sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLe sym
    sym SymInteger sym
    x SymInteger sym
    y
           Pred sym
    y_le_x <- sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLe sym
    sym SymInteger sym
    y SymInteger sym
    x
           case (Pred sym -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred Pred sym
    x_le_y, Pred sym -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred Pred sym
    y_le_x) of
             -- x <= y
             (Just Bool
    True, Maybe Bool
    _) -> SymInteger sym -> IO (SymInteger sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymInteger sym
    x
             -- x < y
             (Maybe Bool
    _, Just Bool
    False) -> SymInteger sym -> IO (SymInteger sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymInteger sym
    x
             -- y < x
             (Just Bool
    False, Maybe Bool
    _) -> SymInteger sym -> IO (SymInteger sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymInteger sym
    y
             -- y <= x
             (Maybe Bool
    _, Just Bool
    True) -> SymInteger sym -> IO (SymInteger sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymInteger sym
    y
             (Maybe Bool, Maybe Bool)
    _ ->
               do let rng_x :: ValueRange Integer
    rng_x = SymInteger sym -> ValueRange Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> ValueRange Integer
    integerBounds SymInteger sym
    x
                  let rng_y :: ValueRange Integer
    rng_y = SymInteger sym -> ValueRange Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> ValueRange Integer
    integerBounds SymInteger sym
    y
                  AbstractValue BaseIntegerType -> SymInteger sym -> SymInteger sym
    forall (tp :: BaseType).
    AbstractValue tp -> SymExpr sym tp -> SymExpr sym tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    AbstractValue tp -> e tp -> e tp
    unsafeSetAbstractValue (ValueRange Integer -> ValueRange Integer -> ValueRange Integer
    forall a. Ord a => ValueRange a -> ValueRange a -> ValueRange a
    rangeMin ValueRange Integer
    rng_x ValueRange Integer
    rng_y) (SymInteger sym -> SymInteger sym)
    -> IO (SymInteger sym) -> IO (SymInteger sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$>
                    sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    intIte sym
    sym Pred sym
    x_le_y SymInteger sym
    x SymInteger sym
    y

      -- | Return the maximum value of two integers.
      intMax :: sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
      intMax sym
    sym SymInteger sym
    x SymInteger sym
    y =
        do Pred sym
    x_le_y <- sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLe sym
    sym SymInteger sym
    x SymInteger sym
    y
           Pred sym
    y_le_x <- sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLe sym
    sym SymInteger sym
    y SymInteger sym
    x
           case (Pred sym -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred Pred sym
    x_le_y, Pred sym -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred Pred sym
    y_le_x) of
             -- x <= y
             (Just Bool
    True, Maybe Bool
    _) -> SymInteger sym -> IO (SymInteger sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymInteger sym
    y
             -- x < y
             (Maybe Bool
    _, Just Bool
    False) -> SymInteger sym -> IO (SymInteger sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymInteger sym
    y
             -- y < x
             (Just Bool
    False, Maybe Bool
    _) -> SymInteger sym -> IO (SymInteger sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymInteger sym
    x
             -- y <= x
             (Maybe Bool
    _, Just Bool
    True) -> SymInteger sym -> IO (SymInteger sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymInteger sym
    x
             (Maybe Bool, Maybe Bool)
    _ ->
               do let rng_x :: ValueRange Integer
    rng_x = SymInteger sym -> ValueRange Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> ValueRange Integer
    integerBounds SymInteger sym
    x
                  let rng_y :: ValueRange Integer
    rng_y = SymInteger sym -> ValueRange Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> ValueRange Integer
    integerBounds SymInteger sym
    y
                  AbstractValue BaseIntegerType -> SymInteger sym -> SymInteger sym
    forall (tp :: BaseType).
    AbstractValue tp -> SymExpr sym tp -> SymExpr sym tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    AbstractValue tp -> e tp -> e tp
    unsafeSetAbstractValue (ValueRange Integer -> ValueRange Integer -> ValueRange Integer
    forall a. Ord a => ValueRange a -> ValueRange a -> ValueRange a
    rangeMax ValueRange Integer
    rng_x ValueRange Integer
    rng_y) (SymInteger sym -> SymInteger sym)
    -> IO (SymInteger sym) -> IO (SymInteger sym)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$>
                    sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    intIte sym
    sym Pred sym
    x_le_y SymInteger sym
    y SymInteger sym
    x

      -- | If-then-else applied to integers.
      intIte :: sym -> Pred sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)

      -- | Integer equality.
      intEq  :: sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)

      -- | Integer less-than-or-equal.
      intLe  :: sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)

      -- | Integer less-than.
      intLt  :: sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
      intLt sym
    sym SymInteger sym
    x SymInteger sym
    y = sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLe sym
    sym SymInteger sym
    y SymInteger sym
    x

      -- | Compute the absolute value of an integer.
      intAbs :: sym -> SymInteger sym -> IO (SymInteger sym)

      -- | @intDiv x y@ computes the integer division of @x@ by @y@.  This division is
      --   interpreted the same way as the SMT-Lib integer theory, which states that
      --   @div@ and @mod@ are the unique Euclidean division operations satisfying the
      --   following for all @y /= 0@:
      --
      --   * @y * (div x y) + (mod x y) == x@
      --   * @ 0 <= mod x y < abs y@
      --
      --   The value of @intDiv x y@ is undefined when @y = 0@.
      --
      --   Integer division requires nonlinear support whenever the divisor is
      --   not a constant.
      --
      --   Note: @div x y@ is @floor (x/y)@ when @y@ is positive
      --   (regardless of sign of @x@) and @ceiling (x/y)@ when @y@ is
      --   negative.  This is neither of the more common "round toward
      --   zero" nor "round toward -inf" definitions.
      --
      --   Some useful theorems that are true of this division/modulus pair:
      --
      --   * @mod x y == mod x (- y) == mod x (abs y)@
      --   * @div x (-y) == -(div x y)@
      intDiv :: sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)

      -- | @intMod x y@ computes the integer modulus of @x@ by @y@.  See 'intDiv' for
      --   more details.
      --
      --   The value of @intMod x y@ is undefined when @y = 0@.
      --
      --   Integer modulus requires nonlinear support whenever the divisor is
      --   not a constant.
      intMod :: sym -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)

      -- | @intDivisible x k@ is true whenever @x@ is an integer divisible
      --   by the known natural number @k@.  In other words `divisible x k`
      --   holds if there exists an integer `z` such that `x = k*z`.
      intDivisible :: sym -> SymInteger sym -> Natural -> IO (Pred sym)

      ----------------------------------------------------------------------
      -- Bitvector operations

      -- | Create a bitvector with the given width and value.
      bvLit :: (1 <= w) => sym -> NatRepr w -> BV.BV w -> IO (SymBV sym w)

      -- | Concatenate two bitvectors.
      bvConcat :: (1 <= u, 1 <= v)
               => sym
               -> SymBV sym u  -- ^ most significant bits
               -> SymBV sym v  -- ^ least significant bits
               -> IO (SymBV sym (u+v))

      -- | Select a subsequence from a bitvector.
      bvSelect :: forall idx n w. (1 <= n, idx + n <= w)
               => sym
               -> NatRepr idx  -- ^ Starting index, from 0 as least significant bit
               -> NatRepr n    -- ^ Number of bits to take
               -> SymBV sym w  -- ^ Bitvector to select from
               -> IO (SymBV sym n)

      -- | 2's complement negation.
      bvNeg :: (1 <= w)
            => sym
            -> SymBV sym w
            -> IO (SymBV sym w)

      -- | Add two bitvectors.
      bvAdd :: (1 <= w)
            => sym
            -> SymBV sym w
            -> SymBV sym w
            -> IO (SymBV sym w)

      -- | Subtract one bitvector from another.
      bvSub :: (1 <= w)
            => sym
            -> SymBV sym w
            -> SymBV sym w
            -> IO (SymBV sym w)
      bvSub sym
    sym SymBV sym w
    x SymBV sym w
    y = sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvAdd sym
    sym SymBV sym w
    x (SymBV sym w -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (SymBV sym w)
    bvNeg sym
    sym SymBV sym w
    y

      -- | Multiply one bitvector by another.
      bvMul :: (1 <= w)
            => sym
            -> SymBV sym w
            -> SymBV sym w
            -> IO (SymBV sym w)

      -- | Unsigned bitvector division.
      --
      --   The result of @bvUdiv x y@ is undefined when @y@ is zero,
      --   but is otherwise equal to @floor( x / y )@.
      bvUdiv :: (1 <= w)
             => sym
             -> SymBV sym w
             -> SymBV sym w
             -> IO (SymBV sym w)

      -- | Unsigned bitvector remainder.
      --
      --   The result of @bvUrem x y@ is undefined when @y@ is zero,
      --   but is otherwise equal to @x - (bvUdiv x y) * y@.
      bvUrem :: (1 <= w)
             => sym
             -> SymBV sym w
             -> SymBV sym w
             -> IO (SymBV sym w)

      -- | Signed bitvector division.  The result is truncated to zero.
      --
      --   The result of @bvSdiv x y@ is undefined when @y@ is zero,
      --   but is equal to @floor(x/y)@ when @x@ and @y@ have the same sign,
      --   and equal to @ceiling(x/y)@ when @x@ and @y@ have opposite signs.
      --
      --   NOTE! However, that there is a corner case when dividing @MIN_INT@ by
      --   @-1@, in which case an overflow condition occurs, and the result is instead
      --   @MIN_INT@.
      bvSdiv :: (1 <= w)
             => sym
             -> SymBV sym w
             -> SymBV sym w
             -> IO (SymBV sym w)

      -- | Signed bitvector remainder.
      --
      --   The result of @bvSrem x y@ is undefined when @y@ is zero, but is
      --   otherwise equal to @x - (bvSdiv x y) * y@.
      bvSrem :: (1 <= w)
             => sym
             -> SymBV sym w
             -> SymBV sym w
             -> IO (SymBV sym w)

      -- | Returns true if the corresponding bit in the bitvector is set.
      testBitBV :: (1 <= w)
                => sym
                -> Natural -- ^ Index of bit (0 is the least significant bit)
                -> SymBV sym w
                -> IO (Pred sym)

      -- | Return true if bitvector is negative.
      bvIsNeg :: (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)
      bvIsNeg sym
    sym SymBV sym w
    x = sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvSlt sym
    sym SymBV sym w
    x (SymBV sym w -> IO (Pred sym)) -> IO (SymBV sym w) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym (SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    x) (NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.zero (SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    x))

      -- | If-then-else applied to bitvectors.
      bvIte :: (1 <= w)
            => sym
            -> Pred sym
            -> SymBV sym w
            -> SymBV sym w
            -> IO (SymBV sym w)

      -- | Return true if bitvectors are equal.
      bvEq  :: (1 <= w)
            => sym
            -> SymBV sym w
            -> SymBV sym w
            -> IO (Pred sym)

      -- | Return true if bitvectors are distinct.
      bvNe  :: (1 <= w)
            => sym
            -> SymBV sym w
            -> SymBV sym w
            -> IO (Pred sym)
      bvNe sym
    sym SymBV sym w
    x SymBV sym w
    y = sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvEq sym
    sym SymBV sym w
    x SymBV sym w
    y

      -- | Unsigned less-than.
      bvUlt  :: (1 <= w)
             => sym
             -> SymBV sym w
             -> SymBV sym w
             -> IO (Pred sym)

      -- | Unsigned less-than-or-equal.
      bvUle  :: (1 <= w)
             => sym
             -> SymBV sym w
             -> SymBV sym w
             -> IO (Pred sym)
      bvUle sym
    sym SymBV sym w
    x SymBV sym w
    y = sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUlt sym
    sym SymBV sym w
    y SymBV sym w
    x

      -- | Unsigned greater-than-or-equal.
      bvUge :: (1 <= w) => sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
      bvUge sym
    sym SymBV sym w
    x SymBV sym w
    y = sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUle sym
    sym SymBV sym w
    y SymBV sym w
    x

      -- | Unsigned greater-than.
      bvUgt :: (1 <= w) => sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
      bvUgt sym
    sym SymBV sym w
    x SymBV sym w
    y = sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUlt sym
    sym SymBV sym w
    y SymBV sym w
    x

      -- | Signed less-than.
      bvSlt :: (1 <= w) => sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)

      -- | Signed greater-than.
      bvSgt :: (1 <= w) => sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
      bvSgt sym
    sym SymBV sym w
    x SymBV sym w
    y = sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvSlt sym
    sym SymBV sym w
    y SymBV sym w
    x

      -- | Signed less-than-or-equal.
      bvSle :: (1 <= w) => sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
      bvSle sym
    sym SymBV sym w
    x SymBV sym w
    y = sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvSlt sym
    sym SymBV sym w
    y SymBV sym w
    x

      -- | Signed greater-than-or-equal.
      bvSge :: (1 <= w) => sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
      bvSge sym
    sym SymBV sym w
    x SymBV sym w
    y = sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvSlt sym
    sym SymBV sym w
    x SymBV sym w
    y

      -- | returns true if the given bitvector is non-zero.
      bvIsNonzero :: (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)

      -- | Left shift.  The shift amount is treated as an unsigned value.
      bvShl :: (1 <= w) => sym ->
                           SymBV sym w {- ^ Shift this -} ->
                           SymBV sym w {- ^ Amount to shift by -} ->
                           IO (SymBV sym w)

      -- | Logical right shift.  The shift amount is treated as an unsigned value.
      bvLshr :: (1 <= w) => sym ->
                            SymBV sym w {- ^ Shift this -} ->
                            SymBV sym w {- ^ Amount to shift by -} ->
                            IO (SymBV sym w)

      -- | Arithmetic right shift.  The shift amount is treated as an
      -- unsigned value.
      bvAshr :: (1 <= w) => sym ->
                            SymBV sym w {- ^ Shift this -} ->
                            SymBV sym w {- ^ Amount to shift by -} ->
                            IO (SymBV sym w)

      -- | Rotate left.  The rotate amount is treated as an unsigned value.
      bvRol :: (1 <= w) =>
        sym ->
        SymBV sym w {- ^ bitvector to rotate -} ->
        SymBV sym w {- ^ amount to rotate by -} ->
        IO (SymBV sym w)

      -- | Rotate right.  The rotate amount is treated as an unsigned value.
      bvRor :: (1 <= w) =>
        sym ->
        SymBV sym w {- ^ bitvector to rotate -} ->
        SymBV sym w {- ^ amount to rotate by -} ->
        IO (SymBV sym w)

      -- | Zero-extend a bitvector.
      bvZext :: (1 <= u, u+1 <= r) => sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)

      -- | Sign-extend a bitvector.
      bvSext :: (1 <= u, u+1 <= r) => sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)

      -- | Truncate a bitvector.
      bvTrunc :: (1 <= r, r+1 <= w) -- Assert result is less than input.
              => sym
              -> NatRepr r
              -> SymBV sym w
              -> IO (SymBV sym r)
      bvTrunc sym
    sym NatRepr r
    w SymBV sym w
    x
        | LeqProof r w
    LeqProof <- LeqProof r (r + 1) -> LeqProof (r + 1) w -> LeqProof r w
    forall (m :: Nat) (n :: Nat) (p :: Nat).
    LeqProof m n -> LeqProof n p -> LeqProof m p
    leqTrans
            (NatRepr r -> NatRepr 1 -> LeqProof r (r + 1)
    forall (f :: Nat -> Type) (n :: Nat) (g :: Nat -> Type) (m :: Nat).
    f n -> g m -> LeqProof n (n + m)
    addIsLeq NatRepr r
    w (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @1))
            (NatRepr (r + 1) -> NatRepr w -> LeqProof (r + 1) w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof (NatRepr r -> NatRepr (r + 1)
    forall (n :: Nat). NatRepr n -> NatRepr (n + 1)
    incNat NatRepr r
    w) (SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    x))
        = sym
    -> NatRepr 0
    -> NatRepr r
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType r))
    forall (idx :: Nat) (n :: Nat) (w :: Nat).
    (1 <= n, (idx + n) <= w) =>
    sym -> NatRepr idx -> NatRepr n -> SymBV sym w -> IO (SymBV sym n)
    forall sym (idx :: Nat) (n :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= n, (idx + n) <= w) =>
    sym -> NatRepr idx -> NatRepr n -> SymBV sym w -> IO (SymBV sym n)
    bvSelect sym
    sym (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @0) NatRepr r
    w SymBV sym w
    x

      -- | Bitwise logical and.
      bvAndBits :: (1 <= w)
                => sym
                -> SymBV sym w
                -> SymBV sym w
                -> IO (SymBV sym w)

      -- | Bitwise logical or.
      bvOrBits  :: (1 <= w)
                => sym
                -> SymBV sym w
                -> SymBV sym w
                -> IO (SymBV sym w)

      -- | Bitwise logical exclusive or.
      bvXorBits :: (1 <= w)
                => sym
                -> SymBV sym w
                -> SymBV sym w
                -> IO (SymBV sym w)

      -- | Bitwise complement.
      bvNotBits :: (1 <= w) => sym -> SymBV sym w -> IO (SymBV sym w)

      -- | @bvSet sym v i p@ returns a bitvector @v'@ where bit @i@ of @v'@ is set to
      -- @p@, and the bits at the other indices are the same as in @v@.
      bvSet :: forall w
             . (1 <= w)
            => sym         -- ^ Symbolic interface
            -> SymBV sym w -- ^ Bitvector to update
            -> Natural     -- ^ 0-based index to set
            -> Pred sym    -- ^ Predicate to set.
            -> IO (SymBV sym w)
      bvSet sym
    sym SymBV sym w
    v Nat
    i Pred sym
    p = Bool -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall a. (?callStack::CallStack) => Bool -> a -> a
    assert (Nat
    i Nat -> Nat -> Bool
    forall a. Ord a => a -> a -> Bool
    < NatRepr w -> Nat
    forall (n :: Nat). NatRepr n -> Nat
    natValue (SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    v)) (IO (SymBV sym w) -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall a b. (a -> b) -> a -> b
    $
        -- NB, this representation based on AND/XOR structure is designed so that a
        -- sequence of bvSet operations will collapse nicely into a xor-linear combination
        -- of the original term and bvFill terms. It has the nice property that we
        -- do not introduce any additional subterm sharing.
        do let w :: NatRepr w
    w    = SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    v
           let mask :: BV w
    mask = NatRepr w -> Nat -> BV w
    forall (w :: Nat). NatRepr w -> Nat -> BV w
    BV.bit' NatRepr w
    w Nat
    i
           SymBV sym w
    pbits <- sym -> NatRepr w -> Pred sym -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> Pred sym -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> Pred sym -> IO (SymBV sym w)
    bvFill sym
    sym NatRepr w
    w Pred sym
    p
           SymBV sym w
    vbits <- sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvAndBits sym
    sym SymBV sym w
    v (SymBV sym w -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (NatRepr w -> BV w -> BV w
    forall (w :: Nat). NatRepr w -> BV w -> BV w
    BV.complement NatRepr w
    w BV w
    mask)
           sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvXorBits sym
    sym SymBV sym w
    vbits (SymBV sym w -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvAndBits sym
    sym SymBV sym w
    pbits (SymBV sym w -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w BV w
    mask

      -- | @bvFill sym w p@ returns a bitvector @w@-bits long where every bit
      --   is given by the boolean value of @p@.
      bvFill :: forall w. (1 <= w) =>
        sym       {-^ symbolic interface -} ->
        NatRepr w {-^ output bitvector width -} ->
        Pred sym  {-^ predicate to fill the bitvector with -} ->
        IO (SymBV sym w)

      -- | Return the bitvector of the desired width with all 0 bits;
      --   this is the minimum unsigned integer.
      minUnsignedBV :: (1 <= w) => sym -> NatRepr w -> IO (SymBV sym w)
      minUnsignedBV sym
    sym NatRepr w
    w = sym -> NatRepr w -> BV w -> IO (SymExpr sym (BaseBVType w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.zero NatRepr w
    w)

      -- | Return the bitvector of the desired width with all bits set;
      --   this is the maximum unsigned integer.
      maxUnsignedBV :: (1 <= w) => sym -> NatRepr w -> IO (SymBV sym w)
      maxUnsignedBV sym
    sym NatRepr w
    w = sym -> NatRepr w -> BV w -> IO (SymExpr sym (BaseBVType w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.maxUnsigned NatRepr w
    w)

      -- | Return the bitvector representing the largest 2's complement
      --   signed integer of the given width.  This consists of all bits
      --   set except the MSB.
      maxSignedBV :: (1 <= w) => sym -> NatRepr w -> IO (SymBV sym w)
      maxSignedBV sym
    sym NatRepr w
    w = sym -> NatRepr w -> BV w -> IO (SymExpr sym (BaseBVType w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (NatRepr w -> BV w
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.maxSigned NatRepr w
    w)

      -- | Return the bitvector representing the smallest 2's complement
      --   signed integer of the given width. This consists of all 0 bits
      --   except the MSB, which is set.
      minSignedBV :: (1 <= w) => sym -> NatRepr w -> IO (SymBV sym w)
      minSignedBV sym
    sym NatRepr w
    w = sym -> NatRepr w -> BV w -> IO (SymExpr sym (BaseBVType w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (NatRepr w -> BV w
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.minSigned NatRepr w
    w)

      -- | Return the number of 1 bits in the input.
      bvPopcount :: (1 <= w) => sym -> SymBV sym w -> IO (SymBV sym w)

      -- | Return the number of consecutive 0 bits in the input, starting from
      --   the most significant bit position.  If the input is zero, all bits are counted
      --   as leading.
      bvCountLeadingZeros :: (1 <= w) => sym -> SymBV sym w -> IO (SymBV sym w)

      -- | Return the number of consecutive 0 bits in the input, starting from
      --   the least significant bit position.  If the input is zero, all bits are counted
      --   as leading.
      bvCountTrailingZeros :: (1 <= w) => sym -> SymBV sym w -> IO (SymBV sym w)

      -- | Unsigned add with overflow bit.
      addUnsignedOF :: (1 <= w)
                    => sym
                    -> SymBV sym w
                    -> SymBV sym w
                    -> IO (Pred sym, SymBV sym w)
      addUnsignedOF sym
    sym SymBV sym w
    x SymBV sym w
    y = do
        -- Compute result
        SymBV sym w
    r   <- sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvAdd sym
    sym SymBV sym w
    x SymBV sym w
    y
        -- Return that this overflows if r is less than either x or y
        Pred sym
    ovx  <- sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUlt sym
    sym SymBV sym w
    r SymBV sym w
    x
        Pred sym
    ovy  <- sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUlt sym
    sym SymBV sym w
    r SymBV sym w
    y
        Pred sym
    ov   <- sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    orPred sym
    sym Pred sym
    ovx Pred sym
    ovy
        (Pred sym, SymBV sym w) -> IO (Pred sym, SymBV sym w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (Pred sym
    ov, SymBV sym w
    r)

      -- | Signed add with overflow bit. Overflow is true if positive +
      -- positive = negative, or if negative + negative = positive.
      addSignedOF :: (1 <= w)
                  => sym
                  -> SymBV sym w
                  -> SymBV sym w
                  -> IO (Pred sym, SymBV sym w)
      addSignedOF sym
    sym SymBV sym w
    x SymBV sym w
    y = do
        SymBV sym w
    xy  <- sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvAdd sym
    sym SymBV sym w
    x SymBV sym w
    y
        Pred sym
    sx  <- sym -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat). (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (Pred sym)
    bvIsNeg sym
    sym SymBV sym w
    x
        Pred sym
    sy  <- sym -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat). (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (Pred sym)
    bvIsNeg sym
    sym SymBV sym w
    y
        Pred sym
    sxy <- sym -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat). (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (Pred sym)
    bvIsNeg sym
    sym SymBV sym w
    xy

        Pred sym
    not_sx  <- sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym Pred sym
    sx
        Pred sym
    not_sy  <- sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym Pred sym
    sy
        Pred sym
    not_sxy <- sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym Pred sym
    sxy

        -- Return this overflowed if the sign bits of sx and sy are equal,
        -- but different from sxy.
        Pred sym
    ov1 <- sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    andPred sym
    sym Pred sym
    not_sxy (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    andPred sym
    sym Pred sym
    sx Pred sym
    sy
        Pred sym
    ov2 <- sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    andPred sym
    sym Pred sym
    sxy (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    andPred sym
    sym Pred sym
    not_sx Pred sym
    not_sy

        Pred sym
    ov  <- sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    orPred sym
    sym Pred sym
    ov1 Pred sym
    ov2
        (Pred sym, SymBV sym w) -> IO (Pred sym, SymBV sym w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (Pred sym
    ov, SymBV sym w
    xy)

      -- | Unsigned subtract with overflow bit. Overflow is true if x < y.
      subUnsignedOF ::
        (1 <= w) =>
        sym ->
        SymBV sym w ->
        SymBV sym w ->
        IO (Pred sym, SymBV sym w)
      subUnsignedOF sym
    sym SymBV sym w
    x SymBV sym w
    y = do
        SymBV sym w
    xy <- sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvSub sym
    sym SymBV sym w
    x SymBV sym w
    y
        Pred sym
    ov <- sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUlt sym
    sym SymBV sym w
    x SymBV sym w
    y
        (Pred sym, SymBV sym w) -> IO (Pred sym, SymBV sym w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (Pred sym
    ov, SymBV sym w
    xy)

      -- | Signed subtract with overflow bit. Overflow is true if positive
      -- - negative = negative, or if negative - positive = positive.
      subSignedOF :: (1 <= w)
                  => sym
                  -> SymBV sym w
                  -> SymBV sym w
                  -> IO (Pred sym, SymBV sym w)
      subSignedOF sym
    sym SymBV sym w
    x SymBV sym w
    y = do
           SymBV sym w
    xy  <- sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvSub sym
    sym SymBV sym w
    x SymBV sym w
    y
           Pred sym
    sx  <- sym -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat). (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (Pred sym)
    bvIsNeg sym
    sym SymBV sym w
    x
           Pred sym
    sy  <- sym -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat). (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (Pred sym)
    bvIsNeg sym
    sym SymBV sym w
    y
           Pred sym
    sxy <- sym -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat). (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (Pred sym)
    bvIsNeg sym
    sym SymBV sym w
    xy
           Pred sym
    ov  <- IO (IO (Pred sym)) -> IO (Pred sym)
    forall (m :: Type -> Type) a. Monad m => m (m a) -> m a
    join ((Pred sym -> Pred sym -> IO (Pred sym))
    -> IO (Pred sym -> Pred sym -> IO (Pred sym))
    forall a. a -> IO a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure (sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    andPred sym
    sym) IO (Pred sym -> Pred sym -> IO (Pred sym))
    -> IO (Pred sym) -> IO (Pred sym -> IO (Pred sym))
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    xorPred sym
    sym Pred sym
    sx Pred sym
    sxy IO (Pred sym -> IO (Pred sym))
    -> IO (Pred sym) -> IO (IO (Pred sym))
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    xorPred sym
    sym Pred sym
    sx Pred sym
    sy)
           (Pred sym, SymBV sym w) -> IO (Pred sym, SymBV sym w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (Pred sym
    ov, SymBV sym w
    xy)

      -- | Compute the carry-less multiply of the two input bitvectors.
      --   This operation is essentially the same as a standard multiply, except that
      --   the partial addends are simply XOR'd together instead of using a standard
      --   adder.  This operation is useful for computing on GF(2^n) polynomials.
      carrylessMultiply ::
        (1 <= w) =>
        sym ->
        SymBV sym w ->
        SymBV sym w ->
        IO (SymBV sym (w+w))
      carrylessMultiply sym
    sym SymBV sym w
    x0 SymBV sym w
    y0
        | Just Integer
    _  <- BV w -> Integer
    forall (w :: Nat). BV w -> Integer
    BV.asUnsigned (BV w -> Integer) -> Maybe (BV w) -> Maybe Integer
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> SymBV sym w -> Maybe (BV w)
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> Maybe (BV w)
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> Maybe (BV w)
    asBV SymBV sym w
    x0
        , Maybe Integer
    Nothing <- BV w -> Integer
    forall (w :: Nat). BV w -> Integer
    BV.asUnsigned (BV w -> Integer) -> Maybe (BV w) -> Maybe Integer
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> SymBV sym w -> Maybe (BV w)
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> Maybe (BV w)
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> Maybe (BV w)
    asBV SymBV sym w
    y0
        = SymBV sym w
    -> SymBV sym w -> IO (SymExpr sym ('BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    SymBV sym w -> SymBV sym w -> IO (SymBV sym (w + w))
    go SymBV sym w
    y0 SymBV sym w
    x0
        | Bool
    otherwise
        = SymBV sym w
    -> SymBV sym w -> IO (SymExpr sym ('BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    SymBV sym w -> SymBV sym w -> IO (SymBV sym (w + w))
    go SymBV sym w
    x0 SymBV sym w
    y0
       where
       go :: (1 <= w) => SymBV sym w -> SymBV sym w -> IO (SymBV sym (w+w))
       go :: forall (w :: Nat).
    (1 <= w) =>
    SymBV sym w -> SymBV sym w -> IO (SymBV sym (w + w))
    go SymBV sym w
    x SymBV sym w
    y =
        do let w :: NatRepr w
    w = SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    x
           let w2 :: NatRepr (w + w)
    w2 = NatRepr w -> NatRepr w -> NatRepr (w + w)
    forall (m :: Nat) (n :: Nat).
    NatRepr m -> NatRepr n -> NatRepr (m + n)
    addNat NatRepr w
    w NatRepr w
    w
           -- 1 <= w
           one_leq_w :: LeqProof 1 w
    one_leq_w@LeqProof 1 w
    LeqProof <- LeqProof 1 w -> IO (LeqProof 1 w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr 1 -> NatRepr w -> LeqProof 1 w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @1) NatRepr w
    w)
           -- 1 <= w implies 1 <= w + w
           LeqProof 1 (w + w)
    LeqProof <- LeqProof 1 (w + w) -> IO (LeqProof 1 (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof 1 w -> NatRepr w -> LeqProof 1 (w + w)
    forall (f :: Nat -> Type) (m :: Nat) (n :: Nat) (p :: Nat).
    LeqProof m n -> f p -> LeqProof m (n + p)
    leqAdd LeqProof 1 w
    one_leq_w NatRepr w
    w)
           -- w <= w
           w_leq_w :: LeqProof w w
    w_leq_w@LeqProof w w
    LeqProof <- LeqProof w w -> IO (LeqProof w w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr w -> NatRepr w -> LeqProof w w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof NatRepr w
    w NatRepr w
    w)
           -- w <= w, 1 <= w implies w + 1 <= w + w
           LeqProof (w + 1) (w + w)
    LeqProof <- LeqProof (w + 1) (w + w) -> IO (LeqProof (w + 1) (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof w w -> LeqProof 1 w -> LeqProof (w + 1) (w + w)
    forall (x_l :: Nat) (x_h :: Nat) (y_l :: Nat) (y_h :: Nat).
    LeqProof x_l x_h
    -> LeqProof y_l y_h -> LeqProof (x_l + y_l) (x_h + y_h)
    leqAdd2 LeqProof w w
    w_leq_w LeqProof 1 w
    one_leq_w)
           SymBV sym (w + w)
    z  <- sym -> NatRepr (w + w) -> BV (w + w) -> IO (SymBV sym (w + w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr (w + w)
    w2 (NatRepr (w + w) -> BV (w + w)
    forall (w :: Nat). NatRepr w -> BV w
    BV.zero NatRepr (w + w)
    w2)
           SymBV sym (w + w)
    x' <- sym -> NatRepr (w + w) -> SymBV sym w -> IO (SymBV sym (w + w))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvZext sym
    sym NatRepr (w + w)
    w2 SymBV sym w
    x
           [SymBV sym (w + w)]
    xs <- [IO (SymBV sym (w + w))] -> IO [SymBV sym (w + w)]
    forall (t :: Type -> Type) (m :: Type -> Type) a.
    (Traversable t, Monad m) =>
    t (m a) -> m (t a)
    forall (m :: Type -> Type) a. Monad m => [m a] -> m [a]
    sequence [ do Pred sym
    p <- sym -> Nat -> SymBV sym w -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Nat -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Nat -> SymBV sym w -> IO (Pred sym)
    testBitBV sym
    sym (BV (w + w) -> Nat
    forall (w :: Nat). BV w -> Nat
    BV.asNatural BV (w + w)
    i) SymBV sym w
    y
                               (sym
     -> Pred sym
     -> SymBV sym (w + w)
     -> SymBV sym (w + w)
     -> IO (SymBV sym (w + w)))
    -> sym
    -> Pred sym
    -> IO (SymBV sym (w + w))
    -> IO (SymBV sym (w + w))
    -> IO (SymBV sym (w + w))
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym
    -> Pred sym
    -> SymBV sym (w + w)
    -> SymBV sym (w + w)
    -> IO (SymBV sym (w + w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym
                                 Pred sym
    p
                                 (sym
    -> SymBV sym (w + w) -> SymBV sym (w + w) -> IO (SymBV sym (w + w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvShl sym
    sym SymBV sym (w + w)
    x' (SymBV sym (w + w) -> IO (SymBV sym (w + w)))
    -> IO (SymBV sym (w + w)) -> IO (SymBV sym (w + w))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> NatRepr (w + w) -> BV (w + w) -> IO (SymBV sym (w + w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr (w + w)
    w2 BV (w + w)
    i)
                                 (SymBV sym (w + w) -> IO (SymBV sym (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymBV sym (w + w)
    z)
                          | BV (w + w)
    i <- BV (w + w) -> BV (w + w) -> [BV (w + w)]
    forall (w :: Nat). BV w -> BV w -> [BV w]
    BV.enumFromToUnsigned (NatRepr (w + w) -> BV (w + w)
    forall (w :: Nat). NatRepr w -> BV w
    BV.zero NatRepr (w + w)
    w2) (NatRepr (w + w) -> Integer -> BV (w + w)
    forall (w :: Nat). NatRepr w -> Integer -> BV w
    BV.mkBV NatRepr (w + w)
    w2 (NatRepr w -> Integer
    forall (n :: Nat). NatRepr n -> Integer
    intValue NatRepr w
    w Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    - Integer
    1))
                          ]
           (SymBV sym (w + w) -> SymBV sym (w + w) -> IO (SymBV sym (w + w)))
    -> SymBV sym (w + w)
    -> [SymBV sym (w + w)]
    -> IO (SymBV sym (w + w))
    forall (t :: Type -> Type) (m :: Type -> Type) b a.
    (Foldable t, Monad m) =>
    (b -> a -> m b) -> b -> t a -> m b
    foldM (sym
    -> SymBV sym (w + w) -> SymBV sym (w + w) -> IO (SymBV sym (w + w))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvXorBits sym
    sym) SymBV sym (w + w)
    z [SymBV sym (w + w)]
    xs

      -- | @unsignedWideMultiplyBV sym x y@ multiplies two unsigned 'w' bit numbers 'x' and 'y'.
      --
      -- It returns a pair containing the top 'w' bits as the first element, and the
      -- lower 'w' bits as the second element.
      unsignedWideMultiplyBV :: (1 <= w)
                             => sym
                             -> SymBV sym w
                             -> SymBV sym w
                             -> IO (SymBV sym w, SymBV sym w)
      unsignedWideMultiplyBV sym
    sym SymBV sym w
    x SymBV sym w
    y = do
           let w :: NatRepr w
    w = SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    x
           let dbl_w :: NatRepr (w + w)
    dbl_w = NatRepr w -> NatRepr w -> NatRepr (w + w)
    forall (m :: Nat) (n :: Nat).
    NatRepr m -> NatRepr n -> NatRepr (m + n)
    addNat NatRepr w
    w NatRepr w
    w
           -- 1 <= w
           one_leq_w :: LeqProof 1 w
    one_leq_w@LeqProof 1 w
    LeqProof <- LeqProof 1 w -> IO (LeqProof 1 w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr 1 -> NatRepr w -> LeqProof 1 w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @1) NatRepr w
    w)
           -- 1 <= w implies 1 <= w + w
           LeqProof 1 (w + w)
    LeqProof <- LeqProof 1 (w + w) -> IO (LeqProof 1 (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof 1 w -> NatRepr w -> LeqProof 1 (w + w)
    forall (f :: Nat -> Type) (m :: Nat) (n :: Nat) (p :: Nat).
    LeqProof m n -> f p -> LeqProof m (n + p)
    leqAdd LeqProof 1 w
    one_leq_w NatRepr w
    w)
           -- w <= w
           w_leq_w :: LeqProof w w
    w_leq_w@LeqProof w w
    LeqProof <- LeqProof w w -> IO (LeqProof w w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr w -> NatRepr w -> LeqProof w w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof NatRepr w
    w NatRepr w
    w)
           -- w <= w, 1 <= w implies w + 1 <= w + w
           LeqProof (w + 1) (w + w)
    LeqProof <- LeqProof (w + 1) (w + w) -> IO (LeqProof (w + 1) (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof w w -> LeqProof 1 w -> LeqProof (w + 1) (w + w)
    forall (x_l :: Nat) (x_h :: Nat) (y_l :: Nat) (y_h :: Nat).
    LeqProof x_l x_h
    -> LeqProof y_l y_h -> LeqProof (x_l + y_l) (x_h + y_h)
    leqAdd2 LeqProof w w
    w_leq_w LeqProof 1 w
    one_leq_w)
           SymExpr sym (BaseBVType (w + w))
    x'  <- sym
    -> NatRepr (w + w)
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvZext sym
    sym NatRepr (w + w)
    dbl_w SymBV sym w
    x
           SymExpr sym (BaseBVType (w + w))
    y'  <- sym
    -> NatRepr (w + w)
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvZext sym
    sym NatRepr (w + w)
    dbl_w SymBV sym w
    y
           SymExpr sym (BaseBVType (w + w))
    s   <- sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvMul sym
    sym SymExpr sym (BaseBVType (w + w))
    x' SymExpr sym (BaseBVType (w + w))
    y'
           SymBV sym w
    lo  <- sym
    -> NatRepr w
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymBV sym w)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr w
    w SymExpr sym (BaseBVType (w + w))
    s
           SymExpr sym (BaseBVType (w + w))
    n   <- sym
    -> NatRepr (w + w)
    -> BV (w + w)
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr (w + w)
    dbl_w (NatRepr (w + w) -> BV w -> BV (w + w)
    forall (w :: Nat) (w' :: Nat).
    ((w + 1) <= w') =>
    NatRepr w' -> BV w -> BV w'
    BV.zext NatRepr (w + w)
    dbl_w (NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.width NatRepr w
    w))
           SymBV sym w
    hi  <- sym
    -> NatRepr w
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymBV sym w)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr w
    w (SymExpr sym (BaseBVType (w + w)) -> IO (SymBV sym w))
    -> IO (SymExpr sym (BaseBVType (w + w))) -> IO (SymBV sym w)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvLshr sym
    sym SymExpr sym (BaseBVType (w + w))
    s SymExpr sym (BaseBVType (w + w))
    n
           (SymBV sym w, SymBV sym w) -> IO (SymBV sym w, SymBV sym w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (SymBV sym w
    hi, SymBV sym w
    lo)

      -- | Compute the unsigned multiply of two values with overflow bit.
      mulUnsignedOF ::
        (1 <= w) =>
        sym ->
        SymBV sym w ->
        SymBV sym w ->
        IO (Pred sym, SymBV sym w)
      mulUnsignedOF sym
    sym SymBV sym w
    x SymBV sym w
    y =
        do let w :: NatRepr w
    w = SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    x
           let dbl_w :: NatRepr (w + w)
    dbl_w = NatRepr w -> NatRepr w -> NatRepr (w + w)
    forall (m :: Nat) (n :: Nat).
    NatRepr m -> NatRepr n -> NatRepr (m + n)
    addNat NatRepr w
    w NatRepr w
    w
           -- 1 <= w
           one_leq_w :: LeqProof 1 w
    one_leq_w@LeqProof 1 w
    LeqProof <- LeqProof 1 w -> IO (LeqProof 1 w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr 1 -> NatRepr w -> LeqProof 1 w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @1) NatRepr w
    w)
           -- 1 <= w implies 1 <= w + w
           LeqProof 1 (w + w)
    LeqProof <- LeqProof 1 (w + w) -> IO (LeqProof 1 (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof 1 w -> NatRepr w -> LeqProof 1 (w + w)
    forall (f :: Nat -> Type) (m :: Nat) (n :: Nat) (p :: Nat).
    LeqProof m n -> f p -> LeqProof m (n + p)
    leqAdd LeqProof 1 w
    one_leq_w NatRepr w
    w)
           -- w <= w
           w_leq_w :: LeqProof w w
    w_leq_w@LeqProof w w
    LeqProof <- LeqProof w w -> IO (LeqProof w w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr w -> NatRepr w -> LeqProof w w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof NatRepr w
    w NatRepr w
    w)
           -- w <= w, 1 <= w implies w + 1 <= w + w
           LeqProof (w + 1) (w + w)
    LeqProof <- LeqProof (w + 1) (w + w) -> IO (LeqProof (w + 1) (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof w w -> LeqProof 1 w -> LeqProof (w + 1) (w + w)
    forall (x_l :: Nat) (x_h :: Nat) (y_l :: Nat) (y_h :: Nat).
    LeqProof x_l x_h
    -> LeqProof y_l y_h -> LeqProof (x_l + y_l) (x_h + y_h)
    leqAdd2 LeqProof w w
    w_leq_w LeqProof 1 w
    one_leq_w)
           SymExpr sym (BaseBVType (w + w))
    x'  <- sym
    -> NatRepr (w + w)
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvZext sym
    sym NatRepr (w + w)
    dbl_w SymBV sym w
    x
           SymExpr sym (BaseBVType (w + w))
    y'  <- sym
    -> NatRepr (w + w)
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvZext sym
    sym NatRepr (w + w)
    dbl_w SymBV sym w
    y
           SymExpr sym (BaseBVType (w + w))
    s   <- sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvMul sym
    sym SymExpr sym (BaseBVType (w + w))
    x' SymExpr sym (BaseBVType (w + w))
    y'
           SymBV sym w
    lo  <- sym
    -> NatRepr w
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymBV sym w)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr w
    w SymExpr sym (BaseBVType (w + w))
    s

           -- overflow if the result is greater than the max representable value in w bits
           Pred sym
    ov  <- sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUgt sym
    sym SymExpr sym (BaseBVType (w + w))
    s (SymExpr sym (BaseBVType (w + w)) -> IO (Pred sym))
    -> IO (SymExpr sym (BaseBVType (w + w))) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> NatRepr (w + w)
    -> BV (w + w)
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr (w + w)
    dbl_w (NatRepr (w + w) -> BV w -> BV (w + w)
    forall (w :: Nat) (w' :: Nat).
    ((w + 1) <= w') =>
    NatRepr w' -> BV w -> BV w'
    BV.zext NatRepr (w + w)
    dbl_w (NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.maxUnsigned NatRepr w
    w))

           (Pred sym, SymBV sym w) -> IO (Pred sym, SymBV sym w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (Pred sym
    ov, SymBV sym w
    lo)

      -- | @signedWideMultiplyBV sym x y@ multiplies two signed 'w' bit numbers 'x' and 'y'.
      --
      -- It returns a pair containing the top 'w' bits as the first element, and the
      -- lower 'w' bits as the second element.
      signedWideMultiplyBV :: (1 <= w)
                           => sym
                           -> SymBV sym w
                           -> SymBV sym w
                           -> IO (SymBV sym w, SymBV sym w)
      signedWideMultiplyBV sym
    sym SymBV sym w
    x SymBV sym w
    y = do
           let w :: NatRepr w
    w = SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    x
           let dbl_w :: NatRepr (w + w)
    dbl_w = NatRepr w -> NatRepr w -> NatRepr (w + w)
    forall (m :: Nat) (n :: Nat).
    NatRepr m -> NatRepr n -> NatRepr (m + n)
    addNat NatRepr w
    w NatRepr w
    w
           -- 1 <= w
           one_leq_w :: LeqProof 1 w
    one_leq_w@LeqProof 1 w
    LeqProof <- LeqProof 1 w -> IO (LeqProof 1 w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr 1 -> NatRepr w -> LeqProof 1 w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @1) NatRepr w
    w)
           -- 1 <= w implies 1 <= w + w
           LeqProof 1 (w + w)
    LeqProof <- LeqProof 1 (w + w) -> IO (LeqProof 1 (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof 1 w -> NatRepr w -> LeqProof 1 (w + w)
    forall (f :: Nat -> Type) (m :: Nat) (n :: Nat) (p :: Nat).
    LeqProof m n -> f p -> LeqProof m (n + p)
    leqAdd LeqProof 1 w
    one_leq_w NatRepr w
    w)
           -- w <= w
           w_leq_w :: LeqProof w w
    w_leq_w@LeqProof w w
    LeqProof <- LeqProof w w -> IO (LeqProof w w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr w -> NatRepr w -> LeqProof w w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof NatRepr w
    w NatRepr w
    w)
           -- w <= w, 1 <= w implies w + 1 <= w + w
           LeqProof (w + 1) (w + w)
    LeqProof <- LeqProof (w + 1) (w + w) -> IO (LeqProof (w + 1) (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof w w -> LeqProof 1 w -> LeqProof (w + 1) (w + w)
    forall (x_l :: Nat) (x_h :: Nat) (y_l :: Nat) (y_h :: Nat).
    LeqProof x_l x_h
    -> LeqProof y_l y_h -> LeqProof (x_l + y_l) (x_h + y_h)
    leqAdd2 LeqProof w w
    w_leq_w LeqProof 1 w
    one_leq_w)
           SymExpr sym (BaseBVType (w + w))
    x'  <- sym
    -> NatRepr (w + w)
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvSext sym
    sym NatRepr (w + w)
    dbl_w SymBV sym w
    x
           SymExpr sym (BaseBVType (w + w))
    y'  <- sym
    -> NatRepr (w + w)
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvSext sym
    sym NatRepr (w + w)
    dbl_w SymBV sym w
    y
           SymExpr sym (BaseBVType (w + w))
    s   <- sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvMul sym
    sym SymExpr sym (BaseBVType (w + w))
    x' SymExpr sym (BaseBVType (w + w))
    y'
           SymBV sym w
    lo  <- sym
    -> NatRepr w
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymBV sym w)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr w
    w SymExpr sym (BaseBVType (w + w))
    s
           SymExpr sym (BaseBVType (w + w))
    n   <- sym
    -> NatRepr (w + w)
    -> BV (w + w)
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr (w + w)
    dbl_w (NatRepr (w + w) -> BV w -> BV (w + w)
    forall (w :: Nat) (w' :: Nat).
    ((w + 1) <= w') =>
    NatRepr w' -> BV w -> BV w'
    BV.zext NatRepr (w + w)
    dbl_w (NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.width NatRepr w
    w))
           SymBV sym w
    hi  <- sym
    -> NatRepr w
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymBV sym w)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr w
    w (SymExpr sym (BaseBVType (w + w)) -> IO (SymBV sym w))
    -> IO (SymExpr sym (BaseBVType (w + w))) -> IO (SymBV sym w)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvLshr sym
    sym SymExpr sym (BaseBVType (w + w))
    s SymExpr sym (BaseBVType (w + w))
    n
           (SymBV sym w, SymBV sym w) -> IO (SymBV sym w, SymBV sym w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (SymBV sym w
    hi, SymBV sym w
    lo)

      -- | Compute the signed multiply of two values with overflow bit.
      mulSignedOF ::
        (1 <= w) =>
        sym ->
        SymBV sym w ->
        SymBV sym w ->
        IO (Pred sym, SymBV sym w)
      mulSignedOF sym
    sym SymBV sym w
    x SymBV sym w
    y =
        do let w :: NatRepr w
    w = SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    x
           let dbl_w :: NatRepr (w + w)
    dbl_w = NatRepr w -> NatRepr w -> NatRepr (w + w)
    forall (m :: Nat) (n :: Nat).
    NatRepr m -> NatRepr n -> NatRepr (m + n)
    addNat NatRepr w
    w NatRepr w
    w
           -- 1 <= w
           one_leq_w :: LeqProof 1 w
    one_leq_w@LeqProof 1 w
    LeqProof <- LeqProof 1 w -> IO (LeqProof 1 w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr 1 -> NatRepr w -> LeqProof 1 w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @1) NatRepr w
    w)
           -- 1 <= w implies 1 <= w + w
           LeqProof 1 (w + w)
    LeqProof <- LeqProof 1 (w + w) -> IO (LeqProof 1 (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof 1 w -> NatRepr w -> LeqProof 1 (w + w)
    forall (f :: Nat -> Type) (m :: Nat) (n :: Nat) (p :: Nat).
    LeqProof m n -> f p -> LeqProof m (n + p)
    leqAdd LeqProof 1 w
    one_leq_w NatRepr w
    w)
           -- w <= w
           w_leq_w :: LeqProof w w
    w_leq_w@LeqProof w w
    LeqProof <- LeqProof w w -> IO (LeqProof w w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (NatRepr w -> NatRepr w -> LeqProof w w
    forall (m :: Nat) (n :: Nat) (f :: Nat -> Type) (g :: Nat -> Type).
    (m <= n) =>
    f m -> g n -> LeqProof m n
    leqProof NatRepr w
    w NatRepr w
    w)
           -- w <= w, 1 <= w implies w + 1 <= w + w
           LeqProof (w + 1) (w + w)
    LeqProof <- LeqProof (w + 1) (w + w) -> IO (LeqProof (w + 1) (w + w))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (LeqProof w w -> LeqProof 1 w -> LeqProof (w + 1) (w + w)
    forall (x_l :: Nat) (x_h :: Nat) (y_l :: Nat) (y_h :: Nat).
    LeqProof x_l x_h
    -> LeqProof y_l y_h -> LeqProof (x_l + y_l) (x_h + y_h)
    leqAdd2 LeqProof w w
    w_leq_w LeqProof 1 w
    one_leq_w)
           SymExpr sym (BaseBVType (w + w))
    x'  <- sym
    -> NatRepr (w + w)
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvSext sym
    sym NatRepr (w + w)
    dbl_w SymBV sym w
    x
           SymExpr sym (BaseBVType (w + w))
    y'  <- sym
    -> NatRepr (w + w)
    -> SymBV sym w
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvSext sym
    sym NatRepr (w + w)
    dbl_w SymBV sym w
    y
           SymExpr sym (BaseBVType (w + w))
    s   <- sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvMul sym
    sym SymExpr sym (BaseBVType (w + w))
    x' SymExpr sym (BaseBVType (w + w))
    y'
           SymBV sym w
    lo  <- sym
    -> NatRepr w
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (SymBV sym w)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr w
    w SymExpr sym (BaseBVType (w + w))
    s

           -- overflow if greater or less than max representable values
           Pred sym
    ov1 <- sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvSlt sym
    sym SymExpr sym (BaseBVType (w + w))
    s (SymExpr sym (BaseBVType (w + w)) -> IO (Pred sym))
    -> IO (SymExpr sym (BaseBVType (w + w))) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> NatRepr (w + w)
    -> BV (w + w)
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr (w + w)
    dbl_w (NatRepr w -> NatRepr (w + w) -> BV w -> BV (w + w)
    forall (w :: Nat) (w' :: Nat).
    (1 <= w, (w + 1) <= w') =>
    NatRepr w -> NatRepr w' -> BV w -> BV w'
    BV.sext NatRepr w
    w NatRepr (w + w)
    dbl_w (NatRepr w -> BV w
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.minSigned NatRepr w
    w))
           Pred sym
    ov2 <- sym
    -> SymExpr sym (BaseBVType (w + w))
    -> SymExpr sym (BaseBVType (w + w))
    -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvSgt sym
    sym SymExpr sym (BaseBVType (w + w))
    s (SymExpr sym (BaseBVType (w + w)) -> IO (Pred sym))
    -> IO (SymExpr sym (BaseBVType (w + w))) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> NatRepr (w + w)
    -> BV (w + w)
    -> IO (SymExpr sym (BaseBVType (w + w)))
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr (w + w)
    dbl_w (NatRepr w -> NatRepr (w + w) -> BV w -> BV (w + w)
    forall (w :: Nat) (w' :: Nat).
    (1 <= w, (w + 1) <= w') =>
    NatRepr w -> NatRepr w' -> BV w -> BV w'
    BV.sext NatRepr w
    w NatRepr (w + w)
    dbl_w (NatRepr w -> BV w
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.maxSigned NatRepr w
    w))
           Pred sym
    ov  <- sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    orPred sym
    sym Pred sym
    ov1 Pred sym
    ov2
           (Pred sym, SymBV sym w) -> IO (Pred sym, SymBV sym w)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (Pred sym
    ov, SymBV sym w
    lo)

      ----------------------------------------------------------------------
      -- Struct operations

      -- | Create a struct from an assignment of expressions.
      mkStruct :: sym
               -> Ctx.Assignment (SymExpr sym) flds
               -> IO (SymStruct sym flds)

      -- | Get the value of a specific field in a struct.
      structField :: sym
                  -> SymStruct sym flds
                  -> Ctx.Index flds tp
                  -> IO (SymExpr sym tp)

      -- | Check if two structs are equal.
      structEq  :: forall flds
                .  sym
                -> SymStruct sym flds
                -> SymStruct sym flds
                -> IO (Pred sym)
      structEq sym
    sym SymStruct sym flds
    x SymStruct sym flds
    y = do
        case SymStruct sym flds -> BaseTypeRepr (BaseStructType flds)
    forall (tp :: BaseType). SymExpr sym tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType SymStruct sym flds
    x of
          BaseStructRepr Assignment BaseTypeRepr ctx
    fld_types -> do
            let sz :: Size ctx
    sz = Assignment BaseTypeRepr ctx -> Size ctx
    forall {k} (f :: k -> Type) (ctx :: Ctx k).
    Assignment f ctx -> Size ctx
    Ctx.size Assignment BaseTypeRepr ctx
    fld_types
            -- Checks to see if the ith struct fields are equal, and all previous entries
            -- are as well.
            let f :: IO (Pred sym) -> Ctx.Index flds tp -> IO (Pred sym)
                f :: forall (tp :: BaseType).
    IO (Pred sym) -> Index flds tp -> IO (Pred sym)
    f IO (Pred sym)
    mp Index flds tp
    i = do
                  SymExpr sym tp
    xi <- sym -> SymStruct sym flds -> Index flds tp -> IO (SymExpr sym tp)
    forall sym (flds :: Ctx BaseType) (tp :: BaseType).
    IsExprBuilder sym =>
    sym -> SymStruct sym flds -> Index flds tp -> IO (SymExpr sym tp)
    forall (flds :: Ctx BaseType) (tp :: BaseType).
    sym -> SymStruct sym flds -> Index flds tp -> IO (SymExpr sym tp)
    structField sym
    sym SymStruct sym flds
    x Index flds tp
    i
                  SymExpr sym tp
    yi <- sym -> SymStruct sym flds -> Index flds tp -> IO (SymExpr sym tp)
    forall sym (flds :: Ctx BaseType) (tp :: BaseType).
    IsExprBuilder sym =>
    sym -> SymStruct sym flds -> Index flds tp -> IO (SymExpr sym tp)
    forall (flds :: Ctx BaseType) (tp :: BaseType).
    sym -> SymStruct sym flds -> Index flds tp -> IO (SymExpr sym tp)
    structField sym
    sym SymStruct sym flds
    y Index flds tp
    i
                  Pred sym
    i_eq <- sym -> SymExpr sym tp -> SymExpr sym tp -> IO (Pred sym)
    forall sym (tp :: BaseType).
    IsExprBuilder sym =>
    sym -> SymExpr sym tp -> SymExpr sym tp -> IO (Pred sym)
    forall (tp :: BaseType).
    sym -> SymExpr sym tp -> SymExpr sym tp -> IO (Pred sym)
    isEq sym
    sym SymExpr sym tp
    xi SymExpr sym tp
    yi
                  case Pred sym -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred Pred sym
    i_eq of
                    Just Bool
    True -> IO (Pred sym)
    mp
                    Just Bool
    False -> Pred sym -> IO (Pred sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (sym -> Pred sym
    forall sym. IsExprBuilder sym => sym -> Pred sym
    falsePred sym
    sym)
                    Maybe Bool
    _ ->  sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    andPred sym
    sym Pred sym
    i_eq (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< IO (Pred sym)
    mp
            Size ctx
    -> (forall (tp :: BaseType).
        IO (Pred sym) -> Index ctx tp -> IO (Pred sym))
    -> IO (Pred sym)
    -> IO (Pred sym)
    forall {k} (ctx :: Ctx k) r.
    Size ctx -> (forall (tp :: k). r -> Index ctx tp -> r) -> r -> r
    Ctx.forIndex Size ctx
    sz IO (Pred sym) -> Index flds tp -> IO (Pred sym)
    IO (Pred sym) -> Index ctx tp -> IO (Pred sym)
    forall (tp :: BaseType).
    IO (Pred sym) -> Index flds tp -> IO (Pred sym)
    forall (tp :: BaseType).
    IO (Pred sym) -> Index ctx tp -> IO (Pred sym)
    f (Pred sym -> IO (Pred sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (sym -> Pred sym
    forall sym. IsExprBuilder sym => sym -> Pred sym
    truePred sym
    sym))

      -- | Take the if-then-else of two structures.
      structIte :: sym
                -> Pred sym
                -> SymStruct sym flds
                -> SymStruct sym flds
                -> IO (SymStruct sym flds)

      -----------------------------------------------------------------------
      -- Array operations

      -- | Create an array where each element has the same value.
      constantArray :: sym -- Interface
                    -> Ctx.Assignment BaseTypeRepr (idx::>tp) -- ^ Index type
                    -> SymExpr sym b -- ^ Constant
                    -> IO (SymArray sym (idx::>tp) b)

      -- | Create an array from an arbitrary symbolic function.
      --
      -- Arrays created this way can typically not be compared
      -- for equality when provided to backend solvers.
      arrayFromFn :: sym
                  -> SymFn sym (idx ::> itp) ret
                  -> IO (SymArray sym (idx ::> itp) ret)

      -- | Create an array by mapping a function over one or more existing arrays.
      arrayMap :: sym
               -> SymFn sym (ctx::>d) r
               -> Ctx.Assignment (ArrayResultWrapper (SymExpr sym) (idx ::> itp)) (ctx::>d)
               -> IO (SymArray sym (idx ::> itp) r)

      -- | Update an array at a specific location.
      arrayUpdate :: sym
                  -> SymArray sym (idx::>tp) b
                  -> Ctx.Assignment (SymExpr sym) (idx::>tp)
                  -> SymExpr sym b
                  -> IO (SymArray sym (idx::>tp) b)

      -- | Return element in array.
      arrayLookup :: sym
                  -> SymArray sym (idx::>tp) b
                  -> Ctx.Assignment (SymExpr sym) (idx::>tp)
                  -> IO (SymExpr sym b)

      -- | Copy elements from the source array to the destination array.
      --
      -- @'arrayCopy' sym dest_arr dest_idx src_arr src_idx len@ copies the elements
      -- from @src_arr@ at indices @[src_idx .. (src_idx + len - 1)]@ into
      -- @dest_arr@ at indices @[dest_idx .. (dest_idx + len - 1)]@.
      --
      -- The result is undefined if either @dest_idx + len@ or @src_idx + len@
      -- wraps around.
      arrayCopy ::
        (1 <= w) =>
        sym ->
        SymArray sym (SingleCtx (BaseBVType w)) a {- ^ @dest_arr@ -}  ->
        SymBV sym w {- ^ @dest_idx@ -} ->
        SymArray sym (SingleCtx (BaseBVType w)) a {- ^ @src_arr@ -} ->
        SymBV sym w {- ^ @src_idx@ -} ->
        SymBV sym w {- ^ @len@ -} ->
        IO (SymArray sym (SingleCtx (BaseBVType w)) a)

      -- | Set elements of the given array.
      --
      -- @'arraySet' sym arr idx val len@ sets the elements of @arr@ at indices
      -- @[idx .. (idx + len - 1)]@ to @val@.
      --
      -- The result is undefined if @idx + len@ wraps around.
      arraySet ::
        (1 <= w) =>
        sym ->
        SymArray sym (SingleCtx (BaseBVType w)) a {- ^ @arr@ -} ->
        SymBV sym w {- ^ @idx@ -} ->
        SymExpr sym a {- ^ @val@ -} ->
        SymBV sym w {- ^ @len@ -} ->
        IO (SymArray sym (SingleCtx (BaseBVType w)) a)

      -- | Check whether the lhs array and rhs array are equal at a range of
      --   indices.
      --
      -- @'arrayRangeEq' sym lhs_arr lhs_idx rhs_arr rhs_idx len@ checks whether the
      -- elements of @lhs_arr@ at indices @[lhs_idx .. (lhs_idx + len - 1)]@ and the
      -- elements of @rhs_arr@ at indices @[rhs_idx .. (rhs_idx + len - 1)]@ are
      -- equal.
      --
      -- The result is undefined if either @lhs_idx + len@ or @rhs_idx + len@
      -- wraps around.
      arrayRangeEq ::
        (1 <= w) =>
        sym ->
        SymArray sym (SingleCtx (BaseBVType w)) a {- ^ @lhs_arr@ -} ->
        SymBV sym w {- ^ @lhs_idx@ -} ->
        SymArray sym (SingleCtx (BaseBVType w)) a {- ^ @rhs_arr@ -} ->
        SymBV sym w {- ^ @rhs_idx@ -} ->
        SymBV sym w {- ^ @len@ -} ->
        IO (Pred sym)

      -- | Create an array from a map of concrete indices to values.
      --
      -- This is implemented, but designed to be overridden for efficiency.
      arrayFromMap :: sym
                   -> Ctx.Assignment BaseTypeRepr (idx ::> itp)
                      -- ^ Types for indices
                   -> AUM.ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
                      -- ^ Value for known indices.
                   -> SymExpr sym tp
                      -- ^ Value for other entries.
                   -> IO (SymArray sym (idx ::> itp) tp)
      arrayFromMap sym
    sym Assignment BaseTypeRepr (idx ::> itp)
    idx_tps ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
    m SymExpr sym tp
    default_value = do
        SymArray sym (idx ::> itp) tp
    a0 <- sym
    -> Assignment BaseTypeRepr (idx ::> itp)
    -> SymExpr sym tp
    -> IO (SymArray sym (idx ::> itp) tp)
    forall sym (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    forall (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    constantArray sym
    sym Assignment BaseTypeRepr (idx ::> itp)
    idx_tps SymExpr sym tp
    default_value
        sym
    -> ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
    -> SymArray sym (idx ::> itp) tp
    -> IO (SymArray sym (idx ::> itp) tp)
    forall sym (idx :: Ctx BaseType) (itp :: BaseType)
           (tp :: BaseType).
    IsExprBuilder sym =>
    sym
    -> ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
    -> SymArray sym (idx ::> itp) tp
    -> IO (SymArray sym (idx ::> itp) tp)
    forall (idx :: Ctx BaseType) (itp :: BaseType) (tp :: BaseType).
    sym
    -> ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
    -> SymArray sym (idx ::> itp) tp
    -> IO (SymArray sym (idx ::> itp) tp)
    arrayUpdateAtIdxLits sym
    sym ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
    m SymArray sym (idx ::> itp) tp
    a0

      -- | Update an array at specific concrete indices.
      --
      -- This is implemented, but designed to be overriden for efficiency.
      arrayUpdateAtIdxLits :: sym
                           -> AUM.ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
                           -- ^ Value for known indices.
                           -> SymArray sym (idx ::> itp) tp
                           -- ^ Value for existing array.
                           -> IO (SymArray sym (idx ::> itp) tp)
      arrayUpdateAtIdxLits sym
    sym ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
    m SymArray sym (idx ::> itp) tp
    a0 = do
        let updateAt :: SymArray sym (idx ::> itp) tp
    -> (Assignment IndexLit (idx ::> itp), SymExpr sym tp)
    -> IO (SymArray sym (idx ::> itp) tp)
    updateAt SymArray sym (idx ::> itp) tp
    a (Assignment IndexLit (idx ::> itp)
    i,SymExpr sym tp
    v) = do
              Assignment (SymExpr sym) (idx ::> itp)
    idx <-  (forall (x :: BaseType). IndexLit x -> IO (SymExpr sym x))
    -> forall (x :: Ctx BaseType).
       Assignment IndexLit x -> IO (Assignment (SymExpr sym) x)
    forall k l (t :: (k -> Type) -> l -> Type) (f :: k -> Type)
           (g :: k -> Type) (m :: Type -> Type).
    (TraversableFC t, Applicative m) =>
    (forall (x :: k). f x -> m (g x))
    -> forall (x :: l). t f x -> m (t g x)
    forall (f :: BaseType -> Type) (g :: BaseType -> Type)
           (m :: Type -> Type).
    Applicative m =>
    (forall (x :: BaseType). f x -> m (g x))
    -> forall (x :: Ctx BaseType). Assignment f x -> m (Assignment g x)
    traverseFC (sym -> IndexLit x -> IO (SymExpr sym x)
    forall sym (idx :: BaseType).
    IsExprBuilder sym =>
    sym -> IndexLit idx -> IO (SymExpr sym idx)
    indexLit sym
    sym) Assignment IndexLit (idx ::> itp)
    i
              sym
    -> SymArray sym (idx ::> itp) tp
    -> Assignment (SymExpr sym) (idx ::> itp)
    -> SymExpr sym tp
    -> IO (SymArray sym (idx ::> itp) tp)
    forall sym (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym
    -> SymArray sym (idx ::> tp) b
    -> Assignment (SymExpr sym) (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    forall (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    sym
    -> SymArray sym (idx ::> tp) b
    -> Assignment (SymExpr sym) (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    arrayUpdate sym
    sym SymArray sym (idx ::> itp) tp
    a Assignment (SymExpr sym) (idx ::> itp)
    idx SymExpr sym tp
    v
        (SymArray sym (idx ::> itp) tp
     -> (Assignment IndexLit (idx ::> itp), SymExpr sym tp)
     -> IO (SymArray sym (idx ::> itp) tp))
    -> SymArray sym (idx ::> itp) tp
    -> [(Assignment IndexLit (idx ::> itp), SymExpr sym tp)]
    -> IO (SymArray sym (idx ::> itp) tp)
    forall (t :: Type -> Type) (m :: Type -> Type) b a.
    (Foldable t, Monad m) =>
    (b -> a -> m b) -> b -> t a -> m b
    foldlM SymArray sym (idx ::> itp) tp
    -> (Assignment IndexLit (idx ::> itp), SymExpr sym tp)
    -> IO (SymArray sym (idx ::> itp) tp)
    updateAt SymArray sym (idx ::> itp) tp
    a0 (ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
    -> [(Assignment IndexLit (idx ::> itp), SymExpr sym tp)]
    forall (e :: BaseType -> Type) (ctx :: Ctx BaseType)
           (tp :: BaseType).
    ArrayUpdateMap e ctx tp -> [(Assignment IndexLit ctx, e tp)]
    AUM.toList ArrayUpdateMap (SymExpr sym) (idx ::> itp) tp
    m)

      -- | If-then-else applied to arrays.
      arrayIte :: sym
               -> Pred sym
               -> SymArray sym idx b
               -> SymArray sym idx b
               -> IO (SymArray sym idx b)

      -- | Return true if two arrays are equal.
      --
      -- Note that in the backend, arrays do not have a fixed number of elements, so
      -- this equality requires that arrays are equal on all elements.
      arrayEq :: sym
              -> SymArray sym idx b
              -> SymArray sym idx b
              -> IO (Pred sym)

      -- | Return true if all entries in the array are true.
      allTrueEntries :: sym -> SymArray sym idx BaseBoolType -> IO (Pred sym)
      allTrueEntries sym
    sym SymArray sym idx BaseBoolType
    a = do
        case SymArray sym idx BaseBoolType
    -> BaseTypeRepr (BaseArrayType idx BaseBoolType)
    forall (tp :: BaseType). SymExpr sym tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType SymArray sym idx BaseBoolType
    a of
          BaseArrayRepr Assignment BaseTypeRepr (idx ::> tp)
    idx_tps BaseTypeRepr xs
    _ ->
            sym
    -> SymExpr sym (BaseArrayType (idx ::> tp) BaseBoolType)
    -> SymExpr sym (BaseArrayType (idx ::> tp) BaseBoolType)
    -> IO (Pred sym)
    forall sym (idx :: Ctx BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym -> SymArray sym idx b -> SymArray sym idx b -> IO (Pred sym)
    forall (idx :: Ctx BaseType) (b :: BaseType).
    sym -> SymArray sym idx b -> SymArray sym idx b -> IO (Pred sym)
    arrayEq sym
    sym SymArray sym idx BaseBoolType
    SymExpr sym (BaseArrayType (idx ::> tp) BaseBoolType)
    a (SymExpr sym (BaseArrayType (idx ::> tp) BaseBoolType)
     -> IO (Pred sym))
    -> IO (SymExpr sym (BaseArrayType (idx ::> tp) BaseBoolType))
    -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> Pred sym
    -> IO (SymExpr sym (BaseArrayType (idx ::> tp) BaseBoolType))
    forall sym (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    forall (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    constantArray sym
    sym Assignment BaseTypeRepr (idx ::> tp)
    idx_tps (sym -> Pred sym
    forall sym. IsExprBuilder sym => sym -> Pred sym
    truePred sym
    sym)

      -- | Return true if the array has the value true at every index satisfying the
      -- given predicate.
      arrayTrueOnEntries
        :: sym
        -> SymFn sym (idx::>itp) BaseBoolType
        -- ^ Predicate that indicates if array should be true.
        -> SymArray sym (idx ::> itp) BaseBoolType
        -> IO (Pred sym)

      ----------------------------------------------------------------------
      -- Lossless (injective) conversions

      -- | Convert an integer to a real number.
      integerToReal :: sym -> SymInteger sym -> IO (SymReal sym)

      -- | Return the unsigned value of the given bitvector as an integer.
      bvToInteger :: (1 <= w) => sym -> SymBV sym w -> IO (SymInteger sym)

      -- | Return the signed value of the given bitvector as an integer.
      sbvToInteger :: (1 <= w) => sym -> SymBV sym w -> IO (SymInteger sym)

      -- | Return @1@ if the predicate is true; @0@ otherwise.
      predToBV :: (1 <= w) => sym -> Pred sym -> NatRepr w -> IO (SymBV sym w)

      ----------------------------------------------------------------------
      -- Lossless combinators

      -- | Convert an unsigned bitvector to a real number.
      uintToReal :: (1 <= w) => sym -> SymBV sym w -> IO (SymReal sym)
      uintToReal sym
    sym = sym -> SymExpr sym (BaseBVType w) -> IO (SymInteger sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> IO (SymInteger sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (SymInteger sym)
    bvToInteger sym
    sym (SymExpr sym (BaseBVType w) -> IO (SymInteger sym))
    -> (SymInteger sym -> IO (SymReal sym))
    -> SymExpr sym (BaseBVType w)
    -> IO (SymReal sym)
    forall (m :: Type -> Type) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> sym -> SymInteger sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymReal sym)
    integerToReal sym
    sym

      -- | Convert an signed bitvector to a real number.
      sbvToReal :: (1 <= w) => sym -> SymBV sym w -> IO (SymReal sym)
      sbvToReal sym
    sym = sym -> SymExpr sym (BaseBVType w) -> IO (SymInteger sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> IO (SymInteger sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (SymInteger sym)
    sbvToInteger sym
    sym (SymExpr sym (BaseBVType w) -> IO (SymInteger sym))
    -> (SymInteger sym -> IO (SymReal sym))
    -> SymExpr sym (BaseBVType w)
    -> IO (SymReal sym)
    forall (m :: Type -> Type) a b c.
    Monad m =>
    (a -> m b) -> (b -> m c) -> a -> m c
    >=> sym -> SymInteger sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymReal sym)
    integerToReal sym
    sym

      ----------------------------------------------------------------------
      -- Lossy (non-injective) conversions

      -- | Round a real number to an integer.
      --
      -- Numbers are rounded to the nearest integer, with rounding away from
      -- zero when two integers are equidistant (e.g., 1.5 rounds to 2).
      realRound :: sym -> SymReal sym -> IO (SymInteger sym)

      -- | Round a real number to an integer.
      --
      -- Numbers are rounded to the nearest integer, with rounding toward
      -- even values when two integers are equidistant (e.g., 2.5 rounds to 2).
      realRoundEven :: sym -> SymReal sym -> IO (SymInteger sym)

      -- | Round down to the nearest integer that is at most this value.
      realFloor :: sym -> SymReal sym -> IO (SymInteger sym)

      -- | Round up to the nearest integer that is at least this value.
      realCeil :: sym -> SymReal sym -> IO (SymInteger sym)

      -- | Round toward zero.  This is @floor(x)@ when x is positive
      --   and @celing(x)@ when @x@ is negative.
      realTrunc :: sym -> SymReal sym -> IO (SymInteger sym)
      realTrunc sym
    sym SymReal sym
    x =
        do Pred sym
    pneg <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realLt sym
    sym SymReal sym
    x (SymReal sym -> IO (Pred sym)) -> IO (SymReal sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    0
           (sym
     -> Pred sym
     -> SymInteger sym
     -> SymInteger sym
     -> IO (SymInteger sym))
    -> sym
    -> Pred sym
    -> IO (SymInteger sym)
    -> IO (SymInteger sym)
    -> IO (SymInteger sym)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> Pred sym
    -> SymInteger sym
    -> SymInteger sym
    -> IO (SymInteger sym)
    intIte sym
    sym Pred sym
    pneg (sym -> SymReal sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realCeil sym
    sym SymReal sym
    x) (sym -> SymReal sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realFloor sym
    sym SymReal sym
    x)

      -- | Convert an integer to a bitvector.  The result is the unique bitvector
      --   whose value (signed or unsigned) is congruent to the input integer, modulo @2^w@.
      --
      --   This operation has the following properties:
      --
      --   *  @bvToInteger (integerToBv x w) == mod x (2^w)@
      --   *  @bvToInteger (integerToBV x w) == x@     when @0 <= x < 2^w@.
      --   *  @sbvToInteger (integerToBV x w) == mod (x + 2^(w-1)) (2^w) - 2^(w-1)@
      --   *  @sbvToInteger (integerToBV x w) == x@    when @-2^(w-1) <= x < 2^(w-1)@
      --   *  @integerToBV (bvToInteger y) w == y@     when @y@ is a @SymBV sym w@
      --   *  @integerToBV (sbvToInteger y) w == y@    when @y@ is a @SymBV sym w@
      integerToBV :: (1 <= w) => sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)

      ----------------------------------------------------------------------
      -- Lossy (non-injective) combinators

      -- | Convert a real number to an integer.
      --
      -- The result is undefined if the given real number does not represent an integer.
      realToInteger :: sym -> SymReal sym -> IO (SymInteger sym)

      -- | Convert a real number to an unsigned bitvector.
      --
      -- Numbers are rounded to the nearest representable number, with rounding away from
      -- zero when two integers are equidistant (e.g., 1.5 rounds to 2).
      -- When the real is negative the result is zero.
      realToBV :: (1 <= w) => sym -> SymReal sym -> NatRepr w -> IO (SymBV sym w)
      realToBV sym
    sym SymReal sym
    r NatRepr w
    w = do
        SymInteger sym
    i <- sym -> SymReal sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realRound sym
    sym SymReal sym
    r
        sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    clampedIntToBV sym
    sym SymInteger sym
    i NatRepr w
    w

      -- | Convert a real number to a signed bitvector.
      --
      -- Numbers are rounded to the nearest representable number, with rounding away from
      -- zero when two integers are equidistant (e.g., 1.5 rounds to 2).
      realToSBV  :: (1 <= w) => sym -> SymReal sym -> NatRepr w -> IO (SymBV sym w)
      realToSBV sym
    sym SymReal sym
    r NatRepr w
    w  = do
        SymInteger sym
    i <- sym -> SymReal sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realRound sym
    sym SymReal sym
    r
        sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    clampedIntToSBV sym
    sym SymInteger sym
    i NatRepr w
    w

      -- | Convert an integer to the nearest signed bitvector.
      --
      -- Numbers are rounded to the nearest representable number.
      clampedIntToSBV :: (1 <= w) => sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
      clampedIntToSBV sym
    sym SymInteger sym
    i NatRepr w
    w
        | Just Integer
    v <- SymInteger sym -> Maybe Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> Maybe Integer
    asInteger SymInteger sym
    i = do
          sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (BV w -> IO (SymBV sym w)) -> BV w -> IO (SymBV sym w)
    forall a b. (a -> b) -> a -> b
    $ NatRepr w -> Integer -> BV w
    forall (w :: Nat). (1 <= w) => NatRepr w -> Integer -> BV w
    BV.signedClamp NatRepr w
    w Integer
    v
        | Bool
    otherwise = do
          -- Handle case where i < minSigned w
          let min_val :: Integer
    min_val = NatRepr w -> Integer
    forall (w :: Nat). (1 <= w) => NatRepr w -> Integer
    minSigned NatRepr w
    w
              min_val_bv :: BV w
    min_val_bv = NatRepr w -> BV w
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.minSigned NatRepr w
    w
          SymInteger sym
    min_sym <- sym -> Integer -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    min_val
          Pred sym
    is_lt <- sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLt sym
    sym SymInteger sym
    i SymInteger sym
    min_sym
          (sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w))
    -> sym
    -> Pred sym
    -> IO (SymBV sym w)
    -> IO (SymBV sym w)
    -> IO (SymBV sym w)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    is_lt (sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w BV w
    min_val_bv) (IO (SymBV sym w) -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall a b. (a -> b) -> a -> b
    $ do
            -- Handle case where i > maxSigned w
            let max_val :: Integer
    max_val = NatRepr w -> Integer
    forall (w :: Nat). (1 <= w) => NatRepr w -> Integer
    maxSigned NatRepr w
    w
                max_val_bv :: BV w
    max_val_bv = NatRepr w -> BV w
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.maxSigned NatRepr w
    w
            SymInteger sym
    max_sym <- sym -> Integer -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    max_val
            Pred sym
    is_gt <- sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLt sym
    sym SymInteger sym
    max_sym SymInteger sym
    i
            (sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w))
    -> sym
    -> Pred sym
    -> IO (SymBV sym w)
    -> IO (SymBV sym w)
    -> IO (SymBV sym w)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    is_gt (sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w BV w
    max_val_bv) (IO (SymBV sym w) -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall a b. (a -> b) -> a -> b
    $ do
              -- Do unclamped conversion.
              sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    integerToBV sym
    sym SymInteger sym
    i NatRepr w
    w

      -- | Convert an integer to the nearest unsigned bitvector.
      --
      -- Numbers are rounded to the nearest representable number.
      clampedIntToBV :: (1 <= w) => sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
      clampedIntToBV sym
    sym SymInteger sym
    i NatRepr w
    w
        | Just Integer
    v <- SymInteger sym -> Maybe Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> Maybe Integer
    asInteger SymInteger sym
    i = do
          sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (BV w -> IO (SymBV sym w)) -> BV w -> IO (SymBV sym w)
    forall a b. (a -> b) -> a -> b
    $ NatRepr w -> Integer -> BV w
    forall (w :: Nat). NatRepr w -> Integer -> BV w
    BV.unsignedClamp NatRepr w
    w Integer
    v
        | Bool
    otherwise = do
          -- Handle case where i < 0
          SymInteger sym
    min_sym <- sym -> Integer -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    0
          Pred sym
    is_lt <- sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLt sym
    sym SymInteger sym
    i SymInteger sym
    min_sym
          (sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w))
    -> sym
    -> Pred sym
    -> IO (SymBV sym w)
    -> IO (SymBV sym w)
    -> IO (SymBV sym w)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    is_lt (sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.zero NatRepr w
    w)) (IO (SymBV sym w) -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall a b. (a -> b) -> a -> b
    $ do
            -- Handle case where i > maxUnsigned w
            let max_val :: Integer
    max_val = NatRepr w -> Integer
    forall (n :: Nat). NatRepr n -> Integer
    maxUnsigned NatRepr w
    w
                max_val_bv :: BV w
    max_val_bv = NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.maxUnsigned NatRepr w
    w
            SymInteger sym
    max_sym <- sym -> Integer -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    max_val
            Pred sym
    is_gt <- sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> SymInteger sym -> IO (Pred sym)
    intLt sym
    sym SymInteger sym
    max_sym SymInteger sym
    i
            (sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w))
    -> sym
    -> Pred sym
    -> IO (SymBV sym w)
    -> IO (SymBV sym w)
    -> IO (SymBV sym w)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    is_gt (sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w BV w
    max_val_bv) (IO (SymBV sym w) -> IO (SymBV sym w))
    -> IO (SymBV sym w) -> IO (SymBV sym w)
    forall a b. (a -> b) -> a -> b
    $
              -- Do unclamped conversion.
              sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymInteger sym -> NatRepr w -> IO (SymBV sym w)
    integerToBV sym
    sym SymInteger sym
    i NatRepr w
    w

      ----------------------------------------------------------------------
      -- Bitvector operations.

      -- | Convert a signed bitvector to the nearest signed bitvector with
      -- the given width. If the resulting width is smaller, this clamps
      -- the value to min-int or max-int when necessary.
      intSetWidth :: (1 <= m, 1 <= n) => sym -> SymBV sym m -> NatRepr n -> IO (SymBV sym n)
      intSetWidth sym
    sym SymBV sym m
    e NatRepr n
    n = do
        let m :: NatRepr m
    m = SymBV sym m -> NatRepr m
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym m
    e
        case NatRepr n
    n NatRepr n -> NatRepr m -> NatCases n m
    forall (m :: Nat) (n :: Nat).
    NatRepr m -> NatRepr n -> NatCases m n
    `testNatCases` NatRepr m
    m of
          -- Truncate when the width of e is larger than w.
          NatCaseLT LeqProof (n + 1) m
    LeqProof -> do
            -- Check if e underflows
            Pred sym
    does_underflow <- sym -> SymBV sym m -> SymBV sym m -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvSlt sym
    sym SymBV sym m
    e (SymBV sym m -> IO (Pred sym)) -> IO (SymBV sym m) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> NatRepr m -> BV m -> IO (SymBV sym m)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr m
    m (NatRepr n -> NatRepr m -> BV n -> BV m
    forall (w :: Nat) (w' :: Nat).
    (1 <= w, (w + 1) <= w') =>
    NatRepr w -> NatRepr w' -> BV w -> BV w'
    BV.sext NatRepr n
    n NatRepr m
    m (NatRepr n -> BV n
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.minSigned NatRepr n
    n))
            (sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n))
    -> sym
    -> Pred sym
    -> IO (SymBV sym n)
    -> IO (SymBV sym n)
    -> IO (SymBV sym n)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    does_underflow (sym -> NatRepr n -> BV n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr n
    n (NatRepr n -> BV n
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.minSigned NatRepr n
    n)) (IO (SymBV sym n) -> IO (SymBV sym n))
    -> IO (SymBV sym n) -> IO (SymBV sym n)
    forall a b. (a -> b) -> a -> b
    $ do
              -- Check if e overflows target signed representation.
              Pred sym
    does_overflow <- sym -> SymBV sym m -> SymBV sym m -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvSgt sym
    sym SymBV sym m
    e (SymBV sym m -> IO (Pred sym)) -> IO (SymBV sym m) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> NatRepr m -> BV m -> IO (SymBV sym m)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr m
    m (NatRepr m -> Integer -> BV m
    forall (w :: Nat). NatRepr w -> Integer -> BV w
    BV.mkBV NatRepr m
    m (NatRepr n -> Integer
    forall (w :: Nat). (1 <= w) => NatRepr w -> Integer
    maxSigned NatRepr n
    n))
              (sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n))
    -> sym
    -> Pred sym
    -> IO (SymBV sym n)
    -> IO (SymBV sym n)
    -> IO (SymBV sym n)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    does_overflow (sym -> NatRepr n -> BV n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr n
    n (NatRepr n -> BV n
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.maxSigned NatRepr n
    n)) (IO (SymBV sym n) -> IO (SymBV sym n))
    -> IO (SymBV sym n) -> IO (SymBV sym n)
    forall a b. (a -> b) -> a -> b
    $ do
                -- Just do truncation.
                sym -> NatRepr n -> SymBV sym m -> IO (SymBV sym n)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr n
    n SymBV sym m
    e
          NatCases n m
    NatCaseEQ -> SymBV sym n -> IO (SymBV sym n)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymBV sym m
    SymBV sym n
    e
          NatCaseGT LeqProof (m + 1) n
    LeqProof -> sym -> NatRepr n -> SymBV sym m -> IO (SymBV sym n)
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvSext sym
    sym NatRepr n
    n SymBV sym m
    e

      -- | Convert an unsigned bitvector to the nearest unsigned bitvector with
      -- the given width (clamp on overflow).
      uintSetWidth :: (1 <= m, 1 <= n) => sym -> SymBV sym m -> NatRepr n -> IO (SymBV sym n)
      uintSetWidth sym
    sym SymBV sym m
    e NatRepr n
    n = do
        let m :: NatRepr m
    m = SymBV sym m -> NatRepr m
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym m
    e
        case NatRepr n
    n NatRepr n -> NatRepr m -> NatCases n m
    forall (m :: Nat) (n :: Nat).
    NatRepr m -> NatRepr n -> NatCases m n
    `testNatCases` NatRepr m
    m of
          NatCaseLT LeqProof (n + 1) m
    LeqProof -> do
            Pred sym
    does_overflow <- sym -> SymBV sym m -> SymBV sym m -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUgt sym
    sym SymBV sym m
    e (SymBV sym m -> IO (Pred sym)) -> IO (SymBV sym m) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> NatRepr m -> BV m -> IO (SymBV sym m)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr m
    m (NatRepr m -> Integer -> BV m
    forall (w :: Nat). NatRepr w -> Integer -> BV w
    BV.mkBV NatRepr m
    m (NatRepr n -> Integer
    forall (n :: Nat). NatRepr n -> Integer
    maxUnsigned NatRepr n
    n))
            (sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n))
    -> sym
    -> Pred sym
    -> IO (SymBV sym n)
    -> IO (SymBV sym n)
    -> IO (SymBV sym n)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    does_overflow (sym -> NatRepr n -> BV n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr n
    n (NatRepr n -> BV n
    forall (w :: Nat). NatRepr w -> BV w
    BV.maxUnsigned NatRepr n
    n)) (IO (SymBV sym n) -> IO (SymBV sym n))
    -> IO (SymBV sym n) -> IO (SymBV sym n)
    forall a b. (a -> b) -> a -> b
    $ sym -> NatRepr n -> SymBV sym m -> IO (SymBV sym n)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr n
    n SymBV sym m
    e
          NatCases n m
    NatCaseEQ -> SymBV sym n -> IO (SymBV sym n)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymBV sym m
    SymBV sym n
    e
          NatCaseGT LeqProof (m + 1) n
    LeqProof -> sym -> NatRepr n -> SymBV sym m -> IO (SymBV sym n)
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvZext sym
    sym NatRepr n
    n SymBV sym m
    e

      -- | Convert an signed bitvector to the nearest unsigned bitvector with
      -- the given width (clamp on overflow).
      intToUInt :: (1 <= m, 1 <= n) => sym -> SymBV sym m -> NatRepr n -> IO (SymBV sym n)
      intToUInt sym
    sym SymBV sym m
    e NatRepr n
    w = do
        Pred sym
    p <- sym -> SymBV sym m -> IO (Pred sym)
    forall (w :: Nat). (1 <= w) => sym -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> IO (Pred sym)
    bvIsNeg sym
    sym SymBV sym m
    e
        (sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n))
    -> sym
    -> Pred sym
    -> IO (SymBV sym n)
    -> IO (SymBV sym n)
    -> IO (SymBV sym n)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    p (sym -> NatRepr n -> BV n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr n
    w (NatRepr n -> BV n
    forall (w :: Nat). NatRepr w -> BV w
    BV.zero NatRepr n
    w)) (sym -> SymBV sym m -> NatRepr n -> IO (SymBV sym n)
    forall (m :: Nat) (n :: Nat).
    (1 <= m, 1 <= n) =>
    sym -> SymBV sym m -> NatRepr n -> IO (SymBV sym n)
    forall sym (m :: Nat) (n :: Nat).
    (IsExprBuilder sym, 1 <= m, 1 <= n) =>
    sym -> SymBV sym m -> NatRepr n -> IO (SymBV sym n)
    uintSetWidth sym
    sym SymBV sym m
    e NatRepr n
    w)

      -- | Convert an unsigned bitvector to the nearest signed bitvector with
      -- the given width (clamp on overflow).
      uintToInt :: (1 <= m, 1 <= n) => sym -> SymBV sym m -> NatRepr n -> IO (SymBV sym n)
      uintToInt sym
    sym SymBV sym m
    e NatRepr n
    n = do
        let m :: NatRepr m
    m = SymBV sym m -> NatRepr m
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym m
    e
        case NatRepr n
    n NatRepr n -> NatRepr m -> NatCases n m
    forall (m :: Nat) (n :: Nat).
    NatRepr m -> NatRepr n -> NatCases m n
    `testNatCases` NatRepr m
    m of
          NatCaseLT LeqProof (n + 1) m
    LeqProof -> do
            -- Get maximum signed n-bit number.
            SymBV sym m
    max_val <- sym -> NatRepr m -> BV m -> IO (SymBV sym m)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr m
    m (NatRepr n -> NatRepr m -> BV n -> BV m
    forall (w :: Nat) (w' :: Nat).
    (1 <= w, (w + 1) <= w') =>
    NatRepr w -> NatRepr w' -> BV w -> BV w'
    BV.sext NatRepr n
    n NatRepr m
    m (NatRepr n -> BV n
    forall (w :: Nat). (1 <= w) => NatRepr w -> BV w
    BV.maxSigned NatRepr n
    n))
            -- Check if expression is less than maximum.
            Pred sym
    p <- sym -> SymBV sym m -> SymBV sym m -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUle sym
    sym SymBV sym m
    e SymBV sym m
    max_val
            -- Select appropriate number then truncate.
            sym -> NatRepr n -> SymBV sym m -> IO (SymBV sym n)
    forall (r :: Nat) (w :: Nat).
    (1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    forall sym (r :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= r, (r + 1) <= w) =>
    sym -> NatRepr r -> SymBV sym w -> IO (SymBV sym r)
    bvTrunc sym
    sym NatRepr n
    n (SymBV sym m -> IO (SymBV sym n))
    -> IO (SymBV sym m) -> IO (SymBV sym n)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Pred sym -> SymBV sym m -> SymBV sym m -> IO (SymBV sym m)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    p SymBV sym m
    e SymBV sym m
    max_val
          NatCases n m
    NatCaseEQ -> do
            SymBV sym n
    max_val <- sym -> NatRepr n -> IO (SymBV sym n)
    forall (w :: Nat). (1 <= w) => sym -> NatRepr w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> IO (SymBV sym w)
    maxSignedBV sym
    sym NatRepr n
    n
            Pred sym
    p <- sym -> SymBV sym n -> SymBV sym n -> IO (Pred sym)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> SymBV sym w -> SymBV sym w -> IO (Pred sym)
    bvUle sym
    sym SymBV sym m
    SymBV sym n
    e SymBV sym n
    max_val
            sym -> Pred sym -> SymBV sym n -> SymBV sym n -> IO (SymBV sym n)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> Pred sym -> SymBV sym w -> SymBV sym w -> IO (SymBV sym w)
    bvIte sym
    sym Pred sym
    p SymBV sym m
    SymBV sym n
    e SymBV sym n
    max_val
          NatCaseGT LeqProof (m + 1) n
    LeqProof -> do
            sym -> NatRepr n -> SymBV sym m -> IO (SymBV sym n)
    forall (u :: Nat) (r :: Nat).
    (1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    forall sym (u :: Nat) (r :: Nat).
    (IsExprBuilder sym, 1 <= u, (u + 1) <= r) =>
    sym -> NatRepr r -> SymBV sym u -> IO (SymBV sym r)
    bvZext sym
    sym NatRepr n
    n SymBV sym m
    e

      ----------------------------------------------------------------------
      -- String operations

      -- | Create an empty string literal
      stringEmpty :: sym -> StringInfoRepr si -> IO (SymString sym si)

      -- | Create a concrete string literal
      stringLit :: sym -> StringLiteral si -> IO (SymString sym si)

      -- | Check the equality of two strings
      stringEq :: sym -> SymString sym si -> SymString sym si -> IO (Pred sym)

      -- | If-then-else on strings
      stringIte :: sym -> Pred sym -> SymString sym si -> SymString sym si -> IO (SymString sym si)

      -- | Concatenate two strings
      stringConcat :: sym -> SymString sym si -> SymString sym si -> IO (SymString sym si)

      -- | Test if the first string contains the second string as a substring
      stringContains ::
        sym ->
        SymString sym si {- ^ string to test -} ->
        SymString sym si {- ^ substring to look for -} ->
        IO (Pred sym)

      -- | Test if the first string is a prefix of the second string
      stringIsPrefixOf ::
        sym ->
        SymString sym si {- ^ prefix string -} ->
        SymString sym si {- ^ string to test -} ->
        IO (Pred sym)

      -- | Test if the first string is a suffix of the second string
      stringIsSuffixOf ::
        sym ->
        SymString sym si {- ^ suffix string -} ->
        SymString sym si {- ^ string to test -} ->
        IO (Pred sym)

      -- | Return the first position at which the second string can be found as a substring
      --   in the first string, starting from the given index.
      --   If no such position exists, return a negative value.
      --   If the given index is out of bounds for the string, return a negative value.
      stringIndexOf ::
        sym ->
        SymString sym si {- ^ string to search in -} ->
        SymString sym si {- ^ substring to search for -} ->
        SymInteger sym   {- ^ starting index for search -} ->
        IO (SymInteger sym)

      -- | Compute the length of a string
      stringLength :: sym -> SymString sym si -> IO (SymInteger sym)

      -- | @stringSubstring s off len@ evaluates to the longest substring
      --   of @s@ of length at most @len@ starting at position @off@.
      --   It evaluates to the empty string if @len@ is negative or @off@ is not in
      --   the interval @[0,l-1]@ where @l@ is the length of @s@.
      stringSubstring ::
        sym ->
        SymString sym si {- ^ string to select a substring from -} ->
        SymInteger sym   {- ^ offset of the beginning of the substring -} ->
        SymInteger sym   {- ^ length of the substring -} ->
        IO (SymString sym si)

      ----------------------------------------------------------------------
      -- Real operations

      -- | Return real number 0.
      realZero :: sym -> SymReal sym

      -- | Create a constant real literal.
      realLit :: sym -> Rational -> IO (SymReal sym)

      -- | Make a real literal from a scientific value. May be overridden
      -- if we want to avoid the overhead of converting scientific value
      -- to rational.
      sciLit :: sym -> Scientific -> IO (SymReal sym)
      sciLit sym
    sym Scientific
    s = sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym (Scientific -> Rational
    forall a. Real a => a -> Rational
    toRational Scientific
    s)

      -- | Check equality of two real numbers.
      realEq :: sym -> SymReal sym -> SymReal sym -> IO (Pred sym)

      -- | Check non-equality of two real numbers.
      realNe :: sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
      realNe sym
    sym SymReal sym
    x SymReal sym
    y = sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realEq sym
    sym SymReal sym
    x SymReal sym
    y

      -- | Check @<=@ on two real numbers.
      realLe :: sym -> SymReal sym -> SymReal sym -> IO (Pred sym)

      -- | Check @<@ on two real numbers.
      realLt :: sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
      realLt sym
    sym SymReal sym
    x SymReal sym
    y = sym -> Pred sym -> IO (Pred sym)
    forall sym. IsExprBuilder sym => sym -> Pred sym -> IO (Pred sym)
    notPred sym
    sym (Pred sym -> IO (Pred sym)) -> IO (Pred sym) -> IO (Pred sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realLe sym
    sym SymReal sym
    y SymReal sym
    x

      -- | Check @>=@ on two real numbers.
      realGe :: sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
      realGe sym
    sym SymReal sym
    x SymReal sym
    y = sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realLe sym
    sym SymReal sym
    y SymReal sym
    x

      -- | Check @>@ on two real numbers.
      realGt :: sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
      realGt sym
    sym SymReal sym
    x SymReal sym
    y = sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realLt sym
    sym SymReal sym
    y SymReal sym
    x

      -- | If-then-else on real numbers.
      realIte :: sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)

      -- | Return the minimum of two real numbers.
      realMin :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
      realMin sym
    sym SymReal sym
    x SymReal sym
    y =
        do Pred sym
    p <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realLe sym
    sym SymReal sym
    x SymReal sym
    y
           sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    p SymReal sym
    x SymReal sym
    y

      -- | Return the maxmimum of two real numbers.
      realMax :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
      realMax sym
    sym SymReal sym
    x SymReal sym
    y =
        do Pred sym
    p <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realLe sym
    sym SymReal sym
    x SymReal sym
    y
           sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    p SymReal sym
    y SymReal sym
    x

      -- | Negate a real number.
      realNeg :: sym -> SymReal sym -> IO (SymReal sym)

      -- | Add two real numbers.
      realAdd :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)

      -- | Multiply two real numbers.
      realMul :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)

      -- | Subtract one real from another.
      realSub :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
      realSub sym
    sym SymReal sym
    x SymReal sym
    y = sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymReal sym
    x (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realNeg sym
    sym SymReal sym
    y

      -- | @realSq sym x@ returns @x * x@.
      realSq :: sym -> SymReal sym -> IO (SymReal sym)
      realSq sym
    sym SymReal sym
    x = sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    x SymReal sym
    x

      -- | @realDiv sym x y@ returns term equivalent to @x/y@.
      --
      -- The result is undefined when @y@ is zero.
      realDiv :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)

      -- | @realMod x y@ returns the value of @x - y * floor(x / y)@ when
      -- @y@ is not zero and @x@ when @y@ is zero.
      realMod :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
      realMod sym
    sym SymReal sym
    x SymReal sym
    y = do
        Pred sym
    isZero <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realEq sym
    sym SymReal sym
    y (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym)
        (sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym))
    -> sym
    -> Pred sym
    -> IO (SymReal sym)
    -> IO (SymReal sym)
    -> IO (SymReal sym)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    isZero (SymReal sym -> IO (SymReal sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymReal sym
    x) (IO (SymReal sym) -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall a b. (a -> b) -> a -> b
    $ do
          sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realSub sym
    sym SymReal sym
    x (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    y
                        (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymInteger sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymReal sym)
    integerToReal sym
    sym
                        (SymInteger sym -> IO (SymReal sym))
    -> IO (SymInteger sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realFloor sym
    sym
                        (SymReal sym -> IO (SymInteger sym))
    -> IO (SymReal sym) -> IO (SymInteger sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymReal sym
    x SymReal sym
    y

      -- | Predicate that holds if the real number is an exact integer.
      isInteger :: sym -> SymReal sym -> IO (Pred sym)

      -- | Return true if the real is non-negative.
      realIsNonNeg :: sym -> SymReal sym -> IO (Pred sym)
      realIsNonNeg sym
    sym SymReal sym
    x = sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realLe sym
    sym (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym) SymReal sym
    x

      -- | @realSqrt sym x@ returns sqrt(x).  Result is undefined
      -- if @x@ is negative.
      realSqrt :: sym -> SymReal sym -> IO (SymReal sym)

      -- | Return value denoting pi.
      realPi :: sym -> IO (SymReal sym)
      realPi sym
    sym = sym -> SpecialFunction EmptyCtx -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SpecialFunction EmptyCtx -> IO (SymReal sym)
    realSpecialFunction0 sym
    sym SpecialFunction EmptyCtx
    Pi

      -- | Natural logarithm.  @realLog x@ is undefined
      --   for @x <= 0@.
      realLog :: sym -> SymReal sym -> IO (SymReal sym)
      realLog sym
    sym SymReal sym
    x = sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    Log SymReal sym
    x

      -- | Natural exponentiation
      realExp :: sym -> SymReal sym -> IO (SymReal sym)
      realExp sym
    sym SymReal sym
    x = sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    Exp SymReal sym
    x

      -- | Sine trig function
      realSin :: sym -> SymReal sym -> IO (SymReal sym)
      realSin sym
    sym SymReal sym
    x = sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    Sin SymReal sym
    x

      -- | Cosine trig function
      realCos :: sym -> SymReal sym -> IO (SymReal sym)
      realCos sym
    sym SymReal sym
    x = sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    Cos SymReal sym
    x

      -- | Tangent trig function.  @realTan x@ is undefined
      --   when @cos x = 0@,  i.e., when @x = pi/2 + k*pi@ for
      --   some integer @k@.
      realTan :: sym -> SymReal sym -> IO (SymReal sym)
      realTan sym
    sym SymReal sym
    x = sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    Tan SymReal sym
    x

      -- | Hyperbolic sine
      realSinh :: sym -> SymReal sym -> IO (SymReal sym)
      realSinh sym
    sym SymReal sym
    x = sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    Sinh SymReal sym
    x

      -- | Hyperbolic cosine
      realCosh :: sym -> SymReal sym -> IO (SymReal sym)
      realCosh sym
    sym SymReal sym
    x = sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    Cosh SymReal sym
    x

      -- | Hyperbolic tangent
      realTanh :: sym -> SymReal sym -> IO (SymReal sym)
      realTanh sym
    sym SymReal sym
    x = sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    Tanh SymReal sym
    x

      -- | Return absolute value of the real number.
      realAbs :: sym -> SymReal sym -> IO (SymReal sym)
      realAbs sym
    sym SymReal sym
    x = do
        Pred sym
    c <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realGe sym
    sym SymReal sym
    x (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym)
        sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    c SymReal sym
    x (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realNeg sym
    sym SymReal sym
    x

      -- | @realHypot x y@ returns sqrt(x^2 + y^2).
      realHypot :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
      realHypot sym
    sym SymReal sym
    x SymReal sym
    y = do
        case (SymReal sym -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational SymReal sym
    x, SymReal sym -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational SymReal sym
    y) of
          (Just Rational
    0, Maybe Rational
    _) -> sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realAbs sym
    sym SymReal sym
    y
          (Maybe Rational
    _, Just Rational
    0) -> sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realAbs sym
    sym SymReal sym
    x
          (Maybe Rational, Maybe Rational)
    _ -> do
            SymReal sym
    x2 <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSq sym
    sym SymReal sym
    x
            SymReal sym
    y2 <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSq sym
    sym SymReal sym
    y
            sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSqrt sym
    sym (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymReal sym
    x2 SymReal sym
    y2

      -- | @realAtan2 sym y x@ returns the arctangent of @y/x@ with a range
      -- of @-pi@ to @pi@; this corresponds to the angle between the positive
      -- x-axis and the line from the origin @(x,y)@.
      --
      -- When @x@ is @0@ this returns @pi/2 * sgn y@.
      --
      -- When @x@ and @y@ are both zero, this function is undefined.
      realAtan2 :: sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
      realAtan2 sym
    sym SymReal sym
    y SymReal sym
    x = sym
    -> SpecialFunction ((EmptyCtx ::> R) ::> R)
    -> SymReal sym
    -> SymReal sym
    -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym
    -> SpecialFunction ((EmptyCtx ::> R) ::> R)
    -> SymReal sym
    -> SymReal sym
    -> IO (SymReal sym)
    realSpecialFunction2 sym
    sym SpecialFunction ((EmptyCtx ::> R) ::> R)
    Arctan2 SymReal sym
    y SymReal sym
    x

      -- | Apply a special function to real arguments
      realSpecialFunction
        :: sym
        -> SpecialFunction args
        -> Ctx.Assignment (SpecialFnArg (SymExpr sym) BaseRealType) args
        -> IO (SymReal sym)

      -- | Access a 0-arity special function constant
      realSpecialFunction0
        :: sym
        -> SpecialFunction EmptyCtx
        -> IO (SymReal sym)
      realSpecialFunction0 sym
    sym SpecialFunction EmptyCtx
    fn =
        sym
    -> SpecialFunction EmptyCtx
    -> Assignment (SpecialFnArg (SymExpr sym) BaseRealType) EmptyCtx
    -> IO (SymReal sym)
    forall sym (args :: Ctx Type).
    IsExprBuilder sym =>
    sym
    -> SpecialFunction args
    -> Assignment (SpecialFnArg (SymExpr sym) BaseRealType) args
    -> IO (SymReal sym)
    forall (args :: Ctx Type).
    sym
    -> SpecialFunction args
    -> Assignment (SpecialFnArg (SymExpr sym) BaseRealType) args
    -> IO (SymReal sym)
    realSpecialFunction sym
    sym SpecialFunction EmptyCtx
    fn Assignment (SpecialFnArg (SymExpr sym) BaseRealType) EmptyCtx
    forall {k} (ctx :: Ctx k) (f :: k -> Type).
    (ctx ~ EmptyCtx) =>
    Assignment f ctx
    Ctx.Empty

      -- | Apply a 1-argument special function
      realSpecialFunction1
        :: sym
        -> SpecialFunction (EmptyCtx ::> R)
        -> SymReal sym
        -> IO (SymReal sym)
      realSpecialFunction1 sym
    sym SpecialFunction (EmptyCtx ::> R)
    fn SymReal sym
    x =
        sym
    -> SpecialFunction (EmptyCtx ::> R)
    -> Assignment
         (SpecialFnArg (SymExpr sym) BaseRealType) (EmptyCtx ::> R)
    -> IO (SymReal sym)
    forall sym (args :: Ctx Type).
    IsExprBuilder sym =>
    sym
    -> SpecialFunction args
    -> Assignment (SpecialFnArg (SymExpr sym) BaseRealType) args
    -> IO (SymReal sym)
    forall (args :: Ctx Type).
    sym
    -> SpecialFunction args
    -> Assignment (SpecialFnArg (SymExpr sym) BaseRealType) args
    -> IO (SymReal sym)
    realSpecialFunction sym
    sym SpecialFunction (EmptyCtx ::> R)
    fn (Assignment (SpecialFnArg (SymExpr sym) BaseRealType) EmptyCtx
    forall {k} (ctx :: Ctx k) (f :: k -> Type).
    (ctx ~ EmptyCtx) =>
    Assignment f ctx
    Ctx.Empty Assignment (SpecialFnArg (SymExpr sym) BaseRealType) EmptyCtx
    -> SpecialFnArg (SymExpr sym) BaseRealType R
    -> Assignment
         (SpecialFnArg (SymExpr sym) BaseRealType) (EmptyCtx ::> R)
    forall {k} (ctx' :: Ctx k) (f :: k -> Type) (ctx :: Ctx k)
           (tp :: k).
    (ctx' ~ (ctx ::> tp)) =>
    Assignment f ctx -> f tp -> Assignment f ctx'
    Ctx.:> SymReal sym -> SpecialFnArg (SymExpr sym) BaseRealType R
    forall {k} (e :: k -> Type) (tp :: k). e tp -> SpecialFnArg e tp R
    SpecialFnArg SymReal sym
    x)

      -- | Apply a 2-argument special function
      realSpecialFunction2
        :: sym
        -> SpecialFunction (EmptyCtx ::> R ::> R)
        -> SymReal sym
        -> SymReal sym
        -> IO (SymReal sym)
      realSpecialFunction2 sym
    sym SpecialFunction ((EmptyCtx ::> R) ::> R)
    fn SymReal sym
    x SymReal sym
    y =
        sym
    -> SpecialFunction ((EmptyCtx ::> R) ::> R)
    -> Assignment
         (SpecialFnArg (SymExpr sym) BaseRealType) ((EmptyCtx ::> R) ::> R)
    -> IO (SymReal sym)
    forall sym (args :: Ctx Type).
    IsExprBuilder sym =>
    sym
    -> SpecialFunction args
    -> Assignment (SpecialFnArg (SymExpr sym) BaseRealType) args
    -> IO (SymReal sym)
    forall (args :: Ctx Type).
    sym
    -> SpecialFunction args
    -> Assignment (SpecialFnArg (SymExpr sym) BaseRealType) args
    -> IO (SymReal sym)
    realSpecialFunction sym
    sym SpecialFunction ((EmptyCtx ::> R) ::> R)
    fn (Assignment (SpecialFnArg (SymExpr sym) BaseRealType) EmptyCtx
    forall {k} (ctx :: Ctx k) (f :: k -> Type).
    (ctx ~ EmptyCtx) =>
    Assignment f ctx
    Ctx.Empty Assignment (SpecialFnArg (SymExpr sym) BaseRealType) EmptyCtx
    -> SpecialFnArg (SymExpr sym) BaseRealType R
    -> Assignment
         (SpecialFnArg (SymExpr sym) BaseRealType) (EmptyCtx ::> R)
    forall {k} (ctx' :: Ctx k) (f :: k -> Type) (ctx :: Ctx k)
           (tp :: k).
    (ctx' ~ (ctx ::> tp)) =>
    Assignment f ctx -> f tp -> Assignment f ctx'
    Ctx.:> SymReal sym -> SpecialFnArg (SymExpr sym) BaseRealType R
    forall {k} (e :: k -> Type) (tp :: k). e tp -> SpecialFnArg e tp R
    SpecialFnArg SymReal sym
    x Assignment
      (SpecialFnArg (SymExpr sym) BaseRealType) (EmptyCtx ::> R)
    -> SpecialFnArg (SymExpr sym) BaseRealType R
    -> Assignment
         (SpecialFnArg (SymExpr sym) BaseRealType) ((EmptyCtx ::> R) ::> R)
    forall {k} (ctx' :: Ctx k) (f :: k -> Type) (ctx :: Ctx k)
           (tp :: k).
    (ctx' ~ (ctx ::> tp)) =>
    Assignment f ctx -> f tp -> Assignment f ctx'
    Ctx.:> SymReal sym -> SpecialFnArg (SymExpr sym) BaseRealType R
    forall {k} (e :: k -> Type) (tp :: k). e tp -> SpecialFnArg e tp R
    SpecialFnArg SymReal sym
    y)

      ----------------------------------------------------------------------
      -- IEEE-754 floating-point operations
      -- | Return floating point number @+0@.
      floatPZero :: sym -> FloatPrecisionRepr fpp -> IO (SymFloat sym fpp)

      -- | Return floating point number @-0@.
      floatNZero :: sym -> FloatPrecisionRepr fpp -> IO (SymFloat sym fpp)

      -- |  Return floating point NaN.
      floatNaN :: sym -> FloatPrecisionRepr fpp -> IO (SymFloat sym fpp)

      -- | Return floating point @+infinity@.
      floatPInf :: sym -> FloatPrecisionRepr fpp -> IO (SymFloat sym fpp)

      -- | Return floating point @-infinity@.
      floatNInf :: sym -> FloatPrecisionRepr fpp -> IO (SymFloat sym fpp)

      -- | Create a floating point literal from a rational literal.
      --   The rational value will be rounded if necessary using the
      --   "round to nearest even" rounding mode.
      floatLitRational
        :: sym -> FloatPrecisionRepr fpp -> Rational -> IO (SymFloat sym fpp)
      floatLitRational sym
    sym FloatPrecisionRepr fpp
    fpp Rational
    x = sym
    -> FloatPrecisionRepr fpp
    -> RoundingMode
    -> SymReal sym
    -> IO (SymExpr sym (BaseFloatType fpp))
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym
    -> FloatPrecisionRepr fpp
    -> RoundingMode
    -> SymReal sym
    -> IO (SymFloat sym fpp)
    forall (fpp :: FloatPrecision).
    sym
    -> FloatPrecisionRepr fpp
    -> RoundingMode
    -> SymReal sym
    -> IO (SymFloat sym fpp)
    realToFloat sym
    sym FloatPrecisionRepr fpp
    fpp RoundingMode
    RNE (SymReal sym -> IO (SymExpr sym (BaseFloatType fpp)))
    -> IO (SymReal sym) -> IO (SymExpr sym (BaseFloatType fpp))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    x

      -- | Create a floating point literal from a @BigFloat@ value.
      floatLit :: sym -> FloatPrecisionRepr fpp -> BigFloat -> IO (SymFloat sym fpp)

      -- | Negate a floating point number.
      floatNeg
        :: sym
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Return the absolute value of a floating point number.
      floatAbs
        :: sym
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Compute the square root of a floating point number.
      floatSqrt
        :: sym
        -> RoundingMode
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Add two floating point numbers.
      floatAdd
        :: sym
        -> RoundingMode
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Subtract two floating point numbers.
      floatSub
        :: sym
        -> RoundingMode
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Multiply two floating point numbers.
      floatMul
        :: sym
        -> RoundingMode
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Divide two floating point numbers.
      floatDiv
        :: sym
        -> RoundingMode
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Compute the reminder: @x - y * n@, where @n@ in Z is nearest to @x / y@
      --   (breaking ties to even values of @n@).
      floatRem
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Return the minimum of two floating point numbers.
      --   If one argument is NaN, return the other argument.
      --   If the arguments are equal when compared as floating-point values,
      --   one of the two will be returned, but it is unspecified which;
      --   this underspecification can (only) be observed with zeros of different signs.
      floatMin
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Return the maximum of two floating point numbers.
      --   If one argument is NaN, return the other argument.
      --   If the arguments are equal when compared as floating-point values,
      --   one of the two will be returned, but it is unspecified which;
      --   this underspecification can (only) be observed with zeros of different signs.
      floatMax
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Compute the fused multiplication and addition: @(x * y) + z@.
      floatFMA
        :: sym
        -> RoundingMode
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Check logical equality of two floating point numbers.
      --
      --   NOTE! This does NOT accurately represent the equality test on floating point
      --   values typically found in programming languages.  See 'floatFpEq' instead.
      floatEq
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)

      -- | Check logical non-equality of two floating point numbers.
      --
      --   NOTE! This does NOT accurately represent the non-equality test on floating point
      --   values typically found in programming languages.  See 'floatFpEq' instead.
      floatNe
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)

      -- | Check IEEE-754 equality of two floating point numbers.
      --
      --   NOTE! This test returns false if either value is @NaN@; in particular
      --   @NaN@ is not equal to itself!  Moreover, positive and negative 0 will
      --   compare equal, despite having different bit patterns.
      --
      --   This test is most appropriate for interpreting the equality tests of
      --   typical languages using floating point.  Moreover, not-equal tests
      --   are usually the negation of this test, rather than the `floatFpNe`
      --   test below.
      floatFpEq
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)

      -- | Check IEEE-754 apartness of two floating point numbers.
      --
      --   NOTE! This test returns false if either value is @NaN@; in particular
      --   @NaN@ is not apart from any other value!  Moreover, positive and
      --   negative 0 will not compare apart, despite having different
      --   bit patterns.  Note that @x@ is apart from @y@ iff @x < y@ or @x > y@.
      --
      --   This test usually does NOT correspond to the not-equal tests found
      --   in programming languages.  Instead, one generally takes the logical
      --   negation of the `floatFpEq` test.
      floatFpApart
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)
      floatFpApart sym
    sym SymFloat sym fpp
    x SymFloat sym fpp
    y =
        do Pred sym
    l <- sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    forall (fpp :: FloatPrecision).
    sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    floatLt sym
    sym SymFloat sym fpp
    x SymFloat sym fpp
    y
           Pred sym
    g <- sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    forall (fpp :: FloatPrecision).
    sym -> SymFloat sym fpp -> SymFloat sym fpp -> IO (Pred sym)
    floatGt sym
    sym SymFloat sym fpp
    x SymFloat sym fpp
    y
           sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    orPred sym
    sym Pred sym
    l Pred sym
    g

      -- | Check if two floating point numbers are "unordered".  This happens
      --   precicely when one or both of the inputs is @NaN@.
      floatFpUnordered
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)
      floatFpUnordered sym
    sym SymFloat sym fpp
    x SymFloat sym fpp
    y =
        do Pred sym
    xnan <- sym -> SymFloat sym fpp -> IO (Pred sym)
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym -> SymFloat sym fpp -> IO (Pred sym)
    forall (fpp :: FloatPrecision).
    sym -> SymFloat sym fpp -> IO (Pred sym)
    floatIsNaN sym
    sym SymFloat sym fpp
    x
           Pred sym
    ynan <- sym -> SymFloat sym fpp -> IO (Pred sym)
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym -> SymFloat sym fpp -> IO (Pred sym)
    forall (fpp :: FloatPrecision).
    sym -> SymFloat sym fpp -> IO (Pred sym)
    floatIsNaN sym
    sym SymFloat sym fpp
    y
           sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    orPred sym
    sym Pred sym
    xnan Pred sym
    ynan

      -- | Check IEEE-754 @<=@ on two floating point numbers.
      --
      --   NOTE! This test returns false if either value is @NaN@; in particular
      --   @NaN@ is not less-than-or-equal-to any other value!  Moreover, positive
      --   and negative 0 are considered equal, despite having different bit patterns.
      floatLe
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)

      -- | Check IEEE-754 @<@ on two floating point numbers.
      --
      --   NOTE! This test returns false if either value is @NaN@; in particular
      --   @NaN@ is not less-than any other value! Moreover, positive
      --   and negative 0 are considered equal, despite having different bit patterns.
      floatLt
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)

      -- | Check IEEE-754 @>=@ on two floating point numbers.
      --
      --   NOTE! This test returns false if either value is @NaN@; in particular
      --   @NaN@ is not greater-than-or-equal-to any other value!  Moreover, positive
      --   and negative 0 are considered equal, despite having different bit patterns.
      floatGe
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)

      -- | Check IEEE-754 @>@ on two floating point numbers.
      --
      --   NOTE! This test returns false if either value is @NaN@; in particular
      --   @NaN@ is not greater-than any other value! Moreover, positive
      --   and negative 0 are considered equal, despite having different bit patterns.
      floatGt
        :: sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (Pred sym)

      -- | Test if a floating-point value is NaN.
      floatIsNaN :: sym -> SymFloat sym fpp -> IO (Pred sym)

      -- | Test if a floating-point value is (positive or negative) infinity.
      floatIsInf :: sym -> SymFloat sym fpp -> IO (Pred sym)

      -- | Test if a floating-point value is (positive or negative) zero.
      floatIsZero :: sym -> SymFloat sym fpp -> IO (Pred sym)

      -- | Test if a floating-point value is positive.  NOTE!
      --   NaN is considered neither positive nor negative.
      floatIsPos :: sym -> SymFloat sym fpp -> IO (Pred sym)

      -- | Test if a floating-point value is negative.  NOTE!
      --   NaN is considered neither positive nor negative.
      floatIsNeg :: sym -> SymFloat sym fpp -> IO (Pred sym)

      -- | Test if a floating-point value is subnormal.
      floatIsSubnorm :: sym -> SymFloat sym fpp -> IO (Pred sym)

      -- | Test if a floating-point value is normal.
      floatIsNorm :: sym -> SymFloat sym fpp -> IO (Pred sym)

      -- | If-then-else on floating point numbers.
      floatIte
        :: sym
        -> Pred sym
        -> SymFloat sym fpp
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)

      -- | Change the precision of a floating point number.
      floatCast
        :: sym
        -> FloatPrecisionRepr fpp
        -> RoundingMode
        -> SymFloat sym fpp'
        -> IO (SymFloat sym fpp)
      -- | Round a floating point number to an integral value.
      floatRound
        :: sym
        -> RoundingMode
        -> SymFloat sym fpp
        -> IO (SymFloat sym fpp)
      -- | Convert from binary representation in IEEE 754-2008 format to
      --   floating point.
      floatFromBinary
        :: (2 <= eb, 2 <= sb)
        => sym
        -> FloatPrecisionRepr (FloatingPointPrecision eb sb)
        -> SymBV sym (eb + sb)
        -> IO (SymFloat sym (FloatingPointPrecision eb sb))
      -- | Convert from floating point from to the binary representation in
      --   IEEE 754-2008 format.
      --
      --   NOTE! @NaN@ has multiple representations, i.e. all bit patterns where
      --   the exponent is @0b1..1@ and the significant is not @0b0..0@.
      --   This functions returns the representation of positive "quiet" @NaN@,
      --   i.e. the bit pattern where the sign is @0b0@, the exponent is @0b1..1@,
      --   and the significant is @0b10..0@.
      floatToBinary
        :: (2 <= eb, 2 <= sb)
        => sym
        -> SymFloat sym (FloatingPointPrecision eb sb)
        -> IO (SymBV sym (eb + sb))
      -- | Convert a unsigned bitvector to a floating point number.
      bvToFloat
        :: (1 <= w)
        => sym
        -> FloatPrecisionRepr fpp
        -> RoundingMode
        -> SymBV sym w
        -> IO (SymFloat sym fpp)
      -- | Convert a signed bitvector to a floating point number.
      sbvToFloat
        :: (1 <= w)
        => sym
        -> FloatPrecisionRepr fpp
        -> RoundingMode
        -> SymBV sym w
        -> IO (SymFloat sym fpp)
      -- | Convert a real number to a floating point number.
      realToFloat
        :: sym
        -> FloatPrecisionRepr fpp
        -> RoundingMode
        -> SymReal sym
        -> IO (SymFloat sym fpp)
      -- | Convert a floating point number to a unsigned bitvector.
      floatToBV
        :: (1 <= w)
        => sym
        -> NatRepr w
        -> RoundingMode
        -> SymFloat sym fpp
        -> IO (SymBV sym w)
      -- | Convert a floating point number to a signed bitvector.
      floatToSBV
        :: (1 <= w)
        => sym
        -> NatRepr w
        -> RoundingMode
        -> SymFloat sym fpp
        -> IO (SymBV sym w)
      -- | Convert a floating point number to a real number.
      floatToReal :: sym -> SymFloat sym fpp -> IO (SymReal sym)

      -- | Apply a special function to floating-point arguments
      floatSpecialFunction
        :: sym
        -> FloatPrecisionRepr fpp
        -> SpecialFunction args
        -> Ctx.Assignment (SpecialFnArg (SymExpr sym) (BaseFloatType fpp)) args
        -> IO (SymFloat sym fpp)

      ----------------------------------------------------------------------
      -- Cplx operations

      -- | Create a complex from cartesian coordinates.
      mkComplex :: sym -> Complex (SymReal sym) -> IO (SymCplx sym)

      -- | @getRealPart x@ returns the real part of @x@.
      getRealPart :: sym -> SymCplx sym -> IO (SymReal sym)

      -- | @getImagPart x@ returns the imaginary part of @x@.
      getImagPart :: sym -> SymCplx sym -> IO (SymReal sym)

      -- | Convert a complex number into the real and imaginary part.
      cplxGetParts :: sym -> SymCplx sym -> IO (Complex (SymReal sym))

      -- | Create a constant complex literal.
      mkComplexLit :: sym -> Complex Rational -> IO (SymCplx sym)
      mkComplexLit sym
    sym Complex Rational
    d = sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (Complex (SymReal sym) -> IO (SymCplx sym))
    -> IO (Complex (SymReal sym)) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (Rational -> IO (SymReal sym))
    -> Complex Rational -> IO (Complex (SymReal sym))
    forall (t :: Type -> Type) (f :: Type -> Type) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: Type -> Type) a b.
    Applicative f =>
    (a -> f b) -> Complex a -> f (Complex b)
    traverse (sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym) Complex Rational
    d

      -- | Create a complex from a real value.
      cplxFromReal :: sym -> SymReal sym -> IO (SymCplx sym)
      cplxFromReal sym
    sym SymReal sym
    r = sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    r SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym)

      -- | If-then-else on complex values.
      cplxIte :: sym -> Pred sym -> SymCplx sym -> SymCplx sym -> IO (SymCplx sym)
      cplxIte sym
    sym Pred sym
    c SymCplx sym
    x SymCplx sym
    y = do
        case Pred sym -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred Pred sym
    c of
          Just Bool
    True -> SymCplx sym -> IO (SymCplx sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymCplx sym
    x
          Just Bool
    False -> SymCplx sym -> IO (SymCplx sym)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymCplx sym
    y
          Maybe Bool
    _ -> do
            SymReal sym
    xr :+ SymReal sym
    xi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
            SymReal sym
    yr :+ SymReal sym
    yi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    y
            SymReal sym
    zr <- sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    c SymReal sym
    xr SymReal sym
    yr
            SymReal sym
    zi <- sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    c SymReal sym
    xi SymReal sym
    yi
            sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    zr SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    zi)

      -- | Negate a complex number.
      cplxNeg :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxNeg sym
    sym SymCplx sym
    x = sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (Complex (SymReal sym) -> IO (SymCplx sym))
    -> IO (Complex (SymReal sym)) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (SymReal sym -> IO (SymReal sym))
    -> Complex (SymReal sym) -> IO (Complex (SymReal sym))
    forall (t :: Type -> Type) (f :: Type -> Type) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: Type -> Type) a b.
    Applicative f =>
    (a -> f b) -> Complex a -> f (Complex b)
    traverse (sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realNeg sym
    sym) (Complex (SymReal sym) -> IO (Complex (SymReal sym)))
    -> IO (Complex (SymReal sym)) -> IO (Complex (SymReal sym))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x

      -- | Add two complex numbers together.
      cplxAdd :: sym -> SymCplx sym -> SymCplx sym -> IO (SymCplx sym)
      cplxAdd sym
    sym SymCplx sym
    x SymCplx sym
    y = do
        SymReal sym
    xr :+ SymReal sym
    xi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        SymReal sym
    yr :+ SymReal sym
    yi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    y
        SymReal sym
    zr <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymReal sym
    xr SymReal sym
    yr
        SymReal sym
    zi <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymReal sym
    xi SymReal sym
    yi
        sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    zr SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    zi)

      -- | Subtract one complex number from another.
      cplxSub :: sym -> SymCplx sym -> SymCplx sym -> IO (SymCplx sym)
      cplxSub sym
    sym SymCplx sym
    x SymCplx sym
    y = do
        SymReal sym
    xr :+ SymReal sym
    xi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        SymReal sym
    yr :+ SymReal sym
    yi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    y
        SymReal sym
    zr <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realSub sym
    sym SymReal sym
    xr SymReal sym
    yr
        SymReal sym
    zi <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realSub sym
    sym SymReal sym
    xi SymReal sym
    yi
        sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    zr SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    zi)

      -- | Multiply two complex numbers together.
      cplxMul :: sym -> SymCplx sym -> SymCplx sym -> IO (SymCplx sym)
      cplxMul sym
    sym SymCplx sym
    x SymCplx sym
    y = do
        SymReal sym
    xr :+ SymReal sym
    xi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        SymReal sym
    yr :+ SymReal sym
    yi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    y
        SymReal sym
    rz0 <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    xr SymReal sym
    yr
        SymReal sym
    rz <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realSub sym
    sym SymReal sym
    rz0 (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    xi SymReal sym
    yi
        SymReal sym
    iz0 <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    xi SymReal sym
    yr
        SymReal sym
    iz <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymReal sym
    iz0 (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    xr SymReal sym
    yi
        sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    rz SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    iz)

      -- | Compute the magnitude of a complex number.
      cplxMag :: sym -> SymCplx sym -> IO (SymReal sym)
      cplxMag sym
    sym SymCplx sym
    x = do
        (SymReal sym
    xr :+ SymReal sym
    xi) <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realHypot sym
    sym SymReal sym
    xr SymReal sym
    xi

      -- | Return the principal square root of a complex number.
      cplxSqrt :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxSqrt sym
    sym SymCplx sym
    x = do
        (SymReal sym
    r_part :+ SymReal sym
    i_part) <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        case (SymReal sym -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational SymReal sym
    r_part Maybe Rational -> Maybe Rational -> Complex (Maybe Rational)
    forall a. a -> a -> Complex a
    :+ SymReal sym -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational SymReal sym
    i_part)of
          (Just Rational
    r :+ Just Rational
    i) | Just Complex Rational
    z <- (Rational -> Maybe Rational)
    -> Complex Rational -> Maybe (Complex Rational)
    forall a (m :: Type -> Type).
    (Ord a, Fractional a, Monad m) =>
    (a -> m a) -> Complex a -> m (Complex a)
    tryComplexSqrt Rational -> Maybe Rational
    tryRationalSqrt (Rational
    r Rational -> Rational -> Complex Rational
    forall a. a -> a -> Complex a
    :+ Rational
    i) ->
            sym -> Complex Rational -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex Rational -> IO (SymCplx sym)
    mkComplexLit sym
    sym Complex Rational
    z

          (Maybe Rational
    _ :+ Just Rational
    0) -> do
            Pred sym
    c <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realGe sym
    sym SymReal sym
    r_part (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym)
            SymReal sym
    u <- (sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym))
    -> sym
    -> Pred sym
    -> IO (SymReal sym)
    -> IO (SymReal sym)
    -> IO (SymReal sym)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    c
              (sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSqrt sym
    sym SymReal sym
    r_part)
              (sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    0)
            SymReal sym
    v <- (sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym))
    -> sym
    -> Pred sym
    -> IO (SymReal sym)
    -> IO (SymReal sym)
    -> IO (SymReal sym)
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    c
              (sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    0)
              (sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSqrt sym
    sym (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realNeg sym
    sym SymReal sym
    r_part)
            sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    u SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    v)

          Complex (Maybe Rational)
    _ -> do
            SymReal sym
    m <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realHypot sym
    sym SymReal sym
    r_part SymReal sym
    i_part
            SymReal sym
    m_plus_r <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymReal sym
    m SymReal sym
    r_part
            SymReal sym
    m_sub_r  <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realSub sym
    sym SymReal sym
    m SymReal sym
    r_part
            SymReal sym
    two <- sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    2
            SymReal sym
    u <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSqrt sym
    sym (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymReal sym
    m_plus_r SymReal sym
    two
            SymReal sym
    v <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSqrt sym
    sym (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymReal sym
    m_sub_r  SymReal sym
    two
            SymReal sym
    neg_v <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realNeg sym
    sym SymReal sym
    v
            Pred sym
    i_part_nonneg <- sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (Pred sym)
    realIsNonNeg sym
    sym SymReal sym
    i_part
            SymReal sym
    v' <- sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    i_part_nonneg SymReal sym
    v SymReal sym
    neg_v
            sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    u SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    v')

      -- | Compute sine of a complex number.
      cplxSin :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxSin sym
    sym SymCplx sym
    arg = do
        c :: Complex (SymReal sym)
    c@(SymReal sym
    x :+ SymReal sym
    y) <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    arg
        case SymReal sym -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational (SymReal sym -> Maybe Rational)
    -> Complex (SymReal sym) -> Complex (Maybe Rational)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Complex (SymReal sym)
    c of
          (Just Rational
    0 :+ Just Rational
    0) -> sym -> SymReal sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymCplx sym)
    cplxFromReal sym
    sym (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym)
          (Maybe Rational
    _ :+ Just Rational
    0) -> sym -> SymReal sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymCplx sym)
    cplxFromReal sym
    sym (SymReal sym -> IO (SymCplx sym))
    -> IO (SymReal sym) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSin sym
    sym SymReal sym
    x
          (Just Rational
    0 :+ Maybe Rational
    _) -> do
            -- sin(0 + bi) = sin(0) cosh(b) + i*cos(0)sinh(b) = i*sinh(b)
            SymReal sym
    sinh_y <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSinh sym
    sym SymReal sym
    y
            sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    sinh_y)
          Complex (Maybe Rational)
    _ -> do
            SymReal sym
    sin_x <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSin sym
    sym SymReal sym
    x
            SymReal sym
    cos_x <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCos sym
    sym SymReal sym
    x
            SymReal sym
    sinh_y <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSinh sym
    sym SymReal sym
    y
            SymReal sym
    cosh_y <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCosh sym
    sym SymReal sym
    y
            SymReal sym
    r_part <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    sin_x SymReal sym
    cosh_y
            SymReal sym
    i_part <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    cos_x SymReal sym
    sinh_y
            sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    r_part SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    i_part)

      -- | Compute cosine of a complex number.
      cplxCos :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxCos sym
    sym SymCplx sym
    arg = do
        c :: Complex (SymReal sym)
    c@(SymReal sym
    x :+ SymReal sym
    y) <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    arg
        case SymReal sym -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational (SymReal sym -> Maybe Rational)
    -> Complex (SymReal sym) -> Complex (Maybe Rational)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Complex (SymReal sym)
    c of
          (Just Rational
    0 :+ Just Rational
    0) -> sym -> SymReal sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymCplx sym)
    cplxFromReal sym
    sym (SymReal sym -> IO (SymCplx sym))
    -> IO (SymReal sym) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    1
          (Maybe Rational
    _ :+ Just Rational
    0) -> sym -> SymReal sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymCplx sym)
    cplxFromReal sym
    sym (SymReal sym -> IO (SymCplx sym))
    -> IO (SymReal sym) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCos sym
    sym SymReal sym
    x
          (Just Rational
    0 :+ Maybe Rational
    _) -> do
            -- cos(0 + bi) = cos(0) cosh(b) - i*sin(0)sinh(b) = cosh(b)
            SymReal sym
    cosh_y    <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCosh sym
    sym SymReal sym
    y
            sym -> SymReal sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymCplx sym)
    cplxFromReal sym
    sym SymReal sym
    cosh_y
          Complex (Maybe Rational)
    _ -> do
            SymReal sym
    neg_sin_x <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realNeg sym
    sym (SymReal sym -> IO (SymReal sym))
    -> IO (SymReal sym) -> IO (SymReal sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSin sym
    sym SymReal sym
    x
            SymReal sym
    cos_x     <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCos sym
    sym SymReal sym
    x
            SymReal sym
    sinh_y    <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSinh sym
    sym SymReal sym
    y
            SymReal sym
    cosh_y    <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCosh sym
    sym SymReal sym
    y
            SymReal sym
    r_part <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    cos_x SymReal sym
    cosh_y
            SymReal sym
    i_part <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    neg_sin_x SymReal sym
    sinh_y
            sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    r_part SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    i_part)

      -- | Compute tangent of a complex number.  @cplxTan x@ is undefined
      --   when @cplxCos x@ is @0@, which occurs only along the real line
      --   in the same conditions where @realCos x@ is @0@.
      cplxTan :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxTan sym
    sym SymCplx sym
    arg = do
        c :: Complex (SymReal sym)
    c@(SymReal sym
    x :+ SymReal sym
    y) <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    arg
        case SymReal sym -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational (SymReal sym -> Maybe Rational)
    -> Complex (SymReal sym) -> Complex (Maybe Rational)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Complex (SymReal sym)
    c of
          (Just Rational
    0 :+ Just Rational
    0) -> sym -> SymReal sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymCplx sym)
    cplxFromReal sym
    sym (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym)
          (Maybe Rational
    _ :+ Just Rational
    0) -> do
            sym -> SymReal sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymCplx sym)
    cplxFromReal sym
    sym (SymReal sym -> IO (SymCplx sym))
    -> IO (SymReal sym) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realTan sym
    sym SymReal sym
    x
          (Just Rational
    0 :+ Maybe Rational
    _) -> do
            SymReal sym
    i_part <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realTanh sym
    sym SymReal sym
    y
            sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    i_part)
          Complex (Maybe Rational)
    _ -> do
            SymReal sym
    sin_x <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSin sym
    sym SymReal sym
    x
            SymReal sym
    cos_x <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCos sym
    sym SymReal sym
    x
            SymReal sym
    sinh_y <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSinh sym
    sym SymReal sym
    y
            SymReal sym
    cosh_y <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCosh sym
    sym SymReal sym
    y
            SymReal sym
    u <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    cos_x SymReal sym
    cosh_y
            SymReal sym
    v <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    sin_x SymReal sym
    sinh_y
            SymReal sym
    u2 <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    u SymReal sym
    u
            SymReal sym
    v2 <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    v SymReal sym
    v
            SymReal sym
    m <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymReal sym
    u2 SymReal sym
    v2
            SymReal sym
    sin_x_cos_x   <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    sin_x SymReal sym
    cos_x
            SymReal sym
    sinh_y_cosh_y <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    sinh_y SymReal sym
    cosh_y
            SymReal sym
    r_part <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymReal sym
    sin_x_cos_x SymReal sym
    m
            SymReal sym
    i_part <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymReal sym
    sinh_y_cosh_y SymReal sym
    m
            sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    r_part SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    i_part)

      -- | @hypotCplx x y@ returns @sqrt(abs(x)^2 + abs(y)^2)@.
      cplxHypot :: sym -> SymCplx sym -> SymCplx sym -> IO (SymCplx sym)
      cplxHypot sym
    sym SymCplx sym
    x SymCplx sym
    y = do
        (SymReal sym
    xr :+ SymReal sym
    xi) <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        (SymReal sym
    yr :+ SymReal sym
    yi) <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    y
        SymReal sym
    xr2 <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSq sym
    sym SymReal sym
    xr
        SymReal sym
    xi2 <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSq sym
    sym SymReal sym
    xi
        SymReal sym
    yr2 <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSq sym
    sym SymReal sym
    yr
        SymReal sym
    yi2 <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSq sym
    sym SymReal sym
    yi

        SymReal sym
    r2 <- (SymReal sym -> SymReal sym -> IO (SymReal sym))
    -> SymReal sym -> [SymReal sym] -> IO (SymReal sym)
    forall (t :: Type -> Type) (m :: Type -> Type) b a.
    (Foldable t, Monad m) =>
    (b -> a -> m b) -> b -> t a -> m b
    foldM (sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym) SymReal sym
    xr2 [SymReal sym
    xi2, SymReal sym
    yr2, SymReal sym
    yi2]
        sym -> SymReal sym -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymCplx sym)
    cplxFromReal sym
    sym (SymReal sym -> IO (SymCplx sym))
    -> IO (SymReal sym) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSqrt sym
    sym SymReal sym
    r2

      -- | @roundCplx x@ rounds complex number to nearest integer.
      -- Numbers with a fractional part of 0.5 are rounded away from 0.
      -- Imaginary and real parts are rounded independently.
      cplxRound :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxRound sym
    sym SymCplx sym
    x = do
        Complex (SymReal sym)
    c <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (Complex (SymReal sym) -> IO (SymCplx sym))
    -> IO (Complex (SymReal sym)) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (SymReal sym -> IO (SymReal sym))
    -> Complex (SymReal sym) -> IO (Complex (SymReal sym))
    forall (t :: Type -> Type) (f :: Type -> Type) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: Type -> Type) a b.
    Applicative f =>
    (a -> f b) -> Complex a -> f (Complex b)
    traverse (sym -> SymInteger sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymReal sym)
    integerToReal sym
    sym (SymInteger sym -> IO (SymReal sym))
    -> (SymReal sym -> IO (SymInteger sym))
    -> SymReal sym
    -> IO (SymReal sym)
    forall (m :: Type -> Type) b c a.
    Monad m =>
    (b -> m c) -> (a -> m b) -> a -> m c
    <=< sym -> SymReal sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realRound sym
    sym) Complex (SymReal sym)
    c

      -- | @cplxFloor x@ rounds to nearest integer less than or equal to x.
      -- Imaginary and real parts are rounded independently.
      cplxFloor :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxFloor sym
    sym SymCplx sym
    x =
        sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (Complex (SymReal sym) -> IO (SymCplx sym))
    -> IO (Complex (SymReal sym)) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (SymReal sym -> IO (SymReal sym))
    -> Complex (SymReal sym) -> IO (Complex (SymReal sym))
    forall (t :: Type -> Type) (f :: Type -> Type) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: Type -> Type) a b.
    Applicative f =>
    (a -> f b) -> Complex a -> f (Complex b)
    traverse (sym -> SymInteger sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymReal sym)
    integerToReal sym
    sym (SymInteger sym -> IO (SymReal sym))
    -> (SymReal sym -> IO (SymInteger sym))
    -> SymReal sym
    -> IO (SymReal sym)
    forall (m :: Type -> Type) b c a.
    Monad m =>
    (b -> m c) -> (a -> m b) -> a -> m c
    <=< sym -> SymReal sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realFloor sym
    sym)
                      (Complex (SymReal sym) -> IO (Complex (SymReal sym)))
    -> IO (Complex (SymReal sym)) -> IO (Complex (SymReal sym))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
      -- | @cplxCeil x@ rounds to nearest integer greater than or equal to x.
      -- Imaginary and real parts are rounded independently.
      cplxCeil :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxCeil sym
    sym SymCplx sym
    x =
        sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (Complex (SymReal sym) -> IO (SymCplx sym))
    -> IO (Complex (SymReal sym)) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (SymReal sym -> IO (SymReal sym))
    -> Complex (SymReal sym) -> IO (Complex (SymReal sym))
    forall (t :: Type -> Type) (f :: Type -> Type) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: Type -> Type) a b.
    Applicative f =>
    (a -> f b) -> Complex a -> f (Complex b)
    traverse (sym -> SymInteger sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymInteger sym -> IO (SymReal sym)
    integerToReal sym
    sym (SymInteger sym -> IO (SymReal sym))
    -> (SymReal sym -> IO (SymInteger sym))
    -> SymReal sym
    -> IO (SymReal sym)
    forall (m :: Type -> Type) b c a.
    Monad m =>
    (b -> m c) -> (a -> m b) -> a -> m c
    <=< sym -> SymReal sym -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymInteger sym)
    realCeil sym
    sym)
                      (Complex (SymReal sym) -> IO (Complex (SymReal sym)))
    -> IO (Complex (SymReal sym)) -> IO (Complex (SymReal sym))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x

      -- | @conjReal x@ returns the complex conjugate of the input.
      cplxConj :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxConj sym
    sym SymCplx sym
    x  = do
        SymReal sym
    r :+ SymReal sym
    i <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        SymReal sym
    ic <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realNeg sym
    sym SymReal sym
    i
        sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    r SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    ic)

      -- | Returns exponential of a complex number.
      cplxExp :: sym -> SymCplx sym -> IO (SymCplx sym)
      cplxExp sym
    sym SymCplx sym
    x = do
        (SymReal sym
    rx :+ SymReal sym
    i_part) <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        SymReal sym
    expx <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realExp sym
    sym SymReal sym
    rx
        SymReal sym
    cosx <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realCos sym
    sym SymReal sym
    i_part
        SymReal sym
    sinx <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realSin sym
    sym SymReal sym
    i_part
        SymReal sym
    rz <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    expx SymReal sym
    cosx
        SymReal sym
    iz <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymReal sym
    expx SymReal sym
    sinx
        sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (SymReal sym
    rz SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    iz)

      -- | Check equality of two complex numbers.
      cplxEq :: sym -> SymCplx sym -> SymCplx sym -> IO (Pred sym)
      cplxEq sym
    sym SymCplx sym
    x SymCplx sym
    y = do
        SymReal sym
    xr :+ SymReal sym
    xi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        SymReal sym
    yr :+ SymReal sym
    yi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    y
        Pred sym
    pr <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realEq sym
    sym SymReal sym
    xr SymReal sym
    yr
        Pred sym
    pj <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realEq sym
    sym SymReal sym
    xi SymReal sym
    yi
        sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    andPred sym
    sym Pred sym
    pr Pred sym
    pj

      -- | Check non-equality of two complex numbers.
      cplxNe :: sym -> SymCplx sym -> SymCplx sym -> IO (Pred sym)
      cplxNe sym
    sym SymCplx sym
    x SymCplx sym
    y = do
        SymReal sym
    xr :+ SymReal sym
    xi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
        SymReal sym
    yr :+ SymReal sym
    yi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    y
        Pred sym
    pr <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realNe sym
    sym SymReal sym
    xr SymReal sym
    yr
        Pred sym
    pj <- sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realNe sym
    sym SymReal sym
    xi SymReal sym
    yi
        sym -> Pred sym -> Pred sym -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    orPred sym
    sym Pred sym
    pr Pred sym
    pj

    -- | This newtype is necessary for @bvJoinVector@ and @bvSplitVector@.
    -- These both use functions from Data.Parameterized.Vector that
    -- that expect a wrapper of kind (Type -> Type), and we can't partially
    -- apply the type synonym (e.g. SymBv sym), whereas we can partially
    -- apply this newtype.
    newtype SymBV' sym w = MkSymBV' (SymBV sym w)

    -- | Join a @Vector@ of smaller bitvectors.  The vector is
    --   interpreted in big endian order; that is, with most
    --   significant bitvector first.
    bvJoinVector :: forall sym n w. (1 <= w, IsExprBuilder sym)
                 => sym
                 -> NatRepr w
                 -> Vector.Vector n (SymBV sym w)
                 -> IO (SymBV sym (n * w))
    bvJoinVector :: forall sym (n :: Nat) (w :: Nat).
    (1 <= w, IsExprBuilder sym) =>
    sym
    -> NatRepr w -> Vector n (SymBV sym w) -> IO (SymBV sym (n * w))
    bvJoinVector sym
    sym NatRepr w
    w =
      (Vector n (SymBV' sym w) -> IO (SymBV' sym (n * w)))
    -> Vector n (SymExpr sym (BaseBVType w))
    -> IO (SymExpr sym (BaseBVType (n * w)))
    forall a b. Coercible a b => a -> b
    coerce ((Vector n (SymBV' sym w) -> IO (SymBV' sym (n * w)))
     -> Vector n (SymExpr sym (BaseBVType w))
     -> IO (SymExpr sym (BaseBVType (n * w))))
    -> (Vector n (SymBV' sym w) -> IO (SymBV' sym (n * w)))
    -> Vector n (SymExpr sym (BaseBVType w))
    -> IO (SymExpr sym (BaseBVType (n * w)))
    forall a b. (a -> b) -> a -> b
    $ forall (m :: Type -> Type) (f :: Nat -> Type) (n :: Nat)
           (w :: Nat).
    (1 <= w, Monad m) =>
    (forall (l :: Nat).
     (1 <= l) =>
     NatRepr l -> f w -> f l -> m (f (w + l)))
    -> NatRepr w -> Vector n (f w) -> m (f (n * w))
    Vector.joinWithM @IO @(SymBV' sym) @n NatRepr l
    -> SymBV' sym w -> SymBV' sym l -> IO (SymBV' sym (w + l))
    forall (l :: Nat).
    (1 <= l) =>
    NatRepr l
    -> SymBV' sym w -> SymBV' sym l -> IO (SymBV' sym (w + l))
    bvConcat' NatRepr w
    w
      where bvConcat' :: forall l. (1 <= l)
                      => NatRepr l
                      -> SymBV' sym w
                      -> SymBV' sym l
                      -> IO (SymBV' sym (w + l))
            bvConcat' :: forall (l :: Nat).
    (1 <= l) =>
    NatRepr l
    -> SymBV' sym w -> SymBV' sym l -> IO (SymBV' sym (w + l))
    bvConcat' NatRepr l
    _ (MkSymBV' SymExpr sym (BaseBVType w)
    x) (MkSymBV' SymBV sym l
    y) = SymBV sym (w + l) -> SymBV' sym (w + l)
    forall sym (w :: Nat). SymBV sym w -> SymBV' sym w
    MkSymBV' (SymBV sym (w + l) -> SymBV' sym (w + l))
    -> IO (SymBV sym (w + l)) -> IO (SymBV' sym (w + l))
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> SymExpr sym (BaseBVType w)
    -> SymBV sym l
    -> IO (SymBV sym (w + l))
    forall (u :: Nat) (v :: Nat).
    (1 <= u, 1 <= v) =>
    sym -> SymBV sym u -> SymBV sym v -> IO (SymBV sym (u + v))
    forall sym (u :: Nat) (v :: Nat).
    (IsExprBuilder sym, 1 <= u, 1 <= v) =>
    sym -> SymBV sym u -> SymBV sym v -> IO (SymBV sym (u + v))
    bvConcat sym
    sym SymExpr sym (BaseBVType w)
    x SymBV sym l
    y

    -- | Split a bitvector to a @Vector@ of smaller bitvectors.
    --   The returned vector is in big endian order; that is, with most
    --   significant bitvector first.
    bvSplitVector :: forall sym n w. (IsExprBuilder sym, 1 <= w, 1 <= n)
                  => sym
                  -> NatRepr n
                  -> NatRepr w
                  -> SymBV sym (n * w)
                  -> IO (Vector.Vector n (SymBV sym w))
    bvSplitVector :: forall sym (n :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= w, 1 <= n) =>
    sym
    -> NatRepr n
    -> NatRepr w
    -> SymBV sym (n * w)
    -> IO (Vector n (SymBV sym w))
    bvSplitVector sym
    sym NatRepr n
    n NatRepr w
    w SymBV sym (n * w)
    x =
      IO (Vector n (SymBV' sym w))
    -> IO (Vector n (SymExpr sym (BaseBVType w)))
    forall a b. Coercible a b => a -> b
    coerce (IO (Vector n (SymBV' sym w))
     -> IO (Vector n (SymExpr sym (BaseBVType w))))
    -> IO (Vector n (SymBV' sym w))
    -> IO (Vector n (SymExpr sym (BaseBVType w)))
    forall a b. (a -> b) -> a -> b
    $ forall (f :: Type -> Type) (g :: Nat -> Type) (w :: Nat)
           (n :: Nat).
    (Applicative f, 1 <= w, 1 <= n) =>
    Endian
    -> (forall (i :: Nat).
        ((i + w) <= (n * w)) =>
        NatRepr (n * w) -> NatRepr i -> g (n * w) -> f (g w))
    -> NatRepr n
    -> NatRepr w
    -> g (n * w)
    -> f (Vector n (g w))
    Vector.splitWithA @IO Endian
    BigEndian NatRepr (n * w)
    -> NatRepr i -> SymBV' sym (n * w) -> IO (SymBV' sym w)
    forall (i :: Nat).
    ((i + w) <= (n * w)) =>
    NatRepr (n * w)
    -> NatRepr i -> SymBV' sym (n * w) -> IO (SymBV' sym w)
    bvSelect' NatRepr n
    n NatRepr w
    w (forall sym (w :: Nat). SymBV sym w -> SymBV' sym w
    MkSymBV' @sym SymBV sym (n * w)
    x)
      where
        bvSelect' :: forall i. (i + w <= n * w)
                  => NatRepr (n * w)
                  -> NatRepr i
                  -> SymBV' sym (n * w)
                  -> IO (SymBV' sym w)
        bvSelect' :: forall (i :: Nat).
    ((i + w) <= (n * w)) =>
    NatRepr (n * w)
    -> NatRepr i -> SymBV' sym (n * w) -> IO (SymBV' sym w)
    bvSelect' NatRepr (n * w)
    _ NatRepr i
    i (MkSymBV' SymBV sym (n * w)
    y) =
          (SymExpr sym (BaseBVType w) -> SymBV' sym w)
    -> IO (SymExpr sym (BaseBVType w)) -> IO (SymBV' sym w)
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap SymExpr sym (BaseBVType w) -> SymBV' sym w
    forall sym (w :: Nat). SymBV sym w -> SymBV' sym w
    MkSymBV' (IO (SymExpr sym (BaseBVType w)) -> IO (SymBV' sym w))
    -> IO (SymExpr sym (BaseBVType w)) -> IO (SymBV' sym w)
    forall a b. (a -> b) -> a -> b
    $ forall sym (idx :: Nat) (n :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= n, (idx + n) <= w) =>
    sym -> NatRepr idx -> NatRepr n -> SymBV sym w -> IO (SymBV sym n)
    bvSelect @_ @i @w sym
    sym NatRepr i
    i NatRepr w
    w SymBV sym (n * w)
    y

    -- | Implement LLVM's "bswap" intrinsic
    --
    -- See <https://llvm.org/docs/LangRef.html#llvm-bswap-intrinsics
    --       the LLVM @bswap@ documentation.>
    --
    -- This is the implementation in SawCore:
    --
    -- > llvmBSwap :: (n :: Nat) -> bitvector (mulNat n 8) -> bitvector (mulNat n 8);
    -- > llvmBSwap n x = join n 8 Bool (reverse n (bitvector 8) (split n 8 Bool x));
    bvSwap :: forall sym n. (1 <= n, IsExprBuilder sym)
           => sym               -- ^ Symbolic interface
           -> NatRepr n
           -> SymBV sym (n*8)   -- ^ Bitvector to swap around
           -> IO (SymBV sym (n*8))
    bvSwap :: forall sym (n :: Nat).
    (1 <= n, IsExprBuilder sym) =>
    sym -> NatRepr n -> SymBV sym (n * 8) -> IO (SymBV sym (n * 8))
    bvSwap sym
    sym NatRepr n
    n SymBV sym (n * 8)
    v = do
      sym
    -> NatRepr 8
    -> Vector n (SymExpr sym (BaseBVType 8))
    -> IO (SymBV sym (n * 8))
    forall sym (n :: Nat) (w :: Nat).
    (1 <= w, IsExprBuilder sym) =>
    sym
    -> NatRepr w -> Vector n (SymBV sym w) -> IO (SymBV sym (n * w))
    bvJoinVector sym
    sym (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @8) (Vector n (SymExpr sym (BaseBVType 8)) -> IO (SymBV sym (n * 8)))
    -> (Vector n (SymExpr sym (BaseBVType 8))
        -> Vector n (SymExpr sym (BaseBVType 8)))
    -> Vector n (SymExpr sym (BaseBVType 8))
    -> IO (SymBV sym (n * 8))
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Vector n (SymExpr sym (BaseBVType 8))
    -> Vector n (SymExpr sym (BaseBVType 8))
    forall a (n :: Nat). (1 <= n) => Vector n a -> Vector n a
    Vector.reverse
        (Vector n (SymExpr sym (BaseBVType 8)) -> IO (SymBV sym (n * 8)))
    -> IO (Vector n (SymExpr sym (BaseBVType 8)))
    -> IO (SymBV sym (n * 8))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> NatRepr n
    -> NatRepr 8
    -> SymBV sym (n * 8)
    -> IO (Vector n (SymExpr sym (BaseBVType 8)))
    forall sym (n :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= w, 1 <= n) =>
    sym
    -> NatRepr n
    -> NatRepr w
    -> SymBV sym (n * w)
    -> IO (Vector n (SymBV sym w))
    bvSplitVector sym
    sym NatRepr n
    n (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @8) SymBV sym (n * 8)
    v

    -- | Swap the order of the bits in a bitvector.
    bvBitreverse :: forall sym w.
      (1 <= w, IsExprBuilder sym) =>
      sym ->
      SymBV sym w ->
      IO (SymBV sym w)
    bvBitreverse :: forall sym (w :: Nat).
    (1 <= w, IsExprBuilder sym) =>
    sym -> SymBV sym w -> IO (SymBV sym w)
    bvBitreverse sym
    sym SymBV sym w
    v = do
      sym
    -> NatRepr 1
    -> Vector w (SymExpr sym (BaseBVType 1))
    -> IO (SymBV sym (w * 1))
    forall sym (n :: Nat) (w :: Nat).
    (1 <= w, IsExprBuilder sym) =>
    sym
    -> NatRepr w -> Vector n (SymBV sym w) -> IO (SymBV sym (n * w))
    bvJoinVector sym
    sym (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @1) (Vector w (SymExpr sym (BaseBVType 1)) -> IO (SymBV sym w))
    -> (Vector w (SymExpr sym (BaseBVType 1))
        -> Vector w (SymExpr sym (BaseBVType 1)))
    -> Vector w (SymExpr sym (BaseBVType 1))
    -> IO (SymBV sym w)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Vector w (SymExpr sym (BaseBVType 1))
    -> Vector w (SymExpr sym (BaseBVType 1))
    forall a (n :: Nat). (1 <= n) => Vector n a -> Vector n a
    Vector.reverse
        (Vector w (SymExpr sym (BaseBVType 1)) -> IO (SymBV sym w))
    -> IO (Vector w (SymExpr sym (BaseBVType 1))) -> IO (SymBV sym w)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> NatRepr w
    -> NatRepr 1
    -> SymBV sym (w * 1)
    -> IO (Vector w (SymExpr sym (BaseBVType 1)))
    forall sym (n :: Nat) (w :: Nat).
    (IsExprBuilder sym, 1 <= w, 1 <= n) =>
    sym
    -> NatRepr n
    -> NatRepr w
    -> SymBV sym (n * w)
    -> IO (Vector n (SymBV sym w))
    bvSplitVector sym
    sym (SymBV sym w -> NatRepr w
    forall (w :: Nat). SymExpr sym (BaseBVType w) -> NatRepr w
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> NatRepr w
    bvWidth SymBV sym w
    v) (forall (n :: Nat). KnownNat n => NatRepr n
    knownNat @1) SymBV sym w
    SymBV sym (w * 1)
    v

    -- | Create a literal from an 'IndexLit'.
    indexLit :: IsExprBuilder sym => sym -> IndexLit idx -> IO (SymExpr sym idx)
    indexLit :: forall sym (idx :: BaseType).
    IsExprBuilder sym =>
    sym -> IndexLit idx -> IO (SymExpr sym idx)
    indexLit sym
    sym (IntIndexLit Integer
    i)  = sym -> Integer -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    i
    indexLit sym
    sym (BVIndexLit NatRepr w
    w BV w
    v) = sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w BV w
    v

    -- | A utility combinator for combining actions
    --   that build terms with if/then/else.
    --   If the given predicate is concretely true or
    --   false only the corresponding "then" or "else"
    --   action is run; otherwise both actions are run
    --   and combined with the given "ite" action.
    iteM :: IsExprBuilder sym =>
      (sym -> Pred sym -> v -> v -> IO v) ->
      sym -> Pred sym -> IO v -> IO v -> IO v
    iteM :: forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> v -> v -> IO v
    ite sym
    sym Pred sym
    p IO v
    mx IO v
    my = do
      case Pred sym -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred Pred sym
    p of
        Just Bool
    True -> IO v
    mx
        Just Bool
    False -> IO v
    my
        Maybe Bool
    Nothing -> IO (IO v) -> IO v
    forall (m :: Type -> Type) a. Monad m => m (m a) -> m a
    join (IO (IO v) -> IO v) -> IO (IO v) -> IO v
    forall a b. (a -> b) -> a -> b
    $ sym -> Pred sym -> v -> v -> IO v
    ite sym
    sym Pred sym
    p (v -> v -> IO v) -> IO v -> IO (v -> IO v)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> IO v
    mx IO (v -> IO v) -> IO v -> IO (IO v)
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> IO v
    my

    -- | An iterated sequence of if/then/else operations.
    --   The list of predicates and "then" results is
    --   constructed as-needed. The "default" value
    --   represents the result of the expression if
    --   none of the predicates in the given list
    --   is true.
    iteList :: IsExprBuilder sym =>
      (sym -> Pred sym -> v -> v -> IO v) ->
      sym ->
      [(IO (Pred sym), IO v)] ->
      (IO v) ->
      IO v
    iteList :: forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> [(IO (Pred sym), IO v)] -> IO v -> IO v
    iteList sym -> Pred sym -> v -> v -> IO v
    _ite sym
    _sym [] IO v
    def = IO v
    def
    iteList sym -> Pred sym -> v -> v -> IO v
    ite sym
    sym ((IO (Pred sym)
    mp,IO v
    mx):[(IO (Pred sym), IO v)]
    xs) IO v
    def =
      do Pred sym
    p <- IO (Pred sym)
    mp
         (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> Pred sym -> IO v -> IO v -> IO v
    iteM sym -> Pred sym -> v -> v -> IO v
    ite sym
    sym Pred sym
    p IO v
    mx ((sym -> Pred sym -> v -> v -> IO v)
    -> sym -> [(IO (Pred sym), IO v)] -> IO v -> IO v
    forall sym v.
    IsExprBuilder sym =>
    (sym -> Pred sym -> v -> v -> IO v)
    -> sym -> [(IO (Pred sym), IO v)] -> IO v -> IO v
    iteList sym -> Pred sym -> v -> v -> IO v
    ite sym
    sym [(IO (Pred sym), IO v)]
    xs IO v
    def)

    -- | A function that can be applied to symbolic arguments.
    --
    -- This type is used by some methods in classes 'IsExprBuilder' and
    -- 'IsSymExprBuilder'.
    type family SymFn sym :: Ctx BaseType -> BaseType -> Type

    data SomeSymFn sym = forall args ret . SomeSymFn (SymFn sym args ret)

    -- | Wrapper for `SymFn` that concatenates the arguments and the return types.
    --
    -- This is useful for implementing `TestEquality` and `OrdF` instances for
    -- `SymFn`, and for using `SymFn` as a key or a value in a `MapF`.
    data SymFnWrapper sym ctx where
      SymFnWrapper :: forall sym args ret . SymFn sym args ret -> SymFnWrapper sym (args ::> ret)

    instance IsSymFn (SymFn sym) => TestEquality (SymFnWrapper sym) where
      testEquality :: forall (a :: Ctx BaseType) (b :: Ctx BaseType).
    SymFnWrapper sym a -> SymFnWrapper sym b -> Maybe (a :~: b)
    testEquality (SymFnWrapper SymFn sym args ret
    fn1) (SymFnWrapper SymFn sym args ret
    fn2) = SymFn sym args ret
    -> SymFn sym args ret
    -> Maybe ((args '::> ret) :~: (args '::> ret))
    forall (args1 :: Ctx BaseType) (ret1 :: BaseType)
           (args2 :: Ctx BaseType) (ret2 :: BaseType).
    SymFn sym args1 ret1
    -> SymFn sym args2 ret2
    -> Maybe ((args1 ::> ret1) :~: (args2 ::> ret2))
    forall (fn :: Ctx BaseType -> BaseType -> Type)
           (args1 :: Ctx BaseType) (ret1 :: BaseType) (args2 :: Ctx BaseType)
           (ret2 :: BaseType).
    IsSymFn fn =>
    fn args1 ret1
    -> fn args2 ret2 -> Maybe ((args1 ::> ret1) :~: (args2 ::> ret2))
    fnTestEquality SymFn sym args ret
    fn1 SymFn sym args ret
    fn2

    instance IsSymFn (SymFn sym) => OrdF (SymFnWrapper sym) where
      compareF :: forall (x :: Ctx BaseType) (y :: Ctx BaseType).
    SymFnWrapper sym x -> SymFnWrapper sym y -> OrderingF x y
    compareF (SymFnWrapper SymFn sym args ret
    fn1) (SymFnWrapper SymFn sym args ret
    fn2) = SymFn sym args ret
    -> SymFn sym args ret -> OrderingF (args '::> ret) (args '::> ret)
    forall (args1 :: Ctx BaseType) (ret1 :: BaseType)
           (args2 :: Ctx BaseType) (ret2 :: BaseType).
    SymFn sym args1 ret1
    -> SymFn sym args2 ret2
    -> OrderingF (args1 ::> ret1) (args2 ::> ret2)
    forall (fn :: Ctx BaseType -> BaseType -> Type)
           (args1 :: Ctx BaseType) (ret1 :: BaseType) (args2 :: Ctx BaseType)
           (ret2 :: BaseType).
    IsSymFn fn =>
    fn args1 ret1
    -> fn args2 ret2 -> OrderingF (args1 ::> ret1) (args2 ::> ret2)
    fnCompare SymFn sym args ret
    fn1 SymFn sym args ret
    fn2

    -- | A class for extracting type representatives from symbolic functions
    class IsSymFn (fn :: Ctx BaseType -> BaseType -> Type) where
      -- | Get the argument types of a function.
      fnArgTypes :: fn args ret -> Ctx.Assignment BaseTypeRepr args

      -- | Get the return type of a function.
      fnReturnType :: fn args ret -> BaseTypeRepr ret

      -- | Test whether two functions are equal.
      --
      -- The implementation may be incomplete, that is, if it returns `Just` then
      -- the functions are equal, while if it returns `Nothing` then the functions
      -- may or may not be equal. The result of `freshTotalUninterpFn` or
      -- `definedFn` tests equal with itself.
      fnTestEquality :: fn args1 ret1 -> fn args2 ret2 -> Maybe ((args1 ::> ret1) :~: (args2 ::> ret2))

      -- | Compare two functions for ordering.
      --
      -- The underlying equality test is provided by `fnTestEquality`.
      fnCompare :: fn args1 ret1 -> fn args2 ret2 -> OrderingF (args1 ::> ret1) (args2 ::> ret2)

    -- | Describes when we unfold the body of defined functions.
    data UnfoldPolicy
      = NeverUnfold
          -- ^ What4 will not unfold the body of functions when applied to arguments
       | AlwaysUnfold
          -- ^ The function will be unfolded into its definition whenever it is
          --   applied to arguments
       | UnfoldConcrete
          -- ^ The function will be unfolded into its definition only if all the provided
          --   arguments are concrete.
     deriving (UnfoldPolicy -> UnfoldPolicy -> Bool
    (UnfoldPolicy -> UnfoldPolicy -> Bool)
    -> (UnfoldPolicy -> UnfoldPolicy -> Bool) -> Eq UnfoldPolicy
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: UnfoldPolicy -> UnfoldPolicy -> Bool
    == :: UnfoldPolicy -> UnfoldPolicy -> Bool
    $c/= :: UnfoldPolicy -> UnfoldPolicy -> Bool
    /= :: UnfoldPolicy -> UnfoldPolicy -> Bool
    Eq, Eq UnfoldPolicy
    Eq UnfoldPolicy =>
    (UnfoldPolicy -> UnfoldPolicy -> Ordering)
    -> (UnfoldPolicy -> UnfoldPolicy -> Bool)
    -> (UnfoldPolicy -> UnfoldPolicy -> Bool)
    -> (UnfoldPolicy -> UnfoldPolicy -> Bool)
    -> (UnfoldPolicy -> UnfoldPolicy -> Bool)
    -> (UnfoldPolicy -> UnfoldPolicy -> UnfoldPolicy)
    -> (UnfoldPolicy -> UnfoldPolicy -> UnfoldPolicy)
    -> Ord UnfoldPolicy
    UnfoldPolicy -> UnfoldPolicy -> Bool
    UnfoldPolicy -> UnfoldPolicy -> Ordering
    UnfoldPolicy -> UnfoldPolicy -> UnfoldPolicy
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: UnfoldPolicy -> UnfoldPolicy -> Ordering
    compare :: UnfoldPolicy -> UnfoldPolicy -> Ordering
    $c< :: UnfoldPolicy -> UnfoldPolicy -> Bool
    < :: UnfoldPolicy -> UnfoldPolicy -> Bool
    $c<= :: UnfoldPolicy -> UnfoldPolicy -> Bool
    <= :: UnfoldPolicy -> UnfoldPolicy -> Bool
    $c> :: UnfoldPolicy -> UnfoldPolicy -> Bool
    > :: UnfoldPolicy -> UnfoldPolicy -> Bool
    $c>= :: UnfoldPolicy -> UnfoldPolicy -> Bool
    >= :: UnfoldPolicy -> UnfoldPolicy -> Bool
    $cmax :: UnfoldPolicy -> UnfoldPolicy -> UnfoldPolicy
    max :: UnfoldPolicy -> UnfoldPolicy -> UnfoldPolicy
    $cmin :: UnfoldPolicy -> UnfoldPolicy -> UnfoldPolicy
    min :: UnfoldPolicy -> UnfoldPolicy -> UnfoldPolicy
    Ord, Int -> UnfoldPolicy -> ShowS
    [UnfoldPolicy] -> ShowS
    UnfoldPolicy -> String
    (Int -> UnfoldPolicy -> ShowS)
    -> (UnfoldPolicy -> String)
    -> ([UnfoldPolicy] -> ShowS)
    -> Show UnfoldPolicy
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> UnfoldPolicy -> ShowS
    showsPrec :: Int -> UnfoldPolicy -> ShowS
    $cshow :: UnfoldPolicy -> String
    show :: UnfoldPolicy -> String
    $cshowList :: [UnfoldPolicy] -> ShowS
    showList :: [UnfoldPolicy] -> ShowS
    Show)

    -- | Evaluates an @UnfoldPolicy@ on a collection of arguments.
    shouldUnfold :: IsExpr e => UnfoldPolicy -> Ctx.Assignment e args -> Bool
    shouldUnfold :: forall (e :: BaseType -> Type) (args :: Ctx BaseType).
    IsExpr e =>
    UnfoldPolicy -> Assignment e args -> Bool
    shouldUnfold UnfoldPolicy
    AlwaysUnfold Assignment e args
    _ = Bool
    True
    shouldUnfold UnfoldPolicy
    NeverUnfold Assignment e args
    _ = Bool
    False
    shouldUnfold UnfoldPolicy
    UnfoldConcrete Assignment e args
    args = (forall (x :: BaseType). e x -> Bool)
    -> forall (x :: Ctx BaseType). Assignment e x -> Bool
    forall {k} {l} (t :: (k -> Type) -> l -> Type) (f :: k -> Type).
    FoldableFC t =>
    (forall (x :: k). f x -> Bool) -> forall (x :: l). t f x -> Bool
    allFC e x -> Bool
    forall (x :: BaseType). e x -> Bool
    forall (e :: BaseType -> Type) (bt :: BaseType).
    IsExpr e =>
    e bt -> Bool
    baseIsConcrete Assignment e args
    args

    -- | This exception is thrown if the user requests to make a bounded variable,
    --   but gives incoherent or out-of-range bounds.
    data InvalidRange where
      InvalidRange ::
        BaseTypeRepr bt ->
        Maybe (ConcreteValue bt) ->
        Maybe (ConcreteValue bt) ->
        InvalidRange

    instance Exception InvalidRange
    instance Show InvalidRange where
      show :: InvalidRange -> String
    show (InvalidRange BaseTypeRepr bt
    bt Maybe (ConcreteValue bt)
    mlo Maybe (ConcreteValue bt)
    mhi) =
        case BaseTypeRepr bt
    bt of
          BaseTypeRepr bt
    BaseIntegerRepr -> [String] -> String
    unwords [String
    "invalid integer range", Maybe Integer -> String
    forall a. Show a => a -> String
    show Maybe Integer
    Maybe (ConcreteValue bt)
    mlo, Maybe Integer -> String
    forall a. Show a => a -> String
    show Maybe Integer
    Maybe (ConcreteValue bt)
    mhi]
          BaseTypeRepr bt
    BaseRealRepr    -> [String] -> String
    unwords [String
    "invalid real range", Maybe Rational -> String
    forall a. Show a => a -> String
    show Maybe Rational
    Maybe (ConcreteValue bt)
    mlo, Maybe Rational -> String
    forall a. Show a => a -> String
    show Maybe Rational
    Maybe (ConcreteValue bt)
    mhi]
          BaseBVRepr NatRepr w
    w    -> [String] -> String
    unwords [String
    "invalid bitvector range", NatRepr w -> String
    forall a. Show a => a -> String
    show NatRepr w
    w String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    "-bit", Maybe Integer -> String
    forall a. Show a => a -> String
    show Maybe Integer
    Maybe (ConcreteValue bt)
    mlo, Maybe Integer -> String
    forall a. Show a => a -> String
    show Maybe Integer
    Maybe (ConcreteValue bt)
    mhi]
          BaseTypeRepr bt
    _               -> [String] -> String
    unwords [String
    "invalid range for type", BaseTypeRepr bt -> String
    forall a. Show a => a -> String
    show BaseTypeRepr bt
    bt]

    -- | This extends the interface for building expressions with operations
    --   for creating new symbolic constants and functions.
    class ( IsExprBuilder sym
          , IsSymFn (SymFn sym)
          , OrdF (SymExpr sym)
          , OrdF (BoundVar sym)
          ) => IsSymExprBuilder sym where

      ----------------------------------------------------------------------
      -- Fresh variables

      -- | Create a fresh top-level uninterpreted constant.
      freshConstant :: sym -> SolverSymbol -> BaseTypeRepr tp -> IO (SymExpr sym tp)

      -- | Create a fresh latch variable.
      freshLatch    :: sym -> SolverSymbol -> BaseTypeRepr tp -> IO (SymExpr sym tp)

      -- | Create a fresh bitvector value with optional lower and upper bounds (which bound the
      --   unsigned value of the bitvector). If provided, the bounds are inclusive.
      --   If inconsistent or out-of-range bounds are given, an @InvalidRange@ exception will be thrown.
      freshBoundedBV :: (1 <= w) =>
        sym ->
        SolverSymbol ->
        NatRepr w ->
        Maybe Natural {- ^ lower bound -} ->
        Maybe Natural {- ^ upper bound -} ->
        IO (SymBV sym w)

      -- | Create a fresh bitvector value with optional lower and upper bounds (which bound the
      --   signed value of the bitvector).  If provided, the bounds are inclusive.
      --   If inconsistent or out-of-range bounds are given, an InvalidRange exception will be thrown.
      freshBoundedSBV :: (1 <= w) =>
        sym ->
        SolverSymbol ->
        NatRepr w ->
        Maybe Integer {- ^ lower bound -} ->
        Maybe Integer {- ^ upper bound -} ->
        IO (SymBV sym w)

      -- | Create a fresh integer constant with optional lower and upper bounds.
      --   If provided, the bounds are inclusive.
      --   If inconsistent bounds are given, an InvalidRange exception will be thrown.
      freshBoundedInt ::
        sym ->
        SolverSymbol ->
        Maybe Integer {- ^ lower bound -} ->
        Maybe Integer {- ^ upper bound -} ->
        IO (SymInteger sym)

      -- | Create a fresh real constant with optional lower and upper bounds.
      --   If provided, the bounds are inclusive.
      --   If inconsistent bounds are given, an InvalidRange exception will be thrown.
      freshBoundedReal ::
        sym ->
        SolverSymbol ->
        Maybe Rational {- ^ lower bound -} ->
        Maybe Rational {- ^ upper bound -} ->
        IO (SymReal sym)

      -- | Return the set of uninterpreted constants in the given expression.
      exprUninterpConstants :: sym -> SymExpr sym tp -> Set (Some (BoundVar sym))

      ----------------------------------------------------------------------
      -- Functions needs to support quantifiers.

      -- | Creates a bound variable.
      --
      -- This will be treated as a free constant when appearing inside asserted
      -- expressions.  These are intended to be bound using quantifiers or
      -- symbolic functions.
      freshBoundVar :: sym -> SolverSymbol -> BaseTypeRepr tp -> IO (BoundVar sym tp)

      -- | Return an expression that references the bound variable.
      varExpr :: sym -> BoundVar sym tp -> SymExpr sym tp

      -- | @forallPred sym v e@ returns an expression that represents @forall v . e@.
      -- Throws a user error if bound var has already been used in a quantifier.
      forallPred :: sym
                 -> BoundVar sym tp
                 -> Pred sym
                 -> IO (Pred sym)

      -- | @existsPred sym v e@ returns an expression that represents @exists v . e@.
      -- Throws a user error if bound var has already been used in a quantifier.
      existsPred :: sym
                 -> BoundVar sym tp
                 -> Pred sym
                 -> IO (Pred sym)

      ----------------------------------------------------------------------
      -- SymFn operations.

      -- | Return a function defined by an expression over bound
      -- variables. The predicate argument allows the user to specify when
      -- an application of the function should be unfolded and evaluated,
      -- e.g. to perform constant folding.
      definedFn :: sym
                -- ^ Symbolic interface
                -> SolverSymbol
                -- ^ The name to give a function (need not be unique)
                -> Ctx.Assignment (BoundVar sym) args
                -- ^ Bound variables to use as arguments for function.
                -> SymExpr sym ret
                -- ^ Operation defining result of defined function.
                -> UnfoldPolicy
                -- ^ Policy for unfolding on applications
                -> IO (SymFn sym args ret)

      -- | Return a function defined by Haskell computation over symbolic expressions.
      inlineDefineFun :: Ctx.CurryAssignmentClass args
                      => sym
                         -- ^ Symbolic interface
                      -> SolverSymbol
                      -- ^ The name to give a function (need not be unique)
                      -> Ctx.Assignment BaseTypeRepr args
                      -- ^ Type signature for the arguments
                      -> UnfoldPolicy
                      -- ^ Policy for unfolding on applications
                      -> Ctx.CurryAssignment args (SymExpr sym) (IO (SymExpr sym ret))
                      -- ^ Operation defining result of defined function.
                      -> IO (SymFn sym args ret)
      inlineDefineFun sym
    sym SolverSymbol
    nm Assignment BaseTypeRepr args
    tps UnfoldPolicy
    policy CurryAssignment args (SymExpr sym) (IO (SymExpr sym ret))
    f = do
        -- Create bound variables for function
        Assignment (BoundVar sym) args
    vars <- (forall (x :: BaseType). BaseTypeRepr x -> IO (BoundVar sym x))
    -> forall (x :: Ctx BaseType).
       Assignment BaseTypeRepr x -> IO (Assignment (BoundVar sym) x)
    forall k l (t :: (k -> Type) -> l -> Type) (f :: k -> Type)
           (g :: k -> Type) (m :: Type -> Type).
    (TraversableFC t, Applicative m) =>
    (forall (x :: k). f x -> m (g x))
    -> forall (x :: l). t f x -> m (t g x)
    forall (f :: BaseType -> Type) (g :: BaseType -> Type)
           (m :: Type -> Type).
    Applicative m =>
    (forall (x :: BaseType). f x -> m (g x))
    -> forall (x :: Ctx BaseType). Assignment f x -> m (Assignment g x)
    traverseFC (sym -> SolverSymbol -> BaseTypeRepr x -> IO (BoundVar sym x)
    forall sym (tp :: BaseType).
    IsSymExprBuilder sym =>
    sym -> SolverSymbol -> BaseTypeRepr tp -> IO (BoundVar sym tp)
    forall (tp :: BaseType).
    sym -> SolverSymbol -> BaseTypeRepr tp -> IO (BoundVar sym tp)
    freshBoundVar sym
    sym SolverSymbol
    emptySymbol) Assignment BaseTypeRepr args
    tps
        -- Call operation on expressions created from variables
        SymExpr sym ret
    r <- CurryAssignment args (SymExpr sym) (IO (SymExpr sym ret))
    -> Assignment (SymExpr sym) args -> IO (SymExpr sym ret)
    forall k (ctx :: Ctx k) (f :: k -> Type) x.
    CurryAssignmentClass ctx =>
    CurryAssignment ctx f x -> Assignment f ctx -> x
    forall (f :: BaseType -> Type) x.
    CurryAssignment args f x -> Assignment f args -> x
    Ctx.uncurryAssignment CurryAssignment args (SymExpr sym) (IO (SymExpr sym ret))
    f ((forall (x :: BaseType). BoundVar sym x -> SymExpr sym x)
    -> forall (x :: Ctx BaseType).
       Assignment (BoundVar sym) x -> Assignment (SymExpr sym) x
    forall k l (t :: (k -> Type) -> l -> Type) (f :: k -> Type)
           (g :: k -> Type).
    FunctorFC t =>
    (forall (x :: k). f x -> g x) -> forall (x :: l). t f x -> t g x
    forall (f :: BaseType -> Type) (g :: BaseType -> Type).
    (forall (x :: BaseType). f x -> g x)
    -> forall (x :: Ctx BaseType). Assignment f x -> Assignment g x
    fmapFC (sym -> BoundVar sym x -> SymExpr sym x
    forall sym (tp :: BaseType).
    IsSymExprBuilder sym =>
    sym -> BoundVar sym tp -> SymExpr sym tp
    forall (tp :: BaseType). sym -> BoundVar sym tp -> SymExpr sym tp
    varExpr sym
    sym) Assignment (BoundVar sym) args
    vars)
        -- Define function
        sym
    -> SolverSymbol
    -> Assignment (BoundVar sym) args
    -> SymExpr sym ret
    -> UnfoldPolicy
    -> IO (SymFn sym args ret)
    forall sym (args :: Ctx BaseType) (ret :: BaseType).
    IsSymExprBuilder sym =>
    sym
    -> SolverSymbol
    -> Assignment (BoundVar sym) args
    -> SymExpr sym ret
    -> UnfoldPolicy
    -> IO (SymFn sym args ret)
    forall (args :: Ctx BaseType) (ret :: BaseType).
    sym
    -> SolverSymbol
    -> Assignment (BoundVar sym) args
    -> SymExpr sym ret
    -> UnfoldPolicy
    -> IO (SymFn sym args ret)
    definedFn sym
    sym SolverSymbol
    nm Assignment (BoundVar sym) args
    vars SymExpr sym ret
    r UnfoldPolicy
    policy

      -- | Create a new uninterpreted function.
      freshTotalUninterpFn :: forall args ret
                            .  sym
                              -- ^ Symbolic interface
                           -> SolverSymbol
                              -- ^ The name to give a function (need not be unique)
                           -> Ctx.Assignment BaseTypeRepr args
                              -- ^ Types of arguments expected by function
                           -> BaseTypeRepr ret
                               -- ^ Return type of function
                           -> IO (SymFn sym args ret)

      -- | Apply a set of arguments to a symbolic function.
      applySymFn :: sym
                    -- ^ Symbolic interface
                 -> SymFn sym args ret
                    -- ^ Function to call
                 -> Ctx.Assignment (SymExpr sym) args
                    -- ^ Arguments to function
                 -> IO (SymExpr sym ret)

      -- | Apply a variable substitution (variable to symbolic expression mapping)
      -- to a symbolic expression.
      substituteBoundVars ::
        sym ->
        MapF (BoundVar sym) (SymExpr sym) ->
        SymExpr sym tp ->
        IO (SymExpr sym tp)

      -- | Apply a function substitution (function to function mapping) to a
      -- symbolic expression.
      substituteSymFns ::
        sym ->
        MapF (SymFnWrapper sym) (SymFnWrapper sym) ->
        SymExpr sym tp ->
        IO (SymExpr sym tp)

    -- | This returns true if the value corresponds to a concrete value.
    baseIsConcrete :: forall e bt
                    . IsExpr e
                   => e bt
                   -> Bool
    baseIsConcrete :: forall (e :: BaseType -> Type) (bt :: BaseType).
    IsExpr e =>
    e bt -> Bool
    baseIsConcrete e bt
    x =
      case e bt -> BaseTypeRepr bt
    forall (tp :: BaseType). e tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType e bt
    x of
        BaseTypeRepr bt
    BaseBoolRepr    -> Maybe Bool -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe Bool -> Bool) -> Maybe Bool -> Bool
    forall a b. (a -> b) -> a -> b
    $ e BaseBoolType -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred e bt
    e BaseBoolType
    x
        BaseTypeRepr bt
    BaseIntegerRepr -> Maybe Integer -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe Integer -> Bool) -> Maybe Integer -> Bool
    forall a b. (a -> b) -> a -> b
    $ e BaseIntegerType -> Maybe Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> Maybe Integer
    asInteger e bt
    e BaseIntegerType
    x
        BaseBVRepr NatRepr w
    _    -> Maybe (BV w) -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe (BV w) -> Bool) -> Maybe (BV w) -> Bool
    forall a b. (a -> b) -> a -> b
    $ e ('BaseBVType w) -> Maybe (BV w)
    forall (w :: Nat). e (BaseBVType w) -> Maybe (BV w)
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> Maybe (BV w)
    asBV e bt
    e ('BaseBVType w)
    x
        BaseTypeRepr bt
    BaseRealRepr    -> Maybe Rational -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe Rational -> Bool) -> Maybe Rational -> Bool
    forall a b. (a -> b) -> a -> b
    $ e BaseRealType -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational e bt
    e BaseRealType
    x
        BaseFloatRepr FloatPrecisionRepr fpp
    _ -> Bool
    False
        BaseStringRepr{} -> Maybe (StringLiteral si) -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe (StringLiteral si) -> Bool)
    -> Maybe (StringLiteral si) -> Bool
    forall a b. (a -> b) -> a -> b
    $ e ('BaseStringType si) -> Maybe (StringLiteral si)
    forall (si :: StringInfo).
    e (BaseStringType si) -> Maybe (StringLiteral si)
    forall (e :: BaseType -> Type) (si :: StringInfo).
    IsExpr e =>
    e (BaseStringType si) -> Maybe (StringLiteral si)
    asString e bt
    e ('BaseStringType si)
    x
        BaseTypeRepr bt
    BaseComplexRepr -> Maybe (Complex Rational) -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe (Complex Rational) -> Bool)
    -> Maybe (Complex Rational) -> Bool
    forall a b. (a -> b) -> a -> b
    $ e BaseComplexType -> Maybe (Complex Rational)
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseComplexType -> Maybe (Complex Rational)
    asComplex e bt
    e BaseComplexType
    x
        BaseStructRepr Assignment BaseTypeRepr ctx
    _ -> case e ('BaseStructType ctx) -> Maybe (Assignment e ctx)
    forall (flds :: Ctx BaseType).
    e (BaseStructType flds) -> Maybe (Assignment e flds)
    forall (e :: BaseType -> Type) (flds :: Ctx BaseType).
    IsExpr e =>
    e (BaseStructType flds) -> Maybe (Assignment e flds)
    asStruct e bt
    e ('BaseStructType ctx)
    x of
            Just Assignment e ctx
    flds -> (forall (x :: BaseType). e x -> Bool)
    -> forall (x :: Ctx BaseType). Assignment e x -> Bool
    forall {k} {l} (t :: (k -> Type) -> l -> Type) (f :: k -> Type).
    FoldableFC t =>
    (forall (x :: k). f x -> Bool) -> forall (x :: l). t f x -> Bool
    allFC e x -> Bool
    forall (x :: BaseType). e x -> Bool
    forall (e :: BaseType -> Type) (bt :: BaseType).
    IsExpr e =>
    e bt -> Bool
    baseIsConcrete Assignment e ctx
    flds
            Maybe (Assignment e ctx)
    Nothing -> Bool
    False
        BaseArrayRepr Assignment BaseTypeRepr (idx ::> tp)
    _ BaseTypeRepr xs
    _bt' -> do
          case e ('BaseArrayType (idx ::> tp) xs) -> Maybe (e xs)
    forall (idx :: Ctx BaseType) (bt :: BaseType).
    e (BaseArrayType idx bt) -> Maybe (e bt)
    forall (e :: BaseType -> Type) (idx :: Ctx BaseType)
           (bt :: BaseType).
    IsExpr e =>
    e (BaseArrayType idx bt) -> Maybe (e bt)
    asConstantArray e bt
    e ('BaseArrayType (idx ::> tp) xs)
    x of
            Just e xs
    x' -> e xs -> Bool
    forall (e :: BaseType -> Type) (bt :: BaseType).
    IsExpr e =>
    e bt -> Bool
    baseIsConcrete e xs
    x'
            Maybe (e xs)
    Nothing -> Bool
    False

    -- | Return some default value for each base type.
    --   For numeric types, this is 0; for booleans, false;
    --   for strings, the empty string.  Structs are
    --   filled with default values for every field,
    --   default arrays are constant arrays of default values.
    baseDefaultValue :: forall sym bt
                      . IsExprBuilder sym
                     => sym
                     -> BaseTypeRepr bt
                     -> IO (SymExpr sym bt)
    baseDefaultValue :: forall sym (bt :: BaseType).
    IsExprBuilder sym =>
    sym -> BaseTypeRepr bt -> IO (SymExpr sym bt)
    baseDefaultValue sym
    sym BaseTypeRepr bt
    bt =
      case BaseTypeRepr bt
    bt of
        BaseTypeRepr bt
    BaseBoolRepr    -> SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType))
    -> SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)
    forall a b. (a -> b) -> a -> b
    $! sym -> SymExpr sym BaseBoolType
    forall sym. IsExprBuilder sym => sym -> Pred sym
    falsePred sym
    sym
        BaseTypeRepr bt
    BaseIntegerRepr -> sym -> Integer -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    0
        BaseBVRepr NatRepr w
    w    -> sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w (NatRepr w -> BV w
    forall (w :: Nat). NatRepr w -> BV w
    BV.zero NatRepr w
    w)
        BaseTypeRepr bt
    BaseRealRepr    -> SymExpr sym BaseRealType -> IO (SymExpr sym BaseRealType)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (SymExpr sym BaseRealType -> IO (SymExpr sym BaseRealType))
    -> SymExpr sym BaseRealType -> IO (SymExpr sym BaseRealType)
    forall a b. (a -> b) -> a -> b
    $! sym -> SymExpr sym BaseRealType
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym
        BaseFloatRepr FloatPrecisionRepr fpp
    fpp -> sym -> FloatPrecisionRepr fpp -> IO (SymFloat sym fpp)
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym -> FloatPrecisionRepr fpp -> IO (SymFloat sym fpp)
    forall (fpp :: FloatPrecision).
    sym -> FloatPrecisionRepr fpp -> IO (SymFloat sym fpp)
    floatPZero sym
    sym FloatPrecisionRepr fpp
    fpp
        BaseTypeRepr bt
    BaseComplexRepr -> sym -> Complex Rational -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex Rational -> IO (SymCplx sym)
    mkComplexLit sym
    sym (Rational
    0 Rational -> Rational -> Complex Rational
    forall a. a -> a -> Complex a
    :+ Rational
    0)
        BaseStringRepr StringInfoRepr si
    si -> sym -> StringInfoRepr si -> IO (SymString sym si)
    forall sym (si :: StringInfo).
    IsExprBuilder sym =>
    sym -> StringInfoRepr si -> IO (SymString sym si)
    forall (si :: StringInfo).
    sym -> StringInfoRepr si -> IO (SymString sym si)
    stringEmpty sym
    sym StringInfoRepr si
    si
        BaseStructRepr Assignment BaseTypeRepr ctx
    flds -> do
          let f :: BaseTypeRepr tp -> IO (SymExpr sym tp)
              f :: forall (tp :: BaseType). BaseTypeRepr tp -> IO (SymExpr sym tp)
    f BaseTypeRepr tp
    v = sym -> BaseTypeRepr tp -> IO (SymExpr sym tp)
    forall sym (bt :: BaseType).
    IsExprBuilder sym =>
    sym -> BaseTypeRepr bt -> IO (SymExpr sym bt)
    baseDefaultValue sym
    sym BaseTypeRepr tp
    v
          sym
    -> Assignment (SymExpr sym) ctx
    -> IO (SymExpr sym ('BaseStructType ctx))
    forall sym (flds :: Ctx BaseType).
    IsExprBuilder sym =>
    sym -> Assignment (SymExpr sym) flds -> IO (SymStruct sym flds)
    forall (flds :: Ctx BaseType).
    sym -> Assignment (SymExpr sym) flds -> IO (SymStruct sym flds)
    mkStruct sym
    sym (Assignment (SymExpr sym) ctx
     -> IO (SymExpr sym ('BaseStructType ctx)))
    -> IO (Assignment (SymExpr sym) ctx)
    -> IO (SymExpr sym ('BaseStructType ctx))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (forall (tp :: BaseType). BaseTypeRepr tp -> IO (SymExpr sym tp))
    -> forall (x :: Ctx BaseType).
       Assignment BaseTypeRepr x -> IO (Assignment (SymExpr sym) x)
    forall k l (t :: (k -> Type) -> l -> Type) (f :: k -> Type)
           (g :: k -> Type) (m :: Type -> Type).
    (TraversableFC t, Applicative m) =>
    (forall (x :: k). f x -> m (g x))
    -> forall (x :: l). t f x -> m (t g x)
    forall (f :: BaseType -> Type) (g :: BaseType -> Type)
           (m :: Type -> Type).
    Applicative m =>
    (forall (x :: BaseType). f x -> m (g x))
    -> forall (x :: Ctx BaseType). Assignment f x -> m (Assignment g x)
    traverseFC BaseTypeRepr x -> IO (SymExpr sym x)
    forall (tp :: BaseType). BaseTypeRepr tp -> IO (SymExpr sym tp)
    f Assignment BaseTypeRepr ctx
    flds
        BaseArrayRepr Assignment BaseTypeRepr (idx ::> tp)
    idx BaseTypeRepr xs
    bt' -> do
          SymExpr sym xs
    elt <- sym -> BaseTypeRepr xs -> IO (SymExpr sym xs)
    forall sym (bt :: BaseType).
    IsExprBuilder sym =>
    sym -> BaseTypeRepr bt -> IO (SymExpr sym bt)
    baseDefaultValue sym
    sym BaseTypeRepr xs
    bt'
          sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym xs
    -> IO (SymExpr sym ('BaseArrayType (idx ::> tp) xs))
    forall sym (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    forall (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    constantArray sym
    sym Assignment BaseTypeRepr (idx ::> tp)
    idx SymExpr sym xs
    elt

    -- | Return predicate equivalent to a Boolean.
    backendPred :: IsExprBuilder sym => sym -> Bool -> Pred sym
    backendPred :: forall sym. IsExprBuilder sym => sym -> Bool -> Pred sym
    backendPred sym
    sym Bool
    True  = sym -> SymExpr sym BaseBoolType
    forall sym. IsExprBuilder sym => sym -> Pred sym
    truePred  sym
    sym
    backendPred sym
    sym Bool
    False = sym -> SymExpr sym BaseBoolType
    forall sym. IsExprBuilder sym => sym -> Pred sym
    falsePred sym
    sym

    -- | Create a value from a rational.
    mkRational :: IsExprBuilder sym => sym -> Rational -> IO (SymCplx sym)
    mkRational :: forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymCplx sym)
    mkRational sym
    sym Rational
    v = sym -> Complex Rational -> IO (SymExpr sym BaseComplexType)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex Rational -> IO (SymCplx sym)
    mkComplexLit sym
    sym (Rational
    v Rational -> Rational -> Complex Rational
    forall a. a -> a -> Complex a
    :+ Rational
    0)

    -- | Create a value from an integer.
    mkReal  :: (IsExprBuilder sym, Real a) => sym -> a -> IO (SymCplx sym)
    mkReal :: forall sym a.
    (IsExprBuilder sym, Real a) =>
    sym -> a -> IO (SymCplx sym)
    mkReal sym
    sym a
    v = sym -> Rational -> IO (SymExpr sym BaseComplexType)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymCplx sym)
    mkRational sym
    sym (a -> Rational
    forall a. Real a => a -> Rational
    toRational a
    v)

    -- | Return 1 if the predicate is true; 0 otherwise.
    predToReal :: IsExprBuilder sym => sym -> Pred sym -> IO (SymReal sym)
    predToReal :: forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> IO (SymReal sym)
    predToReal sym
    sym Pred sym
    p = do
      SymReal sym
    r1 <- sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    1
      sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realIte sym
    sym Pred sym
    p SymReal sym
    r1 (sym -> SymReal sym
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym)

    -- | Extract the value of a rational expression; fail if the
    --   value is not a constant.
    realExprAsRational :: (MonadFail m, IsExpr e) => e BaseRealType -> m Rational
    realExprAsRational :: forall (m :: Type -> Type) (e :: BaseType -> Type).
    (MonadFail m, IsExpr e) =>
    e BaseRealType -> m Rational
    realExprAsRational e BaseRealType
    x = do
      case e BaseRealType -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational e BaseRealType
    x of
        Just Rational
    r -> Rational -> m Rational
    forall a. a -> m a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return Rational
    r
        Maybe Rational
    Nothing -> String -> m Rational
    forall a. String -> m a
    forall (m :: Type -> Type) a. MonadFail m => String -> m a
    fail String
    "Value is not a constant expression."

    -- | Extract the value of a complex expression, which is assumed
    --   to be a constant real number.  Fail if the number has nonzero
    --   imaginary component, or if it is not a constant.
    cplxExprAsRational :: (MonadFail m, IsExpr e) => e BaseComplexType -> m Rational
    cplxExprAsRational :: forall (m :: Type -> Type) (e :: BaseType -> Type).
    (MonadFail m, IsExpr e) =>
    e BaseComplexType -> m Rational
    cplxExprAsRational e BaseComplexType
    x = do
      case e BaseComplexType -> Maybe (Complex Rational)
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseComplexType -> Maybe (Complex Rational)
    asComplex e BaseComplexType
    x of
        Just (Rational
    r :+ Rational
    i) -> do
          Bool -> m () -> m ()
    forall (f :: Type -> Type). Applicative f => Bool -> f () -> f ()
    when (Rational
    i Rational -> Rational -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Rational
    0) (m () -> m ()) -> m () -> m ()
    forall a b. (a -> b) -> a -> b
    $
            String -> m ()
    forall a. String -> m a
    forall (m :: Type -> Type) a. MonadFail m => String -> m a
    fail String
    "Complex value has an imaginary part."
          Rational -> m Rational
    forall a. a -> m a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return Rational
    r
        Maybe (Complex Rational)
    Nothing -> do
          String -> m Rational
    forall a. String -> m a
    forall (m :: Type -> Type) a. MonadFail m => String -> m a
    fail String
    "Complex value is not a constant expression."

    -- | Return a complex value as a constant integer if it exists.
    cplxExprAsInteger :: (MonadFail m, IsExpr e) => e BaseComplexType -> m Integer
    cplxExprAsInteger :: forall (m :: Type -> Type) (e :: BaseType -> Type).
    (MonadFail m, IsExpr e) =>
    e BaseComplexType -> m Integer
    cplxExprAsInteger e BaseComplexType
    x = Rational -> m Integer
    forall (m :: Type -> Type). MonadFail m => Rational -> m Integer
    rationalAsInteger (Rational -> m Integer) -> m Rational -> m Integer
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< e BaseComplexType -> m Rational
    forall (m :: Type -> Type) (e :: BaseType -> Type).
    (MonadFail m, IsExpr e) =>
    e BaseComplexType -> m Rational
    cplxExprAsRational e BaseComplexType
    x

    -- | Return value as a constant integer if it exists.
    rationalAsInteger :: MonadFail m => Rational -> m Integer
    rationalAsInteger :: forall (m :: Type -> Type). MonadFail m => Rational -> m Integer
    rationalAsInteger Rational
    r = do
      Bool -> m () -> m ()
    forall (f :: Type -> Type). Applicative f => Bool -> f () -> f ()
    when (Rational -> Integer
    forall a. Ratio a -> a
    denominator Rational
    r Integer -> Integer -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Integer
    1) (m () -> m ()) -> m () -> m ()
    forall a b. (a -> b) -> a -> b
    $ do
        String -> m ()
    forall a. String -> m a
    forall (m :: Type -> Type) a. MonadFail m => String -> m a
    fail String
    "Value is not an integer."
      Integer -> m Integer
    forall a. a -> m a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (Rational -> Integer
    forall a. Ratio a -> a
    numerator Rational
    r)

    -- | Return value as a constant integer if it exists.
    realExprAsInteger :: (IsExpr e, MonadFail m) => e BaseRealType -> m Integer
    realExprAsInteger :: forall (e :: BaseType -> Type) (m :: Type -> Type).
    (IsExpr e, MonadFail m) =>
    e BaseRealType -> m Integer
    realExprAsInteger e BaseRealType
    x =
      Rational -> m Integer
    forall (m :: Type -> Type). MonadFail m => Rational -> m Integer
    rationalAsInteger (Rational -> m Integer) -> m Rational -> m Integer
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< e BaseRealType -> m Rational
    forall (m :: Type -> Type) (e :: BaseType -> Type).
    (MonadFail m, IsExpr e) =>
    e BaseRealType -> m Rational
    realExprAsRational e BaseRealType
    x

    -- | Compute the conjunction of a sequence of predicates.
    andAllOf :: IsExprBuilder sym
             => sym
             -> Fold s (Pred sym)
             -> s
             -> IO (Pred sym)
    andAllOf :: forall sym s.
    IsExprBuilder sym =>
    sym -> Fold s (Pred sym) -> s -> IO (Pred sym)
    andAllOf sym
    sym Fold s (SymExpr sym BaseBoolType)
    f s
    s = Getting
      (Endo (SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)))
      s
      (SymExpr sym BaseBoolType)
    -> (SymExpr sym BaseBoolType
        -> SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType))
    -> SymExpr sym BaseBoolType
    -> s
    -> IO (SymExpr sym BaseBoolType)
    forall (m :: Type -> Type) r s a.
    Monad m =>
    Getting (Endo (r -> m r)) s a -> (r -> a -> m r) -> r -> s -> m r
    foldlMOf Getting
      (Endo (SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)))
      s
      (SymExpr sym BaseBoolType)
    Fold s (SymExpr sym BaseBoolType)
    f (sym
    -> SymExpr sym BaseBoolType
    -> SymExpr sym BaseBoolType
    -> IO (SymExpr sym BaseBoolType)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    andPred sym
    sym) (sym -> SymExpr sym BaseBoolType
    forall sym. IsExprBuilder sym => sym -> Pred sym
    truePred sym
    sym) s
    s

    -- | Compute the disjunction of a sequence of predicates.
    orOneOf :: IsExprBuilder sym
             => sym
             -> Fold s (Pred sym)
             -> s
             -> IO (Pred sym)
    orOneOf :: forall sym s.
    IsExprBuilder sym =>
    sym -> Fold s (Pred sym) -> s -> IO (Pred sym)
    orOneOf sym
    sym Fold s (SymExpr sym BaseBoolType)
    f s
    s = Getting
      (Endo (SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)))
      s
      (SymExpr sym BaseBoolType)
    -> (SymExpr sym BaseBoolType
        -> SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType))
    -> SymExpr sym BaseBoolType
    -> s
    -> IO (SymExpr sym BaseBoolType)
    forall (m :: Type -> Type) r s a.
    Monad m =>
    Getting (Endo (r -> m r)) s a -> (r -> a -> m r) -> r -> s -> m r
    foldlMOf Getting
      (Endo (SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)))
      s
      (SymExpr sym BaseBoolType)
    Fold s (SymExpr sym BaseBoolType)
    f (sym
    -> SymExpr sym BaseBoolType
    -> SymExpr sym BaseBoolType
    -> IO (SymExpr sym BaseBoolType)
    forall sym.
    IsExprBuilder sym =>
    sym -> Pred sym -> Pred sym -> IO (Pred sym)
    orPred sym
    sym) (sym -> SymExpr sym BaseBoolType
    forall sym. IsExprBuilder sym => sym -> Pred sym
    falsePred sym
    sym) s
    s

    -- | Return predicate that holds if value is non-zero.
    isNonZero :: IsExprBuilder sym => sym -> SymCplx sym -> IO (Pred sym)
    isNonZero :: forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Pred sym)
    isNonZero sym
    sym SymCplx sym
    v = sym -> SymCplx sym -> SymCplx sym -> IO (SymExpr sym BaseBoolType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> SymCplx sym -> IO (Pred sym)
    cplxNe sym
    sym SymCplx sym
    v (SymCplx sym -> IO (SymExpr sym BaseBoolType))
    -> IO (SymCplx sym) -> IO (SymExpr sym BaseBoolType)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Rational -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymCplx sym)
    mkRational sym
    sym Rational
    0

    -- | Return predicate that holds if imaginary part of number is zero.
    isReal :: IsExprBuilder sym => sym -> SymCplx sym -> IO (Pred sym)
    isReal :: forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Pred sym)
    isReal sym
    sym SymCplx sym
    v = do
      SymExpr sym BaseRealType
    i <- sym -> SymCplx sym -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (SymReal sym)
    getImagPart sym
    sym SymCplx sym
    v
      sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (Pred sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (Pred sym)
    realEq sym
    sym SymExpr sym BaseRealType
    i (sym -> SymExpr sym BaseRealType
    forall sym. IsExprBuilder sym => sym -> SymReal sym
    realZero sym
    sym)

    -- | Divide one number by another.
    --
    --   @cplxDiv x y@ is undefined when @y@ is @0@.
    cplxDiv :: IsExprBuilder sym
            => sym
            -> SymCplx sym
            -> SymCplx sym
            -> IO (SymCplx sym)
    cplxDiv :: forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> SymCplx sym -> IO (SymCplx sym)
    cplxDiv sym
    sym SymCplx sym
    x SymCplx sym
    y = do
      SymExpr sym BaseRealType
    xr :+ SymExpr sym BaseRealType
    xi <- sym -> SymCplx sym -> IO (Complex (SymExpr sym BaseRealType))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
      yc :: Complex (SymExpr sym BaseRealType)
    yc@(SymExpr sym BaseRealType
    yr :+ SymExpr sym BaseRealType
    yi) <- sym -> SymCplx sym -> IO (Complex (SymExpr sym BaseRealType))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    y
      case SymExpr sym BaseRealType -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational (SymExpr sym BaseRealType -> Maybe Rational)
    -> Complex (SymExpr sym BaseRealType) -> Complex (Maybe Rational)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Complex (SymExpr sym BaseRealType)
    yc of
        (Maybe Rational
    _ :+ Just Rational
    0) -> do
          Complex (SymExpr sym BaseRealType)
    zc <- SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType)
    forall a. a -> a -> Complex a
    (:+) (SymExpr sym BaseRealType
     -> SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    -> IO (SymExpr sym BaseRealType)
    -> IO
         (SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymExpr sym BaseRealType
    xr SymExpr sym BaseRealType
    yr IO (SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    -> IO (SymExpr sym BaseRealType)
    -> IO (Complex (SymExpr sym BaseRealType))
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymExpr sym BaseRealType
    xi SymExpr sym BaseRealType
    yr
          sym -> Complex (SymExpr sym BaseRealType) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym Complex (SymExpr sym BaseRealType)
    zc
        (Just Rational
    0 :+ Maybe Rational
    _) -> do
          Complex (SymExpr sym BaseRealType)
    zc <- SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType)
    forall a. a -> a -> Complex a
    (:+) (SymExpr sym BaseRealType
     -> SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    -> IO (SymExpr sym BaseRealType)
    -> IO
         (SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymExpr sym BaseRealType
    xi SymExpr sym BaseRealType
    yi IO (SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    -> IO (SymExpr sym BaseRealType)
    -> IO (Complex (SymExpr sym BaseRealType))
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymExpr sym BaseRealType
    xr SymExpr sym BaseRealType
    yi
          sym -> Complex (SymExpr sym BaseRealType) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym Complex (SymExpr sym BaseRealType)
    zc
        Complex (Maybe Rational)
    _ -> do
          SymExpr sym BaseRealType
    yr_abs <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymExpr sym BaseRealType
    yr SymExpr sym BaseRealType
    yr
          SymExpr sym BaseRealType
    yi_abs <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymExpr sym BaseRealType
    yi SymExpr sym BaseRealType
    yi
          SymExpr sym BaseRealType
    y_abs <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymExpr sym BaseRealType
    yr_abs SymExpr sym BaseRealType
    yi_abs

          SymExpr sym BaseRealType
    zr_1 <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymExpr sym BaseRealType
    xr SymExpr sym BaseRealType
    yr
          SymExpr sym BaseRealType
    zr_2 <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymExpr sym BaseRealType
    xi SymExpr sym BaseRealType
    yi
          SymExpr sym BaseRealType
    zr <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAdd sym
    sym SymExpr sym BaseRealType
    zr_1 SymExpr sym BaseRealType
    zr_2

          SymExpr sym BaseRealType
    zi_1 <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymExpr sym BaseRealType
    xi SymExpr sym BaseRealType
    yr
          SymExpr sym BaseRealType
    zi_2 <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realMul sym
    sym SymExpr sym BaseRealType
    xr SymExpr sym BaseRealType
    yi
          SymExpr sym BaseRealType
    zi <- sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realSub sym
    sym SymExpr sym BaseRealType
    zi_1 SymExpr sym BaseRealType
    zi_2

          Complex (SymExpr sym BaseRealType)
    zc <- SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType)
    forall a. a -> a -> Complex a
    (:+) (SymExpr sym BaseRealType
     -> SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    -> IO (SymExpr sym BaseRealType)
    -> IO
         (SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymExpr sym BaseRealType
    zr SymExpr sym BaseRealType
    y_abs IO (SymExpr sym BaseRealType -> Complex (SymExpr sym BaseRealType))
    -> IO (SymExpr sym BaseRealType)
    -> IO (Complex (SymExpr sym BaseRealType))
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymExpr sym BaseRealType
    zi SymExpr sym BaseRealType
    y_abs
          sym -> Complex (SymExpr sym BaseRealType) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym Complex (SymExpr sym BaseRealType)
    zc

    -- | Helper function that returns the principal logarithm of input.
    cplxLog' :: IsExprBuilder sym
             => sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxLog' :: forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxLog' sym
    sym SymCplx sym
    x = do
      SymReal sym
    xr :+ SymReal sym
    xi <- sym -> SymCplx sym -> IO (Complex (SymReal sym))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxGetParts sym
    sym SymCplx sym
    x
      -- Get the magnitude of the value.
      SymReal sym
    xm <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realHypot sym
    sym SymReal sym
    xr SymReal sym
    xi
      -- Get angle of complex number.
      SymReal sym
    xa <- sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realAtan2 sym
    sym SymReal sym
    xi SymReal sym
    xr
      -- Get log of magnitude
      SymReal sym
    zr <- sym -> SymReal sym -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realLog sym
    sym SymReal sym
    xm
      Complex (SymReal sym) -> IO (Complex (SymReal sym))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (Complex (SymReal sym) -> IO (Complex (SymReal sym)))
    -> Complex (SymReal sym) -> IO (Complex (SymReal sym))
    forall a b. (a -> b) -> a -> b
    $! SymReal sym
    zr SymReal sym -> SymReal sym -> Complex (SymReal sym)
    forall a. a -> a -> Complex a
    :+ SymReal sym
    xa

    -- | Returns the principal logarithm of the input value.
    --
    --   @cplxLog x@ is undefined when @x@ is @0@, and has a
    --   cut discontinuity along the negative real line.
    cplxLog :: IsExprBuilder sym
            => sym -> SymCplx sym -> IO (SymCplx sym)
    cplxLog :: forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (SymCplx sym)
    cplxLog sym
    sym SymCplx sym
    x = sym -> Complex (SymExpr sym BaseRealType) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym (Complex (SymExpr sym BaseRealType) -> IO (SymCplx sym))
    -> IO (Complex (SymExpr sym BaseRealType)) -> IO (SymCplx sym)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymCplx sym -> IO (Complex (SymExpr sym BaseRealType))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxLog' sym
    sym SymCplx sym
    x

    -- | Returns logarithm of input at a given base.
    --
    --   @cplxLogBase b x@ is undefined when @x@ is @0@.
    cplxLogBase :: IsExprBuilder sym
                => Rational {- ^ Base for the logarithm -}
                -> sym
                -> SymCplx sym
                -> IO (SymCplx sym)
    cplxLogBase :: forall sym.
    IsExprBuilder sym =>
    Rational -> sym -> SymCplx sym -> IO (SymCplx sym)
    cplxLogBase Rational
    base sym
    sym SymCplx sym
    x = do
      SymExpr sym BaseRealType
    b <- sym -> SymExpr sym BaseRealType -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> IO (SymReal sym)
    realLog sym
    sym (SymExpr sym BaseRealType -> IO (SymExpr sym BaseRealType))
    -> IO (SymExpr sym BaseRealType) -> IO (SymExpr sym BaseRealType)
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> Rational -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    base
      Complex (SymExpr sym BaseRealType)
    z <- (SymExpr sym BaseRealType -> IO (SymExpr sym BaseRealType))
    -> Complex (SymExpr sym BaseRealType)
    -> IO (Complex (SymExpr sym BaseRealType))
    forall (t :: Type -> Type) (f :: Type -> Type) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    forall (f :: Type -> Type) a b.
    Applicative f =>
    (a -> f b) -> Complex a -> f (Complex b)
    traverse (\SymExpr sym BaseRealType
    r -> sym
    -> SymExpr sym BaseRealType
    -> SymExpr sym BaseRealType
    -> IO (SymExpr sym BaseRealType)
    forall sym.
    IsExprBuilder sym =>
    sym -> SymReal sym -> SymReal sym -> IO (SymReal sym)
    realDiv sym
    sym SymExpr sym BaseRealType
    r SymExpr sym BaseRealType
    b) (Complex (SymExpr sym BaseRealType)
     -> IO (Complex (SymExpr sym BaseRealType)))
    -> IO (Complex (SymExpr sym BaseRealType))
    -> IO (Complex (SymExpr sym BaseRealType))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> SymCplx sym -> IO (Complex (SymExpr sym BaseRealType))
    forall sym.
    IsExprBuilder sym =>
    sym -> SymCplx sym -> IO (Complex (SymReal sym))
    cplxLog' sym
    sym SymCplx sym
    x
      sym -> Complex (SymExpr sym BaseRealType) -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex (SymReal sym) -> IO (SymCplx sym)
    mkComplex sym
    sym Complex (SymExpr sym BaseRealType)
    z

    --------------------------------------------------------------------------
    -- Relationship to concrete values

    -- | Return a concrete representation of a value, if it
    --   is concrete.
    asConcrete :: IsExpr e => e tp -> Maybe (ConcreteVal tp)
    asConcrete :: forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> Maybe (ConcreteVal tp)
    asConcrete e tp
    x =
      case e tp -> BaseTypeRepr tp
    forall (tp :: BaseType). e tp -> BaseTypeRepr tp
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> BaseTypeRepr tp
    exprType e tp
    x of
        BaseTypeRepr tp
    BaseBoolRepr       -> Bool -> ConcreteVal tp
    Bool -> ConcreteVal BaseBoolType
    ConcreteBool (Bool -> ConcreteVal tp) -> Maybe Bool -> Maybe (ConcreteVal tp)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> e BaseBoolType -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred e tp
    e BaseBoolType
    x
        BaseTypeRepr tp
    BaseIntegerRepr    -> Integer -> ConcreteVal tp
    Integer -> ConcreteVal BaseIntegerType
    ConcreteInteger (Integer -> ConcreteVal tp)
    -> Maybe Integer -> Maybe (ConcreteVal tp)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> e BaseIntegerType -> Maybe Integer
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseIntegerType -> Maybe Integer
    asInteger e tp
    e BaseIntegerType
    x
        BaseTypeRepr tp
    BaseRealRepr       -> Rational -> ConcreteVal tp
    Rational -> ConcreteVal BaseRealType
    ConcreteReal (Rational -> ConcreteVal tp)
    -> Maybe Rational -> Maybe (ConcreteVal tp)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> e BaseRealType -> Maybe Rational
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseRealType -> Maybe Rational
    asRational e tp
    e BaseRealType
    x
        BaseStringRepr StringInfoRepr si
    _si -> StringLiteral si -> ConcreteVal tp
    StringLiteral si -> ConcreteVal ('BaseStringType si)
    forall (si :: StringInfo).
    StringLiteral si -> ConcreteVal ('BaseStringType si)
    ConcreteString (StringLiteral si -> ConcreteVal tp)
    -> Maybe (StringLiteral si) -> Maybe (ConcreteVal tp)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> e ('BaseStringType si) -> Maybe (StringLiteral si)
    forall (si :: StringInfo).
    e (BaseStringType si) -> Maybe (StringLiteral si)
    forall (e :: BaseType -> Type) (si :: StringInfo).
    IsExpr e =>
    e (BaseStringType si) -> Maybe (StringLiteral si)
    asString e tp
    e ('BaseStringType si)
    x
        BaseTypeRepr tp
    BaseComplexRepr    -> Complex Rational -> ConcreteVal tp
    Complex Rational -> ConcreteVal BaseComplexType
    ConcreteComplex (Complex Rational -> ConcreteVal tp)
    -> Maybe (Complex Rational) -> Maybe (ConcreteVal tp)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> e BaseComplexType -> Maybe (Complex Rational)
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseComplexType -> Maybe (Complex Rational)
    asComplex e tp
    e BaseComplexType
    x
        BaseBVRepr NatRepr w
    w       -> NatRepr w -> BV w -> ConcreteVal ('BaseBVType w)
    forall (w :: Nat).
    (1 <= w) =>
    NatRepr w -> BV w -> ConcreteVal ('BaseBVType w)
    ConcreteBV NatRepr w
    w (BV w -> ConcreteVal tp) -> Maybe (BV w) -> Maybe (ConcreteVal tp)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> e ('BaseBVType w) -> Maybe (BV w)
    forall (w :: Nat). e (BaseBVType w) -> Maybe (BV w)
    forall (e :: BaseType -> Type) (w :: Nat).
    IsExpr e =>
    e (BaseBVType w) -> Maybe (BV w)
    asBV e tp
    e ('BaseBVType w)
    x
        BaseFloatRepr FloatPrecisionRepr fpp
    fpp  -> FloatPrecisionRepr fpp
    -> BigFloat -> ConcreteVal ('BaseFloatType fpp)
    forall (fpp :: FloatPrecision).
    FloatPrecisionRepr fpp
    -> BigFloat -> ConcreteVal ('BaseFloatType fpp)
    ConcreteFloat FloatPrecisionRepr fpp
    fpp (BigFloat -> ConcreteVal tp)
    -> Maybe BigFloat -> Maybe (ConcreteVal tp)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> e ('BaseFloatType fpp) -> Maybe BigFloat
    forall (fpp :: FloatPrecision).
    e (BaseFloatType fpp) -> Maybe BigFloat
    forall (e :: BaseType -> Type) (fpp :: FloatPrecision).
    IsExpr e =>
    e (BaseFloatType fpp) -> Maybe BigFloat
    asFloat e tp
    e ('BaseFloatType fpp)
    x
        BaseStructRepr Assignment BaseTypeRepr ctx
    _   -> Assignment ConcreteVal ctx -> ConcreteVal tp
    Assignment ConcreteVal ctx -> ConcreteVal ('BaseStructType ctx)
    forall (ctx :: Ctx BaseType).
    Assignment ConcreteVal ctx -> ConcreteVal ('BaseStructType ctx)
    ConcreteStruct (Assignment ConcreteVal ctx -> ConcreteVal tp)
    -> Maybe (Assignment ConcreteVal ctx) -> Maybe (ConcreteVal tp)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> (e ('BaseStructType ctx) -> Maybe (Assignment e ctx)
    forall (flds :: Ctx BaseType).
    e (BaseStructType flds) -> Maybe (Assignment e flds)
    forall (e :: BaseType -> Type) (flds :: Ctx BaseType).
    IsExpr e =>
    e (BaseStructType flds) -> Maybe (Assignment e flds)
    asStruct e tp
    e ('BaseStructType ctx)
    x Maybe (Assignment e ctx)
    -> (Assignment e ctx -> Maybe (Assignment ConcreteVal ctx))
    -> Maybe (Assignment ConcreteVal ctx)
    forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
    forall (m :: Type -> Type) a b. Monad m => m a -> (a -> m b) -> m b
    >>= (forall (x :: BaseType). e x -> Maybe (ConcreteVal x))
    -> forall (x :: Ctx BaseType).
       Assignment e x -> Maybe (Assignment ConcreteVal x)
    forall k l (t :: (k -> Type) -> l -> Type) (f :: k -> Type)
           (g :: k -> Type) (m :: Type -> Type).
    (TraversableFC t, Applicative m) =>
    (forall (x :: k). f x -> m (g x))
    -> forall (x :: l). t f x -> m (t g x)
    forall (f :: BaseType -> Type) (g :: BaseType -> Type)
           (m :: Type -> Type).
    Applicative m =>
    (forall (x :: BaseType). f x -> m (g x))
    -> forall (x :: Ctx BaseType). Assignment f x -> m (Assignment g x)
    traverseFC e x -> Maybe (ConcreteVal x)
    forall (x :: BaseType). e x -> Maybe (ConcreteVal x)
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> Maybe (ConcreteVal tp)
    asConcrete)
        BaseArrayRepr Assignment BaseTypeRepr (idx ::> tp)
    idx BaseTypeRepr xs
    _tp -> do
          e xs
    def <- e ('BaseArrayType (idx ::> tp) xs) -> Maybe (e xs)
    forall (idx :: Ctx BaseType) (bt :: BaseType).
    e (BaseArrayType idx bt) -> Maybe (e bt)
    forall (e :: BaseType -> Type) (idx :: Ctx BaseType)
           (bt :: BaseType).
    IsExpr e =>
    e (BaseArrayType idx bt) -> Maybe (e bt)
    asConstantArray e tp
    e ('BaseArrayType (idx ::> tp) xs)
    x
          ConcreteVal xs
    c_def <- e xs -> Maybe (ConcreteVal xs)
    forall (e :: BaseType -> Type) (tp :: BaseType).
    IsExpr e =>
    e tp -> Maybe (ConcreteVal tp)
    asConcrete e xs
    def
          -- TODO: what about cases where there are updates to the array?
          -- Passing Map.empty is probably wrong.
          ConcreteVal tp -> Maybe (ConcreteVal tp)
    forall a. a -> Maybe a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure (Assignment BaseTypeRepr (idx ::> tp)
    -> ConcreteVal xs
    -> Map (Assignment ConcreteVal (idx ::> tp)) (ConcreteVal xs)
    -> ConcreteVal ('BaseArrayType (idx ::> tp) xs)
    forall (idx :: Ctx BaseType) (i :: BaseType) (b :: BaseType).
    Assignment BaseTypeRepr (idx ::> i)
    -> ConcreteVal b
    -> Map (Assignment ConcreteVal (idx ::> i)) (ConcreteVal b)
    -> ConcreteVal ('BaseArrayType (idx ::> i) b)
    ConcreteArray Assignment BaseTypeRepr (idx ::> tp)
    idx ConcreteVal xs
    c_def Map (Assignment ConcreteVal (idx ::> tp)) (ConcreteVal xs)
    forall k a. Map k a
    Map.empty)

    -- | Create a literal symbolic value from a concrete value.
    concreteToSym :: IsExprBuilder sym => sym -> ConcreteVal tp -> IO (SymExpr sym tp)
    concreteToSym :: forall sym (tp :: BaseType).
    IsExprBuilder sym =>
    sym -> ConcreteVal tp -> IO (SymExpr sym tp)
    concreteToSym sym
    sym = \case
       ConcreteBool Bool
    True    -> SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (sym -> SymExpr sym BaseBoolType
    forall sym. IsExprBuilder sym => sym -> Pred sym
    truePred sym
    sym)
       ConcreteBool Bool
    False   -> SymExpr sym BaseBoolType -> IO (SymExpr sym BaseBoolType)
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return (sym -> SymExpr sym BaseBoolType
    forall sym. IsExprBuilder sym => sym -> Pred sym
    falsePred sym
    sym)
       ConcreteInteger Integer
    x    -> sym -> Integer -> IO (SymInteger sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Integer -> IO (SymInteger sym)
    intLit sym
    sym Integer
    x
       ConcreteReal Rational
    x       -> sym -> Rational -> IO (SymReal sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Rational -> IO (SymReal sym)
    realLit sym
    sym Rational
    x
       ConcreteFloat FloatPrecisionRepr fpp
    fpp BigFloat
    bf -> sym -> FloatPrecisionRepr fpp -> BigFloat -> IO (SymFloat sym fpp)
    forall sym (fpp :: FloatPrecision).
    IsExprBuilder sym =>
    sym -> FloatPrecisionRepr fpp -> BigFloat -> IO (SymFloat sym fpp)
    forall (fpp :: FloatPrecision).
    sym -> FloatPrecisionRepr fpp -> BigFloat -> IO (SymFloat sym fpp)
    floatLit sym
    sym FloatPrecisionRepr fpp
    fpp BigFloat
    bf
       ConcreteString StringLiteral si
    x     -> sym -> StringLiteral si -> IO (SymString sym si)
    forall sym (si :: StringInfo).
    IsExprBuilder sym =>
    sym -> StringLiteral si -> IO (SymString sym si)
    forall (si :: StringInfo).
    sym -> StringLiteral si -> IO (SymString sym si)
    stringLit sym
    sym StringLiteral si
    x
       ConcreteComplex Complex Rational
    x    -> sym -> Complex Rational -> IO (SymCplx sym)
    forall sym.
    IsExprBuilder sym =>
    sym -> Complex Rational -> IO (SymCplx sym)
    mkComplexLit sym
    sym Complex Rational
    x
       ConcreteBV NatRepr w
    w BV w
    x       -> sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall (w :: Nat).
    (1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    forall sym (w :: Nat).
    (IsExprBuilder sym, 1 <= w) =>
    sym -> NatRepr w -> BV w -> IO (SymBV sym w)
    bvLit sym
    sym NatRepr w
    w BV w
    x
       ConcreteStruct Assignment ConcreteVal ctx
    xs    -> sym
    -> Assignment (SymExpr sym) ctx
    -> IO (SymExpr sym ('BaseStructType ctx))
    forall sym (flds :: Ctx BaseType).
    IsExprBuilder sym =>
    sym -> Assignment (SymExpr sym) flds -> IO (SymStruct sym flds)
    forall (flds :: Ctx BaseType).
    sym -> Assignment (SymExpr sym) flds -> IO (SymStruct sym flds)
    mkStruct sym
    sym (Assignment (SymExpr sym) ctx
     -> IO (SymExpr sym ('BaseStructType ctx)))
    -> IO (Assignment (SymExpr sym) ctx)
    -> IO (SymExpr sym ('BaseStructType ctx))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< (forall (x :: BaseType). ConcreteVal x -> IO (SymExpr sym x))
    -> forall (x :: Ctx BaseType).
       Assignment ConcreteVal x -> IO (Assignment (SymExpr sym) x)
    forall k l (t :: (k -> Type) -> l -> Type) (f :: k -> Type)
           (g :: k -> Type) (m :: Type -> Type).
    (TraversableFC t, Applicative m) =>
    (forall (x :: k). f x -> m (g x))
    -> forall (x :: l). t f x -> m (t g x)
    forall (f :: BaseType -> Type) (g :: BaseType -> Type)
           (m :: Type -> Type).
    Applicative m =>
    (forall (x :: BaseType). f x -> m (g x))
    -> forall (x :: Ctx BaseType). Assignment f x -> m (Assignment g x)
    traverseFC (sym -> ConcreteVal x -> IO (SymExpr sym x)
    forall sym (tp :: BaseType).
    IsExprBuilder sym =>
    sym -> ConcreteVal tp -> IO (SymExpr sym tp)
    concreteToSym sym
    sym) Assignment ConcreteVal ctx
    xs
       ConcreteArray Assignment BaseTypeRepr (idx ::> i)
    idxTy ConcreteVal b
    def Map (Assignment ConcreteVal (idx ::> i)) (ConcreteVal b)
    xs0 -> [(Assignment ConcreteVal (idx ::> i), ConcreteVal b)]
    -> SymExpr sym ('BaseArrayType (idx ::> i) b)
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    go (Map (Assignment ConcreteVal (idx ::> i)) (ConcreteVal b)
    -> [(Assignment ConcreteVal (idx ::> i), ConcreteVal b)]
    forall k a. Map k a -> [(k, a)]
    Map.toAscList Map (Assignment ConcreteVal (idx ::> i)) (ConcreteVal b)
    xs0) (SymExpr sym ('BaseArrayType (idx ::> i) b)
     -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b)))
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym
    -> Assignment BaseTypeRepr (idx ::> i)
    -> SymExpr sym b
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    forall sym (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    forall (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    sym
    -> Assignment BaseTypeRepr (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    constantArray sym
    sym Assignment BaseTypeRepr (idx ::> i)
    idxTy (SymExpr sym b -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b)))
    -> IO (SymExpr sym b)
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
    =<< sym -> ConcreteVal b -> IO (SymExpr sym b)
    forall sym (tp :: BaseType).
    IsExprBuilder sym =>
    sym -> ConcreteVal tp -> IO (SymExpr sym tp)
    concreteToSym sym
    sym ConcreteVal b
    def
         where
         go :: [(Assignment ConcreteVal (idx ::> i), ConcreteVal b)]
    -> SymExpr sym ('BaseArrayType (idx ::> i) b)
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    go [] SymExpr sym ('BaseArrayType (idx ::> i) b)
    arr = SymExpr sym ('BaseArrayType (idx ::> i) b)
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return SymExpr sym ('BaseArrayType (idx ::> i) b)
    arr
         go ((Assignment ConcreteVal (idx ::> i)
    i,ConcreteVal b
    x):[(Assignment ConcreteVal (idx ::> i), ConcreteVal b)]
    xs) SymExpr sym ('BaseArrayType (idx ::> i) b)
    arr =
            do SymExpr sym ('BaseArrayType (idx ::> i) b)
    arr' <- [(Assignment ConcreteVal (idx ::> i), ConcreteVal b)]
    -> SymExpr sym ('BaseArrayType (idx ::> i) b)
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    go [(Assignment ConcreteVal (idx ::> i), ConcreteVal b)]
    xs SymExpr sym ('BaseArrayType (idx ::> i) b)
    arr
               Assignment (SymExpr sym) (idx ::> i)
    i' <- (forall (x :: BaseType). ConcreteVal x -> IO (SymExpr sym x))
    -> forall (x :: Ctx BaseType).
       Assignment ConcreteVal x -> IO (Assignment (SymExpr sym) x)
    forall k l (t :: (k -> Type) -> l -> Type) (f :: k -> Type)
           (g :: k -> Type) (m :: Type -> Type).
    (TraversableFC t, Applicative m) =>
    (forall (x :: k). f x -> m (g x))
    -> forall (x :: l). t f x -> m (t g x)
    forall (f :: BaseType -> Type) (g :: BaseType -> Type)
           (m :: Type -> Type).
    Applicative m =>
    (forall (x :: BaseType). f x -> m (g x))
    -> forall (x :: Ctx BaseType). Assignment f x -> m (Assignment g x)
    traverseFC (sym -> ConcreteVal x -> IO (SymExpr sym x)
    forall sym (tp :: BaseType).
    IsExprBuilder sym =>
    sym -> ConcreteVal tp -> IO (SymExpr sym tp)
    concreteToSym sym
    sym) Assignment ConcreteVal (idx ::> i)
    i
               SymExpr sym b
    x' <- sym -> ConcreteVal b -> IO (SymExpr sym b)
    forall sym (tp :: BaseType).
    IsExprBuilder sym =>
    sym -> ConcreteVal tp -> IO (SymExpr sym tp)
    concreteToSym sym
    sym ConcreteVal b
    x
               sym
    -> SymExpr sym ('BaseArrayType (idx ::> i) b)
    -> Assignment (SymExpr sym) (idx ::> i)
    -> SymExpr sym b
    -> IO (SymExpr sym ('BaseArrayType (idx ::> i) b))
    forall sym (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    IsExprBuilder sym =>
    sym
    -> SymArray sym (idx ::> tp) b
    -> Assignment (SymExpr sym) (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    forall (idx :: Ctx BaseType) (tp :: BaseType) (b :: BaseType).
    sym
    -> SymArray sym (idx ::> tp) b
    -> Assignment (SymExpr sym) (idx ::> tp)
    -> SymExpr sym b
    -> IO (SymArray sym (idx ::> tp) b)
    arrayUpdate sym
    sym SymExpr sym ('BaseArrayType (idx ::> i) b)
    arr' Assignment (SymExpr sym) (idx ::> i)
    i' SymExpr sym b
    x'

    ------------------------------------------------------------------------
    -- muxNatRange

    {-# INLINABLE muxRange #-}
    {- | This function is used for selecting a value from among potential
    values in a range.

    @muxRange p ite f l h@ returns an expression denoting the value obtained
    from the value @f i@ where @i@ is the smallest value in the range @[l..h]@
    such that @p i@ is true.  If @p i@ is true for no such value, then
    this returns the value @f h@. -}
    muxRange :: (IsExpr e, Monad m) =>
       (Natural -> m (e BaseBoolType))
          {- ^ Returns predicate that holds if we have found the value we are looking
               for.  It is assumed that the predicate must hold for a unique integer in
               the range.
          -} ->
       (e BaseBoolType -> a -> a -> m a) {- ^ Ite function -} ->
       (Natural -> m a) {- ^ Function for concrete values -} ->
       Natural {- ^ Lower bound (inclusive) -} ->
       Natural {- ^ Upper bound (inclusive) -} ->
       m a
    muxRange :: forall (e :: BaseType -> Type) (m :: Type -> Type) a.
    (IsExpr e, Monad m) =>
    (Nat -> m (e BaseBoolType))
    -> (e BaseBoolType -> a -> a -> m a)
    -> (Nat -> m a)
    -> Nat
    -> Nat
    -> m a
    muxRange Nat -> m (e BaseBoolType)
    predFn e BaseBoolType -> a -> a -> m a
    iteFn Nat -> m a
    f Nat
    l Nat
    h
      | Nat
    l Nat -> Nat -> Bool
    forall a. Ord a => a -> a -> Bool
    < Nat
    h = do
        e BaseBoolType
    c <- Nat -> m (e BaseBoolType)
    predFn Nat
    l
        case e BaseBoolType -> Maybe Bool
    forall (e :: BaseType -> Type).
    IsExpr e =>
    e BaseBoolType -> Maybe Bool
    asConstantPred e BaseBoolType
    c of
          Just Bool
    True  -> Nat -> m a
    f Nat
    l
          Just Bool
    False -> (Nat -> m (e BaseBoolType))
    -> (e BaseBoolType -> a -> a -> m a)
    -> (Nat -> m a)
    -> Nat
    -> Nat
    -> m a
    forall (e :: BaseType -> Type) (m :: Type -> Type) a.
    (IsExpr e, Monad m) =>
    (Nat -> m (e BaseBoolType))
    -> (e BaseBoolType -> a -> a -> m a)
    -> (Nat -> m a)
    -> Nat
    -> Nat
    -> m a
    muxRange Nat -> m (e BaseBoolType)
    predFn e BaseBoolType -> a -> a -> m a
    iteFn Nat -> m a
    f (Nat -> Nat
    forall a. Enum a => a -> a
    succ Nat
    l) Nat
    h
          Maybe Bool
    Nothing ->
            do a
    match_branch <- Nat -> m a
    f Nat
    l
               a
    other_branch <- (Nat -> m (e BaseBoolType))
    -> (e BaseBoolType -> a -> a -> m a)
    -> (Nat -> m a)
    -> Nat
    -> Nat
    -> m a
    forall (e :: BaseType -> Type) (m :: Type -> Type) a.
    (IsExpr e, Monad m) =>
    (Nat -> m (e BaseBoolType))
    -> (e BaseBoolType -> a -> a -> m a)
    -> (Nat -> m a)
    -> Nat
    -> Nat
    -> m a
    muxRange Nat -> m (e BaseBoolType)
    predFn e BaseBoolType -> a -> a -> m a
    iteFn Nat -> m a
    f (Nat -> Nat
    forall a. Enum a => a -> a
    succ Nat
    l) Nat
    h
               e BaseBoolType -> a -> a -> m a
    iteFn e BaseBoolType
    c a
    match_branch a
    other_branch
      | Bool
    otherwise = Nat -> m a
    f Nat
    h

    -- | This provides an interface for converting between Haskell values and a
    -- solver representation.
    data SymEncoder sym v tp
       = SymEncoder { forall sym v (tp :: BaseType).
    SymEncoder sym v tp -> BaseTypeRepr tp
    symEncoderType :: !(BaseTypeRepr tp)
                    , forall sym v (tp :: BaseType).
    SymEncoder sym v tp -> sym -> SymExpr sym tp -> IO v
    symFromExpr :: !(sym -> SymExpr sym tp -> IO v)
                    , forall sym v (tp :: BaseType).
    SymEncoder sym v tp -> sym -> v -> IO (SymExpr sym tp)
    symToExpr   :: !(sym -> v -> IO (SymExpr sym tp))
                    }

    ----------------------------------------------------------------------
    -- Statistics

    -- | Statistics gathered on a running expression builder.  See
    -- 'getStatistics'.
    data Statistics
      = Statistics { Statistics -> Integer
    statAllocs :: !Integer
                     -- ^ The number of times an expression node has been
                     -- allocated.
                   , Statistics -> Integer
    statNonLinearOps :: !Integer
                     -- ^ The number of non-linear operations, such as
                     -- multiplications, that have occurred.
                   }
      deriving ( Int -> Statistics -> ShowS
    [Statistics] -> ShowS
    Statistics -> String
    (Int -> Statistics -> ShowS)
    -> (Statistics -> String)
    -> ([Statistics] -> ShowS)
    -> Show Statistics
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Statistics -> ShowS
    showsPrec :: Int -> Statistics -> ShowS
    $cshow :: Statistics -> String
    show :: Statistics -> String
    $cshowList :: [Statistics] -> ShowS
    showList :: [Statistics] -> ShowS
    Show )

    zeroStatistics :: Statistics
    zeroStatistics :: Statistics
    zeroStatistics = Statistics { statAllocs :: Integer
    statAllocs = Integer
    0
                                , statNonLinearOps :: Integer
    statNonLinearOps = Integer
    0 }