diff --git a/_oasis b/_oasis index 044ad498ed1c6fea4a182af54b90b6c0c864d69c..707258ad5d3999092020f6af8b711e11b5852a64 100644 --- a/_oasis +++ b/_oasis @@ -100,7 +100,7 @@ Executable coalg ByteOpt: -cc g++ CCOpt: -std=c++98 -x c++ if flag(static) - CCLib: -static + CCLib: -static -ltinfo -lgpm -lz -ldl -lltdl Executable "cool-owl" CompiledObject: native @@ -160,7 +160,7 @@ Executable debugger ByteOpt: -cc g++ CCOpt: -std=c++98 -x c++ if flag(static) - CCLib: -static + CCLib: -static -lz -ldl -lltdl diff --git a/randmu.py b/randmu.py new file mode 100755 index 0000000000000000000000000000000000000000..2c52877ddcb6fb8750290211d219abf20ee83eab --- /dev/null +++ b/randmu.py @@ -0,0 +1,610 @@ +#!/usr/bin/python3 +# +# Ideal: + +# Start with a single variable. While formula is still below the +# target size, replace a random variable by a random +# connective. once the target size has been reached, replace all +# unguarded variables by propositional atoms. Replace all remaining +# variables by either an allowed fixpoint variable or a +# propositional atom + +import random +import string +import argparse +import os + + +variables = [] +syntax = 'cool' + + +def _gensym(): + i = 0 + while True: + i = i + 1 + yield "G%d" % i + + +gensym = iter(_gensym()) + + + +class Connective: + pass + + + +class Propositional(Connective): + pass + + + +class And(Propositional): + def __init__(self): + self._left = Variable(self) + self._right = Variable(self) + + + def __str__(self): + left = str(self._left) + right = str(self._right) + if syntax == 'tatl': + return "((%s) /\ (%s))" % (left, right) + else: + return "((%s) & (%s))" % (left, right) + + + def replace(self, what, withw): + if what == self._left: + self._left = withw + else: + assert self._right == what + self._right = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._left.finalize(atoms, guarded, unguarded, fixpoint) + self._right.finalize(atoms, guarded, unguarded, fixpoint) + + + +class Or(Propositional): + def __init__(self): + self._left = Variable(self) + self._right = Variable(self) + + + def __str__(self): + left = str(self._left) + right = str(self._right) + if syntax == 'tatl': + return "((%s) \/ (%s))" % (left, right) + else: + return "((%s) | (%s))" % (left, right) + + + def replace(self, what, withw): + if what == self._left: + self._left = withw + else: + assert self._right == what + self._right = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._left.finalize(atoms, guarded, unguarded, fixpoint) + self._right.finalize(atoms, guarded, unguarded, fixpoint) + + + +class Modal(Connective): + pass + + +class Box(Modal): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + if syntax == 'ctl': + return "AX (%s)" % (subformula,) + else: + return "[] (%s)" % (subformula,) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class Diamond(Modal): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + if syntax == 'ctl': + return "EX (%s)" % (subformula,) + else: + return "<> (%s)" % (subformula,) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class Fixpoint(Connective): + pass + +class Mu(Fixpoint): + def __init__(self): + self._subformula = Variable(self) + self._var = next(gensym) + + + def __str__(self): + subformula = str(self._subformula) + if syntax == 'cool': + return "(μ %s . (%s))" % (self._var, subformula) + else: + return "(mu %s . (%s))" % (self._var, subformula) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + if fixpoint == 'nu': + guarded = [] + unguarded = [] + + self._subformula.finalize(atoms, guarded, unguarded + [self._var], 'mu') + + + +class Nu(Fixpoint): + def __init__(self): + self._subformula = Variable(self) + self._var = next(gensym) + + + def __str__(self): + subformula = str(self._subformula) + if syntax == 'cool': + return "(ν %s . (%s))" % (self._var, subformula) + else: + return "(nu %s . (%s))" % (self._var, subformula) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + if fixpoint == 'mu': + guarded = [] + unguarded = [] + + self._subformula.finalize(atoms, guarded, unguarded + [self._var], 'nu') + + + +class CTL(Connective): + pass + + + +class AG(CTL): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + return "AG (%s)" % (subformula,) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class AF(CTL): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + return "AF (%s)" % (subformula,) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class EG(CTL): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + return "EG (%s)" % (subformula,) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class EF(CTL): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + return "EF (%s)" % (subformula,) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class AU(CTL): + def __init__(self): + self._left = Variable(self) + self._right = Variable(self) + + + def __str__(self): + left = str(self._left) + right = str(self._right) + return "A((%s) U (%s))" % (left, right) + + + def replace(self, what, withw): + if what == self._left: + self._left = withw + else: + assert self._right == what + self._right = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._left.finalize(atoms, guarded, unguarded, fixpoint) + self._right.finalize(atoms, guarded, unguarded, fixpoint) + + + +class AR(CTL): + def __init__(self): + self._left = Variable(self) + self._right = Variable(self) + + + def __str__(self): + left = str(self._left) + right = str(self._right) + return "A((%s) R (%s))" % (left, right) + + + def replace(self, what, withw): + if what == self._left: + self._left = withw + else: + assert self._right == what + self._right = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._left.finalize(atoms, guarded, unguarded, fixpoint) + self._right.finalize(atoms, guarded, unguarded, fixpoint) + + + +class EU(CTL): + def __init__(self): + self._left = Variable(self) + self._right = Variable(self) + + + def __str__(self): + left = str(self._left) + right = str(self._right) + return "E((%s) U (%s))" % (left, right) + + + def replace(self, what, withw): + if what == self._left: + self._left = withw + else: + assert self._right == what + self._right = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._left.finalize(atoms, guarded, unguarded, fixpoint) + self._right.finalize(atoms, guarded, unguarded, fixpoint) + + + +class ER(CTL): + def __init__(self): + self._left = Variable(self) + self._right = Variable(self) + + + def __str__(self): + left = str(self._left) + right = str(self._right) + return "E((%s) R (%s))" % (left, right) + + + def replace(self, what, withw): + if what == self._left: + self._left = withw + else: + assert self._right == what + self._right = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._left.finalize(atoms, guarded, unguarded, fixpoint) + self._right.finalize(atoms, guarded, unguarded, fixpoint) + + + +class ATL: + def coalition(self): + if not hasattr(self, '_coalition'): + self._coalition = [] + while len(self._coalition) == 0: + self._coalition = [] + for i in range(1, 6): + if random.getrandbits(1) == 1: + self._coalition.append(str(i)) + + if syntax == 'tatl': + return ",".join(self._coalition) + else: + return " ".join(self._coalition) + + + +class Next(ATL): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + if syntax == 'tatl': + return "<<%s>>X(%s)" % (self.coalition(), subformula,) + else: + return "[{%s}](%s)" % (self.coalition(), subformula,) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class Always(ATL): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + if syntax == 'tatl': + return "<<%s>>G(%s)" % (self.coalition(), subformula,) + else: + return "(ν X . ((%s) & [{%s}]X))" % (subformula,self.coalition()) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class Eventually(ATL): + def __init__(self): + self._subformula = Variable(self) + + + def __str__(self): + subformula = str(self._subformula) + if syntax == 'tatl': + return "<<%s>>F(%s)" % (self.coalition(), subformula,) + else: + return "(μ X . ((%s) | [{%s}]X))" % (subformula, self.coalition()) + + + def replace(self, what, withw): + assert self._subformula == what + self._subformula = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._subformula.finalize(atoms, guarded + unguarded, [], fixpoint) + + + +class Until(ATL): + def __init__(self): + self._left = Variable(self) + self._right = Variable(self) + + + def __str__(self): + left = str(self._left) + right = str(self._right) + if syntax == 'tatl': + return "<<%s>>((%s) U (%s))" % (self.coalition(),left, right) + else: + return "(μ X . ((%s) | ((%s) & [{%s}]X)))" % (right,left,self.coalition()) + + + def replace(self, what, withw): + if what == self._left: + self._left = withw + else: + assert self._right == what + self._right = withw + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + self._left.finalize(atoms, guarded, unguarded, fixpoint) + self._right.finalize(atoms, guarded, unguarded, fixpoint) + + + +connectives = [] + + +class Variable: + def __init__(self, parent): + self._parent = parent + variables.append(self) + + + def __str__(self): + return "(undecided)" + + + def replace(self): + assert self._parent != None + replacement = random.choice(connectives)() + variables.remove(self) + self._parent.replace(self, replacement) + + + def finalize(self, atoms, guarded, unguarded, fixpoint): + choice = random.choice(guarded + atoms) + if choice in atoms: + choice = random.choice([choice, "~%s" % choice]) + + variables.remove(self) + self._parent.replace(self, choice) + + + +def main(args): + global connectives + if args.logic == 'afmu': + connectives = [And, And, Or, Or, Box, Diamond, Mu, Nu] + os.makedirs(os.path.join(args.destdir, 'cool')) + os.makedirs(os.path.join(args.destdir, 'mlsolver')) + + elif args.logic == 'CTL': + connectives = [And, And, Or, Or, Box, Diamond, AF, AG, EF, EG, AU, EU] + os.makedirs(os.path.join(args.destdir, 'ctl')) + + elif args.logic == 'ATL': + connectives = [And, And, Or, Or, Next, Always, Eventually, Until] + os.makedirs(os.path.join(args.destdir, 'cool')) + os.makedirs(os.path.join(args.destdir, 'tatl')) + + for i in range(0, args.count): + global variables + global syntax + variables = [] + formula = random.choice(connectives)() + + for _ in range(0, args.constructors): + random.choice(variables).replace() + + formula.finalize(list(string.ascii_lowercase[:args.atoms]), [], [], 'none') + + if args.logic == 'afmu': + with open(os.path.join(args.destdir, 'cool', 'random.%04d.cool' % i), 'w') as f: + syntax = 'cool' + f.write(str(formula)) + + with open(os.path.join(args.destdir, 'mlsolver', 'random.%04d.mlsolver' % i), 'w') as f: + syntax = 'mlsolver' + f.write(str(formula)) + + elif args.logic == 'CTL': + with open(os.path.join(args.destdir, 'ctl', 'random.%04d.ctl' % i), 'w') as f: + syntax = 'ctl' + f.write(str(formula)) + + elif args.logic == 'ATL': + with open(os.path.join(args.destdir, 'cool', 'random.%04d.cool' % i), 'w') as f: + syntax = 'cool' + f.write(str(formula)) + + with open(os.path.join(args.destdir, 'tatl', 'random.%04d.tatl' % i), 'w') as f: + syntax = 'tatl' + f.write(str(formula)) + + print(args.destdir) + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Generator for random μ-Calculus-Formulas") + parser.add_argument('--atoms', type=int, required=True, + help="Number of propositional arguments to use") + parser.add_argument('--constructors', type=int, required=True, + help="Number of connectives to build") + parser.add_argument('--count', type=int, required=True, + help="Number of formulas to generate") + parser.add_argument('--destdir', type=str, required=True, + help="Directory to place created formulas in") + parser.add_argument('--logic', choices=['CTL', 'ATL', 'afmu'], required=True) + + args = parser.parse_args() + + main(args) diff --git a/src/.dir-locals.el b/src/.dir-locals.el new file mode 100644 index 0000000000000000000000000000000000000000..aeb20dbe97f42350ecc56c745477924220bb7c70 --- /dev/null +++ b/src/.dir-locals.el @@ -0,0 +1,2 @@ +((nil + (indent-tabs-mode . nil))) diff --git a/src/coalg/coalg.ml b/src/coalg/coalg.ml index c270e63ab61f9072306f6e8f2f12b89be823d375..30f4ec3a0d94466609ec0b2834704f752422fae0 100644 --- a/src/coalg/coalg.ml +++ b/src/coalg/coalg.ml @@ -46,9 +46,10 @@ let _ = let printUsage () = print_endline "Usage: \"alc <task> <functor> [<flags>]\" where"; - print_endline " <task> in { sat print nnf prov (is »not.(sat ¬f)«) }"; + print_endline " <task> in { sat print verify nnf prov (is »not.(sat ¬f)«) }"; print_endline " <functor> in { MultiModalK (or equivalently K)"; print_endline " MultiModalKD (or equivalently KD)"; + print_endline " Monotone"; print_endline " CoalitionLogic (or equivalently CL)"; print_endline " Const id1 ... idn (or equivalently Constant id1 ... idn)"; print_endline " Id (or equivalently Identity)"; @@ -167,6 +168,28 @@ let choiceNNF () = done with End_of_file -> () +let choiceGraph () = + choiceSat (); + print_endline "digraph reasonerstate {"; + CM.graphIterCores (fun core -> print_endline (CM.coreToDot core)); + CM.graphIterStates (fun state -> print_endline (CM.stateToDot state)); + print_endline "}" + +let choiceVerify () = + try + while true do + let input = read_line () in + if not (GenAndComp.isEmptyString input) then + let f = CoAlgFormula.importFormula input in + let str = CoAlgFormula.exportFormula f in + incr counter; + print_string ("\nFormula " ^ (string_of_int !counter) ^ ": " ^ str ^ "\n"); + flush stdout; + CoAlgFormula.verifyFormula f; + else () + done + with End_of_file -> () + let rec parseFlags arr offs : unit = let offs = ref (offs) in let getParam () = @@ -198,6 +221,6 @@ let _ = | "prov" -> choiceProvable () | "print" -> choicePrint () | "nnf" -> choiceNNF () + | "verify" -> choiceVerify () + | "graph" -> choiceGraph () | _ -> printUsage () - - diff --git a/src/debugger/debugger.ml b/src/debugger/debugger.ml index e685a5989f0cdaaffb082dba4e9ae259c6f5794e..8e631d43dd6c5776f81789c20dd3a1c12cae764f 100644 --- a/src/debugger/debugger.ml +++ b/src/debugger/debugger.ml @@ -69,6 +69,12 @@ let listCores args = let listStates args = CM.graphIterStates (fun state -> print_endline (CM.stateToString state)) +let exportGraph args = + print_endline "digraph reasonerstate {"; + CM.graphIterCores (fun core -> print_endline (CM.coreToDot core)); + CM.graphIterStates (fun state -> print_endline (CM.stateToDot state)); + print_endline "}" + let showNode = function | (n::_) -> let n = int_of_string n in @@ -101,11 +107,10 @@ let _ = Repl.bind "status" (fun _ -> printStatus ()) "Prints reasoning status" ""; Repl.bind "lscores" listCores "Lists all cores" ""; Repl.bind "lsstates" listStates "Lists all states" ""; + Repl.bind "graphviz" exportGraph "Graphviz source of reasoner state" ""; Repl.bind "node" showNode "shows details of a node" "usage: node n"; Repl.exitBinding ]; } in Repl.start session - - diff --git a/src/lib/CoAlgFormula.ml b/src/lib/CoAlgFormula.ml index 371895edc5dcd334811544fdd3117a0cd9a5b8c0..dcc1856aff5bb0cf56a3d25744fec5ba666f0846 100644 --- a/src/lib/CoAlgFormula.ml +++ b/src/lib/CoAlgFormula.ml @@ -12,7 +12,7 @@ module Str = String (** A general exception for all kinds of errors that can happen in the tableau procedure. - More specific information is given in the argument. + More specific information is given in the argument. *) exception CoAlgException of string @@ -48,7 +48,7 @@ type formula = | MORETHAN of int * string * formula (* diamond of GML *) | MAXEXCEPT of int * string * formula (* box of GML *) | ATLEASTPROB of rational * formula (* = {>= 0.5} C ---> C occurs with *) - (* probability of at least 50% *) + (* probability of at least 50% *) | LESSPROBFAIL of rational * formula (* = [1/2] C = {< 1/2} ¬ C ---> C fails with *) (* probability of less than 50% *) | CONST of string (* constant functor with value string *) @@ -58,6 +58,19 @@ type formula = | NORMN of formula * formula (* \neg NORM (\neg A, \neg B) *) | CHC of formula * formula (* Choice is self-dual *) | FUS of bool * formula + | MU of string * formula + | NU of string * formula + | VAR of string + | AF of formula + | EF of formula + | AG of formula + | EG of formula + | AU of formula * formula + | EU of formula * formula + | AR of formula * formula + | ER of formula * formula + | AB of formula * formula + | EB of formula * formula exception ConversionException of formula @@ -80,14 +93,14 @@ let isNominal s = String.contains s '\'' *) let rec sizeFormula f = match f with - | TRUE - | FALSE + | TRUE + | FALSE | AP _ -> 1 | NOT f1 | AT (_, f1) -> succ (sizeFormula f1) - | OR (f1, f2) + | OR (f1, f2) | AND (f1, f2) - | EQU (f1, f2) + | EQU (f1, f2) | IMP (f1, f2) -> succ (sizeFormula f1 + sizeFormula f2) | EX (_, f1) | AX (_, f1) @@ -106,6 +119,15 @@ let rec sizeFormula f = | CONSTN _ -> 1 | CHC (f1, f2) -> succ (sizeFormula f1 + sizeFormula f2) | FUS (_, f1) -> succ (sizeFormula f1) + | MU (_, f1) + | NU (_, f1) -> succ (succ (sizeFormula f1)) + | VAR _ -> 1 + | AF _ | EF _ + | AG _ | EG _ + | AU _ | EU _ + | AR _ | ER _ + | AB _ | EB _ -> + raise (CoAlgException ("sizeFormula: CTL should have been removed at this point")) (** Determines the size of a sorted formula. @param f A sorted formula. @@ -120,7 +142,7 @@ let rec iter func formula = func formula; let proc = iter func in (* proc = "process" *) match formula with - | TRUE | FALSE | AP _ -> () + | TRUE | FALSE | AP _ | VAR _ -> () | CONST _ | CONSTN _ -> () | NOT a | AT (_,a) @@ -135,38 +157,56 @@ let rec iter func formula = | NORM(a, b) | NORMN(a, b) -> (proc a; proc b) | CHC (a,b) -> (proc a ; proc b) | FUS (_,a) -> proc a + | MU (_, f) | NU (_, f) -> proc f + | AF f | EF f | AG f | EG f -> proc f + | AU (f1, f2) | EU (f1, f2) + | AR (f1, f2) | ER (f1, f2) + | AB (f1, f2) | EB (f1, f2) -> (proc f1; proc f2) let rec convert_post func formula = (* run over all subformulas in post order *) let c = convert_post func in (* some shorthand *) (* replace parts of the formula *) let formula = (match formula with - (* 0-ary constructors *) - | TRUE | FALSE | AP _ -> formula - | CONST _ - | CONSTN _ -> formula - (* unary *) - | NOT a -> NOT (c a) - | AT (s,a) -> AT (s,c a) - (* binary *) - | OR (a,b) -> OR (c a, c b) - | AND (a,b) -> AND (c a, c b) - | EQU (a,b) -> EQU (c a, c b) - | IMP (a,b) -> IMP (c a, c b) - | EX (s,a) -> EX (s,c a) - | AX (s,a) -> AX (s,c a) - | ENFORCES (s,a) -> ENFORCES (s,c a) - | ALLOWS (s,a) -> ALLOWS (s,c a) - | MIN (n,s,a) -> MIN (n,s,c a) - | MAX (n,s,a) -> MAX (n,s,c a) - | ATLEASTPROB (p,a) -> ATLEASTPROB (p, c a) - | LESSPROBFAIL (p,a) -> LESSPROBFAIL (p, c a) - | MORETHAN (n,s,a) -> MORETHAN (n,s,c a) - | MAXEXCEPT (n,s,a) -> MAXEXCEPT (n,s,c a) - | ID(a) -> ID (c a) - | NORM(a, b) -> NORM(c a, c b) - | NORMN(a, b) -> NORMN(c a, c b) - | CHC (a,b) -> CHC (c a, c b) - | FUS (s,a) -> FUS (s, c a)) in + (* 0-ary constructors *) + | TRUE | FALSE | AP _ | VAR _ -> formula + | CONST _ + | CONSTN _ -> formula + (* unary *) + | NOT a -> NOT (c a) + | AT (s,a) -> AT (s,c a) + (* binary *) + | OR (a,b) -> OR (c a, c b) + | AND (a,b) -> AND (c a, c b) + | EQU (a,b) -> EQU (c a, c b) + | IMP (a,b) -> IMP (c a, c b) + | EX (s,a) -> EX (s,c a) + | AX (s,a) -> AX (s,c a) + | ENFORCES (s,a) -> ENFORCES (s,c a) + | ALLOWS (s,a) -> ALLOWS (s,c a) + | MIN (n,s,a) -> MIN (n,s,c a) + | MAX (n,s,a) -> MAX (n,s,c a) + | ATLEASTPROB (p,a) -> ATLEASTPROB (p, c a) + | LESSPROBFAIL (p,a) -> LESSPROBFAIL (p, c a) + | MORETHAN (n,s,a) -> MORETHAN (n,s,c a) + | MAXEXCEPT (n,s,a) -> MAXEXCEPT (n,s,c a) + | ID(a) -> ID (c a) + | NORM(a, b) -> NORM(c a, c b) + | NORMN(a, b) -> NORMN(c a, c b) + | CHC (a,b) -> CHC (c a, c b) + | FUS (s,a) -> FUS (s, c a) + | MU (n, f1) -> MU (n, c f1) + | NU (n, f1) -> NU (n, c f1) + | AF f1 -> AF (c f1) + | EF f1 -> EF (c f1) + | AG f1 -> AG (c f1) + | EG f1 -> EG (c f1) + | AU (f1, f2) -> AU (c f1, c f2) + | EU (f1, f2) -> EU (c f1, c f2) + | AR (f1, f2) -> AR (c f1, c f2) + | ER (f1, f2) -> ER (c f1, c f2) + | AB (f1, f2) -> AB (c f1, c f2) + | EB (f1, f2) -> EB (c f1, c f2)) + in func formula let convertToK formula = (* tries to convert a formula to a pure K formula *) @@ -200,6 +240,36 @@ let convertToGML formula = (* tries to convert a formula to a pure GML formula * in convert_post helper formula +let gensym = Stream.from (fun i -> Some (Printf.sprintf "#gensym%x#" i)) + +let convertToMu formula = + let name = Stream.next gensym in + let helper formula = + match formula with + | AF f1 -> + MU (name, (OR (f1, (AX ("", (VAR name)))))) + | EF f1 -> + MU (name, (OR (f1, (EX ("", (VAR name)))))) + | AG f1 -> + NU (name, (AND (f1, (AX ("", (VAR name)))))) + | EG f1 -> + NU (name, (AND (f1, (EX ("", (VAR name)))))) + | AU (f1, f2) -> + MU (name, (OR (f2, (AND (f1, (AX ("", (VAR name)))))))) + | EU (f1, f2) -> + MU (name, (OR (f2, (AND (f1, (EX ("", (VAR name)))))))) + | AR (f1, f2) -> + NU (name, (AND (f2, (OR (f1, (AX ("", (VAR name)))))))) + | ER (f1, f2) -> + NU (name, (AND (f2, (OR (f1, (EX ("", (VAR name)))))))) + | AB (f1, f2) -> + NOT (MU (name, (OR (f2, (AND ((NOT f1), (EX ("", (VAR name))))))))) + | EB (f1, f2) -> + NOT (MU (name, (OR (f2, (AND ((NOT f1), (AX ("", (VAR name))))))))) + | _ -> formula + in + convert_post helper formula + (** Appends a string representation of a formula to a string buffer. Parentheses are ommited where possible where the preference rules are defined as usual. @@ -214,7 +284,7 @@ let rec exportFormula_buffer sb f = let prio n lf = let prionr = function | EQU _ -> 0 - | IMP _ -> 1 + | IMP _ -> 1 | OR _ -> 2 | AND _ -> 3 | _ -> 4 @@ -348,6 +418,67 @@ let rec exportFormula_buffer sb f = | FUS (first, f1) -> Buffer.add_string sb (if first then "[pi1]" else "[pi2]"); prio 4 f1 + | MU (s, f1) -> + Buffer.add_string sb "μ"; + Buffer.add_string sb s; + Buffer.add_string sb "."; + prio 4 f1 + | NU (s, f1) -> + Buffer.add_string sb "ν"; + Buffer.add_string sb s; + Buffer.add_string sb "."; + prio 4 f1 + | VAR s -> + Buffer.add_string sb s + | AF f1 -> + Buffer.add_string sb "AF "; + prio 4 f1 + | EF f1 -> + Buffer.add_string sb "EF "; + prio 4 f1 + | AG f1 -> + Buffer.add_string sb "AG "; + prio 4 f1 + | EG f1 -> + Buffer.add_string sb "EG "; + prio 4 f1 + | AU (f1, f2) -> + Buffer.add_string sb "A ("; + prio 4 f1; + Buffer.add_string sb " U "; + prio 4 f2; + Buffer.add_string sb ")" + | EU (f1, f2) -> + Buffer.add_string sb "E ("; + prio 4 f1; + Buffer.add_string sb " U "; + prio 4 f2; + Buffer.add_string sb ")" + | AR (f1, f2) -> + Buffer.add_string sb "A ("; + prio 4 f1; + Buffer.add_string sb " R "; + prio 4 f2; + Buffer.add_string sb ")" + | ER (f1, f2) -> + Buffer.add_string sb "E ("; + prio 4 f1; + Buffer.add_string sb " R "; + prio 4 f2; + Buffer.add_string sb ")" + | AB (f1, f2) -> + Buffer.add_string sb "A ("; + prio 4 f1; + Buffer.add_string sb " B "; + prio 4 f2; + Buffer.add_string sb ")" + | EB (f1, f2) -> + Buffer.add_string sb "E ("; + prio 4 f1; + Buffer.add_string sb " B "; + prio 4 f2; + Buffer.add_string sb ")" + (** Converts a formula into a string representation. Parentheses are ommited where possible @@ -367,7 +498,7 @@ let rec exportTatlFormula_buffer sb f = let prio n lf = let prionr = function | EQU _ -> 0 - | IMP _ -> 1 + | IMP _ -> 1 | OR _ -> 2 | AND _ -> 3 | _ -> 4 @@ -433,7 +564,20 @@ let rec exportTatlFormula_buffer sb f = | ID _ | NORM _ | NORMN _ - | FUS _ -> raise (CoAlgException ("export to tatl: Not connectives of CL")) + | FUS _ + | MU _ + | NU _ + | VAR _ + | AF _ + | EF _ + | AG _ + | EG _ + | AU _ + | EU _ + | AR _ + | ER _ + | AB _ + | EB _ -> raise (CoAlgException ("export to tatl: Not connectives of CL")) let exportTatlFormula f = let sb = Buffer.create 128 in @@ -505,26 +649,166 @@ let exportQueryParsable tbox (_,f) = (* NB: True and False are the propositional constants. Lower case true/false are regardes as atomic propositions and we emit a warning *) -let lexer = A.make_lexer +let lexer = A.make_lexer [":";";";"|-";"(";")";"=>";"<=>";"|";"&";"~";"@";"True";"False";"true";"false";"<";">";"[";"]";"{<=";"{>=";"}";"+";"[pi1]";"[pi2]" - ;"[{";"}]";"<{";"}>";",";"/";"{<";"=";"=o";"O" - ] + ;"[{";"}]";"<{";"}>";",";"/";"{<";"=";"=o";"O" + ;"μ";"ν";"." + ;"AX";"EX";"AF";"EF";"AG";"EG";"A";"E";"U";"R";"B" + ] let mk_exn s = CoAlgException s +(** Process from inside out. cons all variables seen, remove them when + binding fixpoint is found. Fixpoint type may only change if last + (inner) fixpoint didn't include any free variables. + *) +let rec verifyMuAltFree formula = + let proc = verifyMuAltFree in + match formula with + | TRUE | FALSE | AP _ -> ("none", []) + | CONST _ + | CONSTN _ -> ("none", []) + | AT (_,a) | NOT a + | EX (_,a) | AX (_,a) -> proc a + | OR (a,b) | AND (a,b) + | EQU (a,b) | IMP (a,b) -> + let (atype, afree) = proc a + and (btype, bfree) = proc b in + if (compare atype "μ" == 0 && compare btype "ν" == 0) || + (compare atype "ν" == 0 && compare btype "μ" == 0) then + raise (CoAlgException ("formula not alternation-free")); + if compare atype "none" == 0 then + (btype, List.flatten [afree; bfree]) + else + (atype, List.flatten [afree; bfree]) + | ENFORCES (_,a) | ALLOWS (_,a) + | MIN (_,_,a) | MAX (_,_,a) + | ATLEASTPROB (_, a) | LESSPROBFAIL (_, a) + | MORETHAN (_,_,a) | MAXEXCEPT (_,_,a) -> proc a + | ID(a) -> proc a + | NORM(a, b) | NORMN(a, b) + | CHC (a,b) -> + let (atype, afree) = proc a + and (btype, bfree) = proc b in + if (compare atype "μ" == 0 && compare btype "ν" == 0) || + (compare atype "ν" == 0 && compare btype "μ" == 0) then + raise (CoAlgException ("formula not alternation-free")); + if compare atype "none" == 0 then + (btype, List.flatten [afree; bfree]) + else + (atype, List.flatten [afree; bfree]) + | FUS (_,a) -> proc a + | MU (s, f) -> + let (fptype, free) = proc f in + (if (compare fptype "ν" == 0) then + raise (CoAlgException ("formula not alternation-free"))); + let predicate x = compare x s != 0 in + let newfree = List.filter predicate free in + if newfree = [] then + ("none", []) + else + ("μ", newfree) + | NU (s, f) -> + let (fptype, free) = proc f in + (if (compare fptype "μ" == 0) then + raise (CoAlgException ("formula not alternation-free"))); + let predicate x = compare x s != 0 in + let newfree = List.filter predicate free in + if newfree = [] then + ("none", []) + else + ("ν", newfree) + | VAR s -> ("none", [s]) + | AF _ | EF _ | AG _ | EG _ | AU _ | EU _ | AR _ | ER _ | AB _ | EB _ -> + raise (CoAlgException ("verifyMuAltFree: CTL should have been removed at this point")) + + +(** Process from outside in. For every variable bound keep the tuple + (name, negations). For every negation crossed map a +1 over snd on + that list. For every variable met check that the matching + negations is even. + *) +let rec verifyMuMonotone negations formula = + let proc = verifyMuMonotone negations in + match formula with + | TRUE | FALSE | AP _ -> () + | CONST _ + | CONSTN _ -> () + | AT (_,a) + | EX (_,a) | AX (_,a) -> proc a + | OR (a,b) | AND (a,b) + | EQU (a,b) | IMP (a,b) -> (proc a ; proc b) + | ENFORCES (_,a) | ALLOWS (_,a) + | MIN (_,_,a) | MAX (_,_,a) + | ATLEASTPROB (_, a) | LESSPROBFAIL (_, a) + | MORETHAN (_,_,a) | MAXEXCEPT (_,_,a) -> proc a + | ID(a) -> proc a + | NORM(a, b) | NORMN(a, b) -> (proc a; proc b) + | CHC (a,b) -> (proc a ; proc b) + | FUS (_,a) -> proc a + | MU (s, f) + | NU (s, f) -> + let newNeg = (s, 0) :: negations in + verifyMuMonotone newNeg f + | VAR s -> + let finder (x, _) = compare x s == 0 in + let (_, neg) = List.find finder negations in + if ((neg land 1) != 0) then raise (CoAlgException ("formula not monotone")) + | NOT a -> + let increment (s, n) = (s, n+1) in + let newNeg = List.map increment negations in + verifyMuMonotone newNeg a + | AF _ | EF _ | AG _ | EG _ | AU _ | EU _ | AR _ | ER _ | AB _ | EB _ -> + raise (CoAlgException ("verifyMuMonotone: CTL should have been removed at this point")) + +let rec verifyMuGuarded unguarded formula = + let proc = verifyMuGuarded unguarded in + match formula with + | TRUE | FALSE | AP _ -> () + | CONST _ + | CONSTN _ -> () + | AT (_,a) | NOT a -> proc a + | EX (_,a) | AX (_,a) -> verifyMuGuarded [] a + | OR (a,b) | AND (a,b) + | EQU (a,b) | IMP (a,b) -> (proc a ; proc b) + | ENFORCES (_,a) | ALLOWS (_,a) + | MIN (_,_,a) | MAX (_,_,a) + | ATLEASTPROB (_, a) | LESSPROBFAIL (_, a) + | MORETHAN (_,_,a) | MAXEXCEPT (_,_,a) -> verifyMuGuarded [] a + | ID(a) -> verifyMuGuarded [] a + | NORM(a, b) | NORMN(a, b) -> (proc a; proc b) + | CHC (a,b) -> (proc a ; proc b) + | FUS (_,a) -> proc a + | MU (s, f) + | NU (s, f) -> + let newUnguard = s :: unguarded in + verifyMuGuarded newUnguard f + | VAR s -> + let finder x = compare x s == 0 in + if List.exists finder unguarded then + raise (CoAlgException ("formula not guarded")) + | AF _ | EF _ | AG _ | EG _ | AU _ | EU _ | AR _ | ER _ | AB _ | EB _ -> + raise (CoAlgException ("verifyMuGuarded: CTL should have been removed at this point")) + +let verifyFormula formula = + verifyMuAltFree formula; + verifyMuMonotone [] formula; + verifyMuGuarded [] formula + (** These functions parse a token stream to obtain a formula. It is a standard recursive descent procedure. @param ts A token stream. @return The resulting (sub-)formula. @raise CoAlgException if ts does not represent a formula. *) -let rec parse_formula ts = - let f1 = parse_imp ts in +let rec parse_formula (symtab: 'a list) ts = + let formula = (parse_imp symtab ts) in + let f1 = convertToMu formula in match Stream.peek ts with | None -> f1 | Some (A.Kwd "<=>") -> Stream.junk ts; - let f2 = parse_formula ts in + let f2 = parse_formula symtab ts in EQU (f1, f2) | _ -> f1 @@ -534,13 +818,13 @@ let rec parse_formula ts = @return The resulting (sub-)formula. @raise CoAlgException if ts does not represent a formula. *) -and parse_imp ts = - let f1 = parse_or ts in +and parse_imp symtab ts= + let f1 = parse_or symtab ts in match Stream.peek ts with | None -> f1 | Some (A.Kwd "=>") -> Stream.junk ts; - let f2 = parse_imp ts in + let f2 = parse_imp symtab ts in IMP (f1, f2) | _ -> f1 @@ -550,13 +834,13 @@ and parse_imp ts = @return The resulting (sub-)formula. @raise CoAlgException if ts does not represent a formula. *) -and parse_or ts = - let f1 = parse_and ts in +and parse_or symtab ts = + let f1 = parse_and symtab ts in match Stream.peek ts with | None -> f1 | Some (A.Kwd "|") -> Stream.junk ts; - let f2 = parse_or ts in + let f2 = parse_or symtab ts in OR (f1, f2) | _ -> f1 @@ -566,13 +850,13 @@ and parse_or ts = @return The resulting (sub-)formula. @raise CoAlgException if ts does not represent a formula. *) -and parse_and ts = - let f1 = parse_cimp ts in +and parse_and symtab ts = + let f1 = parse_cimp symtab ts in match Stream.peek ts with | None -> f1 | Some (A.Kwd "&") -> Stream.junk ts; - let f2 = parse_and ts in + let f2 = parse_and symtab ts in AND (f1, f2) | _ -> f1 @@ -582,13 +866,13 @@ and parse_and ts = @return The resulting (sub-)formula. @raise CoAlgException if ts does not represent a formula. *) -and parse_cimp ts = - let f1 = parse_rest ts in +and parse_cimp symtab ts = + let f1 = parse_rest symtab ts in match Stream.peek ts with | None -> f1 | Some (A.Kwd "=o") -> Stream.junk ts; - let f2 = parse_cimp ts in + let f2 = parse_cimp symtab ts in NORM (f1, f2) | _ -> f1 @@ -598,7 +882,7 @@ and parse_cimp ts = @return The resulting (sub-)formula. @raise CoAlgException if ts does not represent a formula. *) -and parse_rest ts = +and parse_rest symtab ts = let boxinternals noNo es = let n = if noNo then 0 @@ -652,9 +936,14 @@ and parse_rest ts = AP "false" | A.Kwd "True" -> TRUE | A.Kwd "False" -> FALSE - | A.Ident s -> AP s + | A.Ident s -> + (try + let finder (x, _) = compare x s == 0 in + let (_, symbol) = List.find finder symtab in + VAR symbol + with Not_found -> AP s) | A.Kwd "~" -> - let f = parse_rest ts in + let f = parse_rest symtab ts in NOT f | A.Kwd "@" -> let s = @@ -662,39 +951,39 @@ and parse_rest ts = | A.Ident s when isNominal s -> s | t -> A.printError mk_exn ~t ~ts ("nominal expected: ") in - let f = parse_rest ts in + let f = parse_rest symtab ts in AT (s, f) - | A.Kwd "<" -> + | A.Kwd "<" -> let (_, _, s) = boxinternals true ">" in - let f1 = parse_rest ts in - EX (s, f1) - | A.Kwd "[" -> + let f1 = parse_rest symtab ts in + EX (s, f1) + | A.Kwd "[" -> let (_, _, s) = boxinternals true "]" in - let f1 = parse_rest ts in + let f1 = parse_rest symtab ts in AX (s, f1) - | A.Kwd "[{" -> + | A.Kwd "[{" -> let ls = agentlist "}]" in - let f1 = parse_rest ts in + let f1 = parse_rest symtab ts in ENFORCES (ls, f1) - | A.Kwd "<{" -> + | A.Kwd "<{" -> let ls = agentlist "}>" in - let f1 = parse_rest ts in + let f1 = parse_rest symtab ts in ALLOWS (ls, f1) - | A.Kwd "{>=" -> + | A.Kwd "{>=" -> let (n, denom, s) = boxinternals false "}" in - let f1 = parse_rest ts in + let f1 = parse_rest symtab ts in if (denom <> 0) then ATLEASTPROB (rational_of_int n denom, f1) else MIN (n, s, f1) - | A.Kwd "{<=" -> + | A.Kwd "{<=" -> let (n, denom, s) = boxinternals false "}" in - let f1 = parse_rest ts in + let f1 = parse_rest symtab ts in if (denom <> 0) then A.printError mk_exn ~ts "Can not express {<= probability}" else MAX (n, s, f1) - | A.Kwd "{<" -> + | A.Kwd "{<" -> let (n, denom, s) = boxinternals false "}" in - let f1 = parse_rest ts in + let f1 = parse_rest symtab ts in if (denom <> 0) then LESSPROBFAIL (rational_of_int n denom, NOT f1) else A.printError mk_exn ~ts "The \"Less than\" < is not implemented yet" @@ -706,11 +995,11 @@ and parse_rest ts = | _ -> A.printError mk_exn ~ts "constant = expects an identifier afterwards" end | A.Kwd "(" -> begin - let f = parse_formula ts in + let f = parse_formula symtab ts in match Stream.next ts with | A.Kwd ")" -> f | A.Kwd "+" -> begin - let f2 = parse_formula ts in + let f2 = parse_formula symtab ts in match Stream.next ts with | A.Kwd ")" -> CHC (f, f2) | t -> A.printError mk_exn ~t ~ts "\")\" expected: " @@ -718,25 +1007,91 @@ and parse_rest ts = | t -> A.printError mk_exn ~t ~ts "\")\" or \"+\" expected: " end | A.Kwd "O" -> - let f = parse_rest ts in + let f = parse_rest symtab ts in ID f | A.Kwd "[pi1]" -> - let f = parse_rest ts in + let f = parse_rest symtab ts in FUS (true, f) | A.Kwd "[pi2]" -> - let f = parse_rest ts in + let f = parse_rest symtab ts in FUS (false, f) - | t -> A.printError mk_exn ~t ~ts + | A.Kwd "μ" -> + let (_, _, s) = boxinternals true "." in + let symbol = Stream.next gensym in + let newtab = (s, symbol) :: symtab in + let f1 = parse_rest newtab ts in + MU (symbol, f1) + | A.Kwd "ν" -> + let (_, _, s) = boxinternals true "." in + let symbol = Stream.next gensym in + let newtab = (s, symbol) :: symtab in + let f1 = parse_rest newtab ts in + NU (symbol, f1) + | A.Kwd "AF" -> + let f = parse_rest symtab ts in + AF f + | A.Kwd "EF" -> + let f = parse_rest symtab ts in + EF f + | A.Kwd "AG" -> + let f = parse_rest symtab ts in + AG f + | A.Kwd "EG" -> + let f = parse_rest symtab ts in + EG f + | A.Kwd "A" -> + assert (Stream.next ts = A.Kwd "("); + let f1 = parse_formula symtab ts in begin + match Stream.next ts with + | A.Kwd "U" -> + let f2 = parse_formula symtab ts in + assert (Stream.next ts = A.Kwd ")"); + AU (f1, f2) + | A.Kwd "R" -> + let f2 = parse_formula symtab ts in + assert (Stream.next ts = A.Kwd ")"); + AR (f1, f2) + | A.Kwd "B" -> + let f2 = parse_formula symtab ts in + assert (Stream.next ts = A.Kwd ")"); + AB (f1, f2) + | t -> A.printError mk_exn ~t ~ts "one of \"U\" \"R\" \"B\" expected: " + end + | A.Kwd "E" -> + assert (Stream.next ts = A.Kwd "("); + let f1 = parse_formula symtab ts in begin + match Stream.next ts with + | A.Kwd "U" -> + let f2 = parse_formula symtab ts in + assert (Stream.next ts = A.Kwd ")"); + EU (f1, f2) + | A.Kwd "R" -> + let f2 = parse_formula symtab ts in + assert (Stream.next ts = A.Kwd ")"); + ER (f1, f2) + | A.Kwd "B" -> + let f2 = parse_formula symtab ts in + assert (Stream.next ts = A.Kwd ")"); + EB (f1, f2) + | t -> A.printError mk_exn ~t ~ts "one of \"U\" \"R\" \"B\" expected: " + end + | A.Kwd "AX" -> + let f1 = parse_rest symtab ts in + AX ("", f1) + | A.Kwd "EX" -> + let f1 = parse_rest symtab ts in + EX ("", f1) + | t -> A.printError mk_exn ~t ~ts "\"<\", \"[\", \"{>=\", \"{<=\", \"@\", \"~\", \"(\", \"True\", \"False\", \"=\", \"=o\", \"O\" or <ident> expected: " - + (** Parses a sorted formula. @param ts A token stream. @return A sorted formula. @raise CoAlgException If ts does not represent a sorted formula. *) let parse_sortedFormula ts = - let nr = + let nr = match Stream.peek ts with | Some (A.Int n) -> if n >= 0 then begin @@ -749,9 +1104,9 @@ let parse_sortedFormula ts = n end else A.printError mk_exn ~ts ("<non-negative number> expected: ") - | _ -> 0 + | _ -> 0 in - let f = parse_formula ts in + let f = parse_formula [] ts in (nr, f) (** Parses a list of sorted formulae separated by ";". @@ -791,7 +1146,7 @@ let importWrapper fkt s = @return The resulting formula. @raise CoAlgException if s does not represent a formula. *) -let importFormula s = importWrapper parse_formula s +let importFormula s = importWrapper (parse_formula []) s (** Parses a string to obtain a sorted formula. @param s A string representing a sorted formula. @@ -821,7 +1176,7 @@ let importQuery s = Stream.junk ts; let f = parse_sortedFormula ts in (fl, f) - | _ -> + | _ -> if List.length fl = 1 then ([], List.hd fl) else A.printError mk_exn ~ts "\"|-\" expected: " in @@ -840,6 +1195,7 @@ let rec nnfNeg f = | TRUE -> FALSE | FALSE -> TRUE | AP _ -> NOT f + | VAR _ -> f | NOT f1 -> nnf f1 | AT (s, f1) -> AT (s, nnfNeg f1) | OR (f1, f2) -> AND (nnfNeg f1, nnfNeg f2) @@ -861,9 +1217,16 @@ let rec nnfNeg f = | ID (f1) -> ID (nnfNeg f1) | NORM(f1, f2) -> NORMN(nnfNeg f1, nnfNeg f2) | NORMN(f1, f2) -> NORM (nnfNeg f1, nnfNeg f2) - | CHC (f1, f2) -> CHC (nnfNeg f1, nnfNeg f2) + | CHC (f1, f2) -> CHC (nnfNeg f1, nnfNeg f2) | FUS (first, f1) -> FUS (first, nnfNeg f1) - + | MU (s, f1) -> NU(s, nnfNeg f1) + | NU (s, f1) -> MU(s, nnfNeg f1) + | AF _ | EF _ + | AG _ | EG _ + | AU _ | EU _ + | AR _ | ER _ + | AB _ | EB _ -> raise (CoAlgException ("nnfNeg: CTL should have been removed at this point")) + (** Converts a formula to negation normal form by "pushing in" the negations "~". The symbols "<=>" and "=>" are substituted by their usual definitions. @@ -878,7 +1241,8 @@ and nnf f = | AP _ | NOT (AP _) | CONST _ - | CONSTN _ -> f + | CONSTN _ + | VAR _ -> f | NOT f1 -> nnfNeg f1 | AT (s, f1) -> let ft1 = nnf f1 in @@ -893,13 +1257,13 @@ and nnf f = if ft1 == f1 && ft2 == f2 then f else AND (ft1, ft2) | EQU (f1, f2) -> AND (OR (nnfNeg f1, nnf f2), OR (nnfNeg f2, nnf f1)) | IMP (f1, f2) -> OR (nnfNeg f1, nnf f2) - | EX (s, f1) -> + | EX (s, f1) -> let ft = nnf f1 in if ft == f1 then f else EX (s, ft) | AX (s, f1) -> let ft = nnf f1 in if ft == f1 then f else AX (s, ft) - | ENFORCES (s, f1) -> + | ENFORCES (s, f1) -> let ft = nnf f1 in if ft == f1 then f else ENFORCES (s, ft) | ALLOWS (s, f1) -> @@ -943,7 +1307,18 @@ and nnf f = | FUS (first, f1) -> let ft = nnf f1 in if ft == f1 then f else FUS (first, ft) - + | MU (s, f1) -> + let ft = nnf f1 in + if ft == f1 then f else MU (s, ft) + | NU (s, f1) -> + let ft = nnf f1 in + if ft == f1 then f else NU (s, ft) + | AF _ | EF _ + | AG _ | EG _ + | AU _ | EU _ + | AR _ | ER _ + | AB _ | EB _ -> + raise (CoAlgException ("nnf: CTL should have been removed at this point")) (** Simplifies a formula. @param f A formula which must be in negation normal form. @@ -955,7 +1330,9 @@ let rec simplify f = | TRUE | FALSE | AP _ - | NOT (AP _) -> f + | NOT (AP _) + | VAR _ + | NOT (VAR _) -> f | AT (s, f1) -> let ft = simplify f1 in begin @@ -977,7 +1354,7 @@ let rec simplify f = | _, TRUE -> TRUE | _, FALSE -> ft1 | _, _ -> - if (f1 == ft1) && (f2 == ft2) then f + if (f1 == ft1) && (f2 == ft2) then f else OR (ft1, ft2) end | AND (f1, f2) -> @@ -990,7 +1367,7 @@ let rec simplify f = | _, TRUE -> ft1 | _, FALSE -> FALSE | _, _ -> - if (f1 == ft1) && (f2 == ft2) then f + if (f1 == ft1) && (f2 == ft2) then f else AND (ft1, ft2) end | NOT _ @@ -1082,7 +1459,7 @@ let rec simplify f = match ft2 with | TRUE -> TRUE | _ -> - if (f1 == ft1) && (f2 == ft2) then f + if (f1 == ft1) && (f2 == ft2) then f else NORM (ft1, ft2) end | NORMN (f1, f2) -> @@ -1092,7 +1469,7 @@ let rec simplify f = match ft2 with | FALSE -> FALSE | _ -> - if (f1 == ft1) && (f2 == ft2) then f + if (f1 == ft1) && (f2 == ft2) then f else NORMN (ft1, ft2) end | CHC (f1, f2) -> @@ -1103,7 +1480,7 @@ let rec simplify f = | TRUE, TRUE -> TRUE | FALSE, FALSE -> FALSE | _, _ -> - if (f1 == ft1) && (f2 == ft2) then f + if (f1 == ft1) && (f2 == ft2) then f else CHC (ft1, ft2) end | FUS (first, f1) -> @@ -1114,7 +1491,26 @@ let rec simplify f = | TRUE -> TRUE | _ -> if ft == f1 then f else FUS (first, ft) end - + | MU (s, f1) -> + let ft = simplify f1 in + begin + match ft with + | TRUE -> TRUE + | _ -> if ft == f1 then f else MU (s, ft) + end + | NU (s, f1) -> + let ft = simplify f1 in + begin + match ft with + | TRUE -> TRUE + | _ -> if ft == f1 then f else NU (s, ft) + end + | AF _ | EF _ + | AG _ | EG _ + | AU _ | EU _ + | AR _ | ER _ + | AB _ | EB _ -> + raise (CoAlgException ("nnf: CTL should have been removed at this point")) (** Destructs an atomic proposition. @param f An atomic proposition. @@ -1405,7 +1801,7 @@ let is_fusion f = | FUS _ -> true | _ -> false - + (** The constant True. *) let const_true = TRUE @@ -1413,7 +1809,7 @@ let const_true = TRUE (** The constant False. *) let const_false = FALSE - + (** Constructs an atomic proposition. @param s The name of the atomic proposition. @return The atomic proposition with name s. @@ -1437,7 +1833,7 @@ let const_nom s = @return The negation of f. *) let const_not f = NOT f - + (** Constructs an @-formula from a name and a formula. @param s A nominal name. @param f A formula. @@ -1456,7 +1852,7 @@ let const_or f1 f2 = OR (f1, f2) @param f1 The first formula (LHS). @param f2 The second formula (LHS). @return The formula f1 & f2. - *) + *) let const_and f1 f2 = AND (f1, f2) (** Constructs an equivalence from two formulae. @@ -1532,6 +1928,9 @@ let const_fusion first f1 = FUS (first, f1) (** Hash-consed formulae, which are in negation normal form, such that structural and physical equality coincide. + + Also CTL has been replaced by the equivalent μ-Calculus + constructs *) type hcFormula = (hcFormula_node, formula) HC.hash_consed and hcFormula_node = @@ -1557,6 +1956,9 @@ and hcFormula_node = | HCNORMN of hcFormula * hcFormula | HCCHC of hcFormula * hcFormula | HCFUS of bool * hcFormula + | HCMU of string * hcFormula + | HCNU of string * hcFormula + | HCVAR of string (** Determines whether two formula nodes are structurally equal. @param f1 The first formula node. @@ -1580,7 +1982,7 @@ let equal_hcFormula_node f1 f2 = | HCALLOWS (s1, f1), HCALLOWS (s2, f2) -> compare s1 s2 = 0 && f1 == f2 | HCMORETHAN (n1, s1, f1), HCMORETHAN (n2, s2, f2) | HCMAXEXCEPT (n1, s1, f1), HCMAXEXCEPT (n2, s2, f2) -> - n1 = n2 && compare s1 s2 = 0 && f1 == f2 + n1 = n2 && compare s1 s2 = 0 && f1 == f2 | HCATLEASTPROB (p1, f1), HCATLEASTPROB (p2,f2) -> p1 = p2 && f1 == f2 | HCLESSPROBFAIL (p1, f1), HCLESSPROBFAIL (p2,f2) -> @@ -1589,6 +1991,9 @@ let equal_hcFormula_node f1 f2 = | HCNORM (f1a, f1b), HCNORMN (f2a, f2b) -> f1a == f2a && f1b == f2b | HCCHC (f1a, f1b), HCCHC (f2a, f2b) -> f1a == f2a && f1b == f2b | HCFUS (first1, f1), HCFUS (first2, f2) -> first1 = first2 && f1 == f2 + | HCMU (name1, f1), HCMU(name2, f2) -> compare name1 name2 = 0 && f1 == f2 + | HCNU (name1, f1), HCNU(name2, f2) -> compare name1 name2 = 0 && f1 == f2 + | HCVAR name1, HCVAR name2 -> compare name1 name2 = 0 (* The rest could be shortened to | _ -> false, but then the compiler would not warn if the formula type is extended and this function is not updated accordingly.*) @@ -1613,7 +2018,10 @@ let equal_hcFormula_node f1 f2 = | HCNORM _, _ | HCNORMN _, _ | HCCHC _, _ - | HCFUS _, _ -> false + | HCFUS _, _ + | HCMU _, _ + | HCNU _, _ + | HCVAR _, _ -> false (** Computes the hash value of a formula node. @param f A formula node. @@ -1625,7 +2033,8 @@ let hash_hcFormula_node f = | HCTRUE -> 0 | HCFALSE -> 1 | HCAP s - | HCNOT s -> base * Hashtbl.hash s + 1 + | HCNOT s + | HCVAR s -> base * Hashtbl.hash s + 1 | HCAT (s, f1) -> base * (base * (Hashtbl.hash s) + f1.HC.hkey) + 2 | HCOR (f1, f2) -> base * (base * f1.HC.hkey + f2.HC.hkey) + 5 | HCAND (f1, f2) -> base * (base * f1.HC.hkey + f2.HC.hkey) + 6 @@ -1644,6 +2053,8 @@ let hash_hcFormula_node f = | HCNORM (f1, f2) -> base * (base * f1.HC.hkey + f2.HC.hkey) + 18 | HCNORMN (f1, f2) -> base * (base * f1.HC.hkey + f2.HC.hkey) + 19 | HCID (f1) -> base * f1.HC.hkey + 20 + | HCMU (s, f1) -> base * (base * (Hashtbl.hash s) + f1.HC.hkey) + 21 + | HCNU (s, f1) -> base * (base * (Hashtbl.hash s) + f1.HC.hkey) + 22 (** Determines the "real" formula of a formula node. @param f A formula node. @@ -1654,6 +2065,7 @@ let toFml_hcFormula_node f = | HCTRUE -> TRUE | HCFALSE -> FALSE | HCAP s -> AP s + | HCVAR s -> VAR s | HCNOT s -> NOT (AP s) | HCAT (s, f1) -> AT (s, f1.HC.fml) | HCOR (f1, f2) -> OR (f1.HC.fml, f2.HC.fml) @@ -1673,6 +2085,8 @@ let toFml_hcFormula_node f = | HCNORMN (f1, f2) -> NORMN(f1.HC.fml, f2.HC.fml) | HCCHC (f1, f2) -> CHC (f1.HC.fml, f2.HC.fml) | HCFUS (first, f1) -> FUS (first, f1.HC.fml) + | HCMU (var, f1) -> MU (var, f1.HC.fml) + | HCNU (var, f1) -> NU (var, f1.HC.fml) (** Determines the negation (in negation normal form) of a formula node. @param f A formula node. @@ -1684,6 +2098,7 @@ let negNde_hcFormula_node f = | HCFALSE -> HCTRUE | HCAP s -> HCNOT s | HCNOT s -> HCAP s + | HCVAR s -> f | HCAT (s, f1) -> HCAT (s, f1.HC.neg) | HCOR (f1, f2) -> HCAND (f1.HC.neg, f2.HC.neg) | HCAND (f1, f2) -> HCOR (f1.HC.neg, f2.HC.neg) @@ -1702,6 +2117,8 @@ let negNde_hcFormula_node f = | HCNORMN (f1, f2) -> HCNORM(f1.HC.neg, f2.HC.neg) | HCCHC (f1, f2) -> HCCHC (f1.HC.neg, f2.HC.neg) | HCFUS (first, f1) -> HCFUS (first, f1.HC.neg) + | HCMU (name, f1) -> HCNU (name, f1.HC.neg) + | HCNU (name, f1) -> HCMU (name, f1.HC.neg) (** An instantiation of hash-consing for formulae. *) @@ -1727,6 +2144,7 @@ let rec hc_formula hcF f = | TRUE -> HcFormula.hashcons hcF HCTRUE | FALSE -> HcFormula.hashcons hcF HCFALSE | AP s -> HcFormula.hashcons hcF (HCAP s) + | VAR s -> HcFormula.hashcons hcF (HCVAR s) | NOT (AP s) -> HcFormula.hashcons hcF (HCNOT s) | AT (s, f1) -> let tf1 = hc_formula hcF f1 in @@ -1788,6 +2206,139 @@ let rec hc_formula hcF f = | FUS (first, f1) -> let tf1 = hc_formula hcF f1 in HcFormula.hashcons hcF (HCFUS (first, tf1)) + | MU (var, f1) -> + let tf1 = hc_formula hcF f1 in + HcFormula.hashcons hcF (HCMU (var, tf1)) + | NU (var, f1) -> + let tf1 = hc_formula hcF f1 in + HcFormula.hashcons hcF (HCNU (var, tf1)) + | AF _ | EF _ + | AG _ | EG _ + | AU _ | EU _ + | AR _ | ER _ + | AB _ | EB _ -> + raise (CoAlgException ("nnf: CTL should have been removed at this point")) + +(* Replace the Variable name in f with formula formula + hc_replace foo φ ψ => ψ[foo |-> φ] + *) +let rec hc_replace hcF name (formula: hcFormula) (f: hcFormula) = + let func = hc_replace hcF name formula in + let gennew = HcFormula.hashcons hcF in + match f.HC.node with + | HCTRUE + | HCFALSE + | HCAP _ + | HCNOT _ + | HCCONST _ + | HCCONSTN _ -> f + | HCVAR s -> + if compare s name == 0 + then formula + else f + | HCAT (s, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCAT(s, nf1)) + | HCOR (f1, f2) -> + let nf1 = func f1 in + let nf2 = func f2 in + if nf1 == f1 && nf2 == f2 then f else gennew (HCOR(nf1, nf2)) + | HCAND (f1, f2) -> + let nf1 = func f1 in + let nf2 = func f2 in + if nf1 == f1 && nf2 == f2 then f else gennew (HCAND(nf1, nf2)) + | HCEX (s, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCEX(s, nf1)) + | HCAX (s, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCAX(s, nf1)) + | HCENFORCES (s, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCENFORCES(s, nf1)) + | HCALLOWS (s, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCALLOWS(s, nf1)) + | HCMORETHAN (n, s, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCMORETHAN(n, s, nf1)) + | HCMAXEXCEPT (n, s, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCMAXEXCEPT(n, s, nf1)) + | HCATLEASTPROB (p, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCATLEASTPROB(p, nf1)) + | HCLESSPROBFAIL (p, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCLESSPROBFAIL(p, nf1)) + | HCID f1 -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCID(nf1)) + | HCNORM (f1, f2) -> + let nf1 = func f1 in + let nf2 = func f2 in + if nf1 == f1 && nf2 == f2 then f else gennew (HCNORM(nf1, nf2)) + | HCNORMN (f1, f2) -> + let nf1 = func f1 in + let nf2 = func f2 in + if nf1 == f1 && nf2 == f2 then f else gennew (HCNORMN(nf1, nf2)) + | HCCHC (f1, f2) -> + let nf1 = func f1 in + let nf2 = func f2 in + if nf1 == f1 && nf2 == f2 then f else gennew (HCCHC(nf1, nf2)) + | HCFUS (first, f1) -> + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCFUS(first, nf1)) + | HCMU (var, f1) -> + if compare var name != 0 then + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCMU(var, nf1)) + else + f + | HCNU (var, f1) -> + if compare var name != 0 then + let nf1 = func f1 in + if nf1 == f1 then f else gennew (HCNU(var, nf1)) + else + f + +let rec hc_freeIn variable (f: hcFormula) = + match f.HC.node with + | HCTRUE + | HCFALSE + | HCAP _ + | HCNOT _ + | HCCONST _ + | HCCONSTN _ -> false + | HCVAR s -> + if compare variable s == 0 + then true + else false + | HCAT (s, f1) -> + hc_freeIn variable f1 + | HCOR (f1, f2) + | HCAND (f1, f2) -> + hc_freeIn variable f1 || hc_freeIn variable f2 + | HCEX (_, f1) + | HCAX (_, f1) + | HCENFORCES (_, f1) + | HCALLOWS (_, f1) + | HCMORETHAN (_, _, f1) + | HCMAXEXCEPT (_, _, f1) + | HCATLEASTPROB (_, f1) + | HCLESSPROBFAIL (_, f1) + | HCID f1 -> + hc_freeIn variable f1 + | HCNORM (f1, f2) + | HCNORMN (f1, f2) + | HCCHC (f1, f2) -> + hc_freeIn variable f1 || hc_freeIn variable f2 + | HCFUS (first, f1) -> + hc_freeIn variable f1 + | HCMU (var, f1) + | HCNU (var, f1) -> + (* Do we need to exclude bound variables here? *) + hc_freeIn variable f1 (** An instantiation of a hash table (of the standard library) diff --git a/src/lib/CoAlgFormula.mli b/src/lib/CoAlgFormula.mli index 3c70e1d8965589c92105af1e1bd84bef5f0b98e8..7ea6b0f8515081bc7f0cddc6218f7433ba4af04e 100644 --- a/src/lib/CoAlgFormula.mli +++ b/src/lib/CoAlgFormula.mli @@ -41,6 +41,19 @@ type formula = | NORMN of formula * formula (* \neg NORM (\neg A, \neg B) *) | CHC of formula * formula | FUS of bool * formula + | MU of string * formula + | NU of string * formula + | VAR of string + | AF of formula + | EF of formula + | AG of formula + | EG of formula + | AU of formula * formula + | EU of formula * formula + | AR of formula * formula + | ER of formula * formula + | AB of formula * formula + | EB of formula * formula exception ConversionException of formula @@ -66,6 +79,8 @@ val importFormula : string -> formula val importSortedFormula : string -> sortedFormula val importQuery : string -> sortedFormula list * sortedFormula +val verifyFormula : formula -> unit + val nnfNeg : formula -> formula val nnf : formula -> formula @@ -146,9 +161,14 @@ and hcFormula_node = | HCNORMN of hcFormula * hcFormula | HCCHC of hcFormula * hcFormula | HCFUS of bool * hcFormula + | HCMU of string * hcFormula + | HCNU of string * hcFormula + | HCVAR of string module HcFormula : (HashConsing.S with type nde = hcFormula_node and type fml = formula) val hc_formula : HcFormula.t -> formula -> hcFormula +val hc_replace : HcFormula.t -> string -> hcFormula -> hcFormula -> hcFormula +val hc_freeIn : string -> hcFormula -> bool module HcFHt : (Hashtbl.S with type key = hcFormula) diff --git a/src/lib/CoAlgLogics.ml b/src/lib/CoAlgLogics.ml index d4b321b7ae10e98b1d1e2d7a9be2dff627f0e04d..fd46280ae2faeba53026db0dc5be8ff2cccccaf3 100644 --- a/src/lib/CoAlgLogics.ml +++ b/src/lib/CoAlgLogics.ml @@ -11,8 +11,8 @@ open Gmlmip module S = MiscSolver (** directly return a list of rules **) -let mkRuleList_MultiModalK sort bs sl : rule list = - (* arguments: +let mkRuleList_MultiModalK sort bs defer sl : rule list = + (* arguments: sort: type of formulae in bs (needed to disambiguate hashing) sl: sorts functor arguments, e.g. type of argument formulae bs: tableau sequent consisting of modal atoms @@ -26,6 +26,7 @@ let mkRuleList_MultiModalK sort bs sl : rule list = NB: propagating the whole premiss is always safe. *) assert (List.length sl = 1); + let refocusing = bsetCompare (bsetMakeRealEmpty ()) defer = 0 in let dep f bsl = (* dependencies for formula f (f is a diamond) *) assert (List.length bsl = 1); (* -+ *) let bs1 = List.hd bsl in (* -+-> [bs1] := bsl *) @@ -46,17 +47,27 @@ let mkRuleList_MultiModalK sort bs sl : rule list = let getRules f acc = if lfGetType sort f = ExF then (* f = ∃R.C,i.e. a diamond *) let bs1 = bsetMake () in - bsetAdd bs1 (lfGetDest1 sort f); (* bs1 := { C } *) + let defer1 = bsetMakeRealEmpty () in + let nextf = (lfGetDest1 sort f) in + bsetAdd bs1 nextf; (* bs1 := { C } *) + if (refocusing && (lfGetDeferral sort nextf) != (Hashtbl.hash "ε")) || + ((bsetMem defer f) && (lfGetDeferral sort f) = (lfGetDeferral sort nextf)) + then + bsetAdd defer1 nextf; let (role : int) = lfGetDest3 sort f in (* role := R *) let filterFkt f1 = if lfGetType sort f1 = AxF && lfGetDest3 sort f1 = role then (* if f1 = ∀R.D then bs1 = bs1 ∪ { D } *) - bsetAdd bs1 (lfGetDest1 sort f1) + let nextf1 = (lfGetDest1 sort f1) in + bsetAdd bs1 nextf1; + (if (refocusing && (lfGetDeferral sort nextf1) != (Hashtbl.hash "ε")) || + ((bsetMem defer f1) && (lfGetDeferral sort f1) = (lfGetDeferral sort nextf1)) then + bsetAdd defer1 nextf1;) else () in bsetIter filterFkt bs; (* bs1 := bs1 ∪ { D | some "∀R.D" ∈ bs } *) let s1 = List.hd sl in (* [s1] := sl *) - let rle = (dep f, lazylistFromList [(s1, bs1)]) in + let rle = (dep f, lazylistFromList [(s1, bs1, defer1)]) in rle::acc else acc in @@ -72,14 +83,14 @@ let mkRuleList_MultiModalK sort bs sl : rule list = *) bsetFold getRules bs [] -let mkRule_MultiModalK sort bs sl : stateExpander = - let rules = mkRuleList_MultiModalK sort bs sl in +let mkRule_MultiModalK sort bs defer sl : stateExpander = + let rules = mkRuleList_MultiModalK sort bs defer sl in lazylistFromList rules (* TODO: test it with: make && ./coalg sat <<< $'<R> False \n [R] False \n [R] True' *) -let mkRule_MultiModalKD sort bs sl : stateExpander = +let mkRule_MultiModalKD sort bs defer sl : stateExpander = assert (List.length sl = 1); (* functor has just one argument *) let s1 = List.hd sl in (* [s1] = sl *) let roles = S.makeBS () in @@ -114,14 +125,21 @@ let mkRule_MultiModalKD sort bs sl : stateExpander = res in let succs = bsetMake () in (* succs := {D | ∀r.D ∈ bs *) + let defer1 = bsetMakeRealEmpty () in (* TODO: actually track deferrals *) let f formula = if lfGetType sort formula = AxF && lfGetDest3 sort formula = r - then ignore (bsetAdd succs (lfGetDest1 sort formula)) + then + let nextf1 = (lfGetDest1 sort formula) in + bsetAdd succs nextf1; + ignore (if (bsetMem defer formula) && + (lfGetDeferral sort formula) = (lfGetDeferral sort nextf1) + then + bsetAdd defer1 nextf1;) else () in bsetIter f bs; - (dep r, lazylistFromList [(s1, succs)])::acc + (dep r, lazylistFromList [(s1, succs, defer1)])::acc in (* mkRule_MultiModalKD sort bs [s1] @@ -132,12 +150,112 @@ let mkRule_MultiModalKD sort bs sl : stateExpander = } ∪ mkRule_MultiModalK sort bs [s1] *) - let rules = mkRuleList_MultiModalK sort bs sl in + let rules = mkRuleList_MultiModalK sort bs defer sl in (* extend rules from K with enforcing of successors *) let rules = S.foldBS getRules roles rules in lazylistFromList rules +(** directly return a list of rules **) +let mkRuleList_Monotone sort bs defer sl : rule list = + (* arguments: + sort: type of formulae in bs (needed to disambiguate hashing) + sl: sorts functor arguments, e.g. type of argument formulae + bs: tableau sequent consisting of modal atoms + (premiss, conjunctive set of formulae represented by hash values) + result: set R of (propagation function, rule conclusion) pairs + s.t. [ (premiss / conc) : (_, conc) \in R ] are all rules + applicable to premiss. + Propagation functions map unsatisfiable subsets of the + (union of all?) conclusion(s) to unsatisfiable subsets of + the premiss -- this is a hook for backjumping. + NB: propagating the whole premiss is always safe. + *) + assert (List.length sl = 1); + let refocusing = bsetCompare (bsetMakeRealEmpty ()) defer = 0 in + let dep f bsl = (* dependencies for formula f (f is a diamond) *) + assert (List.length bsl = 1); (* -+ *) + let bs1 = List.hd bsl in (* -+-> [bs1] := bsl *) + let res = bsetMake () in + bsetAdd res f; + let (role : int) = lfGetDest3 sort f in (* ♥R.? := f, ♥ ∈ {∃,∀} *) + let filterFkt f1 = + if lfGetType sort f1 = AxF && lfGetDest3 sort f1 = role + && bsetMem bs1 (lfGetDest1 sort f1) + then + (* if f1 = ∀R.C and C ∈ bs1 then res = res ∪ {∀R.C} *) + bsetAdd res f1 + else () + in + bsetIter filterFkt bs; + res + in + let getRules f acc = + if lfGetType sort f = ExF then (* f = ∃R.C,i.e. a diamond *) + let bs1base = bsetMake () in + let defer1base = bsetMakeRealEmpty () in + let nextf = (lfGetDest1 sort f) in + bsetAdd bs1base nextf; (* bs1 := { C } *) + if (refocusing && (lfGetDeferral sort nextf) != (Hashtbl.hash "ε")) || + ((bsetMem defer f) && (lfGetDeferral sort f) = (lfGetDeferral sort nextf)) + then + bsetAdd defer1base nextf + else (); + let (role : int) = lfGetDest3 sort f in (* role := R *) + let filterFkt f1 acc = + if lfGetType sort f1 = AxF && lfGetDest3 sort f1 = role then + let bs1 = bsetCopy bs1base in + let defer1 = bsetCopy defer1base in + (* if f1 = ∀R.D then bs1 = bs1 ∪ { D } *) + let nextf1 = (lfGetDest1 sort f1) in + bsetAdd bs1 nextf1; + if (refocusing && (lfGetDeferral sort nextf1) != (Hashtbl.hash "ε")) || + ((bsetMem defer f1) && (lfGetDeferral sort f1) = (lfGetDeferral sort nextf1)) + then + bsetAdd defer1 nextf1 + else (); + let s1 = List.hd sl in (* [s1] := sl *) + let rle1 = (dep f, lazylistFromList [(s1, bs1, defer1)]) in + rle1::acc + else acc + in + let s1 = List.hd sl in (* [s1] := sl *) + let rle = (dep f, lazylistFromList [(s1, bs1base, defer1base)]) in + let fold = bsetFold filterFkt bs acc in (* bs1 := bs1 ∪ { D | some "∀R.D" ∈ bs } *) + rle::fold + else if lfGetType sort f = AxF then + let bs1 = bsetMake () in + let defer1 = bsetMakeRealEmpty () in + (* if f1 = ∀R.D then bs1 = bs1 ∪ { D } *) + let nextf1 = (lfGetDest1 sort f) in + bsetAdd bs1 nextf1; + if (refocusing && (lfGetDeferral sort nextf1) != (Hashtbl.hash "ε")) || + ((bsetMem defer f) && (lfGetDeferral sort f) = (lfGetDeferral sort nextf1)) + then + bsetAdd defer1 nextf1 + else (); + let s1 = List.hd sl in (* [s1] := sl *) + let rle1 = (dep f, lazylistFromList [(s1, bs1, defer1)]) in + rle1::acc + else acc + in + (* effectively: + mkRule_MultiModalK sort bs [s1] + = { ( λ[bs1]. { ∃R.C } ∪ { ∀R.D + | ∀R.D ∈ bs, D ∈ bs1 + , [(s1, {C}∪{D | "∀R.D" ∈ bs)] + ) + | "∃R.C" ∈ bs + } + *) + bsetFold getRules bs [] + +let mkRule_Monotone sort bs defer sl : stateExpander = + let rules = mkRuleList_Monotone sort bs defer sl in + lazylistFromList rules + + + (* CoalitionLogic: helper functions *) (*val subset : bitset -> bitset -> bool*) let bsetlen (a: bset) : int = @@ -196,14 +314,19 @@ let compatible sort (a: bset) formula1 = / \i=1 a_i /\ b / \j=1 c_j *) -(* Not yet implemented: backjumping hooks. +(* Not yet implemented: backjumping hooks. E.g. in Rule 1, if a subset I of {a_1, ..., a_n} is unsat, then {[C_i] a_i : i \in I} is already unsat. *) -let mkRule_CL sort bs sl : stateExpander = +let mkRule_CL sort bs defer sl : stateExpander = assert (List.length sl = 1); (* TODO: Why? *) + let refocusing = bsetCompare (bsetMakeRealEmpty ()) defer = 0 in + let deferral_tracking f nextf = + (refocusing && (lfGetDeferral sort nextf) != (Hashtbl.hash "ε")) || + ((bsetMem defer f) && (lfGetDeferral sort f) = (lfGetDeferral sort nextf)) + in let s1 = List.hd sl in (* [s1] = List.hd sl *) let boxes = bsetFilter bs (fun f -> lfGetType sort f = EnforcesF) in let diamonds = bsetFilter bs (fun f -> lfGetType sort f = AllowsF) in @@ -231,8 +354,10 @@ let mkRule_CL sort bs sl : stateExpander = print_endline ("N-Cands: " ^(CoAlgMisc.bsetToString sort nCands)); print_endline ("D-Cands: " ^(CoAlgMisc.bsetToString sort dCands)); *) - let c_j : localFormula list = - bsetFold (fun f a -> (lfGetDest1 sort f)::a) nCands [] + let c_j : (localFormula * bool) list = + bsetFold (fun f a -> let nextf = lfGetDest1 sort f in + (nextf, (deferral_tracking f nextf))::a) + nCands [] in (* rule 2 for diamaonds where D is a proper subset of the agent set N *) let getRule2 diamDb acc = (* diamDb = <D> b *) @@ -245,8 +370,11 @@ let mkRule_CL sort bs sl : stateExpander = in let maxdisj = maxDisjoints sort (bsetFilter boxes hasAppropriateAglist) in let createSingleRule acc coalitions = - let a_i : localFormula list = - bsetFold (fun f a -> (lfGetDest1 sort f)::a) coalitions [] + let a_i : (localFormula * bool) list = + bsetFold (fun f a -> + let nextf = lfGetDest1 sort f in + (nextf, (deferral_tracking f nextf))::a) + coalitions [] in (* now do rule 2: coalitions /\ <d> b /\ nCands @@ -254,9 +382,19 @@ let mkRule_CL sort bs sl : stateExpander = a_i /\ b /\ c_j *) let children = bsetMakeRealEmpty () in - List.iter (bsetAdd children) (b::c_j) ; - List.iter (bsetAdd children) (a_i) ; - ((fun bs1 -> bs), lazylistFromList [(s1, children)])::acc + let defer1 = bsetMakeRealEmpty () in + bsetAdd children b; + if deferral_tracking diamDb b + then bsetAdd defer1 b; + List.iter (fun (f, isdefer) -> + bsetAdd children f; + if isdefer then bsetAdd defer1 f) + c_j ; + List.iter (fun (f, isdefer) -> + bsetAdd children f; + if isdefer then bsetAdd defer1 f) + a_i ; + ((fun bs1 -> bs), lazylistFromList [(s1, children, defer1)])::acc in List.fold_left createSingleRule acc maxdisj in @@ -272,8 +410,10 @@ let mkRule_CL sort bs sl : stateExpander = (* create rule 2 once for all the diamonds with a full agent set *) let maxdisj = maxDisjoints sort boxes in let createSingleRule acc coalitions = - let a_i : localFormula list = - bsetFold (fun f a -> (lfGetDest1 sort f)::a) coalitions [] + let a_i : (localFormula * bool) list = + bsetFold (fun f a -> let nextf = lfGetDest1 sort f in + (nextf, (deferral_tracking f nextf))::a) + coalitions [] in (* now do rule 2: coalitions /\ nCands @@ -281,9 +421,16 @@ let mkRule_CL sort bs sl : stateExpander = a_i /\ c_j *) let children = bsetMakeRealEmpty () in - List.iter (bsetAdd children) (c_j) ; - List.iter (bsetAdd children) (a_i) ; - ((fun bs1 -> bs), lazylistFromList [(s1, children)])::acc + let defer1 = bsetMakeRealEmpty () in + List.iter (fun (f, isdefer) -> + bsetAdd children f; + if isdefer then bsetAdd defer1 f) + c_j ; + List.iter (fun (f, isdefer) -> + bsetAdd children f; + if isdefer then bsetAdd defer1 f) + a_i ; + ((fun bs1 -> bs), lazylistFromList [(s1, children, defer1)])::acc in List.fold_left createSingleRule acc maxdisj end else acc @@ -297,8 +444,14 @@ let mkRule_CL sort bs sl : stateExpander = a_i *) let a_i : bset = bsetMakeRealEmpty () in - bsetIter (fun f -> bsetAdd a_i (lfGetDest1 sort f)) coalitions ; - ((fun bs1 -> bs), lazylistFromList [(s1, a_i)])::acc + let defer1 : bset = bsetMakeRealEmpty () in + bsetIter (fun f -> + let nextf = lfGetDest1 sort f in + bsetAdd a_i nextf; + if deferral_tracking f nextf + then bsetAdd defer1 nextf) + coalitions ; + ((fun bs1 -> bs), lazylistFromList [(s1, a_i, defer1)])::acc in let rules = List.fold_left getRule1 rules disjoints in (* @@ -310,8 +463,9 @@ let mkRule_CL sort bs sl : stateExpander = *) lazylistFromList rules -let mkRule_GML sort bs sl : stateExpander = +let mkRule_GML sort bs defer sl : stateExpander = assert (List.length sl = 1); + let defer1 = bsetMake () in (* TODO: track deferrals *) let s1 = List.hd sl in (* [s1] = List.hd sl *) let diamonds = bsetFilter bs (fun f -> lfGetType sort f = MoreThanF) in let boxes = bsetFilter bs (fun f -> lfGetType sort f = MaxExceptF) in @@ -347,7 +501,7 @@ let mkRule_GML sort bs sl : stateExpander = in bsetAdd res f) conj; - (s1,res) + (s1,res, defer1) in let rc = List.map handleConjunction rc in ((fun bs1 -> bs),lazylistFromList rc)::acc @@ -356,8 +510,9 @@ let mkRule_GML sort bs sl : stateExpander = let rules = S.foldBS addRule roles [] in lazylistFromList rules -let mkRule_PML sort bs sl : stateExpander = +let mkRule_PML sort bs defer sl : stateExpander = assert (List.length sl = 1); + let defer1 = bsetMake () in (* TODO: track deferrals *) let s1 = List.hd sl in (* [s1] = List.hd sl *) let diamonds = bsetFilter bs (fun f -> lfGetType sort f = AtLeastProbF) in let boxes = bsetFilter bs (fun f -> lfGetType sort f = LessProbFailF) in @@ -394,7 +549,7 @@ let mkRule_PML sort bs sl : stateExpander = end in List.iter handleLiteral conj; - (s1,res) + (s1,res, defer1) in let rc = List.map handleConjunction rc in ((fun bs1 -> bs),lazylistFromList rc)::acc @@ -403,7 +558,7 @@ let mkRule_PML sort bs sl : stateExpander = lazylistFromList rules (* constant functor *) -let mkRule_Const colors sort bs sl : stateExpander = +let mkRule_Const colors sort bs defer sl : stateExpander = assert (List.length sl = 1); (* just one (formal) argument *) let helper (f:localFormula) (pos, neg) = let col = lfGetDest3 sort f in @@ -412,18 +567,24 @@ let mkRule_Const colors sort bs sl : stateExpander = | ConstF -> ((col::pos), neg) | _ -> (pos, neg) in - let (pos, neg) = bsetFold helper bs ([], []) in (* pos/neg literals *) + let (pos, neg) = bsetFold helper bs ([], []) in (* pos/neg literals *) let clash = List.exists (fun l -> List.mem l pos) neg in (* =a /\ ~ = a *) let allneg = List.length colors = List.length neg in let twopos = List.length pos > 1 in - let rules = if (clash || allneg || twopos) + let rules = if (clash || allneg || twopos) then [((fun x -> bs), lazylistFromList [])] (* no backjumping *) else [] - in + in lazylistFromList rules -let mkRule_Identity sort bs sl : stateExpander = +let mkRule_Identity sort bs defer sl : stateExpander = assert (List.length sl = 1); (* Identity has one argument *) + let refocusing = bsetCompare (bsetMakeRealEmpty ()) defer = 0 in + let deferral_tracking defer f nextf = + if (refocusing && (lfGetDeferral sort nextf) != (Hashtbl.hash "ε")) || + ((bsetMem defer f) && (lfGetDeferral sort f) = (lfGetDeferral sort nextf)) + then bsetAdd defer nextf + in let s1 = List.hd sl in let dep bsl = (* return arguments prefixed with identity operator *) assert (List.length bsl = 1); @@ -439,20 +600,31 @@ let mkRule_Identity sort bs sl : stateExpander = res in let bs1 = bsetMake () in + let defer1 = bsetMakeRealEmpty () in let getRule f = - if lfGetType sort f = IdF - then bsetAdd bs1 (lfGetDest1 sort f) + if lfGetType sort f = IdF + then + begin + deferral_tracking defer1 f (lfGetDest1 sort f); + bsetAdd bs1 (lfGetDest1 sort f) + end else () in bsetIter getRule bs; - lazylistFromList [(dep, lazylistFromList [(s1, bs1)])] + lazylistFromList [(dep, lazylistFromList [(s1, bs1, defer1)])] -let mkRule_DefaultImplication sort bs sl : stateExpander = +let mkRule_DefaultImplication sort bs defer sl : stateExpander = raise (CoAlgFormula.CoAlgException ("Default Implication Not yet implemented.")) - -let mkRule_Choice sort bs sl : stateExpander = + +let mkRule_Choice sort bs defer sl : stateExpander = assert (List.length sl = 2); + let refocusing = bsetCompare (bsetMakeRealEmpty ()) defer = 0 in + let deferral_tracking defer f nextf = + if (refocusing && (lfGetDeferral sort nextf) != (Hashtbl.hash "ε")) || + ((bsetMem defer f) && (lfGetDeferral sort f) = (lfGetDeferral sort nextf)) + then bsetAdd defer nextf + in let dep bsl = assert (List.length bsl = 2); let bs1 = List.nth bsl 0 in @@ -468,21 +640,32 @@ let mkRule_Choice sort bs sl : stateExpander = res in let bs1 = bsetMake () in + let defer1 = bsetMakeRealEmpty () in let bs2 = bsetMake () in + let defer2 = bsetMakeRealEmpty () in let getRule f = - if lfGetType sort f = ChcF then begin - bsetAdd bs1 (lfGetDest1 sort f); - bsetAdd bs2 (lfGetDest2 sort f) - end else () + if lfGetType sort f = ChcF then + begin + bsetAdd bs1 (lfGetDest1 sort f); + deferral_tracking defer1 f (lfGetDest1 sort f); + bsetAdd bs2 (lfGetDest2 sort f); + deferral_tracking defer2 f (lfGetDest2 sort f) + end else () in bsetIter getRule bs; let s1 = List.nth sl 0 in let s2 = List.nth sl 1 in - lazylistFromList [(dep, lazylistFromList [(s1, bs1); (s2, bs2)])] + lazylistFromList [(dep, lazylistFromList [(s1, bs1, defer1); (s2, bs2, defer2)])] -let mkRule_Fusion sort bs sl : stateExpander = +let mkRule_Fusion sort bs defer sl : stateExpander = assert (List.length sl = 2); + let refocusing = bsetCompare (bsetMakeRealEmpty ()) defer = 0 in + let deferral_tracking defer f nextf = + if (refocusing && (lfGetDeferral sort nextf) != (Hashtbl.hash "ε")) || + ((bsetMem defer f) && (lfGetDeferral sort f) = (lfGetDeferral sort nextf)) + then bsetAdd defer nextf + in let dep proj bsl = assert (List.length bsl = 1); let bs1 = List.hd bsl in @@ -497,17 +680,28 @@ let mkRule_Fusion sort bs sl : stateExpander = res in let bs1 = bsetMake () in + let defer1 = bsetMakeRealEmpty () in let bs2 = bsetMake () in + let defer2 = bsetMakeRealEmpty () in let getRule f = if lfGetType sort f = FusF then - if lfGetDest3 sort f = 0 then bsetAdd bs1 (lfGetDest1 sort f) - else bsetAdd bs2 (lfGetDest1 sort f) + if lfGetDest3 sort f = 0 then + begin + deferral_tracking defer1 f (lfGetDest1 sort f); + bsetAdd bs1 (lfGetDest1 sort f) + end + else + begin + deferral_tracking defer2 f (lfGetDest1 sort f); + bsetAdd bs2 (lfGetDest1 sort f) + end else () in bsetIter getRule bs; let s1 = List.nth sl 0 in let s2 = List.nth sl 1 in - lazylistFromList [(dep 0, lazylistFromList [(s1, bs1)]); (dep 1, lazylistFromList [(s2, bs2)])] + lazylistFromList [(dep 0, lazylistFromList [(s1, bs1, defer1)]); + (dep 1, lazylistFromList [(s2, bs2, defer2)])] (* Maps a logic represented by the type "functors" to the corresponding @@ -516,6 +710,7 @@ let mkRule_Fusion sort bs sl : stateExpander = let getExpandingFunctionProducer = function | MultiModalK -> mkRule_MultiModalK | MultiModalKD -> mkRule_MultiModalKD + | Monotone -> mkRule_Monotone | CoalitionLogic -> mkRule_CL | GML -> mkRule_GML | PML -> mkRule_PML diff --git a/src/lib/CoAlgLogics.mli b/src/lib/CoAlgLogics.mli index 48d0958b68bceec89898bf9788866dea0e7084bc..dd5c9ad4230fb0ae152217bd8b8c7cf9755e113d 100644 --- a/src/lib/CoAlgLogics.mli +++ b/src/lib/CoAlgLogics.mli @@ -6,4 +6,4 @@ open CoAlgMisc -val getExpandingFunctionProducer : functors -> sort -> bset -> sort list -> stateExpander +val getExpandingFunctionProducer : functors -> sort -> bset -> bset -> sort list -> stateExpander diff --git a/src/lib/CoAlgMisc.ml b/src/lib/CoAlgMisc.ml index 00174a7c1a4c4a9518f6ab32158a486331613bbb..85d08bcabeaf8f13ceba5442f5eaa76fa0ac5440 100644 --- a/src/lib/CoAlgMisc.ml +++ b/src/lib/CoAlgMisc.ml @@ -21,6 +21,17 @@ module BsSet = Set.Make( (** An instantiation of a hash table (of the standard library) for bitsets. *) module GHt = Hashtbl.Make( + struct + type t = S.bitset * S.bitset + let equal ((bs1l, bs1r) : t) (bs2l, bs2r) = + (S.compareBS bs1l bs2l = 0) && (S.compareBS bs1r bs2r = 0) + let hash ((bsl, bsr) : t) = (S.hashBS bsl) lxor (S.hashBS bsr) + end + ) + +(** An instantiation of a hash table (of the standard library) for bitsets. + *) +module GHtS = Hashtbl.Make( struct type t = S.bitset let equal (bs1 : t) bs2 = S.compareBS bs1 bs2 = 0 @@ -68,6 +79,7 @@ module NHt = Hashtbl.Make( type functors = | MultiModalK | MultiModalKD + | Monotone | CoalitionLogic | GML | PML @@ -89,6 +101,7 @@ type functorName = let unaryfunctor2name : (functorName*string) list = [ (NPa MultiModalK , "MultiModalK") ; (NPa MultiModalKD , "MultiModalKD") + ; (NPa Monotone , "Monotone") ; (NPa GML , "GML") ; (NPa PML , "PML") ; (NPa CoalitionLogic , "CoalitionLogic") @@ -165,6 +178,8 @@ type formulaType = | NormnF (* negation normal form of default implication *) | ChcF (* Choice *) | FusF (* Fusion *) + | MuF + | NuF type localFormula = int type bset = S.bitset @@ -182,6 +197,7 @@ type state = { sortS : sort; modalities (TODO: also @-formulas?). the state is satisfiable if /\bsS is satisfiable. *) + mutable deferralS : bset; (* which formulas still have deferrals *) mutable statusS : nodeStatus; mutable parentsS : core list; mutable childrenS : (dependencies * core list) list; mutable constraintsS : csetSet; expandFkt : stateExpander; @@ -191,11 +207,12 @@ and core = { (* for details, see documentation of newCore *) sortC : sort; mutable bsC : bset; (* a set of arbitrary formulas. the present core is satisfiable if /\ bsC is satisfiable *) + mutable deferralC : bset; (* which formulas still have deferrals *) mutable statusC : nodeStatus; mutable parentsC : (state * int) list; mutable childrenC : state list; mutable constraintsC : csetSet; - solver : Minisat.solver; (* a solver to find satisfying assignemnts for bsC. + mutable solver : Minisat.solver option; (* a solver to find satisfying assignemnts for bsC. the solver returns "satisfiable" iff there is a satisfying assignment of bsC which is not represented by some state from the @@ -211,7 +228,7 @@ and setState = state GHt.t array and setCore = core GHt.t array -and setCnstr = unit GHt.t +and setCnstr = unit GHtS.t (*****************************************************************************) @@ -231,9 +248,17 @@ and nodeStatus = | Sat | Unsat +(* In K, given the singleton list [bs] returns the list of all Ax'es + responsible for the individual members of bs being part of the core + as well as the Ex. + + So given the state { <>φ , []ψ , []η } and the core { φ , ψ , η }, + dependency would map { η } to { <>φ , []η } and { ψ } to { <>φ , []ψ } +*) and dependencies = bset list -> bset -and rule = (dependencies * (sort * bset) lazylist) +(* Note: sort * bset * bset is to be read as sort * formulas_in_core * deferrals_in_core *) +and rule = (dependencies * (sort * bset * bset) lazylist) and 'a lazyliststep = | MultipleElements of 'a list @@ -336,6 +361,7 @@ let queueCores1 = ref ([] : core list) let queueCores2 = ref ([] : core list) let queueCnstrs = ref ([] : cset list) let doPropagation = ref false +let doPropagationCounter = ref 0 let queueInit () = queueStates := []; @@ -352,7 +378,7 @@ let queueInsertState state = queueStates := state::!queueStates (* original version: breadth-first *) let queueInsertCore core = queueCores2 := core::!queueCores2 -(* experiment: depth first +(* experiment: depth first let queueInsertCore core = queueCores1 := core::!queueCores1 *) @@ -381,10 +407,19 @@ let queueGetElement () = let doNominalPropagation () = !doPropagation +let setPropagationCounter count = + doPropagationCounter := count + let doSatPropagation () = - let res = !doPropagation in - doPropagation := false; - res + if !doPropagationCounter == 0 + then true + else begin + doPropagationCounter := !doPropagationCounter - 1; + false + end + (* let res = !doPropagation in *) + (* doPropagation := false; *) + (* res *) (*****************************************************************************) (* "Module type" and a specific implementation of the graph *) @@ -392,14 +427,14 @@ let doSatPropagation () = let graphStates = ref (Array.make 0 (GHt.create 0 : state GHt.t)) let graphCores = ref (Array.make 0 (GHt.create 0 : core GHt.t)) -let graphCnstrs = ref (GHt.create 0 : constrnt GHt.t) +let graphCnstrs = ref (GHtS.create 0 : constrnt GHtS.t) let graphRoot = ref (None : core option) let graphInit () = let size = Array.length !sortTable in graphStates := Array.init size (fun _ -> GHt.create 128); graphCores := Array.init size (fun _ -> GHt.create 128); - graphCnstrs := GHt.create 128; + graphCnstrs := GHtS.create 128; graphRoot := None let graphIterStates fkt = @@ -408,18 +443,18 @@ let graphIterStates fkt = let graphIterCores fkt = Array.iter (fun ht -> GHt.iter (fun _ x -> fkt x) ht) !graphCores -let graphIterCnstrs fkt = GHt.iter fkt !graphCnstrs +let graphIterCnstrs fkt = GHtS.iter fkt !graphCnstrs let graphClearCnstr () = - let newGraph = GHt.create (GHt.length !graphCnstrs) in + let newGraph = GHtS.create (GHtS.length !graphCnstrs) in let copyCnstr cset cnstr = match cnstr with | UnsatC - | SatC -> GHt.add newGraph cset cnstr - | OpenC _ -> GHt.add newGraph cset (OpenC []) - | UnexpandedC _ -> GHt.add newGraph cset (UnexpandedC []) + | SatC -> GHtS.add newGraph cset cnstr + | OpenC _ -> GHtS.add newGraph cset (OpenC []) + | UnexpandedC _ -> GHtS.add newGraph cset (UnexpandedC []) in - GHt.iter copyCnstr !graphCnstrs; + GHtS.iter copyCnstr !graphCnstrs; graphCnstrs := newGraph let graphFindState sort bs = @@ -434,7 +469,7 @@ let graphFindCore sort bs = let graphFindCnstr cset = try - Some (GHt.find !graphCnstrs cset) + Some (GHtS.find !graphCnstrs cset) with Not_found -> None let graphInsertState sort bs state = @@ -446,17 +481,17 @@ let graphInsertCore sort bs core = GHt.add !graphCores.(sort) bs core let graphInsertCnstr cset cnstr = - assert (not (GHt.mem !graphCnstrs cset)); - GHt.add !graphCnstrs cset cnstr + assert (not (GHtS.mem !graphCnstrs cset)); + GHtS.add !graphCnstrs cset cnstr let graphReplaceCnstr cset cnstr = - GHt.replace !graphCnstrs cset cnstr + GHtS.replace !graphCnstrs cset cnstr let graphSizeState () = Array.fold_left (fun acc ht -> acc + GHt.length ht) 0 !graphStates let graphSizeCore () = Array.fold_left (fun acc ht -> acc + GHt.length ht) 0 !graphCores -let graphSizeCnstr () = GHt.length !graphCnstrs +let graphSizeCnstr () = GHtS.length !graphCnstrs let graphAddRoot core = if !graphRoot = None then graphRoot := Some core @@ -493,14 +528,16 @@ let nextNodeIdx () : int = nodeCounter := oldVal + 1; oldVal -let stateMake sort bs exp = - { sortS = sort; bsS = bs; statusS = Expandable; parentsS = []; childrenS = []; +let stateMake sort bs defer exp = + { sortS = sort; bsS = bs; deferralS = defer; statusS = Expandable; parentsS = []; childrenS = []; constraintsS = cssEmpty; expandFkt = exp; idx = nextNodeIdx() } let stateGetSort state = state.sortS let stateGetBs state = state.bsS let stateSetBs state bs = state.bsS <- bs +let stateGetDeferral state = state.deferralS +let stateSetDeferral state bs = state.deferralS <- bs let stateGetStatus state = state.statusS let stateSetStatus state status = state.statusS <- status let stateGetParents state = state.parentsS @@ -520,14 +557,16 @@ let stateGetIdx (state:state) = state.idx (* "Module type" and a specific implementation of core nodes *) (*****************************************************************************) -let coreMake sort bs solver fht = - { sortC = sort; bsC = bs; statusC = Expandable; parentsC = []; childrenC = []; +let coreMake sort bs defer solver fht = + { sortC = sort; bsC = bs; deferralC = defer; statusC = Expandable; parentsC = []; childrenC = []; constraintsC = cssEmpty; solver = solver; fht = fht; constraintParents = []; idx = nextNodeIdx() } let coreGetSort core = core.sortC let coreGetBs core = core.bsC let coreSetBs core bs = core.bsC <- bs +let coreGetDeferral core = core.deferralC +let coreSetDeferral core bs = core.deferralC <- bs let coreGetStatus core = core.statusC let coreSetStatus core status = core.statusC <- status let coreGetParents core = core.parentsC @@ -537,6 +576,7 @@ let coreAddChild core child = core.childrenC <- child::core.childrenC let coreGetConstraints core = core.constraintsC let coreSetConstraints core csets = core.constraintsC <- csets let coreGetSolver core = core.solver +let coreDeallocateSolver core = core.solver <- None; FHt.reset core.fht let coreGetFht core = core.fht let coreGetIdx (core:core) = core.idx let coreGetConstraintParents core = core.constraintParents @@ -551,19 +591,29 @@ let coreAddConstraintParent core cset = let setEmptyState () = Array.init (Array.length !sortTable) (fun _ -> GHt.create 128) let setEmptyCore () = Array.init (Array.length !sortTable) (fun _ -> GHt.create 128) -let setEmptyCnstr () = GHt.create 128 -let setAddState set state = GHt.add set.(stateGetSort state) (stateGetBs state) state -let setAddCore set core = GHt.add set.(coreGetSort core) (coreGetBs core) core -let setAddCnstr set cset = GHt.add set cset () -let setMemState set state = GHt.mem set.(stateGetSort state) (stateGetBs state) -let setMemCore set core = GHt.mem set.(coreGetSort core) (coreGetBs core) -let setMemCnstr set cset = GHt.mem set cset -let setRemoveState set state = GHt.remove set.(stateGetSort state) (stateGetBs state) -let setRemoveCore set core = GHt.remove set.(coreGetSort core) (coreGetBs core) -let setRemoveCnstr set cset = GHt.remove set cset +let setCopyState set = Array.init (Array.length !sortTable) (fun idx -> GHt.copy set.(idx)) +let setCopyCore set = Array.init (Array.length !sortTable) (fun idx -> GHt.copy set.(idx)) +let setEmptyCnstr () = GHtS.create 128 +let setAddState set state = + GHt.add set.(stateGetSort state) ((stateGetBs state), (stateGetDeferral state)) state +let setAddCore set core = + GHt.add set.(coreGetSort core) ((coreGetBs core), (coreGetDeferral core)) core +let setAddCnstr set cset = GHtS.add set cset () +let setMemState set state = + GHt.mem set.(stateGetSort state) ((stateGetBs state), (stateGetDeferral state)) +let setMemCore set core = + GHt.mem set.(coreGetSort core) ((coreGetBs core), (coreGetDeferral core)) +let setMemCnstr set cset = GHtS.mem set cset +let setRemoveState set state = + GHt.remove set.(stateGetSort state) ((stateGetBs state), (stateGetDeferral state)) +let setRemoveCore set core = + GHt.remove set.(coreGetSort core) ((coreGetBs core), (coreGetDeferral core)) +let setRemoveCnstr set cset = GHtS.remove set cset let setIterState fkt set = Array.iter (fun ht -> GHt.iter (fun _ x -> fkt x) ht) set let setIterCore fkt set = Array.iter (fun ht -> GHt.iter (fun _ x -> fkt x) ht) set -let setIterCnstr fkt set = GHt.iter (fun cset () -> fkt cset) set +let setIterCnstr fkt set = GHtS.iter (fun cset () -> fkt cset) set +let setLengthState seta = Array.fold_left (fun acc set -> acc + GHt.length set) 0 seta +let setLengthCore seta = Array.fold_left (fun acc set -> acc + GHt.length set) 0 seta (*****************************************************************************) @@ -605,6 +655,7 @@ let bsetMake () = S.makeBS () let bsetAdd bs lf = S.addBSNoChk bs lf let bsetMem bs lf = S.memBS bs lf let bsetRem bs lf = S.remBS bs lf +let bsetCompare bs1 bs2 = S.compareBS bs1 bs2 let bsetMakeRealEmpty () = let res = bsetMake () in bsetRem res !S.bstrue; (* remove bstrue which is initially in an empty bset *) @@ -664,6 +715,7 @@ let arrayNeg = ref (Array.make 0 (Array.make 0 (-1))) let arrayDest1 = ref (Array.make 0 (Array.make 0 (-1))) (* first subformula *) let arrayDest2 = ref (Array.make 0 (Array.make 0 (-1))) (* second subformula *) let arrayDest3 = ref (Array.make 0 (Array.make 0 (-1))) (* a role *) +let arrayDeferral = ref (Array.make 0 (Array.make 0 (-1))) (* deferral at point *) let arrayDestNum = ref (Array.make 0 (Array.make 0 (-1))) (* an integer *) let arrayDestNum2 = ref (Array.make 0 (Array.make 0 (-1))) (* another integer *) let arrayDestAg = ref (Array.make 0 (Array.make 0 [|0|])) (* arrays of agents *) @@ -677,6 +729,7 @@ let lfGetType sort f = !arrayType.(sort).(f) let lfGetDest1 sort f = !arrayDest1.(sort).(f) let lfGetDest2 sort f = !arrayDest2.(sort).(f) let lfGetDest3 sort f = !arrayDest3.(sort).(f) +let lfGetDeferral sort f = !arrayDeferral.(sort).(f) let lfGetDestNum sort f = !arrayDestNum.(sort).(f) let lfGetDestNum2 sort f = !arrayDestNum2.(sort).(f) let lfGetDestAg sort f = !arrayDestAg.(sort).(f) @@ -689,6 +742,11 @@ let lfToInt lf = lf let lfFromInt num = num let lfGetFormula sort f = !arrayFormula.(sort).(f) +let escapeHtml (input : string) : string = + List.fold_right (fun (x, y) (str : string) -> Str.global_replace (Str.regexp x) y str) + [("<", "<") ; (">", ">") ; ("&", "&")] + input + let bsetToString sort bset : string = let toFormula (lf:localFormula) (lst: string list) : string list = let formula: C.formula = lfGetFormula sort lf in @@ -699,7 +757,7 @@ let bsetToString sort bset : string = let csetToString sort cset = bsetToString sort cset -let coreToString core = +let coreToString (core:core): string = let helper cset lst : string list = (csetToString core.sortC cset):: lst in @@ -713,6 +771,8 @@ let coreToString core = "Core "^(string_of_int core.idx)^" {\n"^ " Status: " ^ (nodeStatusToString core.statusC) ^ "\n"^ " " ^ bsetToString core.sortC core.bsC ^ "\n" ^ + " Deferrals: \n" ^ + " " ^ bsetToString core.sortC core.deferralC ^ "\n" ^ " Constraints: { "^(String.concat "\n " constraints)^" }\n"^ " Children: { "^(String.concat @@ -741,6 +801,8 @@ let stateToString (state:state): string = "State "^(string_of_int state.idx)^" {\n"^ " Status: " ^ (nodeStatusToString state.statusS) ^ "\n"^ " " ^ bsetToString state.sortS state.bsS ^ "\n" ^ + " Deferrals: \n" ^ + " " ^ bsetToString state.sortS state.deferralS ^ "\n" ^ " Constraints: { "^(String.concat "\n " constraints)^" }\n"^ " Children: { "^(String.concat @@ -748,6 +810,60 @@ let stateToString (state:state): string = " Parents: { "^(String.concat ", " parents)^" }\n"^ "}" +let stateToDot (state:state): string = + let color = match state.statusS with + | Sat -> "green" + | Unsat -> "red" + | Open -> "yellow" + | Expandable -> "white" + in + let toFormula (lf:localFormula) (lst: string list) : string list = + let formula: C.formula = lfGetFormula state.sortS lf in + if (bsetMem state.deferralS lf) + then ("<B>"^(escapeHtml (C.string_of_formula formula))^"</B>") :: lst + else (escapeHtml (C.string_of_formula formula)) :: lst + in + let formulaList = bsetFold toFormula state.bsS [] in + let ownidx = (string_of_int state.idx) in + let parents = + List.map (fun (co:core) -> + "Node"^string_of_int co.idx^" -> Node"^ownidx^";") + state.parentsS + in + "Node" ^ ownidx ^ " [shape=ellipse,style=filled,fillcolor=" ^ color + ^ ",label=<State " ^ ownidx + ^ "<BR/>" ^ (String.concat "<BR/>" formulaList) + ^ ">];\n" + ^ (String.concat "\n" parents) + + +let coreToDot (core:core): string = + let color = match core.statusC with + | Sat -> "green" + | Unsat -> "red" + | Open -> "yellow" + | Expandable -> "white" + in + let toFormula (lf:localFormula) (lst: string list) : string list = + let formula: C.formula = lfGetFormula core.sortC lf in + if (bsetMem core.deferralC lf) + then ("<B>"^(escapeHtml (C.string_of_formula formula))^"</B>") :: lst + else (escapeHtml (C.string_of_formula formula)) :: lst + in + let formulaList = bsetFold toFormula core.bsC [] in + let ownidx = (string_of_int core.idx) in + let parents = + List.map (fun (st,_:state*int) -> + "Node"^string_of_int st.idx^" -> Node"^ownidx^";") + core.parentsC + in + "Node" ^ ownidx ^ " [shape=ellipse,style=filled,fillcolor=" ^ color + ^ ",label=<Core " ^ ownidx + ^ "<BR/>" ^ (String.concat "<BR/>" formulaList) + ^ ">];\n" + ^ (String.concat "\n" parents) + + let queuePrettyStatus () = let printList (sl : int list) : string = String.concat ", " (List.map string_of_int sl) @@ -774,19 +890,33 @@ let atFormulaGetNominal f = let lfToAt _ lf = lf +(* Calculate all possible formulae. This includes all subformulae and + in the case of μ-Calculus the Fischer-Ladner closure. -let rec detClosure nomTbl hcF fset atset nomset s f = + TODO: variable sort needs to match epected sort + *) +let rec detClosure vars nomTbl hcF fset vset atset nomset s f = + let newvars = List.filter (fun (x) -> C.hc_freeIn x f) vars in + let detClosure_ = detClosure newvars in + let deferral = if List.length newvars > 0 + then (List.hd newvars) + else "ε" in if s < 0 || s >= Array.length fset then let sstr = string_of_int s in raise (C.CoAlgException ("Invalid sort (i.e. sort out of range): " ^ sstr)) else (); - if C.HcFHt.mem fset.(s) f then () + if C.HcFHt.mem vset.(s) f && + (compare (C.HcFHt.find vset.(s) f) deferral = 0 || + compare deferral "ε" = 0) + then () else + let () = C.HcFHt.add vset.(s) f deferral in let () = C.HcFHt.add fset.(s) f () in let (func, sortlst) = !sortTable.(s) in match f.HC.node with | C.HCTRUE - | C.HCFALSE -> () + | C.HCFALSE + | C.HCVAR _ -> () | C.HCAP name -> if C.isNominal name then begin Hashtbl.replace nomset name s; @@ -808,37 +938,37 @@ let rec detClosure nomTbl hcF fset atset nomset s f = | Some sort -> sort in let hcnom = C.HcFormula.hashcons hcF (C.HCAP name) in - detClosure nomTbl hcF fset atset nomset s1 hcnom; - detClosure nomTbl hcF fset atset nomset s1 f1 + detClosure_ nomTbl hcF fset vset atset nomset s1 hcnom; + detClosure_ nomTbl hcF fset vset atset nomset s1 f1 | C.HCOR (f1, f2) | C.HCAND (f1, f2) -> - detClosure nomTbl hcF fset atset nomset s f1; - detClosure nomTbl hcF fset atset nomset s f2 + detClosure_ nomTbl hcF fset vset atset nomset s f1; + detClosure_ nomTbl hcF fset vset atset nomset s f2 | C.HCEX (_, f1) | C.HCAX (_, f1) -> - if (func <> MultiModalK && func <> MultiModalKD) + if (func <> MultiModalK && func <> MultiModalKD && func <> Monotone) || List.length sortlst <> 1 then raise (C.CoAlgException "Ex/Ax-formula is used in wrong sort.") else (); - detClosure nomTbl hcF fset atset nomset (List.hd sortlst) f1 + detClosure_ nomTbl hcF fset vset atset nomset (List.hd sortlst) f1 | C.HCENFORCES (_, f1) | C.HCALLOWS (_, f1) -> if func <> CoalitionLogic || List.length sortlst <> 1 then raise (C.CoAlgException "[{Agents}]-formula is used in wrong sort.") else (); - detClosure nomTbl hcF fset atset nomset (List.hd sortlst) f1 + detClosure_ nomTbl hcF fset vset atset nomset (List.hd sortlst) f1 | C.HCMORETHAN (_,_,f1) | C.HCMAXEXCEPT (_,_,f1) -> if func <> GML || List.length sortlst <> 1 then raise (C.CoAlgException "[{>=,<=}]-formula is used in wrong sort.") else (); - detClosure nomTbl hcF fset atset nomset (List.hd sortlst) f1 + detClosure_ nomTbl hcF fset vset atset nomset (List.hd sortlst) f1 | C.HCATLEASTPROB (_,f1) | C.HCLESSPROBFAIL (_,f1) -> if func <> PML || List.length sortlst <> 1 then raise (C.CoAlgException "[{>=,<}]-formula with probability is used in wrong sort.") else (); - detClosure nomTbl hcF fset atset nomset (List.hd sortlst) f1; + detClosure_ nomTbl hcF fset vset atset nomset (List.hd sortlst) f1; (* TODO: add ¬ f1 to the closure! detClosure nomTbl hcF fset atset nomset (List.hd sortlst) (f1.HC.node.negNde) @@ -861,28 +991,45 @@ let rec detClosure nomTbl hcF fset atset nomset s f = then raise (C.CoAlgException "Identity operator applied to formula of wrong sort.") else (); - detClosure nomTbl hcF fset atset nomset (List.hd sortlst) f1; + detClosure_ nomTbl hcF fset vset atset nomset (List.hd sortlst) f1; | C.HCNORM (f1, f2) | C.HCNORMN(f1, f2) -> if func <> DefaultImplication || List.length sortlst <> 1 then raise (C.CoAlgException "Default Implication applied to formulae of wrong sort.") else (); - detClosure nomTbl hcF fset atset nomset (List.nth sortlst 0) f1; - detClosure nomTbl hcF fset atset nomset (List.nth sortlst 1) f2 + detClosure_ nomTbl hcF fset vset atset nomset (List.nth sortlst 0) f1; + detClosure_ nomTbl hcF fset vset atset nomset (List.nth sortlst 1) f2 | C.HCCHC (f1, f2) -> if func <> Choice || List.length sortlst <> 2 then raise (C.CoAlgException "Choice formula is used in wrong sort.") else (); - detClosure nomTbl hcF fset atset nomset (List.nth sortlst 0) f1; - detClosure nomTbl hcF fset atset nomset (List.nth sortlst 1) f2 + detClosure_ nomTbl hcF fset vset atset nomset (List.nth sortlst 0) f1; + detClosure_ nomTbl hcF fset vset atset nomset (List.nth sortlst 1) f2 | C.HCFUS (first, f1) -> if func <> Fusion || List.length sortlst <> 2 then raise (C.CoAlgException "Fusion formula is used in wrong sort.") else (); let s1 = List.nth sortlst (if first then 0 else 1) in - detClosure nomTbl hcF fset atset nomset s1 f1 + detClosure_ nomTbl hcF fset vset atset nomset s1 f1 + (* + FL(μ X . φ) = {μ X . φ} ∪ FL(φ[X|->μ X . φ]) + *) + | C.HCMU (name, f1) -> + begin + if C.hc_freeIn name f1 + then + C.HcFHt.replace vset.(s) f name + else (); + let unfold = C.hc_replace hcF name f f1 in + let appendvars = List.append newvars [name] in + detClosure appendvars nomTbl hcF fset vset atset nomset s unfold + end + | C.HCNU (name, f1) -> + let unfold = C.hc_replace hcF name f f1 in + detClosure_ nomTbl hcF fset vset atset nomset s unfold + let detClosureAt hcF atset name f () = match f.HC.node with @@ -892,13 +1039,14 @@ let detClosureAt hcF atset name f () = | C.HCAND _ | C.HCAT _ -> () | _ -> - let at = C.HcFormula.hashcons hcF (C.HCAT (name, f)) in + let at = C.HcFormula.hashcons hcF (C.HCAT (name, f)) in C.HcFHt.replace atset at () (** Initialises the arrays for a formula and its integer representation. *) -let initTables nomTbl hcF htF htR s f n = +let initTables nomTbl hcF htF htR vset s f n = !arrayFormula.(s).(n) <- f.HC.fml; + !arrayDeferral.(s).(n) <- Hashtbl.hash (C.HcFHt.find vset.(s) f); let fneg = f.HC.neg in if C.HcFHt.mem htF.(s) fneg then !arrayNeg.(s).(n) <- C.HcFHt.find htF.(s) fneg; let (_, sortlst) = !sortTable.(s) in @@ -928,10 +1076,10 @@ let initTables nomTbl hcF htF htR s f n = !arrayType.(s).(n) <- AndF; !arrayDest1.(s).(n) <- C.HcFHt.find htF.(s) f1; !arrayDest2.(s).(n) <- C.HcFHt.find htF.(s) f2 - | C.HCEX (role, f1) -> + | C.HCEX (role, f1) -> !arrayType.(s).(n) <- ExF; !arrayDest1.(s).(n) <- C.HcFHt.find htF.(List.hd sortlst) f1; - !arrayDest3.(s).(n) <- + !arrayDest3.(s).(n) <- if Hashtbl.mem htR role then Hashtbl.find htR role else let size = Hashtbl.length htR in @@ -1013,11 +1161,11 @@ let initTables nomTbl hcF htF htR s f n = | C.HCID (f1) -> !arrayType.(s).(n) <- IdF; !arrayDest1.(s).(n) <- C.HcFHt.find htF.(List.nth sortlst 0) f1 - | C.HCNORM (f1, f2) -> + | C.HCNORM (f1, f2) -> !arrayType.(s).(n) <- NormF; !arrayDest1.(s).(n) <- C.HcFHt.find htF.(List.nth sortlst 0) f1; !arrayDest2.(s).(n) <- C.HcFHt.find htF.(List.nth sortlst 1) f2 - | C.HCNORMN (f1, f2) -> + | C.HCNORMN (f1, f2) -> !arrayType.(s).(n) <- NormnF; !arrayDest1.(s).(n) <- C.HcFHt.find htF.(List.nth sortlst 0) f1; !arrayDest2.(s).(n) <- C.HcFHt.find htF.(List.nth sortlst 1) f2 @@ -1031,6 +1179,16 @@ let initTables nomTbl hcF htF htR s f n = let s1 = List.nth sortlst (if first then 0 else 1) in !arrayDest1.(s).(n) <- C.HcFHt.find htF.(s1) f1; !arrayDest3.(s).(n) <- if first then 0 else 1 + | C.HCMU (name, f1) -> + !arrayType.(s).(n) <- MuF; + let unfold = C.hc_replace hcF name f f1 in + !arrayDest1.(s).(n) <- C.HcFHt.find htF.(s) unfold + | C.HCNU (name, f1) -> + !arrayType.(s).(n) <- NuF; + let unfold = C.hc_replace hcF name f f1 in + !arrayDest1.(s).(n) <- C.HcFHt.find htF.(s) unfold + | C.HCVAR _ -> !arrayType.(s).(n) <- Other + let initTablesAt hcF htF name sort = let hcnom = C.HcFormula.hashcons hcF (C.HCAP name) in @@ -1043,7 +1201,7 @@ let initTablesAt hcF htF name sort = | C.HCAND _ | C.HCAT _ -> () | _ -> - let at = C.HcFormula.hashcons hcF (C.HCAT (name, f)) in + let at = C.HcFormula.hashcons hcF (C.HCAT (name, f)) in let atn = C.HcFHt.find htF.(0) at in FHt.add !arrayAt.(sort).(n) nom atn in @@ -1054,6 +1212,7 @@ let ppFormulae nomTbl tbox (s, f) = if card <= 0 then raise (C.CoAlgException "Number of sorts must be positive.") else (); + C.verifyFormula f; let nnfAndSimplify f = C.simplify (C.nnf f) in let f1 = nnfAndSimplify f in let nf1 = nnfAndSimplify (C.NOT f) in @@ -1069,16 +1228,19 @@ let ppFormulae nomTbl tbox (s, f) = let hctrue = C.hc_formula hcF C.TRUE in let fset = Array.init card (fun _ -> C.HcFHt.create 128) in + let vset = Array.init card (fun _ -> C.HcFHt.create 128) in let atset = C.HcFHt.create 64 in let nomset = Hashtbl.create 16 in for i = 0 to card-1 do - detClosure nomTbl hcF fset atset nomset i hcfalse; - detClosure nomTbl hcF fset atset nomset i hctrue; + detClosure [] nomTbl hcF fset vset atset nomset i hcfalse; + detClosure [] nomTbl hcF fset vset atset nomset i hctrue; done; - detClosure nomTbl hcF fset atset nomset s hcf; - detClosure nomTbl hcF fset atset nomset s nhcf; - List.iter (fun (s, f) -> detClosure nomTbl hcF fset atset nomset s f) hctbox; - List.iter (fun (s, f) -> detClosure nomTbl hcF fset atset nomset s f) nhctbox; + detClosure [] nomTbl hcF fset vset atset nomset s hcf; + detClosure [] nomTbl hcF fset vset atset nomset s nhcf; + List.iter (fun (s, f) -> detClosure [] nomTbl hcF fset vset atset nomset s f) + hctbox; + List.iter (fun (s, f) -> detClosure [] nomTbl hcF fset vset atset nomset s f) + nhctbox; Hashtbl.iter (fun n s -> C.HcFHt.iter (detClosureAt hcF atset n) fset.(s)) nomset; let htF = Array.init card (fun _ -> C.HcFHt.create 128) in @@ -1111,12 +1273,13 @@ let ppFormulae nomTbl tbox (s, f) = arrayDest1 := Array.init card (fun _ -> Array.make !size (-1)); arrayDest2 := Array.init card (fun _ -> Array.make !size (-1)); arrayDest3 := Array.init card (fun _ -> Array.make !size (-1)); + arrayDeferral := Array.init card (fun _-> Array.make !size(-1)); arrayNeg := Array.init card (fun _ -> Array.make !size (-1)); arrayDestNum := Array.init card (fun _ -> Array.make !size (-1)); arrayDestNum2 := Array.init card (fun _ -> Array.make !size (-1)); arrayDestAg := Array.init card (fun _ -> Array.make !size (Array.make 0 (-1))); let htR = Hashtbl.create 128 in - Array.iteri (fun s ht -> C.HcFHt.iter (initTables nomTbl hcF htF htR s) ht) htF; + Array.iteri (fun s ht -> C.HcFHt.iter (initTables nomTbl hcF htF htR vset s) ht) htF; arrayAt := Array.init card (fun _ -> Array.init !size (fun _ -> FHt.create 8)); Hashtbl.iter (initTablesAt hcF htF) nomset; diff --git a/src/lib/CoAlgMisc.mli b/src/lib/CoAlgMisc.mli index b248c1803ae99d5a4f41a70706d765ed5399acaa..b93b94ea1a0798dbcabcf1447a2549b1145c1841 100644 --- a/src/lib/CoAlgMisc.mli +++ b/src/lib/CoAlgMisc.mli @@ -12,6 +12,7 @@ type functors = | MultiModalK | MultiModalKD + | Monotone | CoalitionLogic | GML | PML @@ -52,6 +53,8 @@ type formulaType = | NormnF (* negation normal form of default implication *) | ChcF | FusF + | MuF + | NuF type localFormula type bset @@ -93,7 +96,7 @@ and nodeStatus = and dependencies = bset list -> bset -and rule = (dependencies * (sort * bset) lazylist) +and rule = (dependencies * (sort * bset * bset) lazylist) and 'a lazyliststep = | MultipleElements of 'a list @@ -165,6 +168,7 @@ val queueInsertCnstr : cset -> unit val queueGetElement : unit -> queueElement val queuePrettyStatus : unit -> string +val setPropagationCounter : int -> unit val doNominalPropagation : unit -> bool val doSatPropagation : unit -> bool @@ -178,11 +182,11 @@ val graphIterStates : (state -> unit) -> unit val graphIterCores : (core -> unit) -> unit val graphIterCnstrs : (cset -> constrnt -> unit) -> unit val graphClearCnstr : unit -> unit -val graphFindState : sort -> bset -> state option -val graphFindCore : sort -> bset -> core option +val graphFindState : sort -> (bset * bset) -> state option +val graphFindCore : sort -> (bset * bset) -> core option val graphFindCnstr : cset -> constrnt option -val graphInsertState : sort -> bset -> state -> unit -val graphInsertCore : sort -> bset -> core -> unit +val graphInsertState : sort -> (bset * bset) -> state -> unit +val graphInsertCore : sort -> (bset * bset) -> core -> unit val graphInsertCnstr : cset -> constrnt -> unit val graphReplaceCnstr : cset -> constrnt -> unit val graphSizeState : unit -> int @@ -210,10 +214,12 @@ val cssIter : (cset -> unit) -> csetSet -> unit (* "Module type" and a specific implementation of state nodes *) (*****************************************************************************) -val stateMake : sort -> bset -> stateExpander -> state +val stateMake : sort -> bset -> bset -> stateExpander -> state val stateGetSort : state -> sort val stateGetBs : state -> bset val stateSetBs : state -> bset -> unit +val stateGetDeferral : state -> bset +val stateSetDeferral : state -> bset -> unit val stateGetStatus : state -> nodeStatus val stateSetStatus : state -> nodeStatus -> unit val stateGetParents : state -> core list @@ -225,6 +231,7 @@ val stateGetConstraints : state -> csetSet val stateSetConstraints : state -> csetSet -> unit val stateNextRule : state -> ruleEnumeration val stateToString : state -> string +val stateToDot : state -> string val stateGetIdx : state -> int @@ -232,24 +239,28 @@ val stateGetIdx : state -> int (* "Module type" and a specific implementation of core nodes *) (*****************************************************************************) -val coreMake : sort -> bset -> Minisat.solver -> fht -> core +val coreMake : sort -> bset -> bset -> Minisat.solver option -> fht -> core val coreGetSort : core -> sort val coreGetBs : core -> bset -val coreSetBs :core -> bset -> unit +val coreSetBs : core -> bset -> unit +val coreGetDeferral : core -> bset +val coreSetDeferral : core -> bset -> unit val coreGetStatus : core -> nodeStatus val coreSetStatus : core -> nodeStatus -> unit -val coreGetParents :core -> (state * int) list +val coreGetParents : core -> (state * int) list val coreAddParent : core -> state -> int -> unit val coreGetChildren : core -> state list val coreAddChild : core -> state -> unit val coreGetConstraints : core -> csetSet val coreSetConstraints : core -> csetSet -> unit -val coreGetSolver : core -> Minisat.solver +val coreGetSolver : core -> Minisat.solver option +val coreDeallocateSolver : core -> unit val coreGetFht : core -> fht val coreGetIdx : core -> int val coreGetConstraintParents : core -> cset list val coreAddConstraintParent : core -> cset -> unit val coreToString : core -> string +val coreToDot : core -> string (*****************************************************************************) @@ -259,6 +270,8 @@ val coreToString : core -> string val setEmptyState : unit -> setState val setEmptyCore : unit -> setCore +val setCopyState : setState -> setState +val setCopyCore : setCore -> setCore val setEmptyCnstr : unit -> setCnstr val setAddState : setState -> state -> unit val setAddCore : setCore -> core -> unit @@ -272,6 +285,8 @@ val setRemoveCnstr : setCnstr -> cset -> unit val setIterState : (state -> unit) -> setState -> unit val setIterCore : (core -> unit) -> setCore -> unit val setIterCnstr : (cset -> unit) -> setCnstr -> unit +val setLengthState : setState -> int +val setLengthCore : setCore -> int (*****************************************************************************) @@ -303,6 +318,8 @@ val bsetMake : unit -> bset (* a new bset which only contains True *) val bsetMakeRealEmpty : unit -> bset (* a new bset without containing True *) val bsetAdd : bset -> localFormula -> unit val bsetMem : bset -> localFormula -> bool +val bsetRem : bset -> int -> unit +val bsetCompare : bset -> bset -> int val bsetFold : (localFormula -> 'a -> 'a) -> bset -> 'a -> 'a val bsetIter : (localFormula -> unit) -> bset -> unit val bsetFilter : bset -> (localFormula -> bool) -> bset @@ -331,6 +348,7 @@ val lfGetType : sort -> localFormula -> formulaType val lfGetDest1 : sort -> localFormula -> localFormula val lfGetDest2 : sort -> localFormula -> localFormula val lfGetDest3 : sort -> localFormula -> int +val lfGetDeferral : sort -> localFormula -> int val lfGetDestNum : sort -> localFormula -> int val lfGetDestNum2 : sort -> localFormula -> int val lfGetDestAg : sort -> localFormula -> int array diff --git a/src/lib/CoAlgReasoner.ml b/src/lib/CoAlgReasoner.ml index 034d6f28aaa58d987c006800f77557d6ed23fde7..efb1734a8702628fdb1be1267005b5adcbb0d522 100644 --- a/src/lib/CoAlgReasoner.ml +++ b/src/lib/CoAlgReasoner.ml @@ -27,11 +27,12 @@ let propSatFindSucc setCnstr cset = if csetHasDot cset then false else match graphFindCnstr cset with - | None -> raise (ReasonerError "?") - | Some SatC -> true - | Some (OpenC _) -> setMemCnstr setCnstr cset - | Some (UnexpandedC _) - | Some UnsatC -> false + | None -> raise (ReasonerError "?") + | Some SatC -> true + | Some (OpenC _) -> setMemCnstr setCnstr cset + | Some (UnexpandedC _) + | Some UnsatC -> false + let rec propSat setStates setCores setCnstr = function | [] -> () @@ -112,6 +113,160 @@ let propagateSat () = setIterCnstr (fun cset -> graphReplaceCnstr cset SatC) setCnstr +let propagateSatMu () = + let setFinishingStates = setEmptyState () in + let setFinishingCores = setEmptyCore () in + let setStates = setEmptyState () in + let setCores = setEmptyCore () in + let emptySet = bsetMakeRealEmpty () in + let openstates = ref 0 in + + (* Collect two sets of nodes. All nodes that may be satisfiable + * after this iteration are collected into setStates/setCores. + * + * As every cycle containing a node with empty focus or an + * satisfiable node should be considered satisfiable, collect these + * decisive nodes into setFinishingStates/setFinishingCores + * + * This also marks in trivial cases nodes as satisfiable. + *) + let stateCollector state = + match stateGetStatus state with + | Unsat -> () + | Sat -> + setAddState setStates state; + setAddState setFinishingStates state + | Expandable -> () + | Open -> + openstates := !openstates + 1; + if List.length (stateGetRules state) == 0 || (* States with no rules are satisfiable *) + bsetCompare (bsetMake ()) (stateGetBs state) == 0 (* KD generates nodes with just True as formula *) + then begin + setAddState setFinishingStates state; + stateSetStatus state Sat + end else begin + setAddState setStates state; + if bsetCompare (stateGetDeferral state) emptySet == 0 + then begin + setAddState setFinishingStates state + end + else () + end + + (* As it is enough for a core to have one successfull child, we can + * also handle (some) expandable cores. + *) + and coreCollector core = + match coreGetStatus core with + | Unsat -> () + | Sat -> + setAddCore setCores core; + setAddCore setFinishingCores core + | Expandable + | Open -> + setAddCore setCores core; + if bsetCompare (coreGetDeferral core) emptySet == 0 + then begin + setAddCore setFinishingCores core + end + else () + in + graphIterStates stateCollector; + graphIterCores coreCollector; + + setPropagationCounter !openstates; + + (* In a fixpoint the set called setStates / setCores is narrowed + * down. + * + * In each step only those states and cores are retained in setStates + * / setCores which reach one of setFinishing{States,Cores} in + * finitely many steps. This new set of States / Cores is collected + * as allowed{States,Cores} during each fixpoint iteration. + * + * Only those finishing nodes are retained that have allowed or + * Successfull Children. + *) + let rec fixpointstep setStates setCores = + let allowedStates = setEmptyState () in + let allowedCores = setEmptyCore () in + + let rec visitParentStates (core : core) : unit = + if not (setMemCore allowedCores core) + then begin + setAddCore allowedCores core; + let verifyParent (state,_) = + let rules = stateGetRules state in + let ruleiter (dependencies, corelist) = + List.exists (fun (core : core) -> setMemCore allowedCores core || + coreGetStatus core == Sat) + corelist + in + if List.for_all ruleiter rules + then visitParentCores state + in + List.iter verifyParent (coreGetParents core) + end + + and visitParentCores (state : state) : unit = + if not (setMemState allowedStates state) + then begin + setAddState allowedStates state; + let verifyParent core = + let acceptable = + List.exists (fun (state : state) -> setMemState allowedStates state || + stateGetStatus state == Sat) + (coreGetChildren core) + in + if acceptable + then visitParentStates core + in + List.iter verifyParent (stateGetParents state) + end + in + + (* All rule applications need to still be potentially Sat for a + * finishing State to be a valid startingpoint for this fixpoint. + *) + let checkFinishingState (state : state) = + let ruleiter (dependencies, corelist) : bool = + List.for_all (fun (core : core) -> coreGetStatus core == Unsat || + coreGetStatus core == Expandable || + not (setMemCore setCores core)) corelist + in + if not (List.exists ruleiter (stateGetRules state)) then begin + visitParentCores state + end + + (* There needs to be a State still potentially Sat for this core + * to be considered for the fixpoint + *) + and checkFinishingCore (core : core) = + if not (List.for_all (fun (state : state) -> stateGetStatus state == Unsat || + stateGetStatus state == Expandable || + not (setMemState setStates state)) + (coreGetChildren core)) + then begin + visitParentStates core + end + in + setIterState checkFinishingState setFinishingStates; + setIterCore checkFinishingCore setFinishingCores; + + + if (setLengthState setStates) = (setLengthState allowedStates) && + (setLengthCore setCores) = (setLengthCore allowedCores) + then begin + setIterState (fun state -> stateSetStatus state Sat) setStates; + setIterCore (fun core -> coreSetStatus core Sat; if core == graphGetRoot () + then raise (CoAlg_finished true) + else ()) setCores; + end else + fixpointstep allowedStates allowedCores + in + fixpointstep setStates setCores + + (*****************************************************************************) (* Propagation of Unsatisfiability *) (*****************************************************************************) @@ -132,6 +287,9 @@ let lhtMustFind lht l = | Some f -> f | None -> assert false + +(* Gets a list of Things we know are unsatisfiable and propagates this + information backwards *) let rec propagateUnsat = function | [] -> () | propElem::tl -> @@ -161,7 +319,8 @@ let rec propagateUnsat = function let prop acc core = let turnsUnsat = match coreGetStatus core with - | Open -> List.for_all (fun s -> stateGetStatus s = Unsat) (coreGetChildren core) + | Open -> List.for_all (fun s -> stateGetStatus s = Unsat) + (coreGetChildren core) | Expandable | Unsat | Sat -> false @@ -182,7 +341,7 @@ let rec propagateUnsat = function if comesFromCnstr then coreGetBs core else let bs = coreGetBs core in - let solver = coreGetSolver core in + let Some solver = coreGetSolver core in let fht = coreGetFht core in let lht = lhtInit () in let addLits f acc = @@ -207,6 +366,7 @@ let rec propagateUnsat = function in coreSetBs core mbs; coreSetStatus core Unsat; + coreDeallocateSolver core; if core == graphGetRoot () then raise (CoAlg_finished false) else (); let prop acc (state, idx) = let turnsUnsat = @@ -233,7 +393,7 @@ let rec propagateUnsat = function let prop acc node = match node with | State state -> - let turnsUnsat = + let turnsUnsat = match stateGetStatus state with | Expandable | Open -> cssForall isConstraintUnsat (stateGetConstraints state) @@ -255,6 +415,145 @@ let rec propagateUnsat = function in propagateUnsat tl1 +let propagateUnsatMu () = + let setFinishingStates = setEmptyState () in + let setFinishingCores = setEmptyCore () in + let setStates = setEmptyState () in + let setCores = setEmptyCore () in + let emptySet = bsetMakeRealEmpty () in + + (* Collect two sets of nodes. All nodes that may be unsatisfiable + * after this iteration are collected into setStates/setCores. + * + * Nodes reaching Points with empty focus as well as Expandable nodes + * (if not Unsat) can not be declared Unsat so we collect these into + * setFinishingStates/setFinishingCores. + *) + let stateCollector state = + match stateGetStatus state with + | Unsat -> () + | Sat + | Expandable -> + setAddState setStates state; + setAddState setFinishingStates state + | Open -> + setAddState setStates state; + if [] = (stateGetRules state) + then begin + stateSetStatus state Sat; + setAddState setFinishingStates state + end + else (); + if bsetCompare (stateGetDeferral state) emptySet == 0 + then begin + setAddState setFinishingStates state + end + else () + + and coreCollector core = + match coreGetStatus core with + | Unsat -> () + | Expandable + | Sat -> + setAddCore setCores core; + setAddCore setFinishingCores core + | Open -> + setAddCore setCores core; + if bsetCompare (coreGetDeferral core) emptySet == 0 + then begin + setAddCore setFinishingCores core + end + else () + in + graphIterStates stateCollector; + graphIterCores coreCollector; + + (* In a fixpoint the set called setFinishingStates/setFinishingCores + * is narrowed down + * + * In each iteration we start with all Nodes and remove all that can + * reach a finishing Node. We then remove all finishing Nodes from the + * respective set which are becoming Unsat and start with the next + * iteration until the fixpoint is reached + * + * + *) + let rec fixpointstep setPrevUnsatStates setPrevUnsatCores = + let setUnsatStates = setCopyState setStates in + let setUnsatCores = setCopyCore setCores in + + let rec visitParentStates (core : core) : unit = + if setMemCore setUnsatCores core + then begin + setRemoveCore setUnsatCores core; + let verifyParent (state,_) = + let rules = stateGetRules state in + let ruleiter (dependencies, corelist) = + List.exists (fun (core : core) -> not (setMemCore setUnsatCores core) || + coreGetStatus core == Sat) + corelist + in + if List.for_all ruleiter rules + then visitParentCores state + in + List.iter verifyParent (coreGetParents core) + end + + and visitParentCores (state : state) : unit = + if setMemState setUnsatStates state + then begin + setRemoveState setUnsatStates state; + let verifyParent core = + let acceptable = + List.exists (fun (state : state) -> not (setMemState setUnsatStates state) || + stateGetStatus state == Sat) + (coreGetChildren core) + in + if acceptable + then visitParentStates core + in + List.iter verifyParent (stateGetParents state) + end + in + + (* All rule applications need to still be potentially Sat for a + * finishing State to be a valid startingpoint for this fixpoint. + *) + let checkFinishingState (state : state) = + let ruleiter (dependencies, corelist) : bool = + List.for_all (fun (core : core) -> coreGetStatus core == Unsat || + setMemCore setPrevUnsatCores core) corelist + in + if not (List.exists ruleiter (stateGetRules state)) || + stateGetStatus state == Expandable then begin + visitParentCores state + end + + (* There needs to be a State still potentially Sat for this core + * to be considered for the fixpoint + *) + and checkFinishingCore (core : core) = + if not (List.for_all (fun (state : state) -> stateGetStatus state == Unsat || + setMemState setPrevUnsatStates state) + (coreGetChildren core)) || + coreGetStatus core == Expandable + then begin + visitParentStates core + end + in + setIterState checkFinishingState setFinishingStates; + setIterCore checkFinishingCore setFinishingCores; + + if (setLengthState setPrevUnsatStates) = (setLengthState setUnsatStates) && + (setLengthCore setPrevUnsatCores) = (setLengthCore setUnsatCores) + then begin + setIterState (fun state -> stateSetStatus state Unsat) setUnsatStates; + setIterCore (fun core -> propagateUnsat [UCore (core, false)]) setUnsatCores; + end else + fixpointstep setUnsatStates setUnsatCores + in + fixpointstep (setEmptyState ()) (setEmptyCore ()) + (*****************************************************************************) (* Propagation of Nominal Constraints *) @@ -413,7 +712,7 @@ let getLit sort fht solver f = in lit -let newCore sort bs = +let newCore sort bs defer = (* when creating a now core from a set of formulas bs bs = { x_1, ...., x_n } = "x_1 /\ .... /\ x_n" @@ -476,13 +775,30 @@ let newCore sort bs = assert (okay1); let okay2 = M.add_clause solver [M.neg_lit lf; lf2] in assert (okay2) + | MuF + | NuF -> + (* + Dest of a fixpoint is it's unfolded version. This adds just + an simple forward implication that could be optimised out + though not without nontrivial transformation of code + + f = μ X . φ |---> lf + φ[X |-> f] |---> lf1 + + Then adding lf -> lf1 to minisat + *) + let f1 = lfGetDest1 sort f in + addClauses f1; + let lf1 = fhtMustFind fht f1 in + let okay1 = M.add_clause solver [M.neg_lit lf; lf1] in + assert (okay1); | _ -> () (* case 2.(c) We don't need to do anything except adding f to the fht *) in bsetIter addClauses bs; - coreMake sort bs solver fht + coreMake sort bs defer (Some solver) fht let getNextState core = (* Create a new state, which is obtained by a satisfying assignment of the @@ -492,9 +808,16 @@ let getNextState core = minisat calls. *) let bs = coreGetBs core in + let refocusing = bsetCompare (bsetMakeRealEmpty ()) (coreGetDeferral core) = 0 in + let deferralS = + if refocusing then + bsetCopy bs + else + coreGetDeferral core + in let fht = coreGetFht core in let litset = bsetFold (fun f acc -> (fhtMustFind fht f)::acc) bs [] in - let solver = coreGetSolver core in + let Some solver = coreGetSolver core in let isSat = M.invoke_solver solver litset in (* Clearly, if the current core is unsatisfiable, no further child state can be created *) @@ -506,6 +829,7 @@ let getNextState core = satisfiable. *) let newbs = bsetMake () in + let newdefer = bsetMakeRealEmpty () in (* if newbs = { l_1, .... l_n }, i.e. newbs = l_1 /\ ... /\ l_n @@ -517,7 +841,7 @@ let getNextState core = By mkExclClause, newbs is filled, and clause is built in the accumulator acc. *) - let rec mkExclClause f acc = + let rec mkExclClause deferral f acc = (* f is a formula that is true in the current satisfying assignment *) match lfGetType sort f with | OrF -> @@ -526,47 +850,65 @@ let getNextState core = let lf1 = fhtMustFind fht f1 in (* if the first disjunct f1 is true, then we need to add subformulas of f1 to newbs&clause *) - if M.literal_status solver lf1 = M.LTRUE then mkExclClause f1 acc + if M.literal_status solver lf1 = M.LTRUE then mkExclClause deferral f1 acc else (* otherwise f2 must be true *) let f2 = lfGetDest2 sort f in let lf2 = fhtMustFind fht f2 in assert (M.literal_status solver lf2 = M.LTRUE); - mkExclClause f2 acc + mkExclClause deferral f2 acc | AndF -> (* if the true f is a conjuction, then both conjunctions must be true *) let f1 = lfGetDest1 sort f in let lf1 = fhtMustFind fht f1 in assert (M.literal_status solver lf1 = M.LTRUE); - let acc1 = mkExclClause f1 acc in + let acc1 = mkExclClause deferral f1 acc in let f2 = lfGetDest2 sort f in let lf2 = fhtMustFind fht f2 in assert (M.literal_status solver lf2 = M.LTRUE); - mkExclClause f2 acc1 + mkExclClause deferral f2 acc1 + | MuF + | NuF -> + let f1 = lfGetDest1 sort f in + mkExclClause deferral f1 acc | _ -> - (* if f is a trivial formula or modality, then add it ... *) - (* ... to newbs *) - bsetAdd newbs f; - (* ... and to the new clause *) - (M.neg_lit (fhtMustFind fht f))::acc + (* if f is a trivial formula or modality, then add it ... *) + (* ... to newbs *) + bsetAdd newbs f; + let defercandidate = lfGetDeferral sort f in + (if (defercandidate != (Hashtbl.hash "ε") && + (refocusing || deferral = defercandidate)) then + bsetAdd newdefer f); + (* ... and to the new clause *) + (M.neg_lit (fhtMustFind fht f))::acc + in + let init_clause f acc = + let deferral = + (* for each deferral determine which variable it belongs to *) + if bsetMem deferralS f then ( + lfGetDeferral sort f) + else + (Hashtbl.hash "ε") + in + mkExclClause deferral f acc in - let clause = bsetFold mkExclClause bs [] in + let clause = bsetFold init_clause bs [] in let okay = M.add_clause solver clause in assert (okay); - Some (sort, newbs) + Some (sort, newbs, newdefer) -let newState sort bs = +let newState sort bs defer = let (func, sl) = !sortTable.(sort) in let producer = CoAlgLogics.getExpandingFunctionProducer func in - let exp = producer sort bs sl in - stateMake sort bs exp + let exp = producer sort bs defer sl in + stateMake sort bs defer exp -let insertState parent sort bs = +let insertState parent sort bs defer = let child = - match graphFindState sort bs with + match graphFindState sort (bs, defer) with | None -> - let s = newState sort bs in - graphInsertState sort bs s; + let s = newState sort bs defer in + graphInsertState sort (bs, defer) s; queueInsertState s; s | Some s -> s @@ -576,29 +918,32 @@ let insertState parent sort bs = let expandCore core = match getNextState core with - | Some (sort, bs) -> - insertState core sort bs; + | Some (sort, bs, defer) -> + insertState core sort bs defer; queueInsertCore core | None -> let isUnsat = List.for_all (fun s -> stateGetStatus s = Unsat) (coreGetChildren core) in - if isUnsat then propagateUnsat [UCore (core, false)] - else coreSetStatus core Open + if isUnsat + then + propagateUnsat [UCore (core, false)] + else + coreSetStatus core Open -let insertCore sort bs = - match graphFindCore sort bs with +let insertCore sort bs defer = + match graphFindCore sort (bs, defer) with | None -> - let c = newCore sort bs in - graphInsertCore sort bs c; - queueInsertCore c; - c + let c = newCore sort bs defer in + graphInsertCore sort (bs, defer) c; + queueInsertCore c; + c | Some c -> c let insertRule state dep chldrn = let chldrn = listFromLazylist chldrn in - let insert (isUns, acc) (sort, bs) = + let insert (isUns, acc) (sort, bs, defer) = let bs1 = bsetAddTBox sort bs in - let core = insertCore sort bs1 in + let core = insertCore sort bs1 defer in let isUns1 = if coreGetStatus core = Unsat then isUns else false in (isUns1, core::acc) in @@ -646,7 +991,7 @@ let expandCnstr cset = in csetIter cset mkCores; let inCores (sort, _) bs (isUns, acc) = - let core = insertCore sort bs in + let core = insertCore sort bs bs in (* TODO: think of deferral / μ stuff here *) coreAddConstraintParent core cset; (coreGetStatus core = Unsat || isUns, core::acc) in @@ -668,8 +1013,8 @@ let expandNodesLoop (recursiveAction: unit -> unit) = if stateGetStatus state = Expandable then begin expandState state; if doNominalPropagation () then begin - propagateNominals (); - if doSatPropagation () then propagateSat () + (* propagateNominals (); *) + if doSatPropagation () then (propagateUnsatMu (); propagateSatMu ()) end else () end else (); recursiveAction () @@ -677,8 +1022,8 @@ let expandNodesLoop (recursiveAction: unit -> unit) = if coreGetStatus core = Expandable then begin expandCore core; if doNominalPropagation () then begin - propagateNominals (); - if doSatPropagation () then propagateSat () + (* propagateNominals (); *) + if doSatPropagation () then (propagateUnsatMu (); propagateSatMu ()) end else () end else (); recursiveAction () @@ -693,14 +1038,14 @@ let runReasonerStep () = (* if this emptied the queue *) if queueIsEmpty () then begin (* then check whether the nominals would add further queue elements *) - print_endline "Propagating nominals..."; - propagateNominals () + (* print_endline "Propagating nominals..."; *) + (* propagateNominals () *) end else () (* else: the next step would be to expand another node *) let rec buildGraphLoop () = let rec expandNodesFurther () = expandNodesLoop expandNodesFurther in expandNodesFurther (); (* expand as many queue elements as possible *) - propagateNominals (); + (* propagateNominals (); *) (* if propagating nominals added some more queue members, do all again.. *) if queueIsEmpty () then () else buildGraphLoop () @@ -709,16 +1054,22 @@ let initReasoner sorts nomTable tbox sf = let (tbox1, sf1, bs) = ppFormulae nomTable tbox sf in let sort = fst sf in let bs1 = bsetAddTBox sort bs in + let deferrals = bsetMakeRealEmpty() in + let markDeferral f = + if (Hashtbl.hash "ε") != (lfGetDeferral sort f) then ( + bsetAdd deferrals f;) + in + bsetIter markDeferral bs; graphInit (); queueInit (); - let root = insertCore sort bs1 in + let root = insertCore sort bs1 deferrals in graphAddRoot root let isRootSat () = match coreGetStatus (graphGetRoot ()) with | Expandable -> None | Unsat -> Some false - | Sat + | Sat -> Some true | Open -> if (queueIsEmpty()) then Some true else None let reasonerFinished () = @@ -727,7 +1078,7 @@ let reasonerFinished () = | Unsat | Sat -> true | Open -> queueIsEmpty () - + (** A graph-tableau-based decision procedure framework for coalgebraic logics. @param verbose An optional switch which determines @@ -748,6 +1099,7 @@ let isSat ?(verbose = false) sorts nomTable tbox sf = let sat = try buildGraphLoop (); + propagateUnsatMu (); (* get whether the root is satisfiable *) (* we know that the reasoner finished, so the value is there, *) (* i.e. isRootSat() will give a "Some x" and not "None" *) @@ -775,4 +1127,3 @@ let isSat ?(verbose = false) sorts nomTable tbox sf = print_newline () else (); sat - diff --git a/src/lib/HashConsing.ml b/src/lib/HashConsing.ml index a7e88dee447e90c162e6de2702c93d99704522c0..6b75c0b9ee40f79c227f74b8b2096b6dce97dd83 100644 --- a/src/lib/HashConsing.ml +++ b/src/lib/HashConsing.ml @@ -208,11 +208,18 @@ module Make(H : HashedTyped) : (S with type nde = H.nde and type fml = H.fml) = let ndeN = H.negNde nde in let hkeyN = realhash ndeN in let fmlN = H.toFml ndeN in - let ndN = { node = ndeN; hkey = hkeyN; tag = osize + 1; fml = fmlN; neg = nd } in - nd.neg <- ndN; let idxN = hkeyN mod ds in - data.(idxN) <- ndN :: data.(idxN); - hc.size <- osize + 2; + let bucketN = data.(idxN) in + try begin + find ndeN bucketN; + hc.size <- succ osize; + end + with Not_found -> + let ndN = { node = ndeN; hkey = hkeyN; tag = osize + 1; fml = fmlN; neg = nd } in + nd.neg <- ndN; + let idxN = hkeyN mod ds in + data.(idxN) <- ndN :: data.(idxN); + hc.size <- osize + 2 else hc.size <- succ osize; if hc.size > ds lsl 1 then resize hc else (); nd diff --git a/src/testsuite/cool-testsuite.ml b/src/testsuite/cool-testsuite.ml index a6f312d2580134c3a6ee94093b830dc8f5032ee5..0fdc0fbb1594b836848c50b46d51a3df0075de48 100644 --- a/src/testsuite/cool-testsuite.ml +++ b/src/testsuite/cool-testsuite.ml @@ -37,15 +37,15 @@ let k_testcases: satCheck list = ; c Unsat "<R> ((<R> C) & (<S> False))" ; c Unsat "<X> (<S> False) | <R> ((<R> C) & (<S> False))" ; c Unsat "<X> (<S> False) | <R> ((<R> C) & (<S> False))" - ; c Sat "<R> A & <R> B |- [R] C" - ; c Unsat "<R> A & <R> B |- [R] (~A & ~B)" - ; c Unsat "<R> A & <R> B |- [R] ~B" - ; c Sat "<R> A & <R> ~A |- [R] B" - ; c Unsat "<R> A & <R> ~A & (B => [R] ~A) |- [R] B" - ; c Sat "<R> A & <R> ~A & (B => [R] ~A) & (C => ~D) & (D => ~E) & <R> C & <R> D & <R> E |- True" - ; c Unsat "<R> D & <R> E & ((<R> D & <R> E) => [R] E) & ~(D & E) |- True" - ; c Sat "(<R> D | <R> E) & ((<R> D & <R> E) => [R] E) & ~(D & E) |- True" - ; c Sat "<R> D & <R> E & ((<R> D & <R> E) => [R] E) & (D & E => <R> ~(D&E)) |- True" + ; c Sat "<R> a & <R> B |- [R] C" + ; c Unsat "<R> a & <R> B |- [R] (~a & ~B)" + ; c Unsat "<R> a & <R> B |- [R] ~B" + ; c Sat "<R> a & <R> ~a |- [R] B" + ; c Unsat "<R> a & <R> ~a & (B => [R] ~a) |- [R] B" + ; c Sat "<R> a & <R> ~a & (B => [R] ~a) & (C => ~D) & (D => ~e) & <R> C & <R> D & <R> e |- True" + ; c Unsat "<R> D & <R> e & ((<R> D & <R> e) => [R] e) & ~(D & e) |- True" + ; c Sat "(<R> D | <R> e) & ((<R> D & <R> e) => [R] e) & ~(D & e) |- True" + ; c Sat "<R> D & <R> e & ((<R> D & <R> e) => [R] e) & (D & e => <R> ~(D&e)) |- True" ]