Skip to content

Commit

Permalink
summary function, builders, source scc integration
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrozum committed Dec 12, 2023
1 parent 2370fee commit 193ecf4
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 13 deletions.
86 changes: 85 additions & 1 deletion balm/SuccessionDiagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

if TYPE_CHECKING:
from typing import Iterator
from biodivine_aeon import BooleanNetwork

import networkx as nx # type: ignore
from biodivine_aeon import BooleanNetwork

from balm._sd_algorithms.compute_attractor_seeds import compute_attractor_seeds
from balm._sd_algorithms.expand_attractor_seeds import expand_attractor_seeds
from balm._sd_algorithms.expand_bfs import expand_bfs
from balm._sd_algorithms.expand_dfs import expand_dfs
from balm._sd_algorithms.expand_minimal_spaces import expand_minimal_spaces
from balm._sd_algorithms.expand_source_SCCs import expand_source_SCCs
from balm._sd_algorithms.expand_to_target import expand_to_target
from balm.interaction_graph_utils import feedback_vertex_set
from balm.petri_net_translation import network_to_petrinet
Expand Down Expand Up @@ -116,6 +117,75 @@ def __len__(self) -> int:
"""
return self.G.number_of_nodes()

@staticmethod
def from_aeon(model: str) -> SuccessionDiagram:
"""
Read a `BooleanNetwork` from the string contents of an `.aeon` model.
"""
return SuccessionDiagram(BooleanNetwork.from_aeon(model))

@staticmethod
def from_bnet(model: str) -> SuccessionDiagram:
"""
Read a `BooleanNetwork` from the string contents of a `.bnet` model.
"""
return SuccessionDiagram(BooleanNetwork.from_bnet(model))

@staticmethod
def from_sbml(model: str) -> SuccessionDiagram:
"""
Read a `BooleanNetwork` from the string contents of an `.sbml` model.
"""
return SuccessionDiagram(BooleanNetwork.from_sbml(model))

@staticmethod
def from_file(path: str) -> SuccessionDiagram:
"""
Read a `BooleanNetwork` from the given file path. The format is automatically inferred from
the file extension.
"""
return SuccessionDiagram(BooleanNetwork.from_file(path))

def expanded_attractor_seeds(self) -> list[list[dict[str, int]]]:
return [self.node_attractor_seeds(id) for id in self.expanded_ids()]

def summary(self) -> str:
"""
Return a summary of the succession diagram.
"""
var_ordering = sorted(
[self.network.get_variable_name(v) for v in self.network.variables()]
)
report_string = (
f"Succession Diagram with {len(self)} nodes.\n"
f"State order: {', '.join(var_ordering)}\n\n"
"Attractors in diagram:\n\n"
)
for node in self.node_ids():
try:
attrs = self.node_attractor_seeds(node, compute=False)
except KeyError:
continue

space = self.node_space(node)

if self.node_is_minimal(node):
space_str_prefix = "minimal trap space "
else:
space_str_prefix = "motif avoidance in "
space_str = ""
for var in var_ordering:
if var in space:
space_str += str(space[var])
else:
space_str += "*"
report_string += f"{space_str_prefix}{space_str}\n"
for attr in attrs:
attr_str = "".join(str(v) for _, v in sorted(attr.items()))
report_string += "." * len(space_str_prefix) + f"{attr_str}\n"
report_string += "\n"
return report_string

def root(self) -> int:
"""
Return the ID of the root node.
Expand Down Expand Up @@ -341,6 +411,20 @@ def edge_stable_motif(
else:
return cast(dict[str, int], self.G.edges[parent_id, child_id]["motif"])

def build(self):
"""
Expand the succession diagram and search for attractors using default methods.
"""
self.expand_scc()
for node_id in self.node_ids():
self.node_attractor_seeds(node_id, compute=True)

def expand_scc(self, find_motif_avoidant_attractors: bool = True) -> bool:
"""
Expand the succession diagram using the source SCC method.
"""
return expand_source_SCCs(self, check_maa=find_motif_avoidant_attractors)

def expand_bfs(
self,
node_id: int | None = None,
Expand Down
31 changes: 19 additions & 12 deletions balm/_sd_algorithms/expand_source_SCCs.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,33 @@
from __future__ import annotations

import itertools as it
import sys
from typing import Callable, Iterable, cast
from typing import TYPE_CHECKING, Callable, Iterable, cast

import networkx as nx # type: ignore
from biodivine_aeon import BooleanNetwork
from networkx import DiGraph

import balm.SuccessionDiagram
from balm._sd_algorithms.expand_bfs import expand_bfs
from balm.interaction_graph_utils import infer_signed_interaction_graph
from balm.petri_net_translation import extract_variable_names, network_to_petrinet
from balm.space_utils import percolate_network, percolate_space
from balm.SuccessionDiagram import SuccessionDiagram

if TYPE_CHECKING:
expander_function_type = Callable[
[balm.SuccessionDiagram.SuccessionDiagram, int | None, int | None, int | None],
bool,
]

sys.path.append(".")

DEBUG = False

expander_function_type = Callable[
[SuccessionDiagram, int | None, int | None, int | None],
bool,
]


def expand_source_SCCs(
sd: SuccessionDiagram,
expander: expander_function_type = SuccessionDiagram.expand_bfs,
sd: balm.SuccessionDiagram.SuccessionDiagram,
expander: expander_function_type = expand_bfs,
check_maa: bool = True,
) -> bool:
"""
Expand Down Expand Up @@ -252,7 +256,7 @@ def find_source_SCCs(bn: BooleanNetwork) -> list[list[str]]:

def find_scc_sd(
bnet: str, source_scc: list[str], expander: expander_function_type, check_maa: bool
) -> tuple[SuccessionDiagram, bool]:
) -> tuple[balm.SuccessionDiagram.SuccessionDiagram, bool]:
"""
TODO: better way that does not use bnet but rather bn directly or petri_net directly
to find the scc_sd would be useful.
Expand Down Expand Up @@ -291,7 +295,7 @@ def find_scc_sd(
scc_bn = scc_bn.infer_regulatory_graph()

# Compute the succession diagram.
scc_sd = SuccessionDiagram(scc_bn)
scc_sd = balm.SuccessionDiagram.SuccessionDiagram(scc_bn)
fully_expanded = expander(scc_sd) # type: ignore
assert fully_expanded

Expand Down Expand Up @@ -323,7 +327,10 @@ def find_scc_sd(


def attach_scc_sd(
sd: SuccessionDiagram, scc_sd: SuccessionDiagram, branch: int, check_maa: bool
sd: balm.SuccessionDiagram.SuccessionDiagram,
scc_sd: balm.SuccessionDiagram.SuccessionDiagram,
branch: int,
check_maa: bool,
) -> list[int]:
"""
Attach scc_sd to the given branch point of the sd.
Expand Down
14 changes: 14 additions & 0 deletions scratch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# type: ignore

# import pickle

from balm.SuccessionDiagram import SuccessionDiagram

rules = """
A, !A & !B | C
B, !A & !B | C
C, A & B"""

sd = SuccessionDiagram.from_bnet(rules)
sd.build()
print(sd.summary())

1 comment on commit 193ecf4

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coverage

Coverage Report
FileStmtsMissCoverMissing
balm
   SuccessionDiagram.py2003483%6, 125, 132, 139, 147, 150, 156–187, 278, 418–420, 426, 552
   control.py1201389%47, 56, 60, 66, 80, 89–105, 319, 334
   interaction_graph_utils.py142894%6–9, 57, 70, 95–96
   motif_avoidant.py163597%23–24, 130, 184, 309
   petri_net_translation.py84693%23–24, 52, 63–64, 94
   pyeda_utils.py953464%12, 56–66, 90, 95, 98–112, 140–144
   space_utils.py145696%15–16, 189, 218, 233, 290
   state_utils.py681282%15, 55–66, 98, 105, 114
   terminal_restriction_space.py44491%6–7, 80, 97
   trappist_core.py1862089%10–11, 39, 41, 81, 127, 192, 194, 196, 231–233, 259, 317, 319, 349, 389, 391, 422, 451
balm/FVSpython3
   FVS.py481079%93–94, 102, 138, 190–198
   FVS_localsearch_10_python.py90199%179
balm/_sd_algorithms
   compute_attractor_seeds.py29197%6
   expand_attractor_seeds.py51492%6, 95–100
   expand_bfs.py28196%6
   expand_dfs.py30197%6
   expand_minimal_spaces.py37197%6
   expand_source_SCCs.py187896%18, 88, 98, 141, 164–165, 170, 285
   expand_to_target.py30390%6, 37, 42
TOTAL187417291% 

Tests Skipped Failures Errors Time
366 0 💤 0 ❌ 0 🔥 2m 54s ⏱️

Please sign in to comment.