Exemplo n.º 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
Exemplo n.º 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
Exemplo n.º 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
Exemplo n.º 4
0
def print_info(markdown: bool = False):
    """
    prints repository info
    """

    header = [("name", "size", "inputs", "constants", "steady states", "cyclic attractors (mints)")]
    data = []
    for name in get_all_names():
        primes = get_primes(name)
        tspaces = compute_trap_spaces(primes, "min", max_output=MAX_OUTPUT)

        size = str(len(primes))
        inputs = str(len(find_inputs(primes)))
        constants = str(len(find_constants(primes)))
        steady = len([x for x in tspaces if len(x) == len(primes)])
        steady = str(steady) + '+'*(steady == MAX_OUTPUT)
        cyclic = len([x for x in tspaces if len(x) < len(primes)])
        cyclic = str(cyclic) + '+'*(steady == MAX_OUTPUT)

        data.append((name, size, inputs, constants, steady, cyclic))

    data.sort(key=lambda x: int(x[1]))
    data = header + data

    width = {}
    for i in range(len(data[0])):
        width[i] = max(len(x[i]) for x in data) + 2

    if markdown:
        header = '| ' + ' | '.join(x.ljust(width[i]) for i, x in enumerate(data[0])) + ' |'
        print(header)
        print('| ' + ' | '.join('-'*width[i] for i, x in enumerate(data[0])) + ' |')

        body   = data[1:]
        for row in body:
            print('| ' + ' | '.join(x.ljust(width[i]) for i, x in enumerate(row)) + ' |')

    else:
        for row in data:
            print(''.join(x.ljust(width[i]) for i,x in enumerate(row)))
Exemplo n.º 5
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
Exemplo n.º 6
0
def primes2bnet(primes: dict,
                fname_bnet: str = None,
                minimize: bool = False,
                header: bool = False) -> str:
    """
    Saves *primes* as a *bnet* file, including the header *"targets, factors"* for compatibility with :ref:`installation_boolnet`.
    Without minimization, the resuting formulas are disjunctions of all prime implicants and may therefore be very long.
    If *Minimize=True* then a Python version of the Quine-McCluskey algorithm,
    namely :ref:`Prekas2012 <Prekas2012>` which is implemented in :ref:`QuineMcCluskey.primes2mindnf <primes2mindnf>`,
    will be used to minimize the number of clauses for each update function.

    **arguments**:
        * *primes*: prime implicants
        * *fname_bnet*: name of *bnet* file or *None* for the string of the file contents
        * *minimize*: minimize the Boolean expressions
        * *header*: whether to include the "targets, factors" header

    **returns**:
        * *text_bnet*: str contents of bnet file

    **example**::

        >>> primes2bnet(primes, "mapk.bnet")
        >>> primes2bnet(primes, "mapk.bnet", True)
        >>> expr = primes2bnet(primes)
        >>> expr = primes2bnet(primes, True)
    """

    width = max([len(x) for x in primes]) + 3
    igraph = primes2igraph(primes)
    constants = sorted(find_constants(primes))
    inputs = sorted(find_inputs(primes))
    outdag = sorted(find_outdag(igraph))
    outdag = [x for x in outdag if x not in constants]
    body = sorted(x for x in primes
                  if all(x not in X for X in [constants, inputs, outdag]))
    blocks = [constants, inputs, body, outdag]
    blocks = [x for x in blocks if x]

    assert len(constants) + len(inputs) + len(body) + len(outdag) == len(
        primes)

    lines = []
    if header:
        lines += ["targets, factors"]

    if minimize:
        expressions = primes2mindnf(primes)
        for block in blocks:
            for name in block:
                lines += [f"{name + ',': <{width}} {expressions[name]}"]
            lines += [""]

    else:
        for block in blocks:
            for name in block:
                expression = get_dnf(one_implicants=primes[name][1])
                lines += [f"{name+',': <{width}} {expression}"]
            lines += [""]

    text = "\n".join(lines)

    if fname_bnet:
        with open(fname_bnet, "w") as fp:
            fp.writelines(text)
            log.info(f"created {fname_bnet}")

    return text
from pyboolnet.file_exchange import bnet2primes, primes2bnet
from pyboolnet.prime_implicants import find_constants, create_variables
from pyboolnet.repository import get_primes

if __name__ == "__main__":
    bnet = """
    v1,    !v1
    v2,    1
    v3,    v2 & (!v1 | v3)
    """

    primes = bnet2primes(bnet)

    # finding nodes

    const = find_constants(primes)
    print(const)

    # modifying networks

    create_variables(primes, {"v4": "v4 | v2"})
    create_variables(primes, {"v5": lambda v1, v2, v3: v1 + v2 + v3 == 1})

    print(primes2bnet(primes))

    # reading from the repository

    primes = get_primes("remy_tumorigenesis")
    print(primes2bnet(primes))