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
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 intersection(*list_of_dicts): """ each argument must be a list of subspaces (dicts):: >>> intersection([{"v1":1}], [{"v1":0}, {"v2":1, "v3":0}]) """ return [merge_dicts(dicts=x) for x in product(*list_of_dicts)]
def _cartesian_product_of_diagrams(diagrams, factor, edge_data): result = networkx.DiGraph() nodes = [x.nodes(data=True) for x in diagrams] for product in itertools.product(*nodes): data = { "size": functools.reduce(operator.mul, [x["size"] for _, x in product]) * factor, "formula": " & ".join(f"({x['formula']})" for _, x in product) } attractors = [x["attractors"] for _, x in product] attractors = list(itertools.product(*attractors)) attractors = [merge_dicts(x) for x in attractors] data["attractors"] = attractors node = tuple(x for x, _ in product) result.add_node(node) for key, value in data.items(): result.nodes[node][key] = value for source in result.nodes(): for s, diagram in zip(source, diagrams): factor = result.nodes[source]["size"] / diagram.nodes[s]["size"] for _, t, data in diagram.out_edges(s, data=True): data = {} basic_formula = [ "(%s)" % g.nodes[x]["formula"] for x, g in zip(source, diagrams) if not g == diagram ] data["EX_size"] = factor * diagram.adj[s][t]["EX_size"] formula = basic_formula + [ f"({diagram.adj[s][t]['EX_formula']})" ] data["EX_formula"] = " & ".join(formula) if edge_data: data["EF_size"] = factor * diagram.adj[s][t]["EF_size"] formula = basic_formula + [ f"({diagram.adj[s][t]['EF_formula']})" ] data["EF_formula"] = " & ".join(formula) target = tuple(x if g != diagram else t for x, g in zip(source, diagrams)) result.add_edge(source, target) for key, value in data.items(): result.edges[source, target][key] = value result = networkx.convert_node_labels_to_integers(result) return result
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