Exemplo n.º 1
0
    def test_eu(self):
        euspec = eu(sptrue(), spfalse())
        self.assertEqual(euspec.type, parser.EU)
        self.assertIsNotNone(euspec.car)
        self.assertIsNotNone(euspec.cdr)

        with self.assertRaises(ValueError):
            euspec = eu(None, None)
Exemplo n.º 2
0
 def test_explain(self):
     fsm = self.init_model()
     
     initState = fsm.pick_one_state(fsm.init)
     adminNone = eval_ctl_spec(fsm, atom("admin = none"))
     adminAlice = eval_ctl_spec(fsm, atom("admin = alice"))
     egAlice = eval_ctl_spec(fsm, eg(atom("admin = alice")))
     euNoneUAlice = eval_ctl_spec(fsm, eu(atom("admin = none"),
                                          atom("admin = alice")))
     
     spec = Spec(parse_ctl_spec("EX admin = none"))
     path = explain(fsm, initState, spec)
     self.assertEqual(initState, path[0])
     self.assertTrue(path[2] <= adminNone)
     
     state = fsm.pick_one_state(egAlice)
     spec = Spec(parse_ctl_spec("EG admin = alice"))
     path = explain(fsm, state, spec)
     self.assertEqual(state, path[0])
     self.assertIn(path[-1], path[:-1])
     for i in range(0,len(path), 2):
         self.assertTrue(path[i] <= adminAlice)
     self.assertTrue(path[-1] <= adminAlice)
     self.assertTrue(initState <= euNoneUAlice)
     
     spec = Spec(parse_ctl_spec("E[admin = none U admin = alice]"))
     path = explain(fsm, initState, spec)
     self.assertEqual(initState, path[0])
     for i in range(2,len(path)-2,2):
         self.assertTrue(path[i] <= adminNone)
     self.assertTrue(path[-1] <= adminAlice)
Exemplo n.º 3
0
 def test_explain_eu(self):
     fsm = self.init_model()
     manager = fsm.bddEnc.DDmanager
     init = fsm.init
     
     initState = fsm.pick_one_state(init)
     
     adminNone = eval_ctl_spec(fsm, atom("admin = none"))
     adminAlice = eval_ctl_spec(fsm, atom("admin = alice"))
     euNoneUAlice = eval_ctl_spec(fsm, eu(atom("admin = none"),
                                          atom("admin = alice")))
     self.assertTrue(initState <= euNoneUAlice)
     
     path = explainEU(fsm, initState, adminNone, adminAlice)
     self.assertEqual(initState, path[0])
     for i in range(2,len(path)-2,2):
         self.assertTrue(path[i] <= adminNone)
     self.assertTrue(path[-1] <= adminAlice)
Exemplo n.º 4
0
def countex(fsm, state, spec, context):
    """
    Return a TLACE node explaining why state of fsm violates spec.
    
    fsm -- a pynusmv.fsm.BddFsm representing the system.
    state -- a pynusmv.dd.BDD representing a state of fsm.
    spec -- a pynusmv.spec.spec.Spec node representing the specification.
    context -- a pynusmv.spec.spec.Spec representing the context of spec in fsm.
    
    Return a tlacenode.Tlacenode explaining why state of fsm violates spec.
    """
    
    if spec.type == parser.CONTEXT:
        return countex(fsm, state, spec.cdr, spec.car)
        
    elif spec.type == parser.FALSEEXP:
        newspec = sptrue()
        
    elif spec.type == parser.NOT:
        newspec = spec.car
        
    elif spec.type == parser.OR:
        newspec = (~spec.car) & (~spec.cdr)
    
    elif spec.type == parser.AND:
        newspec = (~spec.car) | (~spec.cdr)
    
    elif spec.type == parser.IMPLIES:
        newspec = spec.car & (~spec.cdr)
                            
    elif spec.type == parser.IFF:
        newspec = (spec.car & (~spec.cdr)) | ((~spec.car) & spec.cdr)
                    
    elif spec.type == parser.EX:
        newspec = ax(~spec.car)
                                 
    elif spec.type == parser.EF:
        newspec = ag(~spec.car)
                                 
    elif spec.type == parser.EG:
        newspec = af(~spec.car)
                                 
    elif spec.type == parser.EU:
        newspec = aw(~spec.cdr, (~spec.car) & (~spec.cdr))
                    
    elif spec.type == parser.EW:
        newspec = au(~spec.cdr, (~spec.car) & (~spec.cdr))
                    
    elif spec.type == parser.AX:
        newspec = ex(~spec.car)
        
    elif spec.type == parser.AF:
        newspec = eg(~spec.car)
                                 
    elif spec.type == parser.AG:
        newspec = ef(~spec.car)
                                 
    elif spec.type == parser.AU:
        newspec = ew(~spec.cdr, (~spec.car) & (~spec.cdr))
                        
    elif spec.type == parser.AW:
        newspec = eu(~spec.cdr, (~spec.car) & (~spec.cdr))
                        
    else:
        if spec.type == parser.NOT:
            newspec = spec.car
        else:
            newspec = ~spec
        return Tlacenode(state, (newspec,), None, None)
        
    return witness(fsm, state, newspec, context)
