示例#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
示例#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
示例#3
0
def completeness_naive_with_counterexample(primes: dict, update: str,
                                           trap_spaces: List[Union[dict,
                                                                   str]]):
    """
    The naive approach to deciding whether *Trapspaces* is complete,
    i.e., whether there is no attractor outside of *Trapspaces*.
    The approach is described and discussed in :ref:`Klarner2015(a) <klarner2015trap>`.
    It is decided by a single CTL query of the :ref:`EF_oneof_subspaces <EF_oneof_subspaces>`.
    The state explosion problem limits this function to networks with around 40 variables.
    For networks with more variables (or a faster answer) use :ref:`completeness_iterative <completeness_iterative>`.

    .. note::
        Completeness depends on the update strategy, i.e.,
        a set of subspaces may be complete in the synchronous STG but not complete in the asynchronous STG or vice versa.

    .. note::
        A typical use case is to decide whether the minimal trap spaces of a network are complete.

    .. note::
        The subspaces of *Trapspaces* are in in fact not required to be a trap sets, i.e., it may contain arbitrary subspaces.
        If there are arbitrary subspaces then the semantics of the query is such that it checks whether each attractor *intersects* one of the subspaces.

    **arguments**:
        * *primes*: prime implicants
        * *update*: the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
        * *Trapspaces*: list of subspaces in string or dict representation

    **returns**:
        * *answer*: whether *subspaces* is complete in the STG defined by *primes* and *update*,
        * *counter_example*: a state from which none of the *subspaces* is reachable (if *answer* is *False*)

    **example**::

        >>> mintspaces = trap_spaces(primes, "min")
        >>> answer, counterexample = completeness_naive(primes, "asynchronous", mintspaces)
        >>> answer
        True
    """

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

    if counterexample:
        counterexample = counterexample[-1]

    return answer, counterexample
示例#4
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
def _basin_handle(primes: dict, update: str, subspace: Union[dict, str],
                  minimize: bool, ctl_pattern: str) -> dict:
    """
    The handle for :ref:`weak_basin`, :ref:`strong_basin` and :ref:`cycle_free_basin`.

        **arguments**:
        * *primes*: prime implicants
        * *update*:  the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
        * *minimize*: minimize the Boolean expressions
        * *subspace*: a subspace
        * *CTLpattern*:

        **returns**:
        * *basin*: with keys "size"=number of states, "formula"=state formula and "perc"=percentage of state space

        **example**::

            >>> _basin_handle(primes, update, True, "0---1", "CTLSPEC EF({x})")
            {"size":134,
            "formula": "Erk & !Raf | Mek",
            "perc": 12.89338}
    """

    prop = subspace2proposition(primes, subspace)
    init = "INIT TRUE"
    spec = ctl_pattern.format(x=prop)
    answer, accepting_states = model_checking(primes,
                                              update,
                                              init,
                                              spec,
                                              enable_accepting_states=True)

    size = accepting_states["INITACCEPTING_SIZE"]
    formula = accepting_states["INITACCEPTING"]

    if minimize and formula not in ["TRUE", "FALSE"]:
        formula = minimize_espresso(formula)

    size_total = size_state_space(primes)

    return {"size": size, "formula": formula, "perc": 100. * size / size_total}
