コード例 #1
0
def test_completeness():
    bnet = "\n".join([
        "v0,   v0", "v1,   v2", "v2,   v1", "v3,   v1&v0", "v4,   v2",
        "v5,   v3&!v6", "v6,   v4&v5"
    ])
    primes = bnet2primes(bnet)

    assert completeness(primes, "asynchronous")
    assert not completeness(primes, "synchronous")

    answer, example = completeness_with_counterexample(primes, "synchronous")
    example = state2str(example)
    stg = primes2stg(primes, "synchronous")

    for x in compute_trap_spaces(primes, "min"):
        x = subspace2str(primes, x)

        states = list_states_in_subspace(primes, x)
        states = [state2str(x) for x in states]

        assert not has_path(stg, example, states)

    bnet = "\n".join([
        "v1, !v1&v2&v3 | v1&!v2&!v3", "v2, !v1&!v2 | v1&v3",
        "v3, !v1&v3 | v1&v2", "v4, 1", "v5, v4"
    ])
    primes = bnet2primes(bnet)

    assert not completeness(primes, "asynchronous")

    answer, example = completeness_with_counterexample(primes, "asynchronous")

    assert len(example) == len(primes)
    assert completeness(primes, "synchronous")

    bnet = "\n".join(
        ["v1, !v1&v2&v3 | v1&!v2&!v3", "v2, !v1&!v2 | v1&v3", "v3, v2 | v3"])
    primes = bnet2primes(bnet)

    assert completeness(primes, "asynchronous")
    assert completeness(primes, "synchronous")

    bnet = "\n".join([
        "v1,   !v2", "v2,   v1", "v3,   v1", "v4,   v2", "v5,   v6",
        "v6,   v4&v5", "v7,   v2", "v8,   v5", "v9,   v6&v10", "v10,  v9&v7"
    ])
    primes = bnet2primes(bnet)

    assert completeness(primes, "synchronous")
コード例 #2
0
def add_style_path(stg: networkx.DiGraph,
                   path: Union[List[str], List[dict]],
                   color: str,
                   pen_width: int = 3):
    """
    Sets the color of all nodes and edges involved in the given *path* to *color*.

    **arguments**:
        * *stg*: state transition graph
        * *path*: state dictionaries or state strings
        * *color*: color of the path
        * *pen_width*: width of nodes and edges involved in *path* in pt

    **example**::

        >>> path = ["001", "011", "101"]
        >>> add_style_path(stg, path, "red")
    """

    assert path is not None

    path = [state2str(x) for x in path]

    for x in path:
        stg.nodes[x]["color"] = color
        stg.nodes[x]["penwidth"] = pen_width

    if len(path) > 1:
        for x, y in zip(path[:-1], path[1:]):
            stg.adj[x][y]["color"] = color
            stg.adj[x][y]["penwidth"] = pen_width
コード例 #3
0
def test_find_attractor_state_by_randomwalk_and_ctl():
    fname_in = get_tests_path_in(fname="randomnet.bnet")
    fname_out = get_tests_path_out(fname="randomnet.primes")
    primes = bnet2primes(bnet=fname_in, fname_primes=fname_out)

    subspace = {"Gene1": 0, "Gene3": 0, "Gene5": 0, "Gene7": 0, "Gene9": 0}
    length = 200
    attempts = 10

    min_trap_spaces = {
        "Gene1": 1,
        "Gene11": 0,
        "Gene12": 1,
        "Gene13": 0,
        "Gene14": 1,
        "Gene15": 0,
        "Gene16": 1,
        "Gene17": 1,
        "Gene18": 1,
        "Gene19": 0,
        "Gene2": 1,
        "Gene20": 1,
        "Gene3": 0,
        "Gene4": 1,
        "Gene5": 0,
        "Gene6": 0,
        "Gene8": 0,
        "Gene9": 0
    }

    x = find_attractor_state_by_randomwalk_and_ctl(primes, "asynchronous",
                                                   subspace, length, attempts)
    assert state_is_in_subspace(primes, x, min_trap_spaces)

    y = find_attractor_state_by_randomwalk_and_ctl(primes, "synchronous",
                                                   subspace, length, attempts)
    reachable = list_reachable_states(primes, "synchronous", y, 100)

    assert state2str(y) in reachable

    z = find_attractor_state_by_randomwalk_and_ctl(primes, "mixed", subspace,
                                                   length, attempts)
    assert state_is_in_subspace(primes, z, min_trap_spaces)