Exemplo n.º 5
0
def witness_branch(fsm, state, spec, context, originalspec):
    """
    Return a TLACE branch explaining why state of fsm satisfies spec.

    fsm -- a pynusmv.fsm.BddFsm representing the system.
    state -- a pynusmv.dd.BDD representing a state of fsm.
    spec -- a pynusmv.spec.spec.Spec node representing the specification.
    context -- a pynusmv.spec.spec.Spec representing the context of spec in fsm.
    originalspec -- a pynusmv.spec.spec.Spec representing the original spec;
                    used to annotate the produced branch, despite updated
                    specs.

    Return a tlacebranch.Tlacebranch explaining why state of fsm satisfies spec.
    
    Throw a NonExistentialSpecError if spec is not existential.
    """
    
    if spec.type == parser.EX:
        f = eval_ctl_spec(fsm, spec.car, context)
        path = explainEX(fsm, state, f)
        branch = (Tlacenode(path[0]),
                  path[1],
                  witness(fsm, path[2], spec.car, context))
        return Tlacebranch(originalspec, branch)
        
    elif spec.type == parser.EF:
        newspec = eu(sptrue(), spec.car)
        return witness_branch(fsm, state, newspec, context, originalspec)
        
    elif spec.type == parser.EG:
        f = eval_ctl_spec(fsm, spec.car, context)
        (path, (inloop, loopstate)) = explainEG(fsm, state, f)
        
        branch = []
        # intermediate states
        for s, i in zip(path[::2], path[1::2]):
            wit = witness(fsm, s, spec.car, context)
            branch.append(wit)
            branch.append(i)
            # manage the loop
            if s == loopstate:
                loop = wit
        # last state
        branch.append(witness(fsm, path[-1], spec.car, context))
        
        return Tlacebranch(originalspec, tuple(branch), (inloop, loop))
        
    elif spec.type == parser.EU:
        f = eval_ctl_spec(fsm, spec.car, context)
        g = eval_ctl_spec(fsm, spec.cdr, context)
        path = explainEU(fsm, state, f, g)
        
        branch = []
        # intermediate states
        for s, i in zip(path[::2], path[1::2]):
            branch.append(witness(fsm, s, spec.car, context))
            branch.append(i)
        # last state
        branch.append(witness(fsm, path[-1], spec.cdr, context))
        
        return Tlacebranch(originalspec, tuple(branch))
        
    elif spec.type == parser.EW:
        euspec = eu(spec.car, spec.cdr)
        egspec = eg(spec.car)
        if state.entailed(eval_ctl_spec(fsm, euspec, context)):
            return witness_branch(fsm, state, euspec, context, originalspec)
        else:
            return witness_branch(fsm, state, egspec, context, originalspec)
        
    else:
        # Default case, throw an exception because spec is not existential
        raise NonExistentialSpecError()