示例#6
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
示例#7
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
示例#8
0
def find_attractor_state_by_randomwalk_and_ctl(primes: dict,
                                               update: str,
                                               initial_state: Union[dict,
                                                                    str] = {},
                                               length: int = 0,
                                               attempts: int = 10) -> dict:
    """
    Attempts to find a state inside an attractor by the "long random walk" method,
    see :ref:`Klarner2015(b) <klarner2015approx>` Sec. 3.2 for a formal definition.
    The method generates a random walk of *length* states, starting from a state defined by *initial_state*.
    If *initial_state* is a subspace then :ref:`random_state` will be used to draw a random state from inside it.
    The function then uses CTL model checking, i.e., :ref:`check_primes <check_primes>`,
    to decide whether the last state of the random walk is inside an attractor.
    If so it is returned, otherwise the process is repeated.
    If no attractor state has been found after *Attempts* many trials an exception is raised.

    .. note::
        The default value for length, namely *length=0*, will be replaced by::

            length = 10*len(primes)

        which proved sufficiently large in our computer experiments.

    **arguments**:
        * *primes*: prime implicants
        * *update*: the update strategy, one of *"asynchronous"*, *"synchronous"*, *"mixed"*
        * *initial_state*: an initial state or subspace
        * *length*: length of random walk
        * *attempts*: number of attempts before exception is raised

    **returns**:
        * *attractor_state*: a state that belongs to some attractor
        * raises *Exception* if no attractor state is found

    **example**::
            >>> find_attractor_state_by_randomwalk_and_ctl(primes, "asynchronous")
            {"v1": 1, "v2": 1, "v3": 1}
    """

    if type(initial_state) == str:
        initial_state = state2dict(primes=primes, state=initial_state)

    assert update in UPDATE_STRATEGIES
    assert set(initial_state).issubset(set(primes))

    if length == 0:
        length = 10 * len(primes)

    if update == "asynchronous":
        transition = partial(random_successor_asynchronous, primes)

    elif update == "synchronous":
        transition = partial(successor_synchronous, primes)

    elif update == "mixed":
        transition = partial(random_successor_mixed, primes)
    else:
        log.error(f"unknown update strategy: update={update}")
        raise Exception

    log.info("find_attractor_state_by_randomwalk_and_ctl(..)")
    log.info(
        f"len(primes)={len(primes)}, update={update}, length={length}, attempts={attempts}"
    )

    trials = 0
    while trials < attempts:
        log.info(f"trial {trials}")

        current_state = random_state(primes, initial_state)
        log.info(f"start: {state2str(current_state)}")

        transitions = 0
        while transitions < length:
            current_state = transition(current_state)
            transitions += 1

        log.info(f"end: {state2str(current_state)}")

        formula = all_globally_exists_finally_one_of_sub_spaces(
            primes=primes, sub_spaces=[current_state])
        spec = f"CTLSPEC {formula}"
        init = f"INIT {subspace2proposition(primes=primes, subspace=current_state)}"

        if model_checking(primes, update, init, spec):
            log.info("is attractor state")
            return current_state

        trials += 1

    log.error(
        "could not find attractor state: increase Length or Attempts parameter."
    )
    raise Exception
