44N/A{-# LANGUAGE FlexibleContexts, FlexibleInstances, TypeSynonymInstances #-}
44N/ADescription : Mathematica instance for the AssignmentStore class
44N/ACopyright : (c) Ewaryst Schulz, DFKI Bremen 2010
44N/AMaintainer : Ewaryst.Schulz@dfki.de
44N/AStability : experimental
44N/APortability : non-portable (via imports)
44N/AMathematica as AssignmentStore based on the Mathlink interface
44N/Aimport Prelude hiding (lookup)
44N/A-- ----------------------------------------------------------------------
44N/A-- * Mathematica Types and Instances
44N/A-- ----------------------------------------------------------------------
44N/A-- | MathematicaInterpreter with Translator based on the MathLink interface
44N/Atype MathState = ASState (MLState, Maybe FilePath)
44N/A-- Mathematica interface, built on MathLink
44N/Atype MathematicaIO = ErrorT ASError (StateT MathState ML)
44N/AgetMLState :: MathState -> MLState
44N/AgetMLState = fst . getConnectInfo
44N/AgetMLLogFile :: MathState -> Maybe FilePath
44N/AgetMLLogFile = snd . getConnectInfo
44N/AliftML :: ML a -> MathematicaIO a
44N/AliftML = lift . lift
44N/Ainstance AssignmentStore MathematicaIO where
44N/A assign = genAssign mathematicaAssign
44N/A assigns l = genAssigns mathematicaAssigns l >> return ()
44N/A lookup = genLookup mathematicaLookup
44N/A eval = genEval mathematicaEval
44N/A check = mathematicaCheck
44N/A names = get >>= return . SMem . getBMap
44N/A evalRaw s = get >>= liftIO . mathematicaDirect s
44N/A getUndefinedConstants e = do
44N/A adg <- gets depGraph
44N/A let g = isNothing . depGraphLookup adg
44N/A let (bm, i) = genKey $ getBMap mit
44N/A put mit { getBMap = bm }
44N/A getDepGraph = gets depGraph
44N/A updateConstant n def =
44N/A let f gr = updateGraph gr n
44N/A $ DepGraphAnno { annoDef = def
44N/A mf mit = mit { depGraph = f $ depGraph mit }
44N/Ainstance VCGenerator MathematicaIO where
44N/A vcHdl <- liftM (fromMaybe stdout) $ gets vericondOut
44N/A liftIO $ hPutStrLn vcHdl $ show $ printVCForIsabelle ea "lemma1" e
44N/Ainstance StepDebugger MathematicaIO where
44N/A setDebugMode b = modify mf where mf mit = mit { debugMode = b }
44N/A getDebugMode = gets debugMode
44N/Ainstance SymbolicEvaluator MathematicaIO where
44N/A setSymbolicMode b = modify mf where mf mit = mit { symbolicMode = b }
44N/A getSymbolicMode = gets symbolicMode
44N/Ainstance MessagePrinter MathematicaIO where
44N/A printMessage = liftIO . putStrLn
44N/A-- ----------------------------------------------------------------------
44N/A-- * Mathematica syntax and special terms
44N/A-- ----------------------------------------------------------------------
44N/AmmShowOPNAME :: OPNAME -> String
44N/A OP_neq -> "Unequal"
44N/A OP_leq -> "LessEqual"
44N/A OP_geq -> "GreaterEqual"
44N/A OP_impl -> "Implies"
44N/A OP_false -> "False"
44N/A -- these functions have to be defined in a package
44N/A OP_minus -> "minus"
44N/A OP_fthrt -> "fthrt"
44N/A OP_maxloc -> "maxloc"
44N/A OP_minloc -> "minloc"
44N/A OP_reldist -> "reldist"
44N/A OP_reldistLe -> "reldistLe"
44N/A OP_undef -> "undef"
44N/A OP_failure -> "fail"
44N/AmmShowOPID :: OPID -> String
44N/AmmShowOPID (OpId x) = mmShowOPNAME x
44N/AmmShowOPID (OpUser (SimpleConstant s)) = s
44N/AmmShowOPID _ = error "mmShowOpId: unsupported constant"
44N/AmmFlexFoldOpList :: [OPNAME]
44N/AmmFlexFoldOpList = [ OP_plus, OP_mult, OP_and, OP_or ]
44N/AmathematicaOperatorInfo :: [OpInfo]
44N/AmathematicaOperatorInfo = toFlexFold mmFlexFoldOpList operatorInfo
-- | opInfoMap for mathematica's prdefined symbols
mathematicaOpInfoMap :: OpInfoMap
getOpInfoMap (mmShowOPNAME . opname) mathematicaOperatorInfo
-- | opInfoNameMap for mathematica's prdefined symbols
mathematicaOpInfoNameMap :: OpInfoNameMap
mathematicaOpInfoNameMap =
getOpInfoNameMap mathematicaOperatorInfo
toFlexFold :: [OPNAME] -> [OpInfo] -> [OpInfo]
toFlexFold nl oil = map f oil where
f oi |
Set.member (opname oi) ns = oi { arity = -1, foldNAry = True }
-- | mathematica term "Set"
mtDef :: String -> AssDefinition -> EXPRESSION
mtDef s (ConstDef e) = mkOp "Set" [mkOp s [], e]
mtDef s (FunDef args e) = mkOp "Set" [mkOp s $ map mtVarDecl args, e]
mtVarDecl :: String -> EXPRESSION
mtVarDecl s = mkOp "Pattern" [mkOp s [], mkOp "Blank" []]
mtList :: [EXPRESSION] -> EXPRESSION
mtCompound :: [EXPRESSION] -> EXPRESSION
mtCompound = mkOp "CompoundExpression"
mtIsBlank :: OPID -> Bool
mtIsBlank oi = mmShowOPID oi == "Blank"
-- ----------------------------------------------------------------------
-- * Mathematica pretty printing
-- ----------------------------------------------------------------------
data OfMathematica a = OfMathematica { mmValue :: a }
type MathPrinter = Reader (OfMathematica OpInfoNameMap)
instance ExpressionPrinter MathPrinter where
printOpname = return . text . mmShowOPNAME
printArgs = return . brackets . sepByCommas
printVarDecl s = return $ text s <> text "_"
printMathPretty :: (MathPrinter Doc) -> Doc
printMathPretty = flip runReader $ OfMathematica mathematicaOpInfoNameMap
instance MathPretty EXPRESSION where
mmPretty e = printMathPretty $ printExpression e
instance MathPretty AssDefinition where
mmPretty def = printMathPretty $ printAssDefinition def
instance MathPretty String where
instance (MathPretty a, MathPretty b) => MathPretty [(a, b)] where
mmPretty l = ppPairlist mmPretty mmPretty braces sepBySemis (<>) l
-- ----------------------------------------------------------------------
-- * Mathematica over ML Interface
-- ----------------------------------------------------------------------
sendExpressionString :: String -> ML ()
sendExpressionString s = do
mlPutFunction' "ToExpression" 1
sendExpression :: Bool -- ^ symbolic mode
Var token -> mlPutSymbol (tokStr token) >> return ()
-- blanks get extra empty brackets
| mtIsBlank oi -> mlPutFunction' "Blank" 0 >> return ()
| otherwise -> mlPutSymbol (mmShowOPID oi) >> return ()
mlPutFunction' (mmShowOPID oi) (length exps)
mapM_ (sendExpression sm) exps
Int i _ -> mlPutInteger'' i >> return ()
| otherwise -> mlPutFunction' "N" 1 >> putRational r
where putRational r' = do
let (n1, dn2) = toFraction r'
mlPutFunction' "Rational" 2
List _ _ -> error "sendExpression: List not supported"
Interval _ _ _ -> error "sendExpression: Interval not supported"
receiveExpression :: ML EXPRESSION
let mkMLOp s args = mkAndAnalyzeOp mathematicaOpInfoMap s [] args nullRange
pr | et == dfMLTKSYM = liftM (flip mkMLOp []) mlGetSymbol
| et == dfMLTKINT = liftM (flip Int nullRange) mlGetInteger''
| et == dfMLTKREAL = liftM (flip Rat nullRange . toRational) mlGetReal'
if ac == 0 then mlProcError
-- the head is expected to be a symbol
s <- if et' == dfMLTKSYM then mlGetSymbol else
error $ "receiveExpression: Expecting symbol at "
++ "function head, but got " ++ show et'
return $ Rat (fromFraction nn dn) nullRange
liftM (mkMLOp s) $ forM [
1..ac] $ const receiveExpression
| et == dfMLTKERROR = mlProcError
| otherwise = mlProcError
receiveString :: ML String
if et == dfMLTKSTR then mlGetString
else error $ "receiveString: Got " ++ showTK et
-- ----------------------------------------------------------------------
-- * Methods for Mathematica 'AssignmentStore' Interface
-- ----------------------------------------------------------------------
mathematicaSend :: EXPRESSION -> MathematicaIO ()
prettyInfo3 $ text "Sending expression" <+> braces (mmPretty e)
liftML $ sendEvalPacket (sendExpression sm e) >> skipAnswer >> return ()
mathematicaEval :: EXPRESSION -> MathematicaIO EXPRESSION
prettyInfo3 $ text "Sending expression for evaluation"
res <- liftML $ sendEvalPacket (sendExpression sm e) >> waitForAnswer
prettyInfo3 $ text "Received expression"
<+> braces (mmPretty res)
mathematicaAssign :: String -> AssDefinition -> MathematicaIO EXPRESSION
mathematicaAssign s def = do
prettyInfo $ text "Assigning" <+> mmPretty s <+> mmPretty def
mathematicaEval $ mtDef s def
mathematicaAssigns :: [(String, AssDefinition)] -> MathematicaIO ()
mathematicaAssigns l = do
prettyInfo $ text "Assigning list" <+> mmPretty l
let l' = map (uncurry mtDef) l
mathematicaSend $ mtCompound l'
mathematicaLookup :: String -> MathematicaIO EXPRESSION
mathematicaLookup s = mathematicaEval $ mkOp s []
mathematicaCheck :: EXPRESSION -> MathematicaIO Bool
prettyInfo $ text "Checking expression" <+> mmPretty e
eB <- genCheck mathematicaEval e
throwError $ ASError CASError $
concat [ "mathematicaCheck:", show e, "\n", s ]
mathematicaDirect :: String -> MathState -> IO String
liftM snd $ withMathematica st $ liftML
$ sendTextResultPacket s >> waitForAnswer >> receiveString
-- ----------------------------------------------------------------------
-- * The Mathematica system via MathLink
-- ----------------------------------------------------------------------
loadMathematicaModule :: FilePath -> MathematicaIO ()
loadMathematicaModule fp =
liftML $ sendTextPacket ("<<" ++ show fp) >> skipAnswer >> return ()
withMathematica :: MathState -> MathematicaIO a -> IO (MathState, a)
withMathematica st mprog = do
let stE = runErrorT mprog -- (:: StateT MathState ML (Either ASError a))
mlE = runStateT stE st -- (:: ML (Either ASError a, MathState))
(eRes, st') <- withLink (getMLState st) (getMLLogFile st) mlE
Left err -> throwASError err
Right res -> return (st', res)
-- | Init the Mathematica communication
mathematicaInit :: AssignmentDepGraph ()
-> Int -- ^ Verbosity level
-> Maybe FilePath -- ^ Log MathLink messages into this file
-> Maybe String -- ^ Connection name
-- (launches a new kernel if not specified)
mathematicaInit adg v mFp mN = do
error $ "mathematicaInit: MathLink connection failure " ++ show i
return $ initASState (mlSt, mFp) mathematicaOpInfoMap adg v
mathematicaExit :: MathState -> IO ()
mathematicaExit = closeLink . getMLState
runWithMathematica :: AssignmentDepGraph () -> Int -- ^ Verbosity level
-> Maybe FilePath -- ^ Log MathLink messages into this file
-> Maybe String -- ^ Connection name
-- (launches a new kernel if not specified)
-> [String] -- ^ mathematica modules to load
-> MathematicaIO a -- ^ the mathematica program to run
runWithMathematica adg i mFp mN mods p = do
mst <- mathematicaInit adg i mFp mN
withMathematica mst $ mapM_ loadMathematicaModule mods >> p