Exemplo n.º 6
0
def countex(fsm, state, spec, context):
    """
    Return a TLACE node explaining why state of fsm violates spec.
    
    fsm -- a pynusmv.fsm.BddFsm representing the system.
    state -- a pynusmv.dd.BDD representing a state of fsm.
    spec -- a pynusmv.spec.spec.Spec node representing the specification.
    context -- a pynusmv.spec.spec.Spec representing the context of spec in fsm.
    
    Return a tlacenode.Tlacenode explaining why state of fsm violates spec.
    """

    if spec.type == parser.CONTEXT:
        return countex(fsm, state, spec.cdr, spec.car)

    elif spec.type == parser.FALSEEXP:
        newspec = sptrue()

    elif spec.type == parser.NOT:
        newspec = spec.car

    elif spec.type == parser.OR:
        newspec = (~spec.car) & (~spec.cdr)

    elif spec.type == parser.AND:
        newspec = (~spec.car) | (~spec.cdr)

    elif spec.type == parser.IMPLIES:
        newspec = spec.car & (~spec.cdr)

    elif spec.type == parser.IFF:
        newspec = (spec.car & (~spec.cdr)) | ((~spec.car) & spec.cdr)

    elif spec.type == parser.EX:
        newspec = ax(~spec.car)

    elif spec.type == parser.EF:
        newspec = ag(~spec.car)

    elif spec.type == parser.EG:
        newspec = af(~spec.car)

    elif spec.type == parser.EU:
        newspec = aw(~spec.cdr, (~spec.car) & (~spec.cdr))

    elif spec.type == parser.EW:
        newspec = au(~spec.cdr, (~spec.car) & (~spec.cdr))

    elif spec.type == parser.AX:
        newspec = ex(~spec.car)

    elif spec.type == parser.AF:
        newspec = eg(~spec.car)

    elif spec.type == parser.AG:
        newspec = ef(~spec.car)

    elif spec.type == parser.AU:
        newspec = ew(~spec.cdr, (~spec.car) & (~spec.cdr))

    elif spec.type == parser.AW:
        newspec = eu(~spec.cdr, (~spec.car) & (~spec.cdr))

    else:
        if spec.type == parser.NOT:
            newspec = spec.car
        else:
            newspec = ~spec
        return Tlacenode(state, (newspec, ), None, None)

    return witness(fsm, state, newspec, context)
Exemplo n.º 7
0
def witness_branch(fsm, state, spec, context, originalspec):
    """
    Return a TLACE branch explaining why state of fsm satisfies spec.

    fsm -- a pynusmv.fsm.BddFsm representing the system.
    state -- a pynusmv.dd.BDD representing a state of fsm.
    spec -- a pynusmv.spec.spec.Spec node representing the specification.
    context -- a pynusmv.spec.spec.Spec representing the context of spec in fsm.
    originalspec -- a pynusmv.spec.spec.Spec representing the original spec;
                    used to annotate the produced branch, despite updated
                    specs.

    Return a tlacebranch.Tlacebranch explaining why state of fsm satisfies spec.
    
    Throw a NonExistentialSpecError if spec is not existential.
    """

    if spec.type == parser.EX:
        f = eval_ctl_spec(fsm, spec.car, context)
        path = explainEX(fsm, state, f)
        branch = (Tlacenode(path[0]), path[1],
                  witness(fsm, path[2], spec.car, context))
        return Tlacebranch(originalspec, branch)

    elif spec.type == parser.EF:
        newspec = eu(sptrue(), spec.car)
        return witness_branch(fsm, state, newspec, context, originalspec)

    elif spec.type == parser.EG:
        f = eval_ctl_spec(fsm, spec.car, context)
        (path, (inloop, loopstate)) = explainEG(fsm, state, f)

        branch = []
        # intermediate states
        for s, i in zip(path[::2], path[1::2]):
            wit = witness(fsm, s, spec.car, context)
            branch.append(wit)
            branch.append(i)
            # manage the loop
            if s == loopstate:
                loop = wit
        # last state
        branch.append(witness(fsm, path[-1], spec.car, context))

        return Tlacebranch(originalspec, tuple(branch), (inloop, loop))

    elif spec.type == parser.EU:
        f = eval_ctl_spec(fsm, spec.car, context)
        g = eval_ctl_spec(fsm, spec.cdr, context)
        path = explainEU(fsm, state, f, g)

        branch = []
        # intermediate states
        for s, i in zip(path[::2], path[1::2]):
            branch.append(witness(fsm, s, spec.car, context))
            branch.append(i)
        # last state
        branch.append(witness(fsm, path[-1], spec.cdr, context))

        return Tlacebranch(originalspec, tuple(branch))

    elif spec.type == parser.EW:
        euspec = eu(spec.car, spec.cdr)
        egspec = eg(spec.car)
        if state.entailed(eval_ctl_spec(fsm, euspec, context)):
            return witness_branch(fsm, state, euspec, context, originalspec)
        else:
            return witness_branch(fsm, state, egspec, context, originalspec)

    else:
        # Default case, throw an exception because spec is not existential
        raise NonExistentialSpecError()