示例#9
0
def compute_phenotype_diagram(phenotypes: dict,
                              fname_json: Optional[str] = None,
                              fname_image: Optional[str] = None):
    """
    Computes the phenotype diagram from the phenotypes object obtained from :ref:`phenotypes_compute_json`.
    save the diagram as json data with *fname_json*. useful for e.g. manually renaming nodes.

    **arguments**:
        * *phenotypes*: result of compute_json(..)
        * *fname_json*: save diagram as json
        * *fname_image*: generate image for diagram

    **returns**::
        * *diagram*: the phenotype diagram

    **example**::

        >>> phenos = compute_phenotypes(attrobj, markers)
        >>> compute_phenotype_diagram(phenos, fname_image="phenos.pdf")
        created phenos.pdf
    """

    primes = phenotypes["primes"]
    update = phenotypes["update"]

    assert update in UPDATE_STRATEGIES
    assert primes

    diagram = networkx.DiGraph()
    for key in phenotypes:
        diagram.graph[key] = copy_json_data(phenotypes[key])

    node_id = 0
    flags = [[0, 1]] * len(phenotypes["phenotypes"])
    for i, flags in enumerate(itertools.product(*flags)):

        state_formulas, names = [], []
        for j, flag in enumerate(flags):
            if flag:
                state_formulas.append(
                    phenotypes["phenotypes"][j]["stateformula"])
                names.append(phenotypes["phenotypes"][j]["name"])

        state_formulas.sort()
        names = tuple(sorted(names))

        if not state_formulas:
            unreachable = " & ".join(f"!EF({x['stateformula']})"
                                     for x in phenotypes["phenotypes"])
            spec = f"CTLSPEC {unreachable}"

        else:
            reach = [f"EF({x})" for x in state_formulas]
            reach_all = " & ".join(reach)
            reach_some = " | ".join(reach)
            spec = f"CTLSPEC {reach_all} & AG({reach_some})"

        init = "INIT TRUE"
        answer, accepting = model_checking(primes,
                                           update,
                                           init,
                                           spec,
                                           enable_accepting_states=True)

        data = {
            "names": names,
            "init": init,
            "spec": spec,
            "initaccepting_size": accepting["INITACCEPTING_SIZE"],
            "initaccepting": accepting["INITACCEPTING"]
        }

        if data["initaccepting_size"] > 0:
            log.info(f"[{', '.join(names)}] = {data['initaccepting_size']}")
            diagram.add_node(node_id)

            for key, value in data.items():
                diagram.nodes[node_id][key] = value

            node_id += 1

    for source in diagram:
        for target in diagram:
            if source == target:
                continue

            source_set = set(diagram.nodes[source]["names"])
            target_set = set(diagram.nodes[target]["names"])

            if target_set.issubset(source_set):
                init = f"INIT {diagram.nodes[source]['initaccepting']}"
                spec = f"CTLSPEC EX({diagram.nodes[target]['initaccepting']})"
                answer, accepting = model_checking(
                    primes, update, init, spec, enable_accepting_states=True)

                if accepting["INITACCEPTING_SIZE"] > 0:

                    data = {
                        "init": init,
                        "spec": spec,
                        "initaccepting_size": accepting["INITACCEPTING_SIZE"],
                        "initaccepting": accepting["INITACCEPTING"]
                    }

                    diagram.add_edge(source, target)
                    for key, value in data.items():
                        diagram.edges[source, target][key] = value

                    log.info(
                        f"[{', '.join(diagram.nodes[source]['names'])}] --{data['initaccepting_size']}--> [{', '.join(diagram.nodes[target]['names'])}]"
                    )

    if fname_image:
        phenotype_diagram2image(diagram, fname_image)

    if fname_json:
        save_phenotype_diagram(diagram=diagram, fname_json=fname_json)
        log.info(f"created {fname_json}")

    return diagram
