Esempio n. 1
0
File: mc.py Progetto: yyaan/pynusmv
def explainEX(fsm, state, a):
    """
    Explain why `state` of `fsm` satisfies `EX phi`, where `a` is
    the set of states of `fsm` satisfying `phi`, represented by a BDD.

    :param fsm: the system
    :type fsm: :class:`BddFsm <pynusmv.fsm.BddFsm>`
    :param state: a state of `fsm`
    :type state: :class:`State <pynusmv.dd.State>`
    :param a: the set of states of `fsm` satisfying `phi`
    :type a: :class:`BDD <pynusmv.dd.BDD>`

    Return `(s, i, s')` tuple where `s` (:class:`State <pynusmv.dd.State>`)
    is the given state, `s'` (:class:`State <pynusmv.dd.State>`) is a successor
    of `s` belonging to `a` and `i` (:class:`Inputs <pynusmv.dd.Inputs>`)
    is the inputs to go from `s` to `s'` in `fsm`.

    """
    enc = fsm.bddEnc
    manager = enc.DDmanager
    path = nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(state._ptr)), None)
    bddlist = BDDList(nsmc.ex_explain(fsm._ptr, enc._ptr, path, a._ptr),
                      manager)

    # bddlist is reversed!
    statep = State.from_bdd(bddlist[0], fsm)
    inputs = Inputs.from_bdd(bddlist[1], fsm)
    state = State.from_bdd(bddlist[2], fsm)

    return (state, inputs, statep)
Esempio n. 2
0
File: dd.py Progetto: yyaan/pynusmv
    def from_tuple(bddtuple):
        """
        Create a node-based list from the Python tuple `bddtuple`.

        :param bddtuple: a Python tuple of BDDs

        Return a :class:`BDDList` representing the given tuple,
        using NuSMV nodes.
        All BDDs are assumed from the same DD manager;
        the created list contains the DD manager of the first non-`None` BDD.
        If all elements of `bddtuple` are `None`,
        the manager of the created :class:`BDDList` is `None`.
        """

        # Reverse tuple before, because we build the list reversely.
        bddtuple = bddtuple[::-1]
        nodes = None
        manager = None
        for elem in bddtuple:
            if elem:
                enode = nsnode.bdd2node(nsdd.bdd_dup(elem._ptr))
                if manager is None:
                    manager = elem._manager
            else:
                enode = elem
            nodes = nsnode.cons(enode, nodes)
        return BDDList(nodes, manager, freeit=True)
Esempio n. 3
0
File: dd.py Progetto: yyaan/pynusmv
    def __getitem__(self, val):
        """
        Return the BDD stored at val.

        :param val: the index requested OR a slice.

        .. note:: cannot access elements with negative indices.
        """
        if isinstance(val, int):
            if val < 0:
                raise IndexError("BDDList index out of range")
            ptr = self._ptr
            while val > 0:
                if ptr is None:
                    raise IndexError("BDDList index out of range")
                val -= 1
                ptr = nsnode.cdr(ptr)
            if ptr is None:
                raise IndexError("BDDList index out of range")
            bdd_ptr = nsnode.node2bdd(nsnode.car(ptr))
            if bdd_ptr is not None:
                return BDD(nsdd.bdd_dup(bdd_ptr), self._manager, freeit=True)
            else:
                return None

        elif isinstance(val, slice):
            # TODO Implement slicing
            raise NotImplementedError("BDDList slice not implemented")

        else:
            raise IndexError("BDDList index wrong type")