Exemplo n.º 8
0
 def test_eu(self):
     euspec = eu(sptrue(), spfalse())
     self.assertEqual(euspec.type, parser.EU)
     self.assertIsNotNone(euspec.car)
     self.assertIsNotNone(euspec.cdr)
Exemplo n.º 9
0
def ast_to_spec(ast):
    """
    Return a PyNuSMV specification representing `ast`.

    :param ast: an AST-based CTL formula
    :return: a PyNuSMV specification representing `ast`
    :rtype: :class:`pynusmv.prop.Spec`

    :raise: a :exc:`NotImplementedError` if an operator is not implemented
    """
    if isinstance(ast, TrueExp):
        return true()

    elif isinstance(ast, FalseExp):
        return false()

    elif isinstance(ast, Atom):
        return atom(ast.value)

    elif isinstance(ast, Not):
        return not_(ast_to_spec(ast.child))

    elif isinstance(ast, And):
        return and_(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, Or):
        return or_(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, Imply):
        return imply(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, Iff):
        return iff(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, AX):
        return ax(ast_to_spec(ast.child))

    elif isinstance(ast, AF):
        return af(ast_to_spec(ast.child))

    elif isinstance(ast, AG):
        return ag(ast_to_spec(ast.child))

    elif isinstance(ast, AU):
        return au(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, AW):
        return aw(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, EX):
        return ex(ast_to_spec(ast.child))

    elif isinstance(ast, EF):
        return ef(ast_to_spec(ast.child))

    elif isinstance(ast, EG):
        return eg(ast_to_spec(ast.child))

    elif isinstance(ast, EU):
        return eu(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, EW):
        return ew(ast_to_spec(ast.left), ast_to_spec(ast.right))

    # A(phi oU psi) <=> A(phi U (phi & psi))
    elif isinstance(ast, AoU):
        return au(ast_to_spec(ast.left),
                  and_(ast_to_spec(ast.left), ast_to_spec(ast.right)))

    # A(phi oW psi) <=> A(phi W (phi & psi))
    elif isinstance(ast, AoW):
        return aw(ast_to_spec(ast.left),
                  and_(ast_to_spec(ast.left), ast_to_spec(ast.right)))

    # A(phi dU psi) <=> A(phi U (!phi & psi))
    elif isinstance(ast, AdU):
        return au(ast_to_spec(ast.left),
                  and_(not_(ast_to_spec(ast.left)), ast_to_spec(ast.right)))

    # A(phi dW psi) <=> A(phi W (!phi & psi))
    elif isinstance(ast, AdW):
        return aw(ast_to_spec(ast.left),
                  and_(not_(ast_to_spec(ast.left)), ast_to_spec(ast.right)))

    # E(phi oU psi) <=> E(phi U (phi & psi))
    elif isinstance(ast, EoU):
        return eu(ast_to_spec(ast.left),
                  and_(ast_to_spec(ast.left), ast_to_spec(ast.right)))

    # E(phi oW psi) <=> E(phi W (phi & psi))
    elif isinstance(ast, EoW):
        return ew(ast_to_spec(ast.left),
                  and_(ast_to_spec(ast.left), ast_to_spec(ast.right)))

    # E(phi dU psi) <=> E(phi U (!phi & psi))
    elif isinstance(ast, EdU):
        return eu(ast_to_spec(ast.left),
                  and_(not_(ast_to_spec(ast.left)), ast_to_spec(ast.right)))

    # E(phi dW psi) <=> E(phi W (!phi & psi))
    elif isinstance(ast, EdW):
        return ew(ast_to_spec(ast.left),
                  and_(not_(ast_to_spec(ast.left)), ast_to_spec(ast.right)))

    else:
        raise NotImplementedError(NOT_IMPLEMENTED_MSG.format(op=type(ast)))
