Example #1
0
def faithfulness(primes: dict, update: str, trap_space: Union[dict,
                                                              str]) -> bool:
    """
    The model checking approach for deciding whether *trap_space* is faithful,
    i.e., whether all free variables oscillate in all of the attractors contained in it,
    in the state transition graph defined by *primes* and *update*.
    The approach is described and discussed in :ref:`Klarner2015(a) <klarner2015trap>`.
    It is decided by a single CTL query of the pattern :ref:`EF_all_unsteady <EF_all_unsteady>`
    and the random-walk-approach of the function :ref:`random_walk <random_walk>`.

    .. note::
        In the (very unlikely) case that the random walk does not end in an attractor state an exception will be raised.

    .. note::
        Faithfulness depends on the update strategy, i.e.,
        a trapspace may be faithful in the synchronous STG but not faithful in the asynchronous STG or vice versa.

    .. note::
        A typical use case is to decide whether a minimal trap space is faithful.

    .. note::
        *trap_space* is in fact not required to be a trap set, i.e., it may be an arbitrary subspace.
        If it is an arbitrary subspace then the involved variables are artificially fixed to be constant.

    **arguments**:
        * *primes*: prime implicants
        * *update*: the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
        * *trap_space*: a subspace

    **returns**:
        * *answer*: whether *trap_space* is faithful in the STG defined by *primes* and *update*

    **example**::

        >>> mintspaces = compute_trap_spaces(primes, "min")
        >>> x = mintspaces[0]
        >>> faithfulness(primes, x)
        True
    """

    if len(trap_space) == len(primes):
        return True

    primes = copy_primes(primes=primes)
    create_constants(primes=primes, constants=trap_space)
    percolate(primes=primes, remove_constants=True)
    constants = find_constants(primes=primes)

    if len(constants) > len(trap_space):
        return False

    formula = exists_finally_unsteady_components(names=list(primes))
    spec = f"CTLSPEC AG({formula})"
    init = "INIT TRUE"
    answer = model_checking(primes=primes,
                            update=update,
                            initial_states=init,
                            specification=spec)

    return answer
Example #2
0
def faithfulness_with_counterexample(primes: dict, update: str,
                                     trap_space: dict) -> (bool, List[dict]):
    """
    Performs the same steps as :ref:`faithfulness` but also returns a counterexample which is *None* if it does not exist.
    A counterexample of a faithful test is a state that belongs to an attractor which has more fixed variables than there are in *trap_space*.

    **arguments**:
        * *primes*: prime implicants
        * *update*: the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
        * *trap_space*: a subspace

    **returns**:
        * *answer*: whether *trap_space* is faithful in the STG defined by *primes* and *update*
        * *counter_example*: a state that belongs to an attractor that does not oscillate in all free variables or *None* if no counterexample exists

    **example**::

        >>> mintspaces = compute_trap_spaces(primes, "min")
        >>> x = mintspaces[0]
        >>> faithfulness(primes, x)
        True
    """

    if len(trap_space) == len(primes):
        return True, None

    primes = percolate(primes=primes, add_constants=trap_space, copy=True)
    constants = find_constants(primes=primes)
    remove_all_constants(primes=primes)

    if len(constants) > len(trap_space):
        counterexample = find_attractor_state_by_randomwalk_and_ctl(
            primes=primes, update=update)
        attractor_state = merge_dicts(dicts=[counterexample, constants])

        return False, attractor_state

    spec = f"CTLSPEC AG({exists_finally_unsteady_components(names=list(primes))})"
    answer, counterexample = model_checking(primes=primes,
                                            update=update,
                                            initial_states="INIT TRUE",
                                            specification=spec,
                                            enable_counterexample=True)

    if answer:
        return True, None

    else:
        attractor_state = find_attractor_state_by_randomwalk_and_ctl(
            primes=primes, update=update, initial_state=counterexample[-1])
        attractor_state = merge_dicts(dicts=[attractor_state, constants])

        return False, attractor_state