Esempio n. 4
0
File: mc.py Progetto: yyaan/pynusmv
def explain(fsm, state, spec, context=None):
    """
    Explain why `state` of `fsm` satisfies `spec` in `context`.

    :param fsm: the system
    :type fsm: :class:`BddFsm <pynusmv.fsm.BddFsm>`
    :param state: a state of `fsm`
    :type state: :class:`State <pynusmv.dd.State>`
    :param spec: a specification about `fsm`
    :type spec: :class:`Spec <pynusmv.prop.Spec>`
    :param context: the context in which evaluate `spec`
    :type context: :class:`Spec <pynusmv.prop.Spec>`

    Return a tuple `t` composed of states (:class:`State <pynusmv.dd.State>`)
    and inputs (:class:`Inputs <pynusmv.dd.Inputs>`),
    such that `t[0]` is `state` and `t` represents a path in `fsm` explaining
    why `state` satisfies `spec` in `context`.
    The returned path is looping if the last state of path is equal to a
    previous state along the path.

    """
    if context is not None:
        context_ptr = context._ptr
    else:
        context_ptr = None

    enc = fsm.bddEnc
    manager = enc.DDmanager
    path = nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(state._ptr)), None)

    expl = nsmc.explain(fsm._ptr, enc._ptr, path, spec._ptr, context_ptr)
    if expl is None:
        expl = nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(state._ptr)), None)

    bddlist = BDDList(expl, manager)
    bddlist = bddlist.to_tuple()

    path = []
    path.insert(0, State.from_bdd(bddlist[0], fsm))
    for i in range(1, len(bddlist), 2):
        inputs = Inputs.from_bdd(bddlist[i], fsm)
        state = State.from_bdd(bddlist[i + 1], fsm)

        path.insert(0, inputs)
        path.insert(0, state)

    return tuple(path)
Esempio n. 5
0
File: dd.py Progetto: yyaan/pynusmv
    def dup(self):
        """
        Return a copy of this BDD.

        """
        # Call to bdd_ptr bdd_dup (bdd_ptr);

        return BDD(nsdd.bdd_dup(self._ptr), self._manager, freeit=True)
Esempio n. 6
0
File: dd.py Progetto: yyaan/pynusmv
 def __iter__(self):
     ptr = self._ptr
     while ptr:
         # Yield BDD copy
         bdd_ptr = nsnode.node2bdd(nsnode.car(ptr))
         if bdd_ptr is not None:
             yield BDD(nsdd.bdd_dup(bdd_ptr), self._manager, freeit=True)
         else:
             yield None
         ptr = nsnode.cdr(ptr)
Esempio n. 7
0
File: dd.py Progetto: yyaan/pynusmv
    def from_bdd(bdd, fsm):
        """
        Return a new State of fsm from bdd.

        :param bdd: a BDD representing a single state
        :type bdd: :class:`BDD`
        :param fsm: the FSM from which the BDD comes from
        :type fsm: :class:`BddFsm <pynusmv.fsm.BddFsm>`

        """
        return State(nsdd.bdd_dup(bdd._ptr), fsm)
Esempio n. 8
0
File: dd.py Progetto: yyaan/pynusmv
    def from_bdd(bdd, fsm):
        """
        Return a new Inputs of fsm from bdd.

        :param bdd: a BDD representing a single inputs variables
                    valuation
        :type bdd: :class:`BDD`
        :param fsm: the FSM from which the BDD comes from
        :type fsm: :class:`BddFsm <pynusmv.fsm.BddFsm>`

        """
        return Inputs(nsdd.bdd_dup(bdd._ptr), fsm)
Esempio n. 9
0
File: mc.py Progetto: yyaan/pynusmv
def explainEG(fsm, state, a):
    """
    Explain why `state` of `fsm` satisfies `EG phi`, where `a` the set of
    states of `fsm` satisfying `phi`, represented by a BDD.

    :param fsm: the system
    :type fsm: :class:`BddFsm <pynusmv.fsm.BddFsm>`
    :param state: a state of `fsm`
    :type state: :class:`State <pynusmv.dd.State>`
    :param a: the set of states of `fsm` satisfying `phi`
    :type a: :class:`BDD <pynusmv.dd.BDD>`

    Return a tuple `(t, (i, loop))`
    where `t` is a tuple composed of states (:class:`State <pynusmv.dd.State>`)
    and inputs (:class:`Inputs <pynusmv.dd.Inputs>`),
    such that `t[0]` is state and every other state of `t`
    belongs to `a`. The states of `t` are separated by inputs.
    Furthermore, `t` represents a path in `fsm`.
    `loop` represents the start of the loop contained in `t`,
    i.e. `t[-1]` can lead to `loop` through `i`, and `loop` is a state of `t`.

    """
    enc = fsm.bddEnc
    manager = enc.DDmanager
    path = nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(state._ptr)), None)
    bddlist = BDDList(nsmc.eg_explain(fsm._ptr, enc._ptr, path, a._ptr),
                      manager)
    bddlist = bddlist.to_tuple()

    path = []
    # Discard last state and input, store them as loop indicators
    loopstate = State.from_bdd(bddlist[0], fsm)
    loopinputs = Inputs.from_bdd(bddlist[1], fsm)

    # Consume first state
    curstate = State.from_bdd(bddlist[2], fsm)
    if curstate._ptr == loopstate._ptr:
        loopstate = curstate

    path.insert(0, curstate)

    for i in range(3, len(bddlist), 2):
        inputs = Inputs.from_bdd(bddlist[i], fsm)
        curstate = State.from_bdd(bddlist[i + 1], fsm)
        if curstate._ptr == loopstate._ptr:
            loopstate = curstate

        path.insert(0, inputs)
        path.insert(0, curstate)
    return (tuple(path), (loopinputs, loopstate))
