def testIsATreeAcceptedByANonTerminalOfOurUVWGrammar(self): listOfTestCases = [ ("LTL a", "Phi", True), ("LTL G F G a", "Phi", False), ("LTL G F b", "Phi", True), ("LTL ~ G F b", "Phi", False), ("LTL F G b", "Phi", False), ("LTL F b", "Psi", True), ("LTL G F b", "Psi", False), ("LTL U a U b c", "Phi", True), ("LTL G U & F p G q & ! p G k", "Phi", False), # Maidl's original grammar ("LTL G U & p G q & ! F k G k", "Phi", False), # Maidl's original grammar ("LTL G U & p G q & ! p G k", "Phi", True), # Maidl's original grammar ("LTL G U & p G q & r G k", "Phi", False), # Maidl's original grammar ("LTL G U & & p q G r & ! & p q G k", "Phi", True), # Maidl's original grammar ("LTL G U & & p q G r & | ! p ! q G k", "Phi", True), # Maidl's original grammar ("LTL G U & & p q G r & | ! p q G k", "Phi", False), # Maidl's original grammar ] for (ltl, nonterminal, shouldBeAccepted) in listOfTestCases: tree1 = parser.parse(ltl) tree2 = parser.simplifyTree(tree1) tree3 = parser.elimImplies(tree2) tree4 = parser.computeNNF(tree3) isAccepted = parser.isATreeAcceptedByANonTerminalOfOurUVWGrammar( tree4, nonterminal) assert isAccepted == shouldBeAccepted
def testSimplify(self): listOfTestCases = [("LTL G G F a", "LTL G F a"), ("LTL F F ~ ~ a", "LTL F a")] for (before, after) in listOfTestCases: tree1 = parser.parse(before) tree2 = parser.parse(after) simpler = parser.simplifyTree(tree1) assert str(simpler) == str(tree2)
def testSomeErrorCases(self): # Illegal UVW parsing from strings uvw = uvwBuilder.UVW() uvw.ddMgr.declare('a', 'b') uvwBuilder.UVW.parseFromUVWDescription(uvw.ddMgr, "2(i)-[a]->2,2(i)-[b]->2") with self.assertRaises(Exception): uvwBuilder.UVW.parseFromUVWDescription( uvw.ddMgr, "2(i)-[a]->2,2(i)-[b]->2,1(ik)-[True]->1") # Throw exception if not in NNF with self.assertRaises(Exception): formulaNode = parser.simplifyTree(parser.parse("LTL G ~ G a")) uvw = uvwBuilder.constructUVW(formulaNode) # Throw exception if there is still a "->" in the LTL formula with self.assertRaises(Exception): formulaNode = parser.simplifyTree(parser.parse("LTL G -> a b")) uvw = uvwBuilder.constructUVW(formulaNode)
def testUVWSizeUnminimized(self): listOfTestCases = [ ("LTL G F a", 3), ("LTL || a b", 2), ("LTL || G a G b", 5), # The error state gets duplicated ] for (ltl, expectedSize) in listOfTestCases: formulaNode = parser.computeNNF( parser.simplifyTree(parser.elimImplies(parser.parse(ltl)))) uvw = uvwBuilder.constructUVW(formulaNode) uvw.removeUnreachableStates() assert len(uvw.stateNames) == expectedSize
def testUVWSizeMinimized(self): listOfTestCases = [ ("LTL G F a", 3), ("LTL || a b", 2), ("LTL || G a G b", 4), ("LTL && G a G b", 2), ("LTL || G F a G F b", 3), ("LTL && G F a G F b", 4), ("LTL || || G a G b G c", 8), ("LTL || G a G ~ a", 4), ("LTL F || F a F b", 2), ("LTL F && ~ a a", 1), ("LTL U && ~ a G b && a F d", 4), ("LTL U ! buttonB.click & buttonB.click U ! idle buttonA.enable", 3), ("LTL | G ! buttonB.click U ! buttonB.click & buttonB.click U ! idle buttonA.enable", 3), ("LTL G | G ! buttonB.click U ! buttonB.click & buttonB.click U ! idle buttonA.enable", 3) ] for (ltl, expectedSize) in listOfTestCases: formulaNode = parser.computeNNF( parser.simplifyTree(parser.elimImplies(parser.parse(ltl)))) assert parser.isATreeAcceptedByANonTerminalOfOurUVWGrammar( formulaNode, "Phi") uvw = uvwBuilder.constructUVW(formulaNode) #print(uvw) uvw.removeUnreachableStates() #print(uvw) uvw.simulationBasedMinimization() uvw.removeUnreachableStates() #print(uvw) uvw.mergeEquivalentlyReachableStates() #print(uvw) uvw.removeForwardReachableBackwardSimulatingStates() #print(uvw) if len(uvw.stateNames) != expectedSize: print("Unexpected size:") print(ltl) print(uvw) sys.stdout.flush() assert len(uvw.stateNames) == expectedSize
print("Error: Need a formula file name!", file=sys.stderr) sys.exit(1) with open(sys.argv[1], "r") as inFile: formulaTxt = inFile.readlines() # Assuming the LTL specification is for a never claim for line in formulaTxt: line = line.strip() if len(line) > 0: assert line[0:4] == "LTL " #line = "LTL ! "+line[4:] formulaNode = parser.computeNNF( parser.simplifyTree(parser.elimImplies(parser.parse(line)))) assert parser.isATreeAcceptedByANonTerminalOfOurUVWGrammar( formulaNode, "Phi") # formulaTxt = "LTL F && c F && b F a" ----> Does not work according to the grammar print("================Constructing UVW================", file=sys.stderr) uvw = uvwBuilder.constructUVW(formulaNode) print("================Original Automaton================", file=sys.stderr) # print(uvw) uvw.removeUnreachableStates() print("================Removed Unreachable States================", file=sys.stderr) # print(uvw) uvw.simulationBasedMinimization()
if not filename is None: print("Error: Multiple file names given.",file=sys.stderr) sys.exit(1) filename = arg if filename is None: print("Error: Need a formula file name!",file=sys.stderr) sys.exit(1) with open(sys.argv[1],"r") as inFile: formulaTxt = inFile.readline().strip() # Assuming the LTL specification is for a never claim assert formulaTxt[0:4]=="LTL " formulaNode = parser.computeNNF(parser.simplifyTree(parser.elimImplies(parser.parse(formulaTxt)))) if not parser.isATreeAcceptedByANonTerminalOfOurUVWGrammar(formulaNode,"Phi"): print("Error: Input is not in the supported LTL fragment.",file=sys.stderr) parser.printTreeWithSupportedAnnotatedNonterminalsForUVWGrammar(formulaNode) sys.exit(1) print("================Constructing UVW================",file=sys.stderr) uvw = constructUVW(formulaNode) if singleActionOptimization: uvw.restrictToTheCaseThatThereCanOnlyBeOneActionAtATime() print("================Original Automaton================",file=sys.stderr) # print(uvw,file=sys.stderr) # These two are needed in case "restrictToTheCaseThatThereCanOnlyBeOneActionAtATime" disconnected states # as otherwise the later simulationBasedMinimization may fail. uvw.removeUnreachableStates() uvw.removeStatesWithoutOutgoingTransitions()
def testTreesinUVWGrammar(self): listOfTestCases = [ #Spinroot Example:Blue Spec TM Specification ("LTL G | ! a X U ! b c", True), ("LTL G | & ! a ! b X U ! c | a d", True), ("LTL G | & ! a ! b X U ! c a", True), ("LTL G | | ! a ! b X U ! c d", True), ("LTL G | | ! a ! b X U ! c & a d", True), #Spinroot Example: CORBA General Inter-Orb Protocol ("LTL | G ! p U q r", True), ("LTL G | | ! q G ! r U ! r p", True), ("LTL G | ! p F s", True), ("LTL | G ! p U ! p & ! p s", True), ("LTL G | | ! q G ! r U ! p r", True), ("LTL G | | ! q G ! r U & ! p ! r | r U & p ! r | r U ! p r", True), #Spinroot Example:PLC Control Schedule ("LTL & G F | ! a b G F | ! a c", True), #Spinroot Example:Space Craft Controller ("LTL G | ! a F b", True), ("LTL G | ! a F | b c", True), #Spinroot Example:Group Address Registration Protocol ("LTL G | ! p F G q", False), #Spinroot Example: Needham-Schroeder Public Key Protocol ("LTL G | G ! p U ! p q", True), #Spinroot Example: Cardiac pacemaker model ("LTL G | ! p F & & q r s", True), ("LTL G | ! p r", True), ("LTL G & | ! p ! q | ! r s", True), ("LTL G & p | ! q r", True), ("LTL G | | ! p ! q & r s", True), ("LTL G | & & ! p ! q ! r F x", True), #Example Anderson from paper 'IS THERE A BEST BUCHI AUTOMATA FOR EXPLICIT MC' ("LTL G -> | | ap0 ap1 ap2 F ap3", True), ("LTL ! G -> | | ap0 ap1 ap2 F ap3", False), ("LTL G -> ! ap0 F ap0", True), ("LTL ! G -> ! ap0 F ap0", False), ("LTL G F | ap0 ap1", True), ("LTL ! G F | ap0 ap1", False), ("LTL G -> | | ap0 ap1 ap2 F ap3", True), ("LTL ! G -> | | ap0 ap1 ap2 F ap3", False), ("LTL G -> ! ap0 F ap0", True), ("LTL ! G -> ! ap0 F ap0", False), ("LTL G F | | ap0 ap1 ap2", True), ("LTL ! G F | | ap0 ap1 ap2", False), ("LTL G -> | | ap0 ap1 ap2 F ap3", True), ("LTL ! G -> | | ap0 ap1 ap2 F ap3", False), ("LTL G -> ! ap0 F ap0", True), ("LTL ! G -> ! ap0 F ap0", False), ("LTL G F | | ap0 ap1 ap2", True), ("LTL ! G F | | ap0 ap1 ap2", False), ("LTL G -> | | ap0 ap1 ap2 F ap3", True), ("LTL ! G -> | | ap0 ap1 ap2 F ap3", False), ("LTL G -> ! ap0 F ap0", True), ("LTL ! G -> ! ap0 F ap0", False), ("LTL G F | | | ap0 ap1 ap2 ap3", True), ("LTL ! G F | | | ap0 ap1 ap2 ap3", False), ("LTL G -> | | ap0 ap1 ap2 F ap3", True), ("LTL ! G -> | | ap0 ap1 ap2 F ap3", False), ("LTL G -> ! ap0 F ap0", True), ("LTL ! G -> ! ap0 F ap0", False), ("LTL G F | | | | ap0 ap1 ap2 ap3 ap4", True), ("LTL ! G F | | | | ap0 ap1 ap2 ap3 ap4", False), ("LTL G -> | | ap0 ap1 ap2 F ap3", True), ("LTL ! G -> | | ap0 ap1 ap2 F ap3", False), ("LTL G -> ! ap0 F ap0", True), ("LTL ! G -> ! ap0 F ap0", False), ("LTL G F | | | | | ap0 ap1 ap2 ap3 ap4 ap5", True), ("LTL ! G F | | | | | ap0 ap1 ap2 ap3 ap4 ap5", False), ("LTL G -> | | ap0 ap1 ap2 F ap3", True), ("LTL ! G -> | | ap0 ap1 ap2 F ap3", False), ("LTL G -> ! ap0 F ap0", True), ("LTL ! G -> ! ap0 F ap0", False), ("LTL G F | | | | | ap0 ap1 ap2 ap3 ap4 ap5", True), ("LTL ! G F | | | | | ap0 ap1 ap2 ap3 ap4 ap5", False), ("LTL G -> | | ap0 ap1 ap2 F ap3", True), ("LTL ! G -> | | ap0 ap1 ap2 F ap3", False), ("LTL G -> ! ap0 F ap0", True), ("LTL ! G -> ! ap0 F ap0", False), ("LTL G F | | | | | | ap0 ap1 ap2 ap3 ap4 ap5 ap6", True), ("LTL ! G F | | | | | | ap0 ap1 ap2 ap3 ap4 ap5 ap6", False), ] for (ltl, shouldBeAccepted) in listOfTestCases: tree1 = parser.parse(ltl) tree2 = parser.simplifyTree(tree1) tree3 = parser.elimImplies(tree2) tree4 = parser.computeNNF(tree3) isAccepted = parser.isATreeAcceptedByANonTerminalOfOurUVWGrammar( tree4, "Phi") assert isAccepted == shouldBeAccepted
def testSimpleChainDecomposition(self): listOfTestCases = [ ("LTL G F a", ["1(i)-[True]->1,1-[~a]->2,2(r)-[~a]->2"], True), ("LTL && G a G F b", [ "1(i)-[True]->1,1-[~a]->0", "1(i)-[True]->1,1-[~b]->2,2(r)-[~b]->2" ], True), ("LTL && X G a G F b", [ "2(i)-[True]->1,1-[True]->1,1-[~a]->0", "1(i)-[True]->1,1-[~b]->2,2(r)-[~b]->2" ], True), ("LTL && G a G F b", ["1(i)-[True]->1,1-[~a]->0"], False), ("LTL && G F a G F b", [ "1(i)-[True]->1,1-[~a]->2,2(r)-[~a]->2", "1(i)-[True]->1,1-[~b]->2,2(r)-[~b]->2" ], True), ("LTL && && G F ~ c G F a G F b", [ "1(i)-[True]->1,1-[c]->2,2(r)-[c]->2", "1(i)-[True]->1,1-[~a]->2,2(r)-[~a]->2", "1(i)-[True]->1,1-[~b]->2,2(r)-[~b]->2" ], True), ("LTL U U a b c", [ "1(ir)-[~c]->1,1-[~b & ~c]->2,2(r)-[~b]->2,2-[~a & ~b]->0", "1(ir)-[~c]->1,1-[~c & ~b & ~a]->0" ], True) ] for (ltl, expectedChains, should) in listOfTestCases: formulaNode = parser.computeNNF( parser.simplifyTree(parser.parse(ltl))) uvw = uvwBuilder.constructUVW( parser.Node( parser.NodeTypes.OR, [formulaNode])) # Test single-element or along the way uvw.removeUnreachableStates() uvw.simulationBasedMinimization() uvw.removeUnreachableStates() uvw.mergeEquivalentlyReachableStates() uvw.removeForwardReachableBackwardSimulatingStates() decomposedUVWs = uvw.decomposeIntoSimpleChains() expectedUVWs = [ uvwBuilder.UVW.parseFromUVWDescription(uvw.ddMgr, a) for a in expectedChains ] #print("----orig----",file=sys.stderr) #print(uvw,file=sys.stderr) #print("----decomposed----",file=sys.stderr) #for a in decomposedUVWs: # print(a,file=sys.stderr) # Check if for every expected UVW, there is an equivalent UVW in the decomposed chains # and vice versa foundAll = True for (set1, set2) in [(expectedUVWs, decomposedUVWs), (decomposedUVWs, expectedUVWs)]: for a in set1: foundThisOne = False for b in set2: if uvwBuilder.UVW.isBisimulationEquivalent(a, b): foundThisOne = True foundAll = foundAll and foundThisOne assert should == foundAll
def testSomeConcreteTrees(self): listOfTestCases = [ ("LTL G F a", "1(i)-[True]->1,1-[~a]->2,2(r)-[~a]->2", True), ("LTL G F a", "1(i)-[True]->1,1-[~a]->2,2(r)-[a]->2", False), ("LTL && G a G b", "1(i)-[True]->1,1-[~a | ~b]->0", True), ("LTL && G F a G F b", "1(i)-[True]->1,1-[~a]->2,2(r)-[~a]->2", False), ("LTL && G F a G F b", "1(i)-[True]->1,1-[~a]->2,2(r)-[~a]->2,1-[~b]->3,3(r)-[~b]->3", True), ("LTL U a b", "1(ir)-[a & ~b]->1,1-[~a & ~b]->0", True), ("LTL R b a", "1(i)-[a & ~b]->1,1-[~a]->0", True), ("LTL U a b", "1(i)-[a & ~b]->1,1-[~a & ~b]->0", False), ("LTL R b a", "1(ir)-[a & ~b]->1,1-[~a & ~b]->0", False), ("LTL X && G a G a", "1(ir)-[True]->2,2-[True]->2,2-[~a]->0", True), ("LTL && && X G b X G a X G && c ~ d", "1(ir)-[True]->2,2-[True]->2,2-[~a | ~b | ~c | d]->0", True), ("LTL X && && X X G a X G a X X X G a", "1(i)-[True]->2,2-[True]->3,3-[True]->3,3-[~a]->0", True), ("LTL F && ~ a a", "1(i)-[True]->0", True), ("LTL || a ~ a", "", True), ("LTL U a U b c", "1(ir)-[~c & a]->1,1-[~a & ~c]->2,1-[~a & ~b & ~c]->0,2(r)-[~c]->2,2-[~b & ~c]->0", True), ("LTL U U a b c", "1(ir)-[~c]->1,1-[~a & ~b & ~c]->0,1-[~b & ~c]->2,2(r)-[~b]->2,2-[~a & ~b]->0", True), ("LTL && G -> && a b F || c d G -> a F c", "1(i)-[True]->1,1-[a]->2,2(r)-[~c]->2", False), ("LTL && G -> && a b F || c d G -> a F c", "1(i)-[True]->1,1-[a & ~c]->2,2(r)-[~c]->2", True), ("LTL G R a b", "1(i)-[True]->1,1-[~b]->0", True), ("LTL G R a R b c", "1(i)-[True]->1,1-[~c]->0", True), ] for (ltl, expectedResult, should) in listOfTestCases: formulaNode = parser.computeNNF( parser.elimImplies(parser.simplifyTree(parser.parse(ltl)))) uvw = uvwBuilder.constructUVW(formulaNode) uvw.removeUnreachableStates() uvw.simulationBasedMinimization() uvw.removeUnreachableStates() uvw.mergeEquivalentlyReachableStates() uvw.removeForwardReachableBackwardSimulatingStates() referenceUVW = uvwBuilder.UVW.parseFromUVWDescription( uvw.ddMgr, expectedResult) try: assert parser.isATreeAcceptedByANonTerminalOfOurUVWGrammar( formulaNode, "Phi") assert should == uvwBuilder.UVW.isBisimulationEquivalent( uvw, referenceUVW) if should: assert len(uvw.transitions) <= len( referenceUVW.transitions) # Not too large except AssertionError: print("LTL:", ltl) print("Expected:", referenceUVW) print("Got:", uvw) raise # Test if this terminates uvw.toNeverClaim()