コード例 #4
0
ファイル: attractors.py プロジェクト: carissableker/PyBoolNet
def compute_attractors(primes: dict,
                       update: str,
                       fname_json: Optional[str] = None,
                       check_completeness: bool = True,
                       check_faithfulness: bool = True,
                       check_univocality: bool = True,
                       max_output: int = 1000) -> dict:
    """
    computes all attractors of *primes* including information about completeness, univocality, faithfulness

    **arguments**:
      * *primes*: prime implicants
      * *update*: the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
      * *fname_json*: json file name to save result
      * *check_completeness*: enable completeness check
      * *check_faithfulness*: enable faithfulness check
      * *check_univocality*: enable univocality check

    **returns**:
        * *attractors*: attractor data

    **example**::
      >>> attractors = compute_attractors(primes, update, "attractors.json")
    """

    assert update in UPDATE_STRATEGIES
    assert primes

    attractors = dict()
    attractors["primes"] = copy_primes(primes)
    attractors["update"] = update

    min_tspaces = compute_trap_spaces(primes=primes,
                                      type_="min",
                                      max_output=max_output)

    if check_completeness:
        log.info("attractors.completeness(..)")
        if completeness(primes, update, max_output=max_output):
            attractors["is_complete"] = "yes"
        else:
            attractors["is_complete"] = "no"
        log.info(f"{attractors['is_complete']}")
    else:
        attractors["is_complete"] = "unknown"

    attractors["attractors"] = []

    for i, mints in enumerate(min_tspaces):

        mints_obj = dict()
        mints_obj["str"] = subspace2str(primes=primes, subspace=mints)
        mints_obj["dict"] = mints
        mints_obj["prop"] = subspace2proposition(primes=primes, subspace=mints)

        log.info(
            f" working on minimal trapspace {i+1}/{len(min_tspaces)}: {mints_obj['str']}"
        )

        if check_univocality:
            log.info("attractors.univocality(..)")
            if univocality(primes=primes, update=update, trap_space=mints):
                mints_obj["is_univocal"] = "yes"
            else:
                mints_obj["is_univocal"] = "no"
            log.info(f" {mints_obj['is_univocal']}")
        else:
            mints_obj["is_univocal"] = "unknown"

        if check_faithfulness:
            log.info("attractors.faithfulness(..)")
            if faithfulness(primes=primes, update=update, trap_space=mints):
                mints_obj["is_faithful"] = "yes"
            else:
                mints_obj["is_faithful"] = "no"
            log.info(f"{mints_obj['is_faithful']}")
        else:
            mints_obj["is_faithful"] = "unknown"

        log.info("attractors.find_attractor_state_by_randomwalk_and_ctl(..)")
        state = find_attractor_state_by_randomwalk_and_ctl(primes=primes,
                                                           update=update,
                                                           initial_state=mints)

        state_obj = dict()
        state_obj["str"] = state2str(state)
        state_obj["dict"] = state
        state_obj["prop"] = subspace2proposition(primes, state)

        attractor_obj = dict()
        attractor_obj["min_trap_space"] = mints_obj
        attractor_obj["state"] = state_obj
        attractor_obj["is_steady"] = len(mints) == len(primes)
        attractor_obj["is_cyclic"] = len(mints) != len(primes)

        attractors["attractors"].append(attractor_obj)

    attractors["attractors"] = tuple(
        sorted(attractors["attractors"], key=lambda x: x["state"]["str"]))

    if fname_json:
        write_attractors_json(attractors, fname_json)

    return attractors
