(* ========================================================================= *) (* THE TPTP PROBLEM FILE FORMAT *) (* Copyright (c) 2001 Joe Leslie-Hurd, distributed under the BSD License *) (* ========================================================================= *)
structure Tptp :> Tptp = struct
open Useful;
(* ------------------------------------------------------------------------- *) (* Default TPTP function and relation name mapping. *) (* ------------------------------------------------------------------------- *)
fun isHdTlString hp tp s = let fun ct 0 = true
| ct i = tp (String.sub (s,i)) andalso ct (i - 1)
val n = size s in
n > 0 andalso hp (String.sub (s,0)) andalso ct (n - 1) end;
fun stripSuffix pred s = let fun f 0 = ""
| f n = let val n' = n - 1 in if pred (String.sub (s,n')) then f n' elseString.substring (s,0,n) end in
f (size s) end;
fun variant avoid s = ifnot (StringSet.member s avoid) then s else let val s = stripSuffix Char.isDigit s
fun var i = let val s_i = s ^ Int.toString i in ifnot (StringSet.member s_i avoid) then s_i else var (i + 1) end in
var 0 end;
local fun nonEmptyPred p l = case l of
[] => false
| c :: cs => p (c,cs);
fun existsPred l x = List.exists (fn p => p x) l;
fun isTptpChar #"_" = true
| isTptpChar c = Char.isAlphaNum c;
fun isTptpName l s = nonEmptyPred (existsPred l) (String.explode s);
fun isRegular (c,cs) =
Char.isLower c andalso List.all isTptpChar cs;
fun isNumber (c,cs) =
Char.isDigit c andalso List.all Char.isDigit cs;
fun isDefined (c,cs) =
c = #"$" andalso nonEmptyPred isRegular cs;
fun isSystem (c,cs) =
c = #"$" andalso nonEmptyPred isDefined cs; in fun mkTptpVarName s = let val s = caseList.filter isTptpChar (String.explode s) of
[] => [#"X"]
| l as c :: cs => if Char.isUpper c then l elseif Char.isLower c then Char.toUpper c :: cs else #"X" :: l in String.implode s end;
val isTptpConstName = isTptpName [isRegular,isNumber,isDefined,isSystem] and isTptpFnName = isTptpName [isRegular,isDefined,isSystem] and isTptpPropName = isTptpName [isRegular,isDefined,isSystem] and isTptpRelName = isTptpName [isRegular,isDefined,isSystem];
val isTptpFormulaName = isTptpName [isRegular,isNumber]; end;
datatype varToTptp = VarToTptp of StringSet.set * string NameMap.map;
val emptyVarToTptp = VarToTptp (StringSet.empty, NameMap.new ());
fun addVarToTptp vm v = let val VarToTptp (avoid,mapping) = vm in if NameMap.inDomain v mapping then vm else let val s = variant avoid (mkTptpVarName (Name.toString v))
val avoid = StringSet.add avoid s and mapping = NameMap.insert mapping (v,s) in
VarToTptp (avoid,mapping) end end;
local fun add (v,vm) = addVarToTptp vm v; in val addListVarToTptp = List.foldl add;
val addSetVarToTptp = NameSet.foldl add; end;
val fromListVarToTptp = addListVarToTptp emptyVarToTptp;
val fromSetVarToTptp = addSetVarToTptp emptyVarToTptp;
fun getVarToTptp vm v = let val VarToTptp (_,mapping) = vm in case NameMap.peek mapping v of
SOME s => s
| NONE => raise Bug "Tptp.getVarToTptp: unknown var" end;
(* ------------------------------------------------------------------------- *) (* Mapping to TPTP function and relation names. *) (* ------------------------------------------------------------------------- *)
local val emptyNames : string NameArityMap.map = NameArityMap.new ();
fun addNames ({name,arity,tptp},mapping) =
NameArityMap.insert mapping ((name,arity),tptp);
val fromListNames = List.foldl addNames emptyNames; in fun mkNameToTptp mapping = NameToTptp (fromListNames mapping); end;
local fun escapeChar c = case c of
#"\\" => "\\\\"
| #"'" => "\\'"
| #"\n" => "\\n"
| #"\t" => "\\t"
| _ => str c;
val escapeString = String.translate escapeChar; in fun singleQuote s = "'" ^ escapeString s ^ "'"; end;
fun getNameToTptp isTptp s = if isTptp s then s else singleQuote s;
fun getNameArityToTptp isZeroTptp isPlusTptp (NameToTptp mapping) na = case NameArityMap.peek mapping na of
SOME s => s
| NONE => let val (n,a) = na val isTptp = if a = 0 then isZeroTptp else isPlusTptp val s = Name.toString n in
getNameToTptp isTptp s end;
(* ------------------------------------------------------------------------- *) (* Mapping from TPTP function and relation names. *) (* ------------------------------------------------------------------------- *)
datatype nameFromTptp = NameFromTptp of (string * int, Name.name) Map.map;
local val stringArityCompare = prodCompare String.compare Int.compare;
val emptyStringArityMap = Map.new stringArityCompare;
fun addStringArityMap ({name,arity,tptp},mapping) = Map.insert mapping ((tptp,arity),name);
val fromListStringArityMap = List.foldl addStringArityMap emptyStringArityMap; in fun mkNameFromTptp mapping = NameFromTptp (fromListStringArityMap mapping); end;
fun getNameFromTptp (NameFromTptp mapping) sa = caseMap.peek mapping sa of
SOME n => n
| NONE => let val (s,_) = sa in
Name.fromString s end;
(* ------------------------------------------------------------------------- *) (* Mapping to and from TPTP variable, function and relation names. *) (* ------------------------------------------------------------------------- *)
fun mkMapping mapping = let val {functionMapping,relationMapping} = mapping
val varTo = emptyVarToTptp val fnTo = mkNameToTptp functionMapping val relTo = mkNameToTptp relationMapping
val fnFrom = mkNameFromTptp functionMapping val relFrom = mkNameFromTptp relationMapping in
Mapping
{varTo = varTo,
fnTo = fnTo,
relTo = relTo,
fnFrom = fnFrom,
relFrom = relFrom} end;
fun addVarListMapping mapping vs = let val Mapping
{varTo,
fnTo,
relTo,
fnFrom,
relFrom} = mapping
val varTo = addListVarToTptp varTo vs in
Mapping
{varTo = varTo,
fnTo = fnTo,
relTo = relTo,
fnFrom = fnFrom,
relFrom = relFrom} end;
fun addVarSetMapping mapping vs = let val Mapping
{varTo,
fnTo,
relTo,
fnFrom,
relFrom} = mapping
val varTo = addSetVarToTptp varTo vs in
Mapping
{varTo = varTo,
fnTo = fnTo,
relTo = relTo,
fnFrom = fnFrom,
relFrom = relFrom} end;
fun varToTptp mapping v = let val Mapping {varTo,...} = mapping in
getVarToTptp varTo v end;
fun fnToTptp mapping fa = let val Mapping {fnTo,...} = mapping in
getNameArityToTptp isTptpConstName isTptpFnName fnTo fa end;
fun relToTptp mapping ra = let val Mapping {relTo,...} = mapping in
getNameArityToTptp isTptpPropName isTptpRelName relTo ra end;
fun varFromTptp (_ : mapping) v = getVarFromTptp v;
fun fnFromTptp mapping fa = let val Mapping {fnFrom,...} = mapping in
getNameFromTptp fnFrom fa end;
fun relFromTptp mapping ra = let val Mapping {relFrom,...} = mapping in
getNameFromTptp relFrom ra end;
val defaultMapping = let fun lift {name,arity,tptp} =
{name = Name.fromString name, arity = arity, tptp = tptp}
val functionMapping = List.map lift defaultFunctionMapping and relationMapping = List.map lift defaultRelationMapping
val mapping =
{functionMapping = functionMapping,
relationMapping = relationMapping} in
mkMapping mapping end;
(* ------------------------------------------------------------------------- *) (* Interpreting TPTP functions and relations in a finite model. *) (* ------------------------------------------------------------------------- *)
fun mkFixedMap funcModel relModel = let fun mkEntry {name,arity,model} = ((Name.fromString name, arity), model)
fun mkMap l = NameArityMap.fromList (List.map mkEntry l) in
{functionMap = mkMap funcModel,
relationMap = mkMap relModel} end;
val defaultFixedMap = mkFixedMap defaultFunctionModel defaultRelationModel;
val defaultModel = let val {size = N, fixed = fix} = Model.default
val fix = Model.mapFixed defaultFixedMap fix in
{size = N, fixed = fix} end;
local fun toTptpMap toTptp = let fun add ((src,arity),dest,m) = let val src = Name.fromString (toTptp (src,arity)) in
NameArityMap.insert m ((src,arity),dest) end in
fn m => NameArityMap.foldl add (NameArityMap.new ()) m end;
fun toTptpFixedMap mapping fixMap = let val {functionMap = fnMap, relationMap = relMap} = fixMap
val fnMap = toTptpMap (fnToTptp mapping) fnMap and relMap = toTptpMap (relToTptp mapping) relMap in
{functionMap = fnMap,
relationMap = relMap} end; in fun ppFixedMap mapping fixMap =
Model.ppFixedMap (toTptpFixedMap mapping fixMap); end;
fun ppVar mapping v = let val s = varToTptp mapping v in Print.ppString s end;
fun ppFnName mapping fa = Print.ppString (fnToTptp mapping fa);
fun ppConst mapping c = ppFnName mapping (c,0);
fun ppTerm mapping = let fun term tm = case tm of
Term.Var v => ppVar mapping v
| Term.Fn (f,tms) => case length tms of
0 => ppConst mapping f
| a => Print.inconsistentBlock 2
[ppFnName mapping (f,a), Print.ppString "(", Print.ppOpList "," term tms, Print.ppString ")"] in
fn tm => Print.inconsistentBlock 0 [term tm] end;
fun ppRelName mapping ra = Print.ppString (relToTptp mapping ra);
fun ppProp mapping p = ppRelName mapping (p,0);
fun ppAtom mapping (r,tms) = case length tms of
0 => ppProp mapping r
| a => Print.inconsistentBlock 2
[ppRelName mapping (r,a), Print.ppString "(", Print.ppOpList "," (ppTerm mapping) tms, Print.ppString ")"];
local val neg = Print.sequence (Print.ppString "~") Print.break;
fun fof mapping fm = case fm of
Formula.And _ => assoc_binary mapping ("&", Formula.stripConj fm)
| Formula.Or _ => assoc_binary mapping ("|", Formula.stripDisj fm)
| Formula.Imp a_b => nonassoc_binary mapping ("=>",a_b)
| Formula.Iff a_b => nonassoc_binary mapping ("<=>",a_b)
| _ => unitary mapping fm
val clauseFunctions = let fun funcs (lit,acc) = NameAritySet.union (functionsLiteral lit) acc in List.foldl funcs NameAritySet.empty end;
val clauseRelations = let fun rels (lit,acc) = case relationLiteral lit of
NONE => acc
| SOME r => NameAritySet.add acc r in List.foldl rels NameAritySet.empty end;
val clauseFreeVars = let fun fvs (lit,acc) = NameSet.union (freeVarsLiteral lit) acc in List.foldl fvs NameSet.empty end;
fun clauseSubst sub lits = List.map (literalSubst sub) lits;
fun clauseToFormula lits = Formula.listMkDisj (List.map literalToFormula lits);
fun clauseFromFormula fm = List.map literalFromFormula (Formula.stripDisj fm);
fun clauseFromLiteralSet cl =
clauseFromFormula
(Formula.listMkDisj (LiteralSet.transform Literal.toFormula cl));
fun clauseFromThm th = clauseFromLiteralSet (Thm.clause th);
fun ppClause mapping = Print.ppMap clauseToFormula (ppFof mapping);
fun isNoFormulaSource source = case source of
NoFormulaSource => true
| _ => false;
fun functionsFormulaSource source = case source of
NoFormulaSource => NameAritySet.empty
| StripFormulaSource _ => NameAritySet.empty
| NormalizeFormulaSource data => let val {inference = inf, parents = _} = data in case inf of
Normalize.Axiom fm => Formula.functions fm
| Normalize.Definition (_,fm) => Formula.functions fm
| _ => NameAritySet.empty end
| ProofFormulaSource data => let val {inference = inf, parents = _} = data in case inf of
Proof.Axiom cl => LiteralSet.functions cl
| Proof.Assume atm => Atom.functions atm
| Proof.Subst (sub,_) => Subst.functions sub
| Proof.Resolve (atm,_,_) => Atom.functions atm
| Proof.Refl tm => Term.functions tm
| Proof.Equality (lit,_,tm) =>
NameAritySet.union (Literal.functions lit) (Term.functions tm) end;
fun relationsFormulaSource source = case source of
NoFormulaSource => NameAritySet.empty
| StripFormulaSource _ => NameAritySet.empty
| NormalizeFormulaSource data => let val {inference = inf, parents = _} = data in case inf of
Normalize.Axiom fm => Formula.relations fm
| Normalize.Definition (_,fm) => Formula.relations fm
| _ => NameAritySet.empty end
| ProofFormulaSource data => let val {inference = inf, parents = _} = data in case inf of
Proof.Axiom cl => LiteralSet.relations cl
| Proof.Assume atm => NameAritySet.singleton (Atom.relation atm)
| Proof.Subst _ => NameAritySet.empty
| Proof.Resolve (atm,_,_) => NameAritySet.singleton (Atom.relation atm)
| Proof.Refl tm => NameAritySet.empty
| Proof.Equality (lit,_,_) =>
NameAritySet.singleton (Literal.relation lit) end;
fun freeVarsFormulaSource source = case source of
NoFormulaSource => NameSet.empty
| StripFormulaSource _ => NameSet.empty
| NormalizeFormulaSource data => NameSet.empty
| ProofFormulaSource data => let val {inference = inf, parents = _} = data in case inf of
Proof.Axiom cl => LiteralSet.freeVars cl
| Proof.Assume atm => Atom.freeVars atm
| Proof.Subst (sub,_) => Subst.freeVars sub
| Proof.Resolve (atm,_,_) => Atom.freeVars atm
| Proof.Refl tm => Term.freeVars tm
| Proof.Equality (lit,_,tm) =>
NameSet.union (Literal.freeVars lit) (Term.freeVars tm) end;
local val GEN_INFERENCE = "inference" and GEN_INTRODUCED = "introduced";
fun ppProofParent mapping (p,s) = if Subst.null s then ppParent p elsePrint.ppOp2 " :" ppParent (ppProofSubst mapping) (p,s); in fun ppFormulaSource mapping source = case source of
NoFormulaSource => Print.skip
| StripFormulaSource {inference,parents} => let val gen = GEN_INFERENCE
val name = nameInference inference in Print.inconsistentBlock (size gen + 1)
[Print.ppString gen, Print.ppString "(", Print.ppString name, Print.ppString ",", Print.break, Print.ppBracket "[""]" (ppStrip mapping) inference, Print.ppString ",", Print.break, Print.ppList ppParent parents, Print.ppString ")"] end
| NormalizeFormulaSource {inference,parents} => let val gen = GEN_INFERENCE
val name = nameNormalize inference in Print.inconsistentBlock (size gen + 1)
[Print.ppString gen, Print.ppString "(", Print.ppString name, Print.ppString ",", Print.break, Print.ppBracket "[""]" (ppNormalize mapping) inference, Print.ppString ",", Print.break, Print.ppList ppParent parents, Print.ppString ")"] end
| ProofFormulaSource {inference,parents} => let val isTaut = List.null parents
val gen = if isTaut then GEN_INTRODUCED else GEN_INFERENCE
val name = nameProof inference
val parents = let valsub = case inference of
Proof.Subst (s,_) => s
| _ => Subst.empty in List.map (fn parent => (parent,sub)) parents end in Print.inconsistentBlock (size gen + 1)
([Print.ppString gen, Print.ppString "("] @
(if isTaut then
[Print.ppString "tautology", Print.ppString ",", Print.break, Print.inconsistentBlock 1
[Print.ppString "[", Print.ppString name, Print.ppString ",", Print.break,
ppProof mapping inference, Print.ppString "]"]] else
[Print.ppString name, Print.ppString ",", Print.break,
ppProof mapping inference, Print.ppString ",", Print.break, Print.ppList (ppProofParent mapping) parents]) @
[Print.ppString ")"]) end end;
datatype formula =
Formula of
{name : formulaName,
role : role,
body : formulaBody,
source : formulaSource};
fun nameFormula (Formula {name,...}) = name;
fun roleFormula (Formula {role,...}) = role;
fun bodyFormula (Formula {body,...}) = body;
fun sourceFormula (Formula {source,...}) = source;
fun destCnfFormula fm = destCnfFormulaBody (bodyFormula fm);
val isCnfFormula = can destCnfFormula;
fun destFofFormula fm = destFofFormulaBody (bodyFormula fm);
val isFofFormula = can destFofFormula;
fun functionsFormula fm = let val bodyFns = formulaBodyFunctions (bodyFormula fm) and sourceFns = functionsFormulaSource (sourceFormula fm) in
NameAritySet.union bodyFns sourceFns end;
fun relationsFormula fm = let val bodyRels = formulaBodyRelations (bodyFormula fm) and sourceRels = relationsFormulaSource (sourceFormula fm) in
NameAritySet.union bodyRels sourceRels end;
fun freeVarsFormula fm = let val bodyFvs = formulaBodyFreeVars (bodyFormula fm) and sourceFvs = freeVarsFormulaSource (sourceFormula fm) in
NameSet.union bodyFvs sourceFvs end;
val freeVarsListFormula = let fun add (fm,vs) = NameSet.union vs (freeVarsFormula fm) in List.foldl add NameSet.empty end;
val formulasFunctions = let fun funcs (fm,acc) = NameAritySet.union (functionsFormula fm) acc in List.foldl funcs NameAritySet.empty end;
val formulasRelations = let fun rels (fm,acc) = NameAritySet.union (relationsFormula fm) acc in List.foldl rels NameAritySet.empty end;
fun isCnfConjectureFormula fm = case fm of
Formula {role, body = CnfFormulaBody _, ...} => isCnfConjectureRole role
| _ => false;
fun isFofConjectureFormula fm = case fm of
Formula {role, body = FofFormulaBody _, ...} => isFofConjectureRole role
| _ => false;
fun isConjectureFormula fm =
isCnfConjectureFormula fm orelse
isFofConjectureFormula fm;
(* Parsing and pretty-printing *)
fun ppFormula mapping fm = let val Formula {name,role,body,source} = fm
val gen = case body of
CnfFormulaBody _ => "cnf"
| FofFormulaBody _ => "fof" in Print.inconsistentBlock (size gen + 1)
([Print.ppString gen, Print.ppString "(",
ppFormulaName name, Print.ppString ",", Print.break,
ppRole role, Print.ppString ",", Print.break, Print.consistentBlock 1
[Print.ppString "(",
ppFormulaBody mapping body, Print.ppString ")"]] @
(if isNoFormulaSource source then [] else
[Print.ppString ",", Print.break,
ppFormulaSource mapping source]) @
[Print.ppString ")."]) end;
fun formulaToString mapping = Print.toString (ppFormula mapping);
local open Parse;
infixr 9 >>++
infixr 8 ++
infixr 7 >>
infixr 6 ||
fun someAlphaNum p =
maybe (fn AlphaNum s => if p s then SOME s else NONE | _ => NONE);
fun alphaNumParser s = someAlphaNum (equal s) >> K ();
val lowerParser = someAlphaNum (fn s => Char.isLower (String.sub (s,0)));
val upperParser = someAlphaNum (fn s => Char.isUpper (String.sub (s,0)));
val stringParser = lowerParser || upperParser;
val numberParser = someAlphaNum (List.all Char.isDigit o String.explode);
fun somePunct p =
maybe (fn Punct c => if p c then SOME c else NONE | _ => NONE);
fun punctParser c = somePunct (equal c) >> K ();
val quoteParser = maybe (fn Quote s => SOME s | _ => NONE);
local fun f [] = raise Bug "symbolParser"
| f [x] = x
| f (h :: t) = (h ++ f t) >> K (); in fun symbolParser s = f (List.map punctParser (String.explode s)); end;
val nameParser =
(lowerParser || numberParser || quoteParser) >> FormulaName;
val roleParser = lowerParser >> fromStringRole;
local fun isProposition s = isHdTlString Char.isLower isAlphaNum s; in val propositionParser =
someAlphaNum isProposition ||
definedParser ||
systemParser ||
quoteParser; end;
local fun isFunction s = isHdTlString Char.isLower isAlphaNum s; in val functionParser =
someAlphaNum isFunction ||
definedParser ||
systemParser ||
quoteParser; end;
local fun isConstant s = isHdTlString Char.isLower isAlphaNum s; in val constantParser =
someAlphaNum isConstant ||
definedParser ||
numberParser ||
systemParser ||
quoteParser; end;
val varParser = upperParser;
val varListParser =
(punctParser #"[" ++ varParser ++
many ((punctParser #"," ++ varParser) >> snd) ++
punctParser #"]") >>
(fn ((),(h,(t,()))) => h :: t);
fun mkVarName mapping v = varFromTptp mapping v;
fun mkVar mapping v = let val v = mkVarName mapping v in
Term.Var v end
fun mkFn mapping (f,tms) = let val f = fnFromTptp mapping (f, length tms) in
Term.Fn (f,tms) end;
fun mkConst mapping c = mkFn mapping (c,[]);
fun mkAtom mapping (r,tms) = let val r = relFromTptp mapping (r, length tms) in
(r,tms) end;
fun termParser mapping input = let val fnP = functionArgumentsParser mapping >> mkFn mapping val nonFnP = nonFunctionArgumentsTermParser mapping in
fnP || nonFnP end input
and functionArgumentsParser mapping input = let val commaTmP = (punctParser #"," ++ termParser mapping) >> snd in
(functionParser ++ punctParser #"(" ++ termParser mapping ++
many commaTmP ++ punctParser #")") >>
(fn (f,((),(t,(ts,())))) => (f, t :: ts)) end input
and nonFunctionArgumentsTermParser mapping input = let val varP = varParser >> mkVar mapping val constP = constantParser >> mkConst mapping in
varP || constP end input;
fun binaryAtomParser mapping tm input = let val eqP =
(punctParser #"=" ++ termParser mapping) >>
(fn ((),r) => (true,("$equal",[tm,r])))
val neqP =
(symbolParser "!=" ++ termParser mapping) >>
(fn ((),r) => (false,("$equal",[tm,r]))) in
eqP || neqP end input;
fun maybeBinaryAtomParser mapping (s,tms) input = let val tm = mkFn mapping (s,tms) in
optional (binaryAtomParser mapping tm) >>
(fn SOME lit => lit
| NONE => (true,(s,tms))) end input;
fun literalAtomParser mapping input = let val fnP =
functionArgumentsParser mapping >>++
maybeBinaryAtomParser mapping
val nonFnP =
nonFunctionArgumentsTermParser mapping >>++
binaryAtomParser mapping
val propP = propositionParser >> (fn s => (true,(s,[]))) in
fnP || nonFnP || propP end input;
fun atomParser mapping input = let fun mk (pol,rel) = case rel of
("$true",[]) => Boolean pol
| ("$false",[]) => Boolean (not pol)
| ("$equal",[l,r]) => Literal (pol, Atom.mkEq (l,r))
| (r,tms) => Literal (pol, mkAtom mapping (r,tms)) in
literalAtomParser mapping >> mk end input;
fun literalParser mapping input = let val negP =
(punctParser #"~" ++ atomParser mapping) >>
(negateLiteral o snd)
val posP = atomParser mapping in
negP || posP end input;
fun disjunctionParser mapping input = let val orLitP = (punctParser #"|" ++ literalParser mapping) >> snd in
(literalParser mapping ++ many orLitP) >> (fn (h,t) => h :: t) end input;
fun clauseParser mapping input = let val disjP = disjunctionParser mapping
val bracketDisjP =
(punctParser #"(" ++ disjP ++ punctParser #")") >>
(fn ((),(c,())) => c) in
bracketDisjP || disjP end input;
val binaryConnectiveParser =
(symbolParser "<=>" >> K Formula.Iff) ||
(symbolParser "=>" >> K Formula.Imp) ||
(symbolParser "<=" >> K (fn (f,g) => Formula.Imp (g,f))) ||
(symbolParser "<~>" >> K (Formula.Not o Formula.Iff)) ||
(symbolParser "~|" >> K (Formula.Not o Formula.Or)) ||
(symbolParser "~&" >> K (Formula.Not o Formula.And));
val quantifierParser =
(punctParser #"!" >> K Formula.listMkForall) ||
(punctParser #"?" >> K Formula.listMkExists);
fun fofFormulaParser mapping input = let fun mk (f,NONE) = f
| mk (f, SOME t) = t f in
(unitaryFormulaParser mapping ++
optional (binaryFormulaParser mapping)) >> mk end input
and binaryFormulaParser mapping input = let val nonAssocP = nonAssocBinaryFormulaParser mapping
val assocP = assocBinaryFormulaParser mapping in
nonAssocP || assocP end input
and nonAssocBinaryFormulaParser mapping input = let fun mk (c,g) f = c (f,g) in
(binaryConnectiveParser ++ unitaryFormulaParser mapping) >> mk end input
and assocBinaryFormulaParser mapping input = let val orP = orFormulaParser mapping
val andP = andFormulaParser mapping in
orP || andP end input
and orFormulaParser mapping input = let val orFmP = (punctParser #"|" ++ unitaryFormulaParser mapping) >> snd in
atLeastOne orFmP >>
(fn fs => fn f => Formula.listMkDisj (f :: fs)) end input
and andFormulaParser mapping input = let val andFmP = (punctParser #"&" ++ unitaryFormulaParser mapping) >> snd in
atLeastOne andFmP >>
(fn fs => fn f => Formula.listMkConj (f :: fs)) end input
and unitaryFormulaParser mapping input = let val quantP = quantifiedFormulaParser mapping
val atomP =
atomParser mapping >>
(fn Boolean b => Formula.mkBoolean b
| Literal l => Literal.toFormula l) in
quantP ||
unaryP ||
brackP ||
atomP end input
and quantifiedFormulaParser mapping input = let fun mk (q,(vs,((),f))) = q (List.map (mkVarName mapping) vs, f) in
(quantifierParser ++ varListParser ++ punctParser #":" ++
unitaryFormulaParser mapping) >> mk end input
and unaryFormulaParser mapping input = let fun mk (c,f) = c f in
(unaryConnectiveParser ++ unitaryFormulaParser mapping) >> mk end input
and unaryConnectiveParser input =
(punctParser #"~" >> K Formula.Not) input;
fun cnfParser mapping input = let fun mk ((),((),(name,((),(role,((),(cl,((),())))))))) = let val body = CnfFormulaBody cl val source = NoFormulaSource in
Formula
{name = name,
role = role,
body = body,
source = source} end in
(alphaNumParser "cnf" ++ punctParser #"(" ++
nameParser ++ punctParser #"," ++
roleParser ++ punctParser #"," ++
clauseParser mapping ++ punctParser #")" ++
punctParser #".") >> mk end input;
fun fofParser mapping input = let fun mk ((),((),(name,((),(role,((),(fm,((),())))))))) = let val body = FofFormulaBody fm val source = NoFormulaSource in
Formula
{name = name,
role = role,
body = body,
source = source} end in
(alphaNumParser "fof" ++ punctParser #"(" ++
nameParser ++ punctParser #"," ++
roleParser ++ punctParser #"," ++
fofFormulaParser mapping ++ punctParser #")" ++
punctParser #".") >> mk end input; in fun formulaParser mapping input = let val cnfP = cnfParser mapping
val fofP = fofParser mapping in
cnfP || fofP end input; end;
(* ------------------------------------------------------------------------- *) (* Include declarations. *) (* ------------------------------------------------------------------------- *)
fun ppInclude i = Print.inconsistentBlock 2
[Print.ppString "include('", Print.ppString i, Print.ppString "')."];
val includeToString = Print.toString ppInclude;
local open Parse;
infixr 9 >>++
infixr 8 ++
infixr 7 >>
infixr 6 ||
val filenameParser = maybe (fn Quote s => SOME s | _ => NONE); in val includeParser =
(some (equal (AlphaNum "include")) ++
some (equal (Punct #"(")) ++
filenameParser ++
some (equal (Punct #")")) ++
some (equal (Punct #"."))) >>
(fn (_,(_,(f,(_,_)))) => f); end;
datatype declaration =
IncludeDeclaration ofstring
| FormulaDeclaration of formula;
val partitionDeclarations = let fun part (d,(il,fl)) = case d of
IncludeDeclaration i => (i :: il, fl)
| FormulaDeclaration f => (il, f :: fl) in
fn l => List.foldl part ([],[]) (List.rev l) end;
fun parseChars parser chars = let val tokens = Parse.everything lexer chars in
Parse.everything (parser >> singleton) tokens end; in fun parseDeclaration mapping = parseChars (declarationParser mapping); end;
datatype problem =
Problem of
{comments : comments,
includes : includes,
formulas : formula list};
fun hasCnfConjecture (Problem {formulas,...}) = List.exists isCnfConjectureFormula formulas;
fun hasFofConjecture (Problem {formulas,...}) = List.exists isFofConjectureFormula formulas;
fun hasConjecture (Problem {formulas,...}) = List.exists isConjectureFormula formulas;
fun freeVars (Problem {formulas,...}) = freeVarsListFormula formulas;
local fun bump n avoid = let val s = FormulaName (Int.toString n) in if memberFormulaNameSet s avoid then bump (n + 1) avoid else (s, n, addFormulaNameSet avoid s) end;
fun fromClause defaultRole names roles cl (n,avoid) = let val (name,n,avoid) = case LiteralSetMap.peek names cl of
SOME name => (name,n,avoid)
| NONE => bump n avoid
val role = Option.getOpt (LiteralSetMap.peek roles cl, defaultRole)
val body = CnfFormulaBody (clauseFromLiteralSet cl)
val source = NoFormulaSource
val formula =
Formula
{name = name,
role = role,
body = body,
source = source} in
(formula,(n,avoid)) end; in fun mkProblem {comments,includes,names,roles,problem} = let fun fromCl defaultRole = fromClause defaultRole names roles
val {axioms,conjecture} = problem
val n_avoid = (0, allClauseNames names)
val (axiomFormulas,n_avoid) = maps (fromCl AxiomRole) axioms n_avoid
val (conjectureFormulas,_) =
maps (fromCl NegatedConjectureRole) conjecture n_avoid
val formulas = axiomFormulas @ conjectureFormulas in
Problem
{comments = comments,
includes = includes,
formulas = formulas} end; end;
type normalization =
{problem : Problem.problem,
sources : clauseSources};
datatype problemGoal =
NoGoal
| CnfGoal of (formulaName * clause) list
| FofGoal of (formulaName * Formula.formula) list;
local fun partitionFormula (formula,(cnfAxioms,fofAxioms,cnfGoals,fofGoals)) = let val Formula {name,role,body,...} = formula in case body of
CnfFormulaBody cl => if isCnfConjectureRole role then let val cnfGoals = (name,cl) :: cnfGoals in
(cnfAxioms,fofAxioms,cnfGoals,fofGoals) end else let val cnfAxioms = (name,cl) :: cnfAxioms in
(cnfAxioms,fofAxioms,cnfGoals,fofGoals) end
| FofFormulaBody fm => if isFofConjectureRole role then let val fofGoals = (name,fm) :: fofGoals in
(cnfAxioms,fofAxioms,cnfGoals,fofGoals) end else let val fofAxioms = (name,fm) :: fofAxioms in
(cnfAxioms,fofAxioms,cnfGoals,fofGoals) end end;
fun partitionFormulas fms = let val (cnfAxioms,fofAxioms,cnfGoals,fofGoals) = List.foldl partitionFormula ([],[],[],[]) fms
val goal = case (List.rev cnfGoals, List.rev fofGoals) of
([],[]) => NoGoal
| (cnfGoals,[]) => CnfGoal cnfGoals
| ([],fofGoals) => FofGoal fofGoals
| (_ :: _, _ :: _) => raise Error "TPTP problem has both cnf and fof conjecture formulas" in
{cnfAxioms = List.rev cnfAxioms,
fofAxioms = List.rev fofAxioms,
goal = goal} end;
fun addClauses role clauses acc : normalization = let fun addClause (cl_src,sources) =
LiteralSetMap.insert sources cl_src
val {problem,sources} : normalization = acc val {axioms,conjecture} = problem
val cls = List.map fst clauses val (axioms,conjecture) = if isCnfConjectureRole role then (axioms, cls @ conjecture) else (cls @ axioms, conjecture)
val problem = {axioms = axioms, conjecture = conjecture} and sources = List.foldl addClause sources clauses in
{problem = problem,
sources = sources} end;
fun addCnf role ((name,clause),(norm,cnf)) = ifList.exists (equalBooleanLiteral true) clause then (norm,cnf) else let val cl = List.mapPartial (total destLiteral) clause val cl = LiteralSet.fromList cl
val src = CnfClauseSource (name,clause)
val norm = addClauses role [(cl,src)] norm in
(norm,cnf) end;
val addCnfAxiom = addCnf AxiomRole;
val addCnfGoal = addCnf NegatedConjectureRole;
fun addFof role (th,(norm,cnf)) = let fun sourcify (cl,inf) = (cl, FofClauseSource inf)
val (clauses,cnf) = Normalize.addCnf th cnf val clauses = List.map sourcify clauses val norm = addClauses role clauses norm in
(norm,cnf) end;
fun addFofAxiom ((_,fm),acc) =
addFof AxiomRole (Normalize.mkAxiom fm, acc);
fun normProblem subgoal (norm,_) = let val {problem,sources} = norm val {axioms,conjecture} = problem val problem = {axioms = List.rev axioms, conjecture = List.rev conjecture} in
{subgoal = subgoal,
problem = problem,
sources = sources} end;
val normProblemFalse = normProblem (Formula.False,[]);
fun splitProblem acc = let fun mk parents subgoal = let val subgoal = Formula.generalize subgoal
val th = Normalize.mkAxiom (Formula.Not subgoal)
val acc = addFof NegatedConjectureRole (th,acc) in
normProblem (subgoal,parents) acc end
fun split (name,goal) = let val subgoals = Formula.splitGoal goal val subgoals = ifList.null subgoals then [Formula.True] else subgoals
val parents = [name] in List.map (mk parents) subgoals end in
fn goals => List.concat (List.map split goals) end;
fun clausesToGoal cls = let val cls = List.map (Formula.generalize o clauseToFormula o snd) cls in
Formula.listMkConj cls end;
fun formulasToGoal fms = let val fms = List.map (Formula.generalize o snd) fms in
Formula.listMkConj fms end; in fun goal (Problem {formulas,...}) = let val {cnfAxioms,fofAxioms,goal} = partitionFormulas formulas
val fm = case goal of
NoGoal => Formula.False
| CnfGoal cls => Formula.Imp (clausesToGoal cls, Formula.False)
| FofGoal goals => formulasToGoal goals
val fm = ifList.null fofAxioms then fm else Formula.Imp (formulasToGoal fofAxioms, fm)
val fm = ifList.null cnfAxioms then fm else Formula.Imp (clausesToGoal cnfAxioms, fm) in
fm end;
fun normalize (Problem {formulas,...}) = let val {cnfAxioms,fofAxioms,goal} = partitionFormulas formulas
val acc = (initialNormalization, Normalize.initialCnf) val acc = List.foldl addCnfAxiom acc cnfAxioms val acc = List.foldl addFofAxiom acc fofAxioms in case goal of
NoGoal => [normProblemFalse acc]
| CnfGoal cls => [normProblemFalse (List.foldl addCnfGoal acc cls)]
| FofGoal goals => splitProblem acc goals end; end;
fun stripInitialLineComments acc strm = case strm of
Stream.Nil => (List.rev acc, Stream.Nil)
| Stream.Cons (line,rest) => case total destLineComment line of
SOME s => stripInitialLineComments (s :: acc) (rest ())
| NONE => (List.rev acc, strm);
fun advanceComment c state = case state of
NoComment =>
(case c of
#"\n" => (Stream.Nil, EnteringLineComment)
| #"/" => (Stream.Nil, EnteringBlockComment)
| #"'" => (Stream.singleton #"'", InsideSingleQuoteComment)
| _ => (Stream.singleton c, NoComment))
| EnteringLineComment =>
(case c of
#"%" => (Stream.singleton #"\n", InsideLineComment)
| #"\n" => (Stream.singleton #"\n", EnteringLineComment)
| #"/" => (Stream.singleton #"\n", EnteringBlockComment)
| #"'" => (Stream.fromList [#"\n",#"'"], InsideSingleQuoteComment)
| _ => (Stream.fromList [#"\n",c], NoComment))
| InsideLineComment =>
(case c of
#"\n" => (Stream.Nil, EnteringLineComment)
| _ => (Stream.Nil, InsideLineComment))
| EnteringBlockComment =>
(case c of
#"*" => (Stream.Nil, InsideBlockComment)
| #"\n" => (Stream.singleton #"/", EnteringLineComment)
| #"/" => (Stream.singleton #"/", EnteringBlockComment)
| #"'" => (Stream.fromList [#"/",#"'"], InsideSingleQuoteComment)
| _ => (Stream.fromList [#"/",c], NoComment))
| InsideBlockComment =>
(case c of
#"*" => (Stream.Nil, LeavingBlockComment)
| _ => (Stream.Nil, InsideBlockComment))
| LeavingBlockComment =>
(case c of
#"/" => (Stream.Nil, NoComment)
| #"*" => (Stream.Nil, LeavingBlockComment)
| _ => (Stream.Nil, InsideBlockComment))
| InsideSingleQuoteComment =>
(case c of
#"'" => (Stream.singleton #"'", NoComment)
| #"\\" => (Stream.singleton #"\\", EscapedSingleQuoteComment)
| _ => (Stream.singleton c, InsideSingleQuoteComment))
| EscapedSingleQuoteComment =>
(Stream.singleton c, InsideSingleQuoteComment);
fun eofComment state = case state of
NoComment => Stream.Nil
| EnteringLineComment => Stream.singleton #"\n"
| InsideLineComment => Stream.Nil
| EnteringBlockComment => Stream.singleton #"/"
| InsideBlockComment => raise Error "EOF inside a block comment"
| LeavingBlockComment => raise Error "EOF inside a block comment"
| InsideSingleQuoteComment => raise Error "EOF inside a single quote"
| EscapedSingleQuoteComment => raise Error "EOF inside a single quote";
val stripComments = Stream.mapsConcat advanceComment eofComment NoComment; in fun read {mapping,filename} = let (* Estimating parse error line numbers *)
val lines = Stream.fromTextFile {filename = filename}
val {chars,parseErrorLocation} = Parse.initialize {lines = lines} in
(let (* The character stream *)
val (comments,chars) = stripInitialLineComments [] chars
val chars = Parse.everything Parse.any chars
val chars = stripComments chars
(* The declaration stream *)
val declarations = Stream.toList (parseDeclaration mapping chars)
val (includes,formulas) = partitionDeclarations declarations in
Problem
{comments = comments,
includes = includes,
formulas = formulas} end handle Parse.NoParse => raise Error "parse error") handle Error err => raise Error ("error in TPTP file \"" ^ filename ^ "\" " ^
parseErrorLocation () ^ "\n" ^ err) end; end;
local val newline = Stream.singleton "\n";
fun spacer top = if top then Stream.Nil else newline;
fun mkComment comment = mkLineComment comment ^ "\n";
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.