what4-1.6: src/What4/Expr/MATLAB.hs
{-|
Module : What4.Expr.MATLAB
Description : Low-level support for MATLAB-style arithmetic operations
Copyright : (c) Galois, Inc, 2016-2020
License : BSD3
Maintainer : Joe Hendrix <jhendrix@galois.com>
This module provides an interface that a symbolic backend should
implement to support MATLAB intrinsics.
-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
module What4.Expr.MATLAB
( MatlabSolverFn(..)
, matlabSolverArgTypes
, matlabSolverReturnType
, ppMatlabSolverFn
, evalMatlabSolverFn
, testSolverFnEq
, traverseMatlabSolverFn
, MatlabSymbolicArrayBuilder(..)
-- * Utilities for definition
, clampedIntAdd
, clampedIntSub
, clampedIntMul
, clampedIntNeg
, clampedIntAbs
, clampedUIntAdd
, clampedUIntSub
, clampedUIntMul
) where
import Control.Monad (join)
import qualified Data.BitVector.Sized as BV
import Data.Kind (Type)
import Data.Hashable
import Data.Parameterized.Classes
import Data.Parameterized.Context as Ctx
import Data.Parameterized.TH.GADT
import Data.Parameterized.TraversableFC
import Prettyprinter
import What4.BaseTypes
import What4.Interface
import What4.Utils.Complex
import What4.Utils.OnlyIntRepr
------------------------------------------------------------------------
-- MatlabSolverFn
clampedIntAdd :: (IsExprBuilder sym, 1 <= w)
=> sym
-> SymBV sym w
-> SymBV sym w
-> IO (SymBV sym w)
clampedIntAdd sym x y = do
let w = bvWidth x
withAddPrefixLeq w (knownNat :: NatRepr 1) $ do
-- Compute result with 1 additional bit to catch clamping
let w' = incNat w
x' <- bvSext sym w' x
y' <- bvSext sym w' y
-- Compute result.
r' <- bvAdd sym x' y'
-- Check is result is greater than or equal to max value.
too_high <- bvSgt sym r' =<< bvLit sym w' (BV.maxSigned w')
max_int <- bvLit sym w (BV.maxSigned w)
-- Check is result is less than min value.
too_low <- bvSlt sym r' =<< bvLit sym w' (BV.minSigned w')
min_int <- bvLit sym w (BV.minSigned w)
-- Clamp integer range.
r <- bvTrunc sym w r'
r_low <- bvIte sym too_low min_int r
bvIte sym too_high max_int r_low
clampedIntSub :: (IsExprBuilder sym, 1 <= w)
=> sym
-> SymBV sym w
-> SymBV sym w
-> IO (SymBV sym w)
clampedIntSub sym x y = do
let w = bvWidth x
(ov, xy) <- subSignedOF sym x y
ysign <- bvIsNeg sym y
minint <- minSignedBV sym w
maxint <- maxSignedBV sym w
ov_val <- bvIte sym ysign maxint minint
bvIte sym ov ov_val xy
clampedIntMul :: (IsExprBuilder sym, 1 <= w)
=> sym
-> SymBV sym w
-> SymBV sym w
-> IO (SymBV sym w)
clampedIntMul sym x y = do
let w = bvWidth x
(hi,lo) <- signedWideMultiplyBV sym x y
zro <- bvZero sym w
ones <- maxUnsignedBV sym w
ok_pos <- join $ andPred sym <$> (notPred sym =<< bvIsNeg sym lo)
<*> bvEq sym hi zro
ok_neg <- join $ andPred sym <$> bvIsNeg sym lo
<*> bvEq sym hi ones
ov <- notPred sym =<< orPred sym ok_pos ok_neg
minint <- minSignedBV sym w
maxint <- maxSignedBV sym w
hisign <- bvIsNeg sym hi
ov_val <- bvIte sym hisign minint maxint
bvIte sym ov ov_val lo
-- | Compute the clamped negation of a signed bitvector.
--
-- The only difference between this operation and the usual
-- 2's complement negation function is the handling of MIN_INT.
-- The usual 2's complement negation sends MIN_INT to MIN_INT;
-- however, the clamped version instead sends MIN_INT to MAX_INT.
clampedIntNeg :: (IsExprBuilder sym, 1 <= w)
=> sym
-> SymBV sym w
-> IO (SymBV sym w)
clampedIntNeg sym x = do
let w = bvWidth x
minint <- minSignedBV sym w
-- return maxint when x == minint, and neg(x) otherwise
p <- bvEq sym x minint
iteM bvIte sym p (maxSignedBV sym w) (bvNeg sym x)
-- | Compute the clamped absolute value of a signed bitvector.
--
-- The only difference between this operation and the usual 2's
-- complement operation is the handling of MIN_INT. The usual 2's
-- complement absolute value function sends MIN_INT to MIN_INT;
-- however, the clamped version instead sends MIN_INT to MAX_INT.
clampedIntAbs :: (IsExprBuilder sym, 1 <= w)
=> sym
-> SymBV sym w
-> IO (SymBV sym w)
clampedIntAbs sym x = do
isNeg <- bvIsNeg sym x
iteM bvIte sym isNeg (clampedIntNeg sym x) (pure x)
clampedUIntAdd :: (IsExprBuilder sym, 1 <= w)
=> sym
-> SymBV sym w
-> SymBV sym w
-> IO (SymBV sym w)
clampedUIntAdd sym x y = do
let w = bvWidth x
(ov, xy) <- addUnsignedOF sym x y
maxint <- maxUnsignedBV sym w
bvIte sym ov maxint xy
clampedUIntSub :: (IsExprBuilder sym, 1 <= w)
=> sym
-> SymBV sym w
-> SymBV sym w
-> IO (SymBV sym w)
clampedUIntSub sym x y = do
let w = bvWidth x
no_underflow <- bvUge sym x y
iteM bvIte
sym
no_underflow
(bvSub sym x y) -- Perform subtraction if y >= x
(bvZero sym w) -- Otherwise return min int
clampedUIntMul :: (IsExprBuilder sym, 1 <= w)
=> sym
-> SymBV sym w
-> SymBV sym w
-> IO (SymBV sym w)
clampedUIntMul sym x y = do
let w = bvWidth x
(hi, lo) <- unsignedWideMultiplyBV sym x y
maxint <- maxUnsignedBV sym w
ov <- bvIsNonzero sym hi
bvIte sym ov maxint lo
------------------------------------------------------------------------
-- MatlabSolverFn
-- | Builtin functions that can be used to generate symbolic functions.
--
-- These functions are expected to be total, but the value returned may not be
-- specified. e.g. 'IntegerToNatFn' must return some natural number for every
-- integer, but for negative integers, the particular number is unspecified.
data MatlabSolverFn (f :: BaseType -> Type) args ret where
-- Or two Boolean variables
BoolOrFn :: MatlabSolverFn f (EmptyCtx ::> BaseBoolType ::> BaseBoolType) BaseBoolType
-- Returns true if the real value is an integer.
IsIntegerFn :: MatlabSolverFn f (EmptyCtx ::> BaseRealType) BaseBoolType
-- Return true if first value is less than or equal to second.
IntLeFn :: MatlabSolverFn f (EmptyCtx ::> BaseIntegerType ::> BaseIntegerType) BaseBoolType
-- A function for mapping a unsigned bitvector to an integer.
BVToIntegerFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType w) BaseIntegerType
-- A function for mapping a signed bitvector to a integer.
SBVToIntegerFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType w) BaseIntegerType
-- A function for mapping an integer to equivalent real.
IntegerToRealFn :: MatlabSolverFn f (EmptyCtx ::> BaseIntegerType) BaseRealType
-- A function for mapping a real to equivalent integer.
--
-- Function may return any value if input is not an integer.
RealToIntegerFn :: MatlabSolverFn f (EmptyCtx ::> BaseRealType) BaseIntegerType
-- A function that maps Booleans logical value to an integer
-- (either 0 for false, or 1 for true)
PredToIntegerFn :: MatlabSolverFn f (EmptyCtx ::> BaseBoolType) BaseIntegerType
-- 'IntSeqFn base c' denotes the function '\i _ -> base + c*i
IntSeqFn :: !(f BaseIntegerType)
-> !(f BaseIntegerType)
-> MatlabSolverFn f (EmptyCtx ::> BaseIntegerType ::> BaseIntegerType) BaseIntegerType
-- 'RealSeqFn base c' denotes the function '\_ i -> base + c*i
RealSeqFn :: !(f BaseRealType)
-> !(f BaseRealType)
-> MatlabSolverFn f (EmptyCtx ::> BaseIntegerType ::> BaseIntegerType) BaseRealType
-- 'IndicesInRange tps upper_bounds' returns a predicate that is true if all the arguments
-- (which must be natural numbers) are between 1 and the given upper bounds (inclusive).
IndicesInRange :: !(Assignment OnlyIntRepr (idx ::> itp))
-> !(Assignment f (idx ::> itp))
-- Upper bounds on indices
-> MatlabSolverFn f (idx ::> itp) BaseBoolType
IsEqFn :: !(BaseTypeRepr tp)
-> MatlabSolverFn f (EmptyCtx ::> tp ::> tp) BaseBoolType
------------------------------------------------------------------------
-- Bitvector functions
-- Returns true if the bitvector is non-zero.
BVIsNonZeroFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType w) BaseBoolType
-- Negate a signed bitvector
ClampedIntNegFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType w) (BaseBVType w)
-- Get absolute value of a signed bitvector
ClampedIntAbsFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType w) (BaseBVType w)
-- Add two values without wrapping but rather rounding to
-- 0/max value when the result is out of range.
ClampedIntAddFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f
(EmptyCtx ::> BaseBVType w ::> BaseBVType w)
(BaseBVType w)
-- Subtract one value from another without wrapping but rather rounding to
-- 0/max value when the result is out of range.
ClampedIntSubFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f
(EmptyCtx ::> BaseBVType w ::> BaseBVType w)
(BaseBVType w)
-- Multiple two values without wrapping but rather rounding to
-- 0/max value when the result is out of range.
ClampedIntMulFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f
(EmptyCtx ::> BaseBVType w ::> BaseBVType w)
(BaseBVType w)
-- Add two values without wrapping but rather rounding to
-- 0/max value when the result is out of range.
ClampedUIntAddFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f
(EmptyCtx ::> BaseBVType w ::> BaseBVType w)
(BaseBVType w)
-- Subtract one value from another without wrapping but rather rounding to
-- 0/max value when the result is out of range.
ClampedUIntSubFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f
(EmptyCtx ::> BaseBVType w ::> BaseBVType w)
(BaseBVType w)
-- Multiple two values without wrapping but rather rounding to
-- 0/max value when the result is out of range.
ClampedUIntMulFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f
(EmptyCtx ::> BaseBVType w ::> BaseBVType w)
(BaseBVType w)
-- Convert a signed integer to the nearest signed integer with the
-- given width. This clamps the value to min-int or max int when truncated
-- the width.
IntSetWidthFn :: (1 <= m, 1 <= n)
=> !(NatRepr m)
-> !(NatRepr n)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType m) (BaseBVType n)
-- Convert a unsigned integer to the nearest unsigned integer with the
-- given width. This clamps the value to min-int or max int when truncated
-- the width.
UIntSetWidthFn :: (1 <= m, 1 <= n)
=> !(NatRepr m)
-> !(NatRepr n)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType m) (BaseBVType n)
-- Convert a unsigned integer to the nearest signed integer with the
-- given width. This clamps the value to min-int or max int when truncated
-- the width.
UIntToIntFn :: (1 <= m, 1 <= n)
=> !(NatRepr m)
-> !(NatRepr n)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType m) (BaseBVType n)
-- Convert a signed integer to the nearest unsigned integer with the
-- given width. This clamps the value to min-int or max int when truncated
-- the width.
IntToUIntFn :: (1 <= m, 1 <= n)
=> !(NatRepr m)
-> !(NatRepr n)
-> MatlabSolverFn f (EmptyCtx ::> BaseBVType m) (BaseBVType n)
------------------------------------------------------------------------
-- Real functions
-- Returns true if the complex number is non-zero.
RealIsNonZeroFn :: MatlabSolverFn f (EmptyCtx ::> BaseRealType) BaseBoolType
RealCosFn :: MatlabSolverFn f (EmptyCtx ::> BaseRealType) BaseRealType
RealSinFn :: MatlabSolverFn f (EmptyCtx ::> BaseRealType) BaseRealType
------------------------------------------------------------------------
-- Conversion functions
RealToSBVFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f (EmptyCtx ::> BaseRealType) (BaseBVType w)
RealToUBVFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f (EmptyCtx ::> BaseRealType) (BaseBVType w)
-- Return 1 if the predicate is true; 0 otherwise.
PredToBVFn :: (1 <= w)
=> !(NatRepr w)
-> MatlabSolverFn f (EmptyCtx ::> BaseBoolType) (BaseBVType w)
------------------------------------------------------------------------
-- Complex functions
-- Returns true if the complex number is non-zero.
CplxIsNonZeroFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseBoolType
-- Returns true if the imaginary part of complex number is zero.
CplxIsRealFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseBoolType
-- A function for mapping a real to equivalent complex with imaginary number equals 0.
RealToComplexFn :: MatlabSolverFn f (EmptyCtx ::> BaseRealType) BaseComplexType
-- Returns the real component out of a complex number.
RealPartOfCplxFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseRealType
-- Returns the imag component out of a complex number.
ImagPartOfCplxFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseRealType
-- Return the complex number formed by negating both components.
CplxNegFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseComplexType
-- Add two complex values.
CplxAddFn :: MatlabSolverFn f
(EmptyCtx ::> BaseComplexType ::> BaseComplexType)
BaseComplexType
-- Subtract one complex value from another.
CplxSubFn :: MatlabSolverFn f
(EmptyCtx ::> BaseComplexType ::> BaseComplexType)
BaseComplexType
-- Multiply two complex values.
CplxMulFn :: MatlabSolverFn f
(EmptyCtx ::> BaseComplexType ::> BaseComplexType)
BaseComplexType
-- Return the complex number formed by rounding both components.
--
-- Rounding is away from zero.
CplxRoundFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseComplexType
-- Return the complex number formed by taking floor of both components.
CplxFloorFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseComplexType
-- Return the complex number formed by taking ceiling of both components.
CplxCeilFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseComplexType
-- Return magningture of complex number.
CplxMagFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseRealType
-- Return the principal square root of a complex number.
CplxSqrtFn :: MatlabSolverFn f (EmptyCtx ::> BaseComplexType) BaseComplexType
-- Returns complex exponential of input
CplxExpFn :: MatlabSolverFn f
(EmptyCtx ::> BaseComplexType)
BaseComplexType
-- Returns complex natural logarithm of input
CplxLogFn :: MatlabSolverFn f
(EmptyCtx ::> BaseComplexType)
BaseComplexType
-- Returns complex natural logarithm of input
CplxLogBaseFn :: !Integer
-> MatlabSolverFn f
(EmptyCtx ::> BaseComplexType)
BaseComplexType
-- Returns complex sine of input
CplxSinFn :: MatlabSolverFn f
(EmptyCtx ::> BaseComplexType)
BaseComplexType
-- Returns complex cosine of input
CplxCosFn :: MatlabSolverFn f
(EmptyCtx ::> BaseComplexType)
BaseComplexType
-- Returns tangent of input.
--
CplxTanFn :: MatlabSolverFn f
(EmptyCtx ::> BaseComplexType)
BaseComplexType
-- Dummy declaration splice to bring App into template haskell scope.
$(return [])
traverseMatlabSolverFn :: Applicative m
=> (forall tp . e tp -> m (f tp))
-> MatlabSolverFn e a r
-> m (MatlabSolverFn f a r)
traverseMatlabSolverFn f fn_id =
case fn_id of
BoolOrFn -> pure $ BoolOrFn
IsIntegerFn -> pure $ IsIntegerFn
IntLeFn -> pure $ IntLeFn
BVToIntegerFn w -> pure $ BVToIntegerFn w
SBVToIntegerFn w -> pure $ SBVToIntegerFn w
IntegerToRealFn -> pure $ IntegerToRealFn
RealToIntegerFn -> pure $ RealToIntegerFn
PredToIntegerFn -> pure $ PredToIntegerFn
IntSeqFn b i -> IntSeqFn <$> f b <*> f i
RealSeqFn b i -> RealSeqFn <$> f b <*> f i
IndicesInRange tps a -> IndicesInRange tps <$> traverseFC f a
IsEqFn tp -> pure $ IsEqFn tp
BVIsNonZeroFn w -> pure $ BVIsNonZeroFn w
ClampedIntNegFn w -> pure $ ClampedIntNegFn w
ClampedIntAbsFn w -> pure $ ClampedIntAbsFn w
ClampedIntAddFn w -> pure $ ClampedIntAddFn w
ClampedIntSubFn w -> pure $ ClampedIntSubFn w
ClampedIntMulFn w -> pure $ ClampedIntMulFn w
ClampedUIntAddFn w -> pure $ ClampedUIntAddFn w
ClampedUIntSubFn w -> pure $ ClampedUIntSubFn w
ClampedUIntMulFn w -> pure $ ClampedUIntMulFn w
IntSetWidthFn i o -> pure $ IntSetWidthFn i o
UIntSetWidthFn i o -> pure $ UIntSetWidthFn i o
UIntToIntFn i o -> pure $ UIntToIntFn i o
IntToUIntFn i o -> pure $ IntToUIntFn i o
RealCosFn -> pure $ RealCosFn
RealSinFn -> pure $ RealSinFn
RealIsNonZeroFn -> pure $ RealIsNonZeroFn
RealToSBVFn w -> pure $ RealToSBVFn w
RealToUBVFn w -> pure $ RealToUBVFn w
PredToBVFn w -> pure $ PredToBVFn w
CplxIsNonZeroFn -> pure $ CplxIsNonZeroFn
CplxIsRealFn -> pure $ CplxIsRealFn
RealToComplexFn -> pure $ RealToComplexFn
RealPartOfCplxFn -> pure $ RealPartOfCplxFn
ImagPartOfCplxFn -> pure $ ImagPartOfCplxFn
CplxNegFn -> pure $ CplxNegFn
CplxAddFn -> pure $ CplxAddFn
CplxSubFn -> pure $ CplxSubFn
CplxMulFn -> pure $ CplxMulFn
CplxRoundFn -> pure $ CplxRoundFn
CplxFloorFn -> pure $ CplxFloorFn
CplxCeilFn -> pure $ CplxCeilFn
CplxMagFn -> pure $ CplxMagFn
CplxSqrtFn -> pure $ CplxSqrtFn
CplxExpFn -> pure $ CplxExpFn
CplxLogFn -> pure $ CplxLogFn
CplxLogBaseFn b -> pure $ CplxLogBaseFn b
CplxSinFn -> pure $ CplxSinFn
CplxCosFn -> pure $ CplxCosFn
CplxTanFn -> pure $ CplxTanFn
-- | Utilities to make a pair with the same value.
binCtx :: BaseTypeRepr tp -> Ctx.Assignment BaseTypeRepr (EmptyCtx ::> tp ::> tp)
binCtx tp = Ctx.empty Ctx.:> tp Ctx.:> tp
-- | Get arg tpyes of solver fn.
matlabSolverArgTypes :: MatlabSolverFn f args ret -> Assignment BaseTypeRepr args
matlabSolverArgTypes f =
case f of
BoolOrFn -> knownRepr
IsIntegerFn -> knownRepr
IntLeFn -> knownRepr
BVToIntegerFn w -> Ctx.singleton (BaseBVRepr w)
SBVToIntegerFn w -> Ctx.singleton (BaseBVRepr w)
IntegerToRealFn -> knownRepr
RealToIntegerFn -> knownRepr
PredToIntegerFn -> knownRepr
IntSeqFn{} -> knownRepr
IndicesInRange tps _ -> fmapFC toBaseTypeRepr tps
RealSeqFn _ _ -> knownRepr
IsEqFn tp -> binCtx tp
BVIsNonZeroFn w -> Ctx.singleton (BaseBVRepr w)
ClampedIntNegFn w -> Ctx.singleton (BaseBVRepr w)
ClampedIntAbsFn w -> Ctx.singleton (BaseBVRepr w)
ClampedIntAddFn w -> binCtx (BaseBVRepr w)
ClampedIntSubFn w -> binCtx (BaseBVRepr w)
ClampedIntMulFn w -> binCtx (BaseBVRepr w)
ClampedUIntAddFn w -> binCtx (BaseBVRepr w)
ClampedUIntSubFn w -> binCtx (BaseBVRepr w)
ClampedUIntMulFn w -> binCtx (BaseBVRepr w)
IntSetWidthFn i _ -> Ctx.singleton (BaseBVRepr i)
UIntSetWidthFn i _ -> Ctx.singleton (BaseBVRepr i)
UIntToIntFn i _ -> Ctx.singleton (BaseBVRepr i)
IntToUIntFn i _ -> Ctx.singleton (BaseBVRepr i)
RealCosFn -> knownRepr
RealSinFn -> knownRepr
RealIsNonZeroFn -> knownRepr
RealToSBVFn _ -> knownRepr
RealToUBVFn _ -> knownRepr
PredToBVFn _ -> knownRepr
CplxIsNonZeroFn -> knownRepr
CplxIsRealFn -> knownRepr
RealToComplexFn -> knownRepr
RealPartOfCplxFn -> knownRepr
ImagPartOfCplxFn -> knownRepr
CplxNegFn -> knownRepr
CplxAddFn -> knownRepr
CplxSubFn -> knownRepr
CplxMulFn -> knownRepr
CplxRoundFn -> knownRepr
CplxFloorFn -> knownRepr
CplxCeilFn -> knownRepr
CplxMagFn -> knownRepr
CplxSqrtFn -> knownRepr
CplxExpFn -> knownRepr
CplxLogFn -> knownRepr
CplxLogBaseFn _ -> knownRepr
CplxSinFn -> knownRepr
CplxCosFn -> knownRepr
CplxTanFn -> knownRepr
-- | Get return type of solver fn.
matlabSolverReturnType :: MatlabSolverFn f args ret -> BaseTypeRepr ret
matlabSolverReturnType f =
case f of
BoolOrFn -> knownRepr
IsIntegerFn -> knownRepr
IntLeFn -> knownRepr
BVToIntegerFn{} -> knownRepr
SBVToIntegerFn{} -> knownRepr
IntegerToRealFn -> knownRepr
RealToIntegerFn -> knownRepr
PredToIntegerFn -> knownRepr
IntSeqFn{} -> knownRepr
IndicesInRange{} -> knownRepr
RealSeqFn _ _ -> knownRepr
IsEqFn{} -> knownRepr
BVIsNonZeroFn _ -> knownRepr
ClampedIntNegFn w -> BaseBVRepr w
ClampedIntAbsFn w -> BaseBVRepr w
ClampedIntAddFn w -> BaseBVRepr w
ClampedIntSubFn w -> BaseBVRepr w
ClampedIntMulFn w -> BaseBVRepr w
ClampedUIntAddFn w -> BaseBVRepr w
ClampedUIntSubFn w -> BaseBVRepr w
ClampedUIntMulFn w -> BaseBVRepr w
IntSetWidthFn _ o -> BaseBVRepr o
UIntSetWidthFn _ o -> BaseBVRepr o
UIntToIntFn _ o -> BaseBVRepr o
IntToUIntFn _ o -> BaseBVRepr o
RealCosFn -> knownRepr
RealSinFn -> knownRepr
RealIsNonZeroFn -> knownRepr
RealToSBVFn w -> BaseBVRepr w
RealToUBVFn w -> BaseBVRepr w
PredToBVFn w -> BaseBVRepr w
CplxIsNonZeroFn -> knownRepr
CplxIsRealFn -> knownRepr
RealToComplexFn -> knownRepr
RealPartOfCplxFn -> knownRepr
ImagPartOfCplxFn -> knownRepr
CplxNegFn -> knownRepr
CplxAddFn -> knownRepr
CplxSubFn -> knownRepr
CplxMulFn -> knownRepr
CplxRoundFn -> knownRepr
CplxFloorFn -> knownRepr
CplxCeilFn -> knownRepr
CplxMagFn -> knownRepr
CplxSqrtFn -> knownRepr
CplxExpFn -> knownRepr
CplxLogFn -> knownRepr
CplxLogBaseFn _ -> knownRepr
CplxSinFn -> knownRepr
CplxCosFn -> knownRepr
CplxTanFn -> knownRepr
ppMatlabSolverFn :: IsExpr f => MatlabSolverFn f a r -> Doc ann
ppMatlabSolverFn f =
case f of
BoolOrFn -> pretty "bool_or"
IsIntegerFn -> pretty "is_integer"
IntLeFn -> pretty "int_le"
BVToIntegerFn w -> parens $ pretty "bv_to_int" <+> ppNatRepr w
SBVToIntegerFn w -> parens $ pretty "sbv_to_int" <+> ppNatRepr w
IntegerToRealFn -> pretty "integer_to_real"
RealToIntegerFn -> pretty "real_to_integer"
PredToIntegerFn -> pretty "pred_to_integer"
IntSeqFn b i -> parens $ pretty "nat_seq" <+> printSymExpr b <+> printSymExpr i
RealSeqFn b i -> parens $ pretty "real_seq" <+> printSymExpr b <+> printSymExpr i
IndicesInRange _ bnds ->
parens (pretty "indices_in_range" <+> sep (toListFC printSymExpr bnds))
IsEqFn{} -> pretty "is_eq"
BVIsNonZeroFn w -> parens $ pretty "bv_is_nonzero" <+> ppNatRepr w
ClampedIntNegFn w -> parens $ pretty "clamped_int_neg" <+> ppNatRepr w
ClampedIntAbsFn w -> parens $ pretty "clamped_neg_abs" <+> ppNatRepr w
ClampedIntAddFn w -> parens $ pretty "clamped_int_add" <+> ppNatRepr w
ClampedIntSubFn w -> parens $ pretty "clamped_int_sub" <+> ppNatRepr w
ClampedIntMulFn w -> parens $ pretty "clamped_int_mul" <+> ppNatRepr w
ClampedUIntAddFn w -> parens $ pretty "clamped_uint_add" <+> ppNatRepr w
ClampedUIntSubFn w -> parens $ pretty "clamped_uint_sub" <+> ppNatRepr w
ClampedUIntMulFn w -> parens $ pretty "clamped_uint_mul" <+> ppNatRepr w
IntSetWidthFn i o -> parens $ pretty "int_set_width" <+> ppNatRepr i <+> ppNatRepr o
UIntSetWidthFn i o -> parens $ pretty "uint_set_width" <+> ppNatRepr i <+> ppNatRepr o
UIntToIntFn i o -> parens $ pretty "uint_to_int" <+> ppNatRepr i <+> ppNatRepr o
IntToUIntFn i o -> parens $ pretty "int_to_uint" <+> ppNatRepr i <+> ppNatRepr o
RealCosFn -> pretty "real_cos"
RealSinFn -> pretty "real_sin"
RealIsNonZeroFn -> pretty "real_is_nonzero"
RealToSBVFn w -> parens $ pretty "real_to_sbv" <+> ppNatRepr w
RealToUBVFn w -> parens $ pretty "real_to_sbv" <+> ppNatRepr w
PredToBVFn w -> parens $ pretty "pred_to_bv" <+> ppNatRepr w
CplxIsNonZeroFn -> pretty "cplx_is_nonzero"
CplxIsRealFn -> pretty "cplx_is_real"
RealToComplexFn -> pretty "real_to_complex"
RealPartOfCplxFn -> pretty "real_part_of_complex"
ImagPartOfCplxFn -> pretty "imag_part_of_complex"
CplxNegFn -> pretty "cplx_neg"
CplxAddFn -> pretty "cplx_add"
CplxSubFn -> pretty "cplx_sub"
CplxMulFn -> pretty "cplx_mul"
CplxRoundFn -> pretty "cplx_round"
CplxFloorFn -> pretty "cplx_floor"
CplxCeilFn -> pretty "cplx_ceil"
CplxMagFn -> pretty "cplx_mag"
CplxSqrtFn -> pretty "cplx_sqrt"
CplxExpFn -> pretty "cplx_exp"
CplxLogFn -> pretty "cplx_log"
CplxLogBaseFn b -> parens $ pretty "cplx_log_base" <+> pretty b
CplxSinFn -> pretty "cplx_sin"
CplxCosFn -> pretty "cplx_cos"
CplxTanFn -> pretty "cplx_tan"
ppNatRepr :: NatRepr w -> Doc ann
ppNatRepr = viaShow
-- | Test 'MatlabSolverFn' values for equality.
testSolverFnEq :: TestEquality f
=> MatlabSolverFn f ax rx
-> MatlabSolverFn f ay ry
-> Maybe ((ax ::> rx) :~: (ay ::> ry))
testSolverFnEq = $(structuralTypeEquality [t|MatlabSolverFn|]
[ ( DataArg 0 `TypeApp` AnyType
, [|testEquality|]
)
, ( ConType [t|NatRepr|] `TypeApp` AnyType
, [|testEquality|]
)
, ( ConType [t|Assignment|] `TypeApp` AnyType `TypeApp` AnyType
, [|testEquality|]
)
, ( ConType [t|BaseTypeRepr|] `TypeApp` AnyType
, [|testEquality|]
)
]
)
instance TestEquality f => Eq (MatlabSolverFn f args tp) where
x == y = isJust (testSolverFnEq x y)
instance ( Hashable (f BaseRealType)
, Hashable (f BaseIntegerType)
, HashableF f
, TestEquality f
)
=> Hashable (MatlabSolverFn f args tp) where
hashWithSalt = $(structuralHashWithSalt [t|MatlabSolverFn|] [])
realIsNonZero :: IsExprBuilder sym => sym -> SymReal sym -> IO (Pred sym)
realIsNonZero sym = realNe sym (realZero sym)
evalMatlabSolverFn :: forall sym args ret
. IsExprBuilder sym
=> MatlabSolverFn (SymExpr sym) args ret
-> sym
-> Assignment (SymExpr sym) args
-> IO (SymExpr sym ret)
evalMatlabSolverFn f sym =
case f of
BoolOrFn -> uncurryAssignment $ orPred sym
IsIntegerFn -> uncurryAssignment $ isInteger sym
IntLeFn -> uncurryAssignment $ intLe sym
BVToIntegerFn{} -> uncurryAssignment $ bvToInteger sym
SBVToIntegerFn{} -> uncurryAssignment $ sbvToInteger sym
IntegerToRealFn -> uncurryAssignment $ integerToReal sym
RealToIntegerFn -> uncurryAssignment $ realToInteger sym
PredToIntegerFn -> uncurryAssignment $ \p ->
iteM intIte sym p (intLit sym 1) (intLit sym 0)
IntSeqFn b inc -> uncurryAssignment $ \idx _ -> do
intAdd sym b =<< intMul sym inc idx
RealSeqFn b inc -> uncurryAssignment $ \_ idx -> do
realAdd sym b =<< realMul sym inc =<< integerToReal sym idx
IndicesInRange tps0 bnds0 -> \args ->
Ctx.forIndex (Ctx.size tps0) (g tps0 bnds0 args) (pure (truePred sym))
where g :: Assignment OnlyIntRepr ctx
-> Assignment (SymExpr sym) ctx
-> Assignment (SymExpr sym) ctx
-> IO (Pred sym)
-> Index ctx tp
-> IO (Pred sym)
g tps bnds args m i = do
case tps Ctx.! i of
OnlyIntRepr -> do
let v = args ! i
let bnd = bnds ! i
one <- intLit sym 1
p <- join $ andPred sym <$> intLe sym one v <*> intLe sym v bnd
andPred sym p =<< m
IsEqFn{} -> Ctx.uncurryAssignment $ \x y -> do
isEq sym x y
BVIsNonZeroFn _ -> Ctx.uncurryAssignment $ bvIsNonzero sym
ClampedIntNegFn _ -> Ctx.uncurryAssignment $ clampedIntNeg sym
ClampedIntAbsFn _ -> Ctx.uncurryAssignment $ clampedIntAbs sym
ClampedIntAddFn _ -> Ctx.uncurryAssignment $ clampedIntAdd sym
ClampedIntSubFn _ -> Ctx.uncurryAssignment $ clampedIntSub sym
ClampedIntMulFn _ -> Ctx.uncurryAssignment $ clampedIntMul sym
ClampedUIntAddFn _ -> Ctx.uncurryAssignment $ clampedUIntAdd sym
ClampedUIntSubFn _ -> Ctx.uncurryAssignment $ clampedUIntSub sym
ClampedUIntMulFn _ -> Ctx.uncurryAssignment $ clampedUIntMul sym
IntSetWidthFn _ o -> Ctx.uncurryAssignment $ \v -> intSetWidth sym v o
UIntSetWidthFn _ o -> Ctx.uncurryAssignment $ \v -> uintSetWidth sym v o
UIntToIntFn _ o -> Ctx.uncurryAssignment $ \v -> uintToInt sym v o
IntToUIntFn _ o -> Ctx.uncurryAssignment $ \v -> intToUInt sym v o
RealIsNonZeroFn -> Ctx.uncurryAssignment $ realIsNonZero sym
RealCosFn -> Ctx.uncurryAssignment $ realCos sym
RealSinFn -> Ctx.uncurryAssignment $ realSin sym
RealToSBVFn w -> Ctx.uncurryAssignment $ \v -> realToSBV sym v w
RealToUBVFn w -> Ctx.uncurryAssignment $ \v -> realToBV sym v w
PredToBVFn w -> Ctx.uncurryAssignment $ \v -> predToBV sym v w
CplxIsNonZeroFn -> Ctx.uncurryAssignment $ \x -> do
(real_x :+ imag_x) <- cplxGetParts sym x
join $ orPred sym <$> realIsNonZero sym real_x <*> realIsNonZero sym imag_x
CplxIsRealFn -> Ctx.uncurryAssignment $ isReal sym
RealToComplexFn -> Ctx.uncurryAssignment $ cplxFromReal sym
RealPartOfCplxFn -> Ctx.uncurryAssignment $ getRealPart sym
ImagPartOfCplxFn -> Ctx.uncurryAssignment $ getImagPart sym
CplxNegFn -> Ctx.uncurryAssignment $ cplxNeg sym
CplxAddFn -> Ctx.uncurryAssignment $ cplxAdd sym
CplxSubFn -> Ctx.uncurryAssignment $ cplxSub sym
CplxMulFn -> Ctx.uncurryAssignment $ cplxMul sym
CplxRoundFn -> Ctx.uncurryAssignment $ cplxRound sym
CplxFloorFn -> Ctx.uncurryAssignment $ cplxFloor sym
CplxCeilFn -> Ctx.uncurryAssignment $ cplxCeil sym
CplxMagFn -> Ctx.uncurryAssignment $ cplxMag sym
CplxSqrtFn -> Ctx.uncurryAssignment $ cplxSqrt sym
CplxExpFn -> Ctx.uncurryAssignment $ cplxExp sym
CplxLogFn -> Ctx.uncurryAssignment $ cplxLog sym
CplxLogBaseFn b -> Ctx.uncurryAssignment $ cplxLogBase (toRational b) sym
CplxSinFn -> Ctx.uncurryAssignment $ cplxSin sym
CplxCosFn -> Ctx.uncurryAssignment $ cplxCos sym
CplxTanFn -> Ctx.uncurryAssignment $ cplxTan sym
-- | This class is provides functions needed to implement the symbolic
-- array intrinsic functions
class IsSymExprBuilder sym => MatlabSymbolicArrayBuilder sym where
-- | Create a Matlab solver function from its prototype.
mkMatlabSolverFn :: sym
-> MatlabSolverFn (SymExpr sym) args ret
-> IO (SymFn sym args ret)