コード例 #5
0
def best_first_reachability(primes: dict,
                            initial_space: Union[str, dict],
                            goal_space: Union[str, dict],
                            memory: int = 1000):
    """
    Performs a best-first search in the asynchronous transition system defined by *primes* to answer the question whether there
    is a path from a random state in *InitalSpace* to a state in *GoalSpace*.
    *Memory* specifies the maximal number of states that can be kept in memory as "already explored" before the algorithm terminates.
    The search is guided by minimizing the Hamming distance between the current state of an incomplete path and the *GoalSpace*
    where variables that are free in *GoalSpace* are ignored.

    .. note::
        If the number of variables is less than 40 you should use LTL or CTL model checking to answer questions of reachability.
        :ref:`best_first_reachability` is meant for systems with more than 40 variables.
        If :ref:`best_first_reachability` returns *None* then that does not prove that there is no path between *InitialSpace* and *GoalSpace*.

    **arguments**:
        * *primes*: prime implicants
        * *initial_space*: initial subspace
        * *goal_space*: goal subspace
        * *memory*: maximal number of states memorized before search is stopped

    **returns**:
        * *path*: a path from *InitalSpace* to *GoalSpace* if it was found, or *None* otherwise.

    **example**::

        >>> initspace = "1--0"
        >>> goalspace = "0--1"
        >>> path = best_first_reachability(primes, initialstate, goalspace)
        >>> if path: print(len(path))
        4
    """

    if type(initial_space) is str:
        initial_space = subspace2dict(primes, initial_space)
    if type(goal_space) is str:
        goal_space = subspace2dict(primes, goal_space)

    xdict = random_state(primes, subspace=initial_space)
    x = state2str(xdict)

    fringe = []
    seen = set([])
    heapq.heappush(fringe, (hamming_distance(xdict, goal_space), [x]))
    seen.add(x)

    while fringe:
        dist, path = heapq.heappop(fringe)
        if dist == 0:
            return path

        x = path[-1]
        for ydict in successors_asynchronous(primes, state2dict(primes, x)):
            y = state2str(ydict)
            if y not in seen:
                seen.add(y)
                heapq.heappush(
                    fringe, (hamming_distance(ydict, goal_space), path + [y]))

        if len(seen) > memory:
            break

    log.info(f"explored {len(seen)} transitions, no path found.")
コード例 #6
0
def list_reachable_states(primes: dict, update: str, initial_states: List[str],
                          memory: int):
    """
    Performs a depth-first search in the transition system defined by *primes* and *update* to list all states that
    are reachable from the *inital states*. *Memory* specifies the maximum number of states that can be kept in
    memory as "already explored" before the algorithm terminates.

    **arguments**:
        * *primes*: prime implicants
        * *update*: update strategy (either asynchronous or snchronous)
        * *initial_states*: a list of initial states
        * *memory*: maximal number of states memorized before search is stopped

    **returns**:
        * *reachable_states*: a list of all states explored

    **example**::

        >>> initial_states = ["1000", "1001"]
        >>> update = "asynchronous"
        >>> memory = 1000
        >>> states = list_reachable_states(primes, update, initial_states, memory)
        >>> print(len(states))
        287
    """

    if not initial_states:
        return []

    if type(initial_states) in [dict, str]:
        initial_states = [initial_states]

    initial_states = [subspace2str(primes, x) for x in initial_states]

    assert update in ["asynchronous", "synchronous"]

    if update == "asynchronous":
        transition_func = lambda state: successors_asynchronous(primes, state)
    else:
        transition_func = lambda state: [successor_synchronous(primes, state)]

    explored = set([])
    stack = set(initial_states)

    memory_reached = False
    counter = 0

    while stack:
        state = stack.pop()
        new_states = set([state2str(x) for x in transition_func(state)])
        not_explored = new_states.difference(explored)
        stack.update(not_explored)
        explored.add(state2str(state))
        counter += 1

        if len(explored) > memory:
            memory_reached = True
            break

    log.info(f"states explored: {counter}")
    if memory_reached:
        log.info(
            f"result incomplete. stack size at termination: {len(stack)} increase memory parameter"
        )

    return explored
