def test_cycle_graph(n: int, edge_sign: int): primes = cycle_graph(n=n, edge_sign=edge_sign) ig = primes2igraph(primes) cycle = networkx.cycle_graph(n=n, create_using=networkx.DiGraph) assert networkx.is_isomorphic(ig, cycle) assert_edge_signs_agree(ig, edge_sign, loop_sign=edge_sign)
def test_primes2igraph2(): fname_in = get_tests_path_in(fname="interactiongraphs_irma.primes") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) nodes = sorted(igraph.nodes(data=True)) expected_nodes = [("Ash1", {}), ("Cbf1", {}), ("Gal4", {}), ("Gal80", {}), ("Swi5", {}), ("gal", {})] assert nodes == expected_nodes edges = sorted(igraph.edges(data=True)) expected_edges = [("Ash1", "Cbf1", { "sign": {1} }), ("Cbf1", "Ash1", { "sign": {1} }), ("Gal4", "Swi5", { "sign": {-1} }), ("Gal80", "Gal4", { "sign": {1} }), ("Swi5", "Gal4", { "sign": {-1} }), ("gal", "Ash1", { "sign": {1} }), ("gal", "Gal80", { "sign": {-1} }), ("gal", "gal", { "sign": {1} })] assert edges == expected_edges
def test_path_graph(n: int, edge_sign: int, loop_sign: int): primes = path_graph(n=n, edge_sign=edge_sign, loop_sign=loop_sign) ig = primes2igraph(primes) path = networkx.path_graph(n=n, create_using=networkx.DiGraph) path.add_edge(0, 0) assert networkx.is_isomorphic(ig, path) assert_edge_signs_agree(ig, edge_sign, loop_sign)
def primes2bns(primes: dict, fname_bns: Optional[str] = None) -> str: """ Saves Primes as a *bns* file for the computation of all attractors of the synchronous transition system. BNS_ is based on :ref:`Dubrova2011 <Dubrova2011>`. It is available at http://people.kth.se/~dubrova/bns.html. **arguments**: * *primes*: prime implicants * *fname_bns*: name of *bns* file or *None* to return file as string **example**:: >>> primes2bns(primes, "mapk.bns") """ names_sorted = sorted(primes) lines = ["# " + ", ".join(names_sorted), ""] lines += [f".v {len(names_sorted)}", ""] ig = primes2igraph(primes) for i, name in enumerate(names_sorted): i += 1 lines += [f"# {name}"] regulators = sorted(ig.predecessors(name)) number_regs = len(regulators) ids_regs = " ".join( [str(names_sorted.index(reg) + 1) for reg in regulators]) lines += [f".n {i} {number_regs} {ids_regs}"] for v in [0, 1]: for prime in primes[name][v]: seq = [] for reg in regulators: if reg in prime: if prime[reg] == 1: seq.append("1") else: seq.append("0") else: seq.append("-") if regulators: seq.append(" ") seq.append(str(v)) lines += ["".join(seq)] lines += [""] text = "\n".join(lines) if fname_bns: with open(fname_bns, "w") as f: f.write(text) log.info(f"created {fname_bns}") return text
def test_find_minimal_autonomous_nodes(): primes = get_primes("randomnet_n15k3") igraph = primes2igraph(primes) nodes = find_minimal_autonomous_nodes(igraph, core=set()) expected = [{ "Gene8", "Gene9", "Gene1", "Gene2", "Gene3", "Gene4", "Gene5", "Gene6", "Gene7", "Gene12", "Gene13", "Gene10", "Gene11", "Gene14" }] assert expected == nodes
def test_balanced_tree(height: int, branching_factor: int, edge_sign: int, loop_sign: int): primes = balanced_tree(height, branching_factor, edge_sign, loop_sign) ig = primes2igraph(primes) path = networkx.balanced_tree(r=branching_factor, h=height, create_using=networkx.DiGraph) path.add_edge(0, 0) assert networkx.is_isomorphic(ig, path) assert_edge_signs_agree(ig, edge_sign, loop_sign)
def test_primes2igraph1(): fname_in = get_tests_path_in(fname="interactiongraphs_irma.primes") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) nodes = sorted(igraph.nodes()) expected_nodes = ["Ash1", "Cbf1", "Gal4", "Gal80", "Swi5", "gal"] assert nodes == expected_nodes edges = sorted(igraph.edges()) expected_edges = [("Ash1", "Cbf1"), ("Cbf1", "Ash1"), ("Gal4", "Swi5"), ("Gal80", "Gal4"), ("Swi5", "Gal4"), ("gal", "Ash1"), ("gal", "Gal80"), ("gal", "gal")] assert edges == expected_edges
def test_primes2igraph4(): primes = { "A": [[{}], []], "B": [[{ "B": 0 }], [{ "B": 1 }]], "C": [[{ "C": 1 }], [{ "C": 0 }]], "D": [[{ "B": 0, "C": 0 }, { "B": 1, "C": 1 }], [{ "B": 1, "C": 0 }, { "B": 0, "C": 1 }]] } igraph = primes2igraph(primes=primes) nodes = sorted(igraph.nodes(data=True)) expected_nodes = [("A", {}), ("B", {}), ("C", {}), ("D", {})] assert nodes == expected_nodes edges = sorted(igraph.edges(data=True)) expected_edges = [("B", "B", { "sign": {1} }), ("B", "D", { "sign": {1, -1} }), ("C", "C", { "sign": {-1} }), ("C", "D", { "sign": {1, -1} })] assert edges == expected_edges
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
def test_activities2animation(): fname_in = get_tests_path_in(fname="irma.primes") fname_out1 = get_tests_path_out(fname="irma*.png") fname_out2 = get_tests_path_out(fname="irma.gif") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes) activities = [ { "gal": 0, "Cbf1": 1, "Gal80": 1, "Ash1": 0, "Gal4": 0, "Swi5": 1 }, { "gal": 1, "Cbf1": 1, "Gal80": 1, "Ash1": 0, "Gal4": 0, "Swi5": 1 }, { "gal": 1, "Cbf1": 0, "Gal80": 1, "Ash1": 0, "Gal4": 0, "Swi5": 1 }, { "gal": 1, "Cbf1": 0, "Gal80": 0, "Ash1": 0, "Gal4": 0, "Swi5": 1 }, { "gal": 1, "Cbf1": 0, "Gal80": 0, "Ash1": 1, "Gal4": 0, "Swi5": 1 }, { "gal": 1, "Cbf1": 0, "Gal80": 0, "Ash1": 1, "Gal4": 1, "Swi5": 1 }, { "gal": 1, "Cbf1": 0, "Gal80": 0, "Ash1": 1, "Gal4": 1, "Swi5": 0 }, ] activities2animation(igraph=igraph, activities=activities, fname_tmp=fname_out1, fname_gif=fname_out2)
def test_styles(): fname_in = get_tests_path_in(fname="interactiongraphs_topology.primes") fname_out_dot = get_tests_path_out( fname="interactiongraphs_style_interactionsigns.dot") fname_out_pdf = get_tests_path_out( fname="interactiongraphs_style_interactionsigns.pdf") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) add_style_interactionsigns(igraph=igraph) igraph2dot(igraph=igraph, fname_dot=fname_out_dot) dot2image(fname_dot=fname_out_dot, fname_image=fname_out_pdf) igraph2image(igraph=igraph, fname_image=fname_out_pdf) fname_out_dot = get_tests_path_out( fname="interactiongraphs_style_activities.dot") fname_out_pdf = get_tests_path_out( fname="interactiongraphs_style_activities.pdf") add_style_interactionsigns(igraph=igraph) igraph2dot(igraph=igraph, fname_dot=fname_out_dot) dot2image(fname_dot=fname_out_dot, fname_image=fname_out_pdf) igraph2image(igraph=igraph, fname_image=fname_out_pdf) igraph = primes2igraph(primes=primes) activities = {"v1": 1, "v2": 0, "v3": 1, "v4": 1, "v5": 1, "v6": 0} add_style_activities(igraph=igraph, activities=activities) igraph2dot(igraph=igraph, fname_dot=fname_out_dot) dot2image(fname_dot=fname_out_dot, fname_image=fname_out_pdf) fname_in = get_tests_path_in(fname="interactiongraphs_topology.primes") fname_out_dot = get_tests_path_out( fname="interactiongraphs_style_sccs.dot") fname_out_pdf = get_tests_path_out( fname="interactiongraphs_style_sccs.pdf") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) add_style_sccs(igraph=igraph) igraph2dot(igraph=igraph, fname_dot=fname_out_dot) dot2image(fname_dot=fname_out_dot, fname_image=fname_out_pdf) fname_in = get_tests_path_in(fname="interactiongraphs_topology.primes") fname_out_pdf = get_tests_path_out(fname="interactiongraphs_style_ioc.pdf") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) add_style_inputs(igraph=igraph) add_style_constants(igraph=igraph) add_style_outputs(igraph=igraph) igraph2image(igraph=igraph, fname_image=fname_out_pdf) fname_in = get_tests_path_in(fname="interactiongraphs_topology.primes") fname_out_pdf = get_tests_path_out( fname="interactiongraphs_style_subgrapghs.pdf") fname_out_dot = get_tests_path_out( fname="interactiongraphs_style_subgrapghs.dot") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) subgraphs = [(["v1", "v2"], {}), (["v3", "v4"], {"label": "jo"})] add_style_subgraphs(igraph=igraph, subgraphs=subgraphs) igraph2dot(igraph=igraph, fname_dot=fname_out_dot) dot2image(fname_dot=fname_out_dot, fname_image=fname_out_pdf)
def test_igraph2image(): fname_in = get_tests_path_in(fname="interactiongraphs_irma.primes") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) fname_out = get_tests_path_out(fname="interactiongraphs_igraph2image.png") igraph2image(igraph=igraph, fname_image=fname_out)
def test_igraph2dot_string(): fname_in = get_tests_path_in(fname="interactiongraphs_irma.primes") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) igraph2dot(igraph=igraph, fname_dot=None)
def test_igraph2dot(): fname_in = get_tests_path_in(fname="interactiongraphs_irma.primes") fname_out = get_tests_path_out(fname="interactiongraphs_igraph2dot.dot") primes = read_primes(fname_json=fname_in) igraph = primes2igraph(primes=primes) igraph2dot(igraph=igraph, fname_dot=fname_out)
import pyboolnet.state_space from pyboolnet.interaction_graphs import primes2igraph, igraph2image, local_igraph_of_state, add_style_interactionsigns from pyboolnet.repository import get_primes from pyboolnet.state_transition_graphs import create_stg_image if __name__ == "__main__": primes = get_primes("remy_tumorigenesis") create_stg_image(primes, update="asynchronous", fname_image="igraph.pdf") create_stg_image(primes, update="asynchronous", fname_image="igraph2.pdf", styles=["anonymous", "sccs"]) # advances drawing igraph = primes2igraph(primes) for x in igraph.nodes: if "GF" in x: igraph.nodes[x]["shape"] = "square" igraph.nodes[x]["fillcolor"] = "lightblue" igraph2image(igraph, "igraph3.pdf") # local interaction graphs state = pyboolnet.state_space.random_state(primes) local_igraph = local_igraph_of_state(primes, state) add_style_interactionsigns(local_igraph) igraph2image(local_igraph, "local_igraph.pdf")
def compute_commitment_diagram(attractors: dict, fname_image: Optional[str] = None, fname_json=None, edge_data=False) -> networkx.DiGraph: """ Computes the commitment diagram for the AttrJson and STG defined in *attractors*, a json object computed by :ref:`AttrJson_compute_json` The nodes of the diagram represent states that can reach the exact same subset of *attractors*. Edges indicate the existence of a transition between two nodes in the respective commitment sets. Edges are labeled by the number of states of the source set that can reach the target set and, if *EdgeData* is true, additionally by the size of the border. **arguments**: * *attractors*: json attractor data, see :ref:`compute_attractors` * *fname_image*: generate image for diagram * *fname_json*: save diagram as json * *edge_data*: toggles computation of additional edge data **returns**:: * *diagram*: the commitment diagram **example**:: >>> attractors = compute_attractors(primes, update) >>> diagram = compute_phenotype_diagram(attractors) """ primes = attractors["primes"] update = attractors["update"] subspaces = [] for x in attractors["attractors"]: if x["min_trap_space"]["is_univocal"] and x["min_trap_space"][ "is_faithful"]: subspaces.append(x["min_trap_space"]["dict"]) else: subspaces.append(x["state"]["dict"]) log.info("Commitment.compute_diagram(..)") size_total = size_state_space(primes) if len(subspaces) == 1: log.info(" single attractor, trivial case.") diagram = networkx.DiGraph() counter_mc = 0 diagram.add_node("0") diagram.nodes["0"]["attractors"] = subspaces diagram.nodes["0"]["size"] = size_total diagram.nodes["0"]["formula"] = "TRUE" else: igraph = primes2igraph(primes) outdag = find_outdag(igraph) attractor_nodes = [x for A in subspaces for x in A] critical_nodes = find_ancestors(igraph, attractor_nodes) outdag = [x for x in outdag if x not in critical_nodes] igraph.remove_nodes_from(outdag) log.info(f"excluding the non-critical out-dag nodes {outdag}") components = networkx.connected_components(igraph.to_undirected()) components = [list(x) for x in components] log.info(f"working on {len(components)} connected component(s)") counter_mc = 0 diagrams = [] for component in components: sub_primes = copy_primes(primes) remove_all_variables_except(sub_primes, component) attractors_projected = _project_attractors(subspaces, component) diagram, count = _compute_diagram_component( sub_primes, update, attractors_projected, edge_data) counter_mc += count diagrams.append(diagram) factor = 2**len(outdag) diagram = _cartesian_product_of_diagrams(diagrams, factor, edge_data) for x in attractors: diagram.graph[x] = copy_json_data(attractors[x]) nodes_sum = 0 for x in diagram.nodes(): projection = diagram.nodes[x]["attractors"] diagram.nodes[x]["attractors"] = _lift_attractors( subspaces, projection) nodes_sum += diagram.nodes[x]["size"] if not nodes_sum == size_total: log.warning( "commitment diagram does not partition the state space, this may be due to rounding of large numbers." ) sorted_ids = sorted(diagram, key=lambda x: diagram.nodes[x]["formula"]) mapping = {x: str(sorted_ids.index(x)) for x in diagram} networkx.relabel_nodes(diagram, mapping, copy=False) log.info(f"total executions of NuSMV: {counter_mc}") if fname_image: commitment_diagram2image(diagram, fname_image=fname_image, style_inputs=True, style_edges=edge_data, style_ranks=True, first_index=1) if fname_json: save_commitment_diagram(diagram, fname_json) return diagram
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