-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathProveHermit.hs
278 lines (248 loc) · 10.1 KB
/
ProveHermit.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
{- |
Module : ./OWL2/ProveHermit.hs
Description : Interface to the OWL Ontology prover via Pellett.
Copyright : (c) Heng Jiang, Uni Bremen 2004-2008
License : GPLv2 or higher, see LICENSE.txt
Maintainer : rick.adamy@ovgu.de
Stability : provisional
Portability : needs POSIX
Interface for the Hermit Reasoner, uses GUI.GenericATP.
See <http://www.w3.org/2004/OWL/> for details on OWL, and
<http://www.hermit-reasoner.com> for Hermit
-}
module OWL2.ProveHermit
( runTimedHermit
, hermitJar
, hermitEnv
, hermitProver
, hermitConsChecker
) where
import Logic.Prover
import OWL2.Morphism
import OWL2.Sign
import OWL2.ProfilesAndSublogics
import OWL2.ProverState
import OWL2.AS
import GUI.GenericATP
import Interfaces.GenericATPState
import Proofs.BatchProcessing
import Common.AS_Annotation
import Common.ProofTree
import Common.Result as Result
import Common.ProverTools
import Common.Utils
import Data.Char (isDigit)
import Data.List (isPrefixOf)
import Data.Maybe
import Data.Time (timeToTimeOfDay)
import Data.Time.Clock (secondsToDiffTime)
import System.Directory
import Control.Monad (when)
import Control.Concurrent
import Debug.Trace
hermitS :: String
hermitS = "Hermit"
hermitJar :: String
hermitJar = "HermiT.jar"
hermitEnv :: String
hermitEnv = "HERMIT_PATH"
hermitCheck :: IO (Maybe String)
hermitCheck = fmap
(\ l ->
if null l
then Just $ hermitJar ++ " not found in $" ++ hermitEnv
else Nothing)
$ check4FileAux hermitJar hermitEnv
{- |
The Prover implementation. First runs the batch prover (with graphical
feedback), then starts the GUI prover.
-}
hermitProver :: Prover Sign Axiom OWLMorphism ProfSub ProofTree
hermitProver =
(mkAutomaticProver "java" hermitS dlS hermitGUI hermitCMDLautomaticBatch)
{ proverUsable = hermitCheck }
hermitConsChecker :: ConsChecker Sign Axiom ProfSub OWLMorphism ProofTree
hermitConsChecker = (mkConsChecker hermitS topS consCheck)
{ ccNeedsTimer = False
, ccUsable = hermitCheck }
{- |
Record for prover specific functions. This is used by both GUI and command
line interface.
-}
atpFun :: String -- ^ theory name
-> ATPFunctions Sign Axiom OWLMorphism ProofTree ProverState
atpFun _ = ATPFunctions
{ initialProverState = owlProverState
, atpTransSenName = id -- transSenName,
, atpInsertSentence = insertOWLAxiom
, goalOutput = \ a b _ -> showOWLProblem a b
, proverHelpText = "http://www.hermit-reasoner.com/using.html\n"
, batchTimeEnv = "HETS_HermiT_BATCH_TIME_LIMIT"
, fileExtensions = FileExtensions { problemOutput = ".owl" -- owl-hets
, proverOutput = ".pellet"
, theoryConfiguration = ".pconf" }
, runProver = runHermit
, createProverOptions = extraOpts }
-- ** GUI
{- |
Invokes the generic prover GUI.
-}
hermitGUI :: String -- ^ theory name
-> Theory Sign Axiom ProofTree
-> [FreeDefMorphism Axiom OWLMorphism] -- ^ freeness constraints
-> IO [ProofStatus ProofTree] -- ^ proof status for each goal
hermitGUI thName th freedefs =
genericATPgui (atpFun thName) True hermitS thName th
freedefs emptyProofTree
-- ** command line function
{- |
Implementation of 'Logic.Prover.proveCMDLautomaticBatch' which provides an
automatic command line interface to the Hermit prover via MathServe.
Hermit specific functions are omitted by data type ATPFunctions.
-}
hermitCMDLautomaticBatch ::
Bool -- ^ True means include proved theorems
-> Bool -- ^ True means save problem file
-> MVar (Result.Result [ProofStatus ProofTree])
-- ^ used to store the result of the batch run
-> String -- ^ theory name
-> TacticScript -- ^ default tactic script
-> Theory Sign Axiom ProofTree -- ^ theory
-> [FreeDefMorphism Axiom OWLMorphism] -- ^ freeness constraints
-> IO (ThreadId, MVar ())
{- ^ fst: identifier of the batch thread for killing it
snd: MVar to wait for the end of the thread -}
hermitCMDLautomaticBatch inclProvedThs saveProblem_batch resultMVar
thName defTS th freedefs =
genericCMDLautomaticBatch (atpFun thName) inclProvedThs saveProblem_batch
resultMVar hermitS thName
(parseTacticScript batchTimeLimit [] defTS) th freedefs emptyProofTree
-- * Main prover functions
{- |
Runs the Pellet service.
-}
consCheck :: String
-> TacticScript
-> TheoryMorphism Sign Axiom OWLMorphism ProofTree
-> [FreeDefMorphism Axiom OWLMorphism] -- ^ freeness constraints
-> IO (CCStatus ProofTree)
consCheck thName (TacticScript tl) tm freedefs = case tTarget tm of
Theory sig nSens -> do
let proverStateI = owlProverState sig (toNamedList nSens) freedefs
prob = showOWLProblemS proverStateI
pStatus out tUsed = CCStatus
{ ccResult = Nothing
, ccProofTree = ProofTree $ unlines out ++ "\n\n" ++ prob
, ccUsedTime = timeToTimeOfDay $ secondsToDiffTime $ toInteger tUsed }
tLim = readMaybe tl
res <- runTimedHermit "consistency" (basename thName ++ ".owl") prob Nothing
$ fromMaybe maxBound $ readMaybe tl
return $ case res of
Nothing -> pStatus ["Timeout after " ++ tl ++ " seconds"]
(fromMaybe (0 :: Int) tLim)
Just (progTh, outp, eOut) -> if progTh then
let (_, exCode, out, tUsed) = analyseOutput outp eOut
in (pStatus out tUsed) { ccResult = exCode }
else pStatus ["Hermit not found"] (0 :: Int)
runTimedHermit :: String -- ^ pellet subcommand
-> FilePath -- ^ basename of problem file
-> String -- ^ problem content
-> Maybe String -- ^ entail content
-> Int -- ^ time limit in seconds
-> IO (Maybe (Bool, String, String)) -- ^ timeout or (success, stdout, stderr)
runTimedHermit opts tmpFileName prob entail secs = do
(progTh, pPath) <- check4jarFile hermitEnv hermitJar
if progTh then withinDirectory pPath $ do
timeTmpFile <- getTempFile prob tmpFileName
timeTmpEnt <- getTempFile (fromMaybe "" entail) tmpFileName
let entFile = timeTmpFile ++ ".entail.owl"
doEntail = trace (show opts) (isJust entail)
args = "-Xmx1024M" : "-jar" : hermitJar
: (if doEntail then ["--premise=file://"++timeTmpFile, "--conclusion=file://"++entFile, "-E"]
else ["-k", timeTmpFile]) ++ words opts
case entail of
Just c -> writeFile entFile c
Nothing -> return ()
mex <- timeoutCommand secs "java" args
removeFile timeTmpEnt
when doEntail $ removeFile entFile
return $ fmap (\ (_, outS, errS) -> (True, outS, errS)) mex
else return $ Just (False, "", "")
runHermit :: ProverState
{- ^ logical part containing the input Sign and axioms and possibly
goals that have been proved earlier as additional axioms -}
-> GenericConfig ProofTree -- ^ configuration to use
-> Bool -- ^ True means save TPTP file
-> String -- ^ name of the theory in the DevGraph
-> Named Axiom -- ^ goal to prove
-> IO (ATPRetval, GenericConfig ProofTree)
-- ^ (retval, configuration with proof status and complete output)
runHermit sps cfg saveHermit thName nGoal = do
let simpleOptions = extraOpts cfg
tLimit = fromMaybe 800 $ timeLimit cfg
goalSuffix = '_' : senAttr nGoal
tmpFileName = basename thName ++ goalSuffix ++ ".owl"
tScript = TacticScript $ show ATPTacticScript
{ tsTimeLimit = configTimeLimit cfg
, tsExtraOpts = simpleOptions }
defaultProofStatus out =
(openProofStatus (senAttr nGoal) hermitS $ ProofTree out)
{ tacticScript = tScript }
prob = showOWLProblemS sps
entail = showOWLProblemS
sps { initialState = [ nGoal {isAxiom = True } ] }
when saveHermit $ do
writeFile tmpFileName prob
writeFile (tmpFileName ++ ".entail.owl") entail
res <- runTimedHermit "" tmpFileName prob (Just entail) tLimit
((err, retval), output, tUsed) <- return $ case res of
Nothing ->
((ATPTLimitExceeded, defaultProofStatus "Timeout"), [], tLimit)
Just (progTh, output, eOut) ->
if progTh then
let (atpr, exCode, outp, tUsed) = analyseOutput output eOut
openStat = defaultProofStatus $ unlines outp
disProvedStatus = openStat
{ goalStatus = Disproved
, usedTime =
timeToTimeOfDay $ secondsToDiffTime $ toInteger tUsed }
provedStatus = disProvedStatus
{ goalStatus = Proved True
, usedAxioms = map senAttr $ initialState sps }
proofStat = case exCode of
Just True -> provedStatus
Just False -> disProvedStatus
_ -> openStat
in ((atpr, proofStat), outp, tUsed)
else
((ATPError "Could not find hermit reasoner. Is $HERMIT_PATH set?"
, defaultProofStatus ""), [], 0)
return (err, cfg
{ proofStatus = retval
, resultOutput = output
, timeUsed = timeToTimeOfDay $ secondsToDiffTime $ toInteger tUsed
})
analyseOutput :: String -> String -> (ATPRetval, Maybe Bool, [String], Int)
analyseOutput err outp =
let ls = lines outp ++ lines err
anaHelp (atp, exCode, to) line =
case words line of
"Consistent:" : v : _ -> case v of
"Yes" -> (ATPSuccess, Just True, to)
"No" -> (ATPSuccess, Just False, to)
_ -> (atp, exCode, to)
["true"] ->
(ATPSuccess, Just True, to)
["false"] ->
(ATPSuccess, Just False, to)
ne : _ | isPrefixOf "Non-entailments" ne ->
(ATPSuccess, Just False, to)
"Usage:" : "java" : "Hermit" : _ -> (ATPError line, Nothing, to)
"ERROR:" : _ -> (ATPError line, Nothing, to)
tm : num : _ | isPrefixOf "Time" tm && all isDigit num ->
(atp, exCode, read num)
_ -> (atp, exCode, to)
(atpr, st, tmo) = foldl anaHelp (ATPError "", Nothing, -1) ls
in case atpr of
ATPError s | null s -> (ATPError "unexpected hermit output", st, ls, tmo)
_ -> (atpr, st, ls, tmo)