Example #3
0
def univocality_with_counterexample(
        primes: dict, update: str,
        trap_space: Union[dict, str]) -> (bool, List[dict]):
    """
    Performs the same steps as :ref:`univocality` but also returns a counterexample which is *None* if it does not exist.
    A counterexample of a univocality test are two states that belong to different attractors.

    **arguments**:
        * *primes*: prime implicants
        * *update*: the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
        * *trap_space*: a subspace

    **returns**:
        * *answer*: whether *trap_space* is univocal in the STG defined by *primes* and *update*
        * *counter_example*: two states that belong to different attractors or *None* if no counterexample exists

    **example**::

        >>> mintspaces = compute_trap_spaces(primes, "min")
        >>> trapspace = mintrapspaces[0]
        >>> answer, counterex = univocality_with_counterexample(primes, trapspace, "asynchronous")
    """

    primes = percolate(primes=primes, add_constants=trap_space, copy=True)
    constants = find_constants(primes=primes)
    remove_all_constants(primes=primes)

    if primes == {}:
        return True, None

    attractor_state = find_attractor_state_by_randomwalk_and_ctl(primes=primes,
                                                                 update=update)
    spec = f"CTLSPEC {exists_finally_one_of_subspaces(primes=primes, subspaces=[attractor_state])}"
    init = "INIT TRUE"
    answer, counterexample = model_checking(primes=primes,
                                            update=update,
                                            initial_states=init,
                                            specification=spec,
                                            enable_counterexample=True)

    if answer:
        return True, None

    else:
        attractor_state2 = find_attractor_state_by_randomwalk_and_ctl(
            primes=primes, update=update, initial_state=counterexample[-1])
        attractor_state2 = merge_dicts(dicts=[attractor_state2, constants])
        attractor_state = merge_dicts(dicts=[attractor_state, constants])
        counterexample = attractor_state, attractor_state2

        return False, counterexample
Example #4
0
def iterative_completeness_algorithm(
        primes: dict,
        update: str,
        compute_counterexample: bool,
        max_output: int = 1000) -> Union[Tuple[bool, Optional[dict]], bool]:
    """
    The iterative algorithm for deciding whether the minimal trap spaces are complete.
    The function is implemented by line-by-line following of the pseudo code algorithm given in
    "Approximating attractors of Boolean networks by iterative CTL model checking", Klarner and Siebert 2015.

    **arguments**:
        * *primes*: prime implicants
        * *update*: the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
        * *compute_counterexample*: whether to compute a counterexample

    **returns**:
        * *answer*: whether *subspaces* is complete in the STG defined by *primes* and *update*,
        * *counterexample*: a state that can not reach one of the minimal trap spaces of *primes* or *None* if no counterexample exists

    **example**::

        >>> answer, counterexample = completeness_with_counterexample(primes, "asynchronous")
        >>> answer
        False
        >>> state2str(counterexample)
        10010111101010100001100001011011111111
    """

    primes = percolate(primes=primes, copy=True)
    constants_global = find_constants(primes=primes)
    remove_all_constants(primes=primes)

    min_trap_spaces = compute_trap_spaces(primes=primes,
                                          type_="min",
                                          max_output=max_output)
    if min_trap_spaces == [{}]:
        if compute_counterexample:
            return True, None
        else:
            return True

    current_set = [({}, set([]))]
    while current_set:
        p, w = current_set.pop()
        primes_reduced = copy_primes(primes=primes)
        create_constants(primes=primes_reduced, constants=p)
        igraph = primes2igraph(primes=primes_reduced)

        cgraph = digraph2condensationgraph(digraph=igraph)
        cgraph_dash = cgraph.copy()

        for U in cgraph.nodes():
            if set(U).issubset(set(w)):
                cgraph_dash.remove_node(U)

        w_dash = w.copy()
        refinement = []
        top_layer = [
            U for U in cgraph_dash.nodes() if cgraph_dash.in_degree(U) == 0
        ]

        for U in top_layer:
            u_dash = find_ancestors(igraph, U)

            primes_restricted = copy_primes(primes_reduced)
            remove_all_variables_except(primes=primes_restricted, names=u_dash)

            q = compute_trap_spaces(primes=primes_restricted,
                                    type_="min",
                                    max_output=max_output)

            phi = exists_finally_one_of_subspaces(primes=primes_restricted,
                                                  subspaces=q)

            init = "INIT TRUE"
            spec = f"CTLSPEC {phi}"

            if compute_counterexample:
                answer, counterexample = model_checking(
                    primes=primes_restricted,
                    update=update,
                    initial_states=init,
                    specification=spec,
                    enable_counterexample=True)
                if not answer:
                    downstream = [x for x in igraph if x not in U]
                    arbitrary_state = random_state(downstream)
                    top_layer_state = counterexample[-1]
                    counterexample = merge_dicts([
                        constants_global, p, top_layer_state, arbitrary_state
                    ])

                    return False, counterexample
            else:
                answer = model_checking(primes=primes_restricted,
                                        update=update,
                                        initial_states=init,
                                        specification=spec)
                if not answer:
                    return False

            refinement += intersection([p], q)
            w_dash.update(u_dash)

        for q in intersection(refinement):
            q_tilde = find_constants(
                primes=percolate(primes=primes, add_constants=q, copy=True))

            if q_tilde not in min_trap_spaces:
                current_set.append((q_tilde, w_dash))

    if compute_counterexample:
        return True, None
    else:
        return True