def _compute_diagram_component(primes: dict, update: str, subspaces,
                               edge_data: bool):
    """
    Computes the commitment diagram but without removing out-DAGs or considering connected components separately.
    """

    assert update in UPDATE_STRATEGIES
    assert primes

    counter_mc = 0
    node_id = 0
    worst_case_nodes = 0
    inputs = find_inputs(primes)
    states_per_case = pyboolnet.state_space.size_state_space(primes,
                                                             fixed_inputs=True)
    diagram = networkx.DiGraph()
    log.info("_compute_diagram_component(..)")
    log.info(f"inputs: {len(inputs)} ({', '.join(inputs)})")
    log.info(f"combinations:  {2**len(inputs)}")

    for i, combination in enumerate(list_input_combinations(primes)):
        attr = [
            x for x in subspaces if pyboolnet.state_space.is_subspace(
                primes, this=x, other=combination)
        ]
        worst_case_nodes += 2**len(attr) - 1
        states_covered = 0
        specs = [subspace2proposition(primes, x) for x in attr]
        vectors = len(attr) * [[0, 1]]
        vectors = list(itertools.product(*vectors))
        random.shuffle(vectors)
        combination_formula = subspace2proposition(primes, combination)

        log.info(
            f"input combination {i}, worst case #nodes: {2 ** len(attr) - 1}")

        for vector in vectors:
            if sum(vector) == 0: continue
            if states_covered == states_per_case:
                log.info("avoided executions of NuSMV due to state counting")
                break

            if len(vector) == 1:
                data = {
                    "attractors": attr,
                    "size": states_per_case,
                    "formula": combination_formula
                }

            else:
                init = f"INIT {combination_formula}"
                reach = [f"EF({x})" for flag, x in zip(vector, specs) if flag]
                reach_all = " & ".join(reach)
                reach_some = " | ".join(reach)
                spec = f"CTLSPEC {reach_all} & AG({reach_some})"

                answer, accepting_states = model_checking(
                    primes, update, init, spec, enable_accepting_states=True)
                counter_mc += 1

                data = {
                    "attractors": [x for flag, x in zip(vector, attr) if flag],
                    "size": accepting_states["INITACCEPTING_SIZE"],
                    "formula": accepting_states["INITACCEPTING"]
                }

            if data["size"] > 0:
                diagram.add_node(node_id)
                for key, value in data.items():
                    diagram.nodes[node_id][key] = value

                node_id += 1
                states_covered += data["size"]

    perc = f"= {(100 * diagram.order() / worst_case_nodes)}" if worst_case_nodes else ""
    log.info(f"worst case #nodes: {worst_case_nodes}")
    log.info(f"actual nodes: {diagram.order()} {perc}")

    potential_targets = {}
    for source, source_data in diagram.nodes(data=True):
        successors = []

        for target, target_data in diagram.nodes(data=True):
            if source == target:
                continue

            if all(x in source_data["attractors"]
                   for x in target_data["attractors"]):
                successors.append((target, target_data))

        potential_targets[source] = successors

    worst_case_edges = sum(len(x) for x in potential_targets.values())
    log.info(f"worst case #edges: {worst_case_edges}")

    for source, source_data in diagram.nodes(data=True):
        for target, target_data in potential_targets[source]:
            init = f"INIT {source_data['formula']}"
            spec = f"CTLSPEC EX({target_data['formula']})"
            answer, accepting_states = model_checking(
                primes, update, init, spec, enable_accepting_states=True)
            counter_mc += 1
            data = {
                "EX_size": accepting_states["INITACCEPTING_SIZE"],
                "EX_formula": accepting_states["INITACCEPTING"]
            }

            if data["EX_size"] > 0:

                if edge_data:
                    if len(potential_targets[source]) == 1:
                        data["EF_size"] = source_data["size"]
                        data["EF_formula"] = source_data["formula"]

                    else:
                        spec = f"CTLSPEC E[{source_data['formula']} U {target_data['formula']}]"
                        answer, accepting_states = model_checking(
                            primes,
                            update,
                            init,
                            spec,
                            enable_accepting_states=True)
                        counter_mc += 1

                        data["EF_size"] = accepting_states[
                            "INITACCEPTING_SIZE"]
                        data["EF_formula"] = accepting_states["INITACCEPTING"]

                diagram.add_edge(source, target)
                for key, value in data.items():
                    diagram.edges[source, target][key] = value

    perc = f"= {100 * diagram.size() / worst_case_edges:.2f}%" if worst_case_edges else ""
    log.info(f"actual edges: {diagram.size()} {perc}")
    log.info(f"total executions of NuSMV: {counter_mc}")

    return diagram, counter_mc
示例#11
0
from pyboolnet.model_checking import model_checking
from pyboolnet.repository import get_primes
from pyboolnet.state_transition_graphs import best_first_reachability

if __name__ == "__main__":

    # basic model checking

    primes = get_primes("remy_tumorigenesis")
    init = "INIT TRUE"
    spec = "CTLSPEC DNA_damage -> AG(EF(Apoptosis_medium))"

    #tournier_apoptosis

    answer = model_checking(primes, "asynchronous", init, spec)
    print(answer)

    # model checking with accepting states

    answer, accepting_states = model_checking(primes,
                                              "asynchronous",
                                              init,
                                              spec,
                                              enable_accepting_states=True)
    for key, value in accepting_states.items():
        print(f"{key} = {value}")

    # model checking with counter examples

    spec = "CTLSPEC DNA_damage -> AG(EF(Proliferation))"
    answer, counterexample = model_checking(primes,