コード例 #7
0
def primes2stg(primes: dict,
               update: str,
               initial_states=lambda x: True) -> networkx.DiGraph:
    """
    Creates the state transition graph (STG) of a network defined by *primes* and *update*.
    The *initial_states* are either a list of states (in *dict* or *str* representation),
    a function that flags states that belong to the initial states, or
    a subspace (in *dict* or *str* representation).
    If *initial_states* is a function then it must take a single parameter *state* in dict representation
    and return a Boolean value that indicates whether it belongs to the initial states or not.

    The STG is constructed by a depth first search (DFS) starting from the given initial states.
    The default for *initial_states* is ``lambda x: True``, i.e., every state is initial.
    For a single initial state, say *"100"* use *initial_states="100"*,
    for a set of initial states use *initial_states=["100", "101"]* and
    for a initial subspace use *initial_states="1--"* or the *dict* representation of subspaces.

    **arguments**:
        * *primes*: prime implicants
        * *update*: either *"asynchronous"* or *"synchronous"*
        * *initial_states*: a function, a subspace, a state or a list of states

    **returns**:
        * *stg*: state transition graph

    **example**::

        >>> primes = FEX.read_primes("mapk.primes")
        >>> update = "asynchronous"
        >>> init = lambda x: x["ERK"]+x["RAF"]+x["RAS"]>=2
        >>> stg = primes2stg(primes, update, init)

        >>> stg.order()
        32

        >>> stg.edges()[0]
        ('01000','11000')

        >>> init = ["00100", "00001"]
        >>> stg = primes2stg(primes, update, init)

        >>> init = {"ERK":0, "RAF":0, "RAS":0, "MEK":0, "p38":1}
        >>> stg = primes2stg(primes, update, init)
    """

    if update not in ['asynchronous', 'synchronous']:
        log.warning("The chosen update might lead to a very big STG")

    if len(primes) > 15:
        log.warning(
            f"The state transition graph will consist of up to 2**{len(primes)}={2 ** len(primes)} states, depending on the initial states."
        )

    stg = networkx.DiGraph()

    if len(primes) == 0:
        log.warning("No Primes were given. Hence, the stg is empty.")
        return stg

    if update == "asynchronous":
        successors = lambda x: successors_asynchronous(primes, x)

    if update == "synchronous":
        successors = lambda x: [successor_synchronous(primes, x)]

    if update == "mixed":
        successors = lambda x: successors_mixed(primes, x)

    names = sorted(primes)
    space = len(names) * [[0, 1]]

    if hasattr(initial_states, "__call__"):
        fringe = [
            dict(zip(names, values)) for values in itertools.product(*space)
        ]
        fringe = [state2str(x) for x in fringe if initial_states(x)]

    elif type(initial_states) in [str, dict]:
        fringe = list_states_in_subspace(primes=primes,
                                         subspace=initial_states)

    else:
        fringe = [state2str(x) for x in initial_states]

    seen = set([])
    while fringe:
        source = fringe.pop()
        if source in seen:
            continue

        for target in successors(source):
            target = state2str(target)
            stg.add_edge(source, target)

            if target not in seen:
                fringe.append(target)

        seen.add(source)

    stg.graph["node"] = {
        "shape": "rect",
        "color": "none",
        "style": "filled",
        "fillcolor": "none"
    }
    stg.graph["edge"] = {}
    stg.graph["subgraphs"] = []

    if update == "synchronous":
        stg.graph["overlap"] = "compress"
    else:
        stg.graph["overlap"] = "scale"

    return stg
コード例 #8
0
def test_state2str():
    state = {"v2": 0, "v1": 1, "v3": 1}
    answer = state2str(state)

    assert answer == "101"