Example #5
0
def univocality(primes: dict, update: str, trap_space: Union[dict,
                                                             str]) -> bool:
    """
    The model checking and random-walk-based method for deciding whether *trap_space* is univocal,
    i.e., whether there is a unique attractor contained in it,
    in the state transition graph defined by *primes* and *update*.
    The approach is described and discussed in :ref:`Klarner2015(a) <klarner2015trap>`.
    The function performs two steps: first it searches for a state that belongs to an attractor inside of *trap_space* using
    the random-walk-approach and the function :ref:`random_walk <random_walk>`,
    then it uses CTL model checking, specifically the pattern :ref:`AGEF_oneof_subspaces <AGEF_oneof_subspaces>`,
    to decide if the attractor is unique inside *trap_space*.

    .. note::
        In the (very unlikely) case that the random walk does not end in an attractor state an exception will be raised.

    .. note::
        Univocality depends on the update strategy, i.e.,
        a trapspace may be univocal in the synchronous STG but not univocal in the asynchronous STG or vice versa.

    .. note::
        A typical use case is to decide whether a minimal trap space is univocal.

    .. note::
        *trap_space* is in fact not required to be a trap set, i.e., it may be an arbitrary subspace.
        If it is an arbitrary subspace then the involved variables are artificially fixed to be constant.

    **arguments**:
        * *primes*: prime implicants
        * *update*: the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
        * *trap_space*: a subspace

    **returns**:
        * *answer*: whether *trap_space* is univocal in the STG defined by *primes* and *update*

    **example**::

        >>> mintspaces = compute_trap_spaces(primes, "min")
        >>> x = mintrapspaces[0]
        >>> univocality(primes, "asynchronous", x)
        True
    """

    primes = copy_primes(primes=primes)
    create_constants(primes=primes, constants=trap_space)
    percolate(primes=primes, remove_constants=True)

    if primes == {}:
        return True

    attractor_state = find_attractor_state_by_randomwalk_and_ctl(primes=primes,
                                                                 update=update)

    formula = exists_finally_one_of_subspaces(primes=primes,
                                              subspaces=[attractor_state])
    spec = f"CTLSPEC {formula}"
    init = "INIT TRUE"
    answer = model_checking(primes=primes,
                            update=update,
                            initial_states=init,
                            specification=spec)

    return answer