Exemplo n.º 10
0
def ast_to_spec(ast):
    """
    Return a PyNuSMV specification representing `ast`.

    :param ast: an AST-based CTL formula
    :return: a PyNuSMV specification representing `ast`
    :rtype: :class:`pynusmv.prop.Spec`

    :raise: a :exc:`NotImplementedError` if an operator is not implemented
    """
    if isinstance(ast, TrueExp):
        return true()

    elif isinstance(ast, FalseExp):
        return false()

    elif isinstance(ast, Atom):
        return atom(ast.value)

    elif isinstance(ast, Not):
        return not_(ast_to_spec(ast.child))

    elif isinstance(ast, And):
        return and_(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, Or):
        return or_(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, Imply):
        return imply(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, Iff):
        return iff(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, AX):
        return ax(ast_to_spec(ast.child))

    elif isinstance(ast, AF):
        return af(ast_to_spec(ast.child))

    elif isinstance(ast, AG):
        return ag(ast_to_spec(ast.child))

    elif isinstance(ast, AU):
        return au(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, AW):
        return aw(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, EX):
        return ex(ast_to_spec(ast.child))

    elif isinstance(ast, EF):
        return ef(ast_to_spec(ast.child))

    elif isinstance(ast, EG):
        return eg(ast_to_spec(ast.child))

    elif isinstance(ast, EU):
        return eu(ast_to_spec(ast.left), ast_to_spec(ast.right))

    elif isinstance(ast, EW):
        return ew(ast_to_spec(ast.left), ast_to_spec(ast.right))

    # A(phi oU psi) <=> A(phi U (phi & psi))
    elif isinstance(ast, AoU):
        return au(ast_to_spec(ast.left),
                  and_(ast_to_spec(ast.left), ast_to_spec(ast.right)))

    # A(phi oW psi) <=> A(phi W (phi & psi))
    elif isinstance(ast, AoW):
        return aw(ast_to_spec(ast.left),
                  and_(ast_to_spec(ast.left), ast_to_spec(ast.right)))

    # A(phi dU psi) <=> A(phi U (!phi & psi))
    elif isinstance(ast, AdU):
        return au(ast_to_spec(ast.left),
                  and_(not_(ast_to_spec(ast.left)), ast_to_spec(ast.right)))

    # A(phi dW psi) <=> A(phi W (!phi & psi))
    elif isinstance(ast, AdW):
        return aw(ast_to_spec(ast.left),
                  and_(not_(ast_to_spec(ast.left)), ast_to_spec(ast.right)))

    # E(phi oU psi) <=> E(phi U (phi & psi))
    elif isinstance(ast, EoU):
        return eu(ast_to_spec(ast.left),
                  and_(ast_to_spec(ast.left), ast_to_spec(ast.right)))

    # E(phi oW psi) <=> E(phi W (phi & psi))
    elif isinstance(ast, EoW):
        return ew(ast_to_spec(ast.left),
                  and_(ast_to_spec(ast.left), ast_to_spec(ast.right)))

    # E(phi dU psi) <=> E(phi U (!phi & psi))
    elif isinstance(ast, EdU):
        return eu(ast_to_spec(ast.left),
                  and_(not_(ast_to_spec(ast.left)), ast_to_spec(ast.right)))

    # E(phi dW psi) <=> E(phi W (!phi & psi))
    elif isinstance(ast, EdW):
        return ew(ast_to_spec(ast.left),
                  and_(not_(ast_to_spec(ast.left)), ast_to_spec(ast.right)))

    else:
        raise NotImplementedError(NOT_IMPLEMENTED_MSG.format(op=type(ast)))