Description : Logic for manipulating the graph in the Central GUI
Copyright : (c) Jorina Freya Gerken, Till Mossakowski, Uni Bremen 2002-2006
Maintainer : till@informatik.uni-bremen.de
Portability : non-portable (imports Logic)
This module provides functions for all the menus in the Hets GUI.
, checkconservativityOfNode
, checkconservativityOfEdge
import
GUI.Taxonomy (displayConceptGraph, displaySubsortGraph)
import
Driver.Options ( HetcatsOpts, putIfVerbose, outtypes, doDump, verbose
import
Data.List (partition, delete, isPrefixOf)
-- | Locks the global lock and runs function
runAndLock :: GInfo -> IO () -> IO ()
runAndLock (GInfo { functionLock = lock
locked <- tryPutMVar lock ()
"an other function is still working ... please wait ..."
-- | Undo one step of the History
undo :: GInfo -> Bool -> IO ()
intSt <- readIORef $ intState gInfo
nwSt <- if isUndo then undoOneStepWithUpdate intSt $ updateGraphAux gInfo
else redoOneStepWithUpdate intSt $ updateGraphAux gInfo
writeIORef (intState gInfo) nwSt
updateGraph :: GInfo -> [DGChange] -> IO ()
updateGraph gInfo@(GInfo { libName = ln }) changes = do
ost <- readIORef $ intState gInfo
Just ist -> updateGraphAux gInfo ln changes $ lookupDGraph ln $ i_libEnv ist
updateGraphAux :: GInfo -> LibName -> [DGChange] -> DGraph -> IO ()
updateGraphAux gInfo' ln changes dg = do
og <- readIORef $ openGraphs gInfo'
Just gInfo@(GInfo { graphInfo = gi
, options = opts }) -> do
let edges = if flagHideEdges flags then hideEdgesAux dg else []
(nodes, comp) = if flagHideNodes flags then hideNodesAux dg edges
"Applying development graph calculus proof rule..."
"Development graph calculus proof rule finished."
-- | Toggles to display internal node names
hideNames :: GInfo -> IO ()
hideNames (GInfo { options = opts
, internalNames = updaterIORef }) = do
updater <- readIORef updaterIORef
mapM_ (\ (s, upd) -> upd (const $ if flagHideNames flags then "" else s))
-- | Toggles to display internal node names
toggleHideNames :: GInfo -> IO ()
toggleHideNames gInfo@(GInfo { graphInfo = gi
let hide = not $ flagHideNames flags
writeIORef opts $ flags { flagHideNames = hide }
else "Revealing internal names..."
-- | hides all unnamed internal nodes that are proven
hideNodesAux :: DGraph -> [EdgeId]
hideNodesAux dg ignoreEdges =
let nodes = selectNodesByType dg
(\ n -> isInternalSpec n && isProvenNode n && isProvenCons n)
edges = getCompressedEdges dg nodes ignoreEdges
toggleHideNodes :: GInfo -> IO ()
toggleHideNodes gInfo@(GInfo { graphInfo = gi
let hide = not $ flagHideNodes flags
writeIORef opts $ flags { flagHideNodes = hide }
else "Revealing hidden nodes..."
hideEdgesAux :: DGraph -> [EdgeId]
hideEdgesAux dg = map dgl_id
$ filter (\ (DGLink { dgl_type = linktype }) ->
ScopedLink _ (ThmLink s) c ->
isProvenThmLinkStatus s && isProvenConsStatusLink c
HidingFreeOrCofreeThm _ _ s -> isProvenThmLinkStatus s
$ foldl (\ e c -> case c of
InsertEdge (_, _, lbl) -> lbl : e
DeleteEdge (_, _, lbl) -> delete lbl e
toggleHideEdges :: GInfo -> IO ()
toggleHideEdges gInfo@(GInfo { graphInfo = gi
let hide = not $ flagHideEdges flags
writeIORef opts $ flags { flagHideEdges = hide }
else "Revealing hidden proven edges..."
-- | generates from list of HistElem one list of DGChanges
flattenHistory :: [HistElem] -> [DGChange] -> [DGChange]
flattenHistory [] cs = cs
flattenHistory (HistElem c : r) cs = flattenHistory r $ c : cs
flattenHistory (HistGroup _ ph : r) cs =
-- | selects all nodes of a type with outgoing edges
selectNodesByType :: DGraph -> (DGNodeType -> Bool) -> [Node]
selectNodesByType dg types =
filter (\ n -> not (null $ outDG dg n) && hasUnprovenEdges dg n) $ map fst
$ filter (types . getRealDGNodeType . snd) $ labNodesDG dg
hasUnprovenEdges :: DGraph -> Node -> Bool
foldl (\ b (_, _, l) -> case edgeTypeModInc $ getRealDGLinkType l of
ThmType { isProvenEdge = False } -> False
_ -> b) True . (\ n -> innDG dg n ++ outDG dg n)
-- | compresses a list of types to the highest one
compressTypes :: Bool -> [DGEdgeType] -> (DGEdgeType, Bool)
compressTypes _ [] = error "compressTypes: wrong usage"
compressTypes b (t : []) = (t, b)
compressTypes b (t1 : t2 : r)
| t1 == t2 = compressTypes b (t1 : r)
| t1 > t2 = compressTypes False (t1 : r)
| otherwise = compressTypes False (t2 : r)
-- | innDG with filter of not shown edges
fInnDG :: [EdgeId] -> DGraph -> Node -> [LEdge DGLinkLab]
fInnDG ignore dg = filter (\ (_, _, l) -> notElem (dgl_id l) ignore) . innDG dg
-- | outDG with filter of not shown edges
fOutDG :: [EdgeId] -> DGraph -> Node -> [LEdge DGLinkLab]
fOutDG ignore dg = filter (\ (_, _, l) -> notElem (dgl_id l) ignore) . outDG dg
-- | returns a list of compressed edges
getCompressedEdges :: DGraph -> [Node] -> [EdgeId]
-> [(Node, Node, DGEdgeType, Bool)]
getCompressedEdges dg hidden ign = filterDuplicates $ getShortPaths
$ concatMap (\ e@(_, t, _) -> map (e :) $ getPaths dg t hidden [] ign) inEdges
inEdges = filter (\ (_, t, _) -> elem t hidden)
$ concatMap (fOutDG ign dg)
$ foldr (\ (n, _, _) i -> if elem n hidden
|| elem n i then i else n : i) []
$ concatMap (fInnDG ign dg) hidden
-- | filter duplicate paths
filterDuplicates :: [(Node, Node, DGEdgeType, Bool)]
-> [(Node, Node, DGEdgeType, Bool)]
filterDuplicates r@((s, t, _, _) : _) = edges ++ filterDuplicates others
(same, others) = partition (\ (s', t', _, _) -> s == s' && t == t') r
(mtypes, stypes) = partition (\ (_, _, _, b) -> not b) same
stypes' = foldr (\ e es -> if elem e es then es else e : es) [] stypes
(et', _) = compressTypes False $ map (\ (_, _, et, _) -> et) mtypes
edges = if null mtypes then stypes' else (s, t, et', False) : stypes'
-- | returns the pahts of a given node through hidden nodes
getPaths :: DGraph -> Node -> [Node] -> [Node] -> [EdgeId]
getPaths dg node hidden seen' ign = if elem node hidden then
else concatMap (\ e@(_, t, _) -> map (e :) $ getPaths dg t hidden seen ign)
edges = filter (\ (_, t, _) -> notElem t seen) $ fOutDG ign dg node
-- | returns source and target node of a path with the compressed type
getShortPaths :: [[LEdge DGLinkLab]]
-> [(Node, Node, DGEdgeType, Bool)]
(et, b) = compressTypes True $ map (\ (_, _, e) -> getRealDGLinkType e) p
-- | Let the user select a Node to focus
focusNode :: GInfo -> IO ()
focusNode gInfo@(GInfo { graphInfo = gi
ost <- readIORef $ intState gInfo
$ labNodesDG $ lookupDGraph ln le
selection <- listBox "Select a node to focus"
$ map (\ (n, l) -> shows n " " ++ getDGNodeName l) idsnodes
showLibGraph :: GInfo -> LibFunc -> IO ()
showLibGraph gInfo showLib = do
saveProofStatus :: GInfo -> FilePath -> IO ()
saveProofStatus gInfo@(GInfo { hetcatsOpts = opts
}) file = encapsulateWaitTermAct $ do
ost <- readIORef $ intState gInfo
let proofStatus = i_libEnv ist
writeShATermFile file (ln, lookupHistory ln proofStatus)
putIfVerbose opts 2 $ "Wrote " ++ file
-- | implementation of open menu, read in a proof status
openProofStatus :: GInfo -> FilePath -> ConvFunc -> LibFunc
openProofStatus gInfo@(GInfo { hetcatsOpts = opts
, libName = ln }) file convGraph showLib = do
ost <- readIORef $ intState gInfo
mh <- readVerbose logicGraph opts ln file
Nothing -> errorDialog "Error" $
"Could not read proof status from file '" ++ file ++ "'"
let libfile = libNameToFile ln
m <- anaLib opts { outtypes = [] } libfile
Nothing -> errorDialog "Error"
$ "Could not read original development graph from '"
Nothing -> errorDialog "Error" $ "Could not get original"
++ "development graph for '" ++ showDoc ln "'"
let oldEnv = i_libEnv ist
proofStatus =
Map.insert ln (applyProofHistory h dg) oldEnv
nwst = ost { i_state = Just ist { i_libEnv = proofStatus } }
writeIORef (intState gInfo) nwst
gInfo' <- copyGInfo gInfo ln
convGraph gInfo' "Proof Status " showLib
-- | apply a rule of the development graph calculus
-> (LibEnv -> IO (Result LibEnv))
proofMenu gInfo@(GInfo { hetcatsOpts = hOpts
ost <- readIORef $ intState gInfo
let proofStatus = i_libEnv ist
putIfVerbose hOpts 4 "Proof started via menu"
Result ds res <- proofFun proofStatus
putIfVerbose hOpts 4 "Analyzing result of proof"
Just newProofStatus -> do
let newGr = lookupDGraph ln newProofStatus
history = snd $ splitHistory (lookupDGraph ln proofStatus) newGr
lln = map DgCommandChange $ calcGlobalHistory
proofStatus newProofStatus
nst = add2history cmd ost lln
nwst = nst { i_state = Just ist { i_libEnv = newProofStatus}}
doDump hOpts "PrintHistory" $ do
print $ prettyHistory history
writeIORef (intState gInfo) nwst
updateGraph gInfo (reverse $ flatHistory history)
calcGlobalHistory :: LibEnv -> LibEnv -> [LibName]
calcGlobalHistory old new = let
changes = filter (\ ln -> length' ln old < length' ln new) $
Map.keys old
in concatMap (\ ln -> replicate (length' ln new - length' ln old) ln) changes
showNodeInfo :: Int -> DGraph -> IO ()
showNodeInfo descr dgraph = do
let dgnode = labDG dgraph descr
title = (if isDGRef dgnode then ("reference " ++) else
if isInternalNode dgnode then ("internal " ++) else id)
"node " ++ getDGNodeName dgnode ++ " " ++ show descr
createTextDisplay title (title ++ "\n" ++ showDoc dgnode "")
showDiagMessAux :: Int -> [Diagnosis] -> IO ()
showDiagMessAux v ds = let es = filterDiags v ds in
unless (null es) $ (if hasErrors es then errorDialog "Error"
else infoDialog "Info") $ unlines $ map show es
showDiagMess :: HetcatsOpts -> [Diagnosis] -> IO ()
showDiagMess = showDiagMessAux . verbose
{- | outputs the theory of a node in a window;
getTheoryOfNode :: GInfo -> Int -> DGraph -> IO ()
getTheoryOfNode gInfo descr dgraph = do
ost <- readIORef $ intState gInfo
Just ist -> case computeTheory (i_libEnv ist) (libName gInfo) descr of
errorDialog "Error" $ "no global theory for node " ++ show descr
Just th -> displayTheoryWithWarning "Theory" (getNameOfNode descr dgraph)
(addHasInHidingWarning dgraph descr) th
{- | translate the theory of a node in a window;
translateTheoryOfNode :: GInfo -> Int -> DGraph -> IO ()
translateTheoryOfNode gInfo@(GInfo { hetcatsOpts = opts
, libName = ln }) node dgraph = do
ost <- readIORef $ intState gInfo
let libEnv = i_libEnv ist
case computeTheory libEnv ln node of
Just th@(G_theory lid sign _ sens _) -> do
-- find all comorphism paths starting from lid
let paths = findComorphismPaths logicGraph (sublogicOfTh th)
-- let the user choose one
sel <- listBox "Choose a node logic translation" $ map show paths
Nothing -> errorDialog "Error" "no node logic translation chosen"
Comorphism cid <- return (paths !! i)
let lidS = sourceLogic cid
sign' <- coerceSign lid lidS "" sign
sens' <- coerceThSens lid lidS "" sens
-- translate theory along chosen comorphism
let Result es mTh = wrapMapTheory cid
(plainSign sign', toNamedList sens')
Nothing -> showDiagMess opts es
Just (sign'', sens1) -> displayTheoryWithWarning
"Translated Theory" (getNameOfNode node dgraph)
(addHasInHidingWarning dgraph node)
$ G_theory lidT (mkExtSign sign'') startSigId (toThSens sens1)
errorDialog "Error" $ "no global theory for node " ++ show node
-- | Show proof status of a node
showProofStatusOfNode :: GInfo -> Int -> DGraph -> IO ()
showProofStatusOfNode _ descr dgraph =
let dgnode = labDG dgraph descr
stat = showStatusAux dgnode
title = "Proof status of node " ++ showName (dgn_name dgnode)
in createTextDisplay title stat
showStatusAux :: DGNodeLab -> String
showStatusAux dgnode = case dgn_theory dgnode of
consGoal = "\nconservativity of this node"
in "Proven proof goals:\n"
++ if not $ hasOpenNodeConsStatus True dgnode
++ "\nOpen proof goals:\n"
++ if hasOpenNodeConsStatus False dgnode
hidingWarnDiag :: DGNodeLab -> IO Bool
hidingWarnDiag dgn = if labelHasHiding dgn then
warningDialog "Warning" $ unwords $ hidingWarning ++ ["Try anyway?"]
-- | start local theorem proving or consistency checking at a node
proveAtNode :: GInfo -> Int -> DGraph -> IO ()
proveAtNode gInfo descr dgraph = do
(dgraph', dgn', le') <- if hasLock dgn then return (dgraph, dgn, le)
(dgraph', dgn') <- initLocking (lookupDGraph ln le) (descr, dgn)
nwst = ost { i_state = Just $ ist { i_libEnv = nwle} }
return (dgraph', dgn', nwle)
acquired <- tryLockLocal dgn'
res@(Result d _) <- basicInferenceNode logicGraph ln dgraph'
when (null d || diagString (head d) /= "
Proofs.Proofs: selection")
$ runProveAtNode gInfo (descr, dgn') res
else errorDialog "Error" "Proofwindow already open"
runProveAtNode :: GInfo -> LNode DGNodeLab
-> Result G_theory -> IO ()
runProveAtNode gInfo (v, dgnode) (Result ds mres) = case mres of
let oldTh = dgn_theory dgnode
rTh = propagateProofs oldTh newTh in
unless (rTh == oldTh) $ do
let (ost', mhist) = updateNodeProof ln ost (v, dgnode) $ Just rTh
runAndLock gInfo $ updateGraph gInfo hist
checkconservativityOfNode :: GInfo -> Int -> DGraph -> IO ()
checkconservativityOfNode gInfo descr dgraph = do
nlbl = labDG dgraph descr
(str, libEnv', ph) <- checkConservativityNode True (descr, nlbl)
if isPrefixOf "No conservativity" str then
errorDialog "Result of conservativity check" str
createTextDisplay "Result of conservativity check" str
let nst = add2history (SelectCmd Node $ showDoc descr "")
nwst = nst { i_state = Just $ iist { i_libEnv = libEnv' }}
runAndLock gInfo $ updateGraph gInfo (reverse $ flatHistory ph)
edgeErr descr = errorDialog "Error" $ "edge with descriptor " ++ show descr
++ " not found in the development graph"
-- | print the id, origin, type, proof-status and morphism of the edge
showEdgeInfo :: Int -> Maybe (LEdge DGLinkLab) -> IO ()
showEdgeInfo descr me = case me of
Just e@(_, _, l) -> let estr = showLEdge e in
createTextDisplay ("Info of " ++ estr)
(estr ++ "\n" ++ showDoc l "")
-- | check conservativity of the edge
checkconservativityOfEdge :: Int -> GInfo -> Maybe (LEdge DGLinkLab) -> IO ()
checkconservativityOfEdge descr gInfo me = case me of
Just lnk@(_, _, lbl) -> do
(str, nwle, _, ph) <- checkConservativityEdge True lnk
if isPrefixOf "No conservativity" str
errorDialog "Result of conservativity check" str
createTextDisplay "Result of conservativity check" str
let nst = add2history (SelectCmd Link $ showDoc (dgl_id lbl) "")
nwst = nst { i_state = Just $ iist { i_libEnv = nwle}}
runAndLock gInfo $ updateGraph gInfo $ reverse $ flatHistory ph
-- | show library referened by a DGRef node (=node drawn as a box)
showReferencedLibrary :: Int -> GInfo -> ConvFunc -> LibFunc -> IO ()
showReferencedLibrary descr gInfo@(GInfo { libName = ln })
ost <- readIORef $ intState gInfo
refNode = labDG (lookupDGraph ln le) descr
refLibname = if isDGRef refNode then dgn_libname refNode
else error "showReferencedLibrary"
gInfo' <- copyGInfo gInfo refLibname
convGraph gInfo' "development graph" showLib
let gi = graphInfo gInfo'
Nothing -> error $ "The referenced library (" ++ show refLibname
-- | display a window of translated graph with maximal sublogic.
translateGraph :: GInfo -> IO (Maybe LibEnv)
translateGraph gInfo@(GInfo { hetcatsOpts = opts }) = do
ost <- readIORef $ intState gInfo
Nothing -> return Nothing
Result diagsSl mSublogic = getDGLogic le
myErrMess = showDiagMess opts
error' = errorDialog "Error"
if hasErrors diagsSl then do
error' "No maximal sublogic found."
let paths = findComorphismPaths logicGraph sublogic
error' "This graph has no comorphism to translation."
sel <- listBox "Choose a logic translation" $ map show paths
error' "no logic translation chosen"
let Result diag mle = libEnv_translation le $ paths !! j
showDiagMess opts $ diagsSl ++ diag
myErrMess $ diagsSl ++ diag
-- DaVinciGraph to String
-- Functions to convert a DaVinciGraph to a String to store as a .udg file
-- | saves the uDrawGraph graph to a file
saveUDGraph :: GInfo ->
Map.Map DGNodeType (Shape value, String)
saveUDGraph gInfo@(GInfo { graphInfo = gi
, libName = ln }) nodemap linkmap = do
ost <- readIORef $ intState gInfo
maybeFilePath <- fileSaveDialog (rmSuffix (libNameToFile ln) ++ ".udg")
[ ("uDrawGraph", ["*.udg"])
, ("All Files", ["*"])] Nothing
nstring <- nodes2String gInfo nodemap linkmap
writeFile filepath nstring
-- | Converts the nodes of the graph to String representation
nodes2String :: GInfo ->
Map.Map DGNodeType (Shape value, String)
nodes2String gInfo@(GInfo { graphInfo = gi
, libName = ln }) nodemap linkmap = do
ost <- readIORef $ intState gInfo
$ labNodesDG $ lookupDGraph ln le
fmap ((if null s then s else s ++ ",\n") ++)
. node2String gInfo nodemap linkmap)
return $ "[" ++ nstring ++ "]"
-- | Converts a node to String representation
node2String :: GInfo ->
Map.Map DGNodeType (Shape value, String)
-> LNode DGNodeLab -> IO String
node2String gInfo nodemap linkmap (nid, dgnode) = do
label <- getNodeLabel gInfo dgnode
let ntype = getRealDGNodeType dgnode
(shape, color) <- case
Map.lookup ntype nodemap of
Nothing -> error $ "SaveGraph: can't lookup nodetype: " ++ show ntype
Just (s, c) -> return (s, c)
object = "a(\"OBJECT\",\"" ++ label ++ "\"),"
color' = "a(\"COLOR\",\"" ++ color ++ "\"),"
shape' = "a(\"_GO\",\"" ++ map toLower (show shape) ++ "\")"
links <- links2String gInfo linkmap nid
return $ "l(\"" ++ show nid ++ "\",n(\"" ++ show ntype ++ "\","
++ "[" ++ object ++ color' ++ shape' ++ "],"
++ "\n [" ++ links ++ "]))"
-- | Converts all links of a node to String representation
links2String gInfo@(GInfo { graphInfo = gi
, libName = ln }) linkmap nodeid = do
ost <- readIORef $ intState gInfo
edges <- filterM (\ (src, _, edge) -> do
return $ not b && src == nodeid)
$ labEdgesDG $ lookupDGraph ln le
s' <- link2String linkmap edge
return $ (if null s then "" else s ++ ",\n") ++ s') "" edges
-- | Converts a link to String representation
-> LEdge DGLinkLab -> IO String
link2String linkmap (nodeid1, nodeid2, edge) = do
let (EdgeId linkid) = dgl_id edge
ltype = getRealDGLinkType edge
Nothing -> error $ "SaveGraph: can't lookup linktype: " ++ show ltype
Just (l, c) -> return (l, c)
nm = "\"" ++ show linkid ++ ":" ++ show nodeid1 ++ "->"
color' = "a(\"EDGECOLOR\",\"" ++ color ++ "\"),"
line' = "a(\"EDGEPATTERN\",\"" ++ map toLower (show line) ++ "\")"
return $ "l(" ++ nm ++ ",e(\"" ++ show ltype ++ "\","
++ "[" ++ color' ++ line' ++ "],"
++ "r(\"" ++ show nodeid2 ++ "\")))"
-- | Returns the name of the Node
getNodeLabel :: GInfo -> DGNodeLab -> IO String
getNodeLabel (GInfo { options = opts }) dgnode = do
return $ if flagHideNames flags && isInternalNode dgnode
then "" else getDGNodeName dgnode