Esempio n. 10
0
File: mc.py Progetto: yyaan/pynusmv
def explainEU(fsm, state, a, b):
    """
    Explain why `state` of `fsm` satisfies `E[phi U psi]`,
    where `a is the set of states of `fsm` satisfying `phi`
    and `b` is the set of states of `fsm` satisfying `psi`, both represented
    by BDDs.

    :param fsm: the system
    :type fsm: :class:`BddFsm <pynusmv.fsm.BddFsm>`
    :param state: a state of `fsm`
    :type state: :class:`State <pynusmv.dd.State>`
    :param a: the set of states of `fsm` satisfying `phi`
    :type a: :class:`BDD <pynusmv.dd.BDD>`
    :param b: the set of states of `fsm` satisfying `psi`
    :type b: :class:`BDD <pynusmv.dd.BDD>`

    Return a tuple `t` composed of states (:class:`State <pynusmv.dd.State>`)
    and inputs (:class:`Inputs <pynusmv.dd.Inputs>`),
    such that `t[0]` is `state`, `t[-1]` belongs to `b`, and every other state
    of `t` belongs to `a`. The states of `t` are separated by inputs.
    Furthermore, `t` represents a path in `fsm`.

    """
    enc = fsm.bddEnc
    manager = enc.DDmanager
    path = nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(state._ptr)), None)
    bddlist = BDDList(nsmc.eu_explain(fsm._ptr, enc._ptr,
                                      path, a._ptr, b._ptr), manager)
    bddlist = bddlist.to_tuple()

    path = []
    path.insert(0, State.from_bdd(bddlist[0], fsm))
    for i in range(1, len(bddlist), 2):
        inputs = Inputs.from_bdd(bddlist[i], fsm)
        state = State.from_bdd(bddlist[i + 1], fsm)

        path.insert(0, inputs)
        path.insert(0, state)

    return tuple(path)
Esempio n. 11
0
File: mc.py Progetto: yyaan/pynusmv
def check_explain_ltl_spec(spec):
    """
    Return whether the loaded SMV model satisfies or not the LTL given `spec`,
    that is, whether all initial states of le model satisfies `spec` or not.
    Return also an explanation for why the model does not satisfy `spec`,
    if it is the case, or `None` otherwise.
    
    The result is a tuple where the first element is a boolean telling whether
    `spec` is satisfied, and the second element is either `None` if the first
    element is `True`, or a path of the SMV model violating `spec` otherwise.
    
    The explanation is a tuple of alternating states and inputs, starting and
    ennding with a state. The path is looping if the last state is somewhere
    else in the sequence. States and inputs are represented by dictionaries
    where keys are state and inputs variable of the loaded SMV model, and
    values are their value.

    :param spec: a specification
    :type spec: :class:`Spec <pynusmv.prop.Spec>`
    :rtype: tuple

    """
    # Check that a model has been compiled
    assert(glob.prop_database().master is not None)
    
    # Create a property from the given spec
    prop = nsprop.Prop_create_partial(spec._ptr, propTypes["LTL"])
    
    # Save settings
    o = nsopt.OptsHandler_get_enum_option_value(
            nsopt.OptsHandler_get_instance(),
            "oreg_justice_emptiness_bdd_algorithm")
    if (nscompile.
            FlatHierarchy_get_compassion(glob.
                                         global_compile_flathierarchy())
            is None and
            o == nsfsmbdd.BDD_OREG_JUSTICE_EMPTINESS_BDD_ALGORITHM_EL_FWD):
        
        saved_options = nsfsmbdd.Bdd_elfwd_check_set_and_save_options(
                            nsfsmbdd.BDD_ELFWD_OPT_ALL)
    else:
        saved_options = None
    
    # Create, build and check the structure for LTL model checking
    ltl_struct = nsltl.Ltl_StructCheckLtlSpec_create(prop)
    nsltl.Ltl_StructCheckLtlSpec_build(ltl_struct)
    nsltl.Ltl_StructCheckLtlSpec_check(ltl_struct)
    
    # Get the result
    result = nsprop.Prop_get_status(prop) == nsprop.Prop_True
    
    # explain
    if not result:
        # Extract explanation
        bdd_fsm = BddFsm(ltl_struct.fsm)
        
        full_fairness = (not nsfsmbdd.FairnessList_is_empty(
                             nsfsmbdd.compassionList2fairnessList(
                             nsfsmbdd.BddFsm_get_compassion(bdd_fsm._ptr))))
        
        # Counterexample construction for forward Emerson-Lei not yet
        # implemented
        assert(full_fairness or not o)

        tmp = BDD(nsencbdd.BddEnc_pick_one_state(ltl_struct.bdd_enc,
                                                 ltl_struct.s0),
                  dd_manager=DDManager(nsencbdd.BddEnc_get_dd_manager(
                                       ltl_struct.bdd_enc)))
        
        if full_fairness:
            exp = BDDList(nsltl.witness(bdd_fsm._ptr,
                                        ltl_struct.bdd_enc,
                                        tmp._ptr),
                          ddmanager=tmp._manager)
        else:
            path = nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(tmp._ptr)), None)
            exp = BDDList(nsnode.reverse(
                          nsmc.explain(bdd_fsm._ptr,
                                       ltl_struct.bdd_enc,
                                       path,
                                       ltl_struct.spec_formula,
                                       None)),
                          ddmanager=tmp._manager)
        
        if exp is None: # The counterexample consists of one initial state
            exp = BDDList(nsnode.cons(nsnode.bdd2node(nsdd.bdd_dup(tmp._ptr)),
                                      None),
                          ddmanager=tmp._manager)
        exp = exp.to_tuple()

        # removes all the tableau variables from the result before
        # building the resulting trace. This will make simulation
        # working, but may show unexistent loops in the shown trace
        def clean(bdd):
            tableau_cube = Cube(nsencbdd.BddEnc_get_layer_vars_cube(
                                    ltl_struct.bdd_enc,
                                    ltl_struct.tableau_layer,
                                    nssymb_table.VFT_ALL),
                                dd_manager=bdd._manager)
            return bdd.forsome(tableau_cube)
        
        # exp has at least one element
        explanation = [bdd_fsm.pick_one_state(clean(exp[0])).get_str_values()]
        for inputs_bdd, state_bdd in zip(exp[1::2], exp[2::2]):
            explanation.append(bdd_fsm.pick_one_inputs(
                               clean(inputs_bdd))
                               .get_str_values())
            explanation.append(bdd_fsm.pick_one_state(
                               clean(state_bdd))
                               .get_str_values())
    else:
        explanation = None
    
    # Destroy the intermediate structure
    nsltl.Ltl_StructCheckLtlSpec_destroy(ltl_struct)
    
    # Restore settings
    if saved_options is not None:
        nsfsmbdd.Bdd_elfwd_restore_options(nsfsmbdd.BDD_ELFWD_OPT_ALL,
                                           saved_options)
    
    # Destroy prop
    nsprop.Prop_destroy(prop)
    
    return (result, explanation if explanation is None else tuple(explanation))