Skip to content

Commit

Permalink
lots of extra type hint fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrozum committed May 2, 2023
1 parent 71f423c commit 490fef4
Show file tree
Hide file tree
Showing 22 changed files with 862 additions and 617 deletions.
25 changes: 12 additions & 13 deletions nfvsmotifs/SignedGraph.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
from __future__ import annotations

import os
import networkx as nx # type: ignore

class SignedGraph:
V: int
num_vertices: int
adjacency_list_positive: dict[str, list[str]]
adjacency_list_negative: dict[str, list[str]]

def __init__(self, vertex_list: list[str]):
self.V = len(vertex_list)
self.num_vertices = len(vertex_list)
self.adjacency_list_positive = {}
self.adjacency_list_negative = {}
for node in vertex_list:
Expand All @@ -22,15 +21,15 @@ def convert_to_undirected_graph(self) -> nx.DiGraph:

udGraph = nx.DiGraph()
for node in self.adjacency_list_positive:
udGraph.add_node(node)
udGraph.add_node(node) # pyright: ignore[reportUnknownMemberType]


for node in self.adjacency_list_negative:
edgeList = self.adjacency_list_negative[node]

for v in edgeList:
udGraph.add_edge(node, v)
udGraph.add_edge(v, node)
udGraph.add_edge(node, v) # pyright: ignore[reportUnknownMemberType]
udGraph.add_edge(v, node) # pyright: ignore[reportUnknownMemberType]


for node in self.adjacency_list_positive:
Expand All @@ -41,11 +40,11 @@ def convert_to_undirected_graph(self) -> nx.DiGraph:
new_vertex_index += 1

new_vertex = "v_new_" + str(new_vertex_index)
udGraph.add_node(new_vertex)
udGraph.add_edge(node, new_vertex)
udGraph.add_edge(new_vertex, node)
udGraph.add_edge(new_vertex, v)
udGraph.add_edge(v, new_vertex)
udGraph.add_node(new_vertex) # pyright: ignore[reportUnknownMemberType]
udGraph.add_edge(node, new_vertex) # pyright: ignore[reportUnknownMemberType]
udGraph.add_edge(new_vertex, node) # pyright: ignore[reportUnknownMemberType]
udGraph.add_edge(new_vertex, v) # pyright: ignore[reportUnknownMemberType]
udGraph.add_edge(v, new_vertex) # pyright: ignore[reportUnknownMemberType]


return udGraph
Expand All @@ -59,7 +58,7 @@ def set_edge(self, y: str, x: str, sign: int):


def get_self_negative_loops(self) -> list[str]:
result = []
result: list[str] = []

for node in self.adjacency_list_negative:
edgeList = self.adjacency_list_negative[node]
Expand All @@ -75,7 +74,7 @@ def remove_vertex(self, v: str):
del self.adjacency_list_positive[v]
del self.adjacency_list_negative[v]

self.V = self.V - 1
self.num_vertices = self.num_vertices - 1

# update the edge list of each vertex
for node in self.adjacency_list_positive:
Expand Down
49 changes: 25 additions & 24 deletions nfvsmotifs/SuccessionDiagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Set
from biodivine_aeon.biodivine_aeon import BooleanNetwork # type: ignore
from biodivine_aeon import BooleanNetwork


import networkx as nx # type: ignore

from nfvsmotifs.petri_net_translation import network_to_petrinet
from nfvsmotifs.interaction_graph_utils import find_minimum_NFVS, feedback_vertex_set
from nfvsmotifs.interaction_graph_utils import feedback_vertex_set
from nfvsmotifs.trappist_core import trappist, compute_fixed_point_reduced_STG
from nfvsmotifs.space_utils import percolate_space, intersect
from nfvsmotifs.space_utils import percolate_space
from nfvsmotifs.motif_avoidant import detect_motif_avoidant_attractors
from nfvsmotifs.state_utils import state_list_to_bdd
from nfvsmotifs.terminal_restriction_space import get_terminal_restriction_space

# Enables helpful "progress" messages.
Expand Down Expand Up @@ -62,20 +61,20 @@ def max_depth(self) -> int:
Depth is counted from zero (root has depth zero).
"""
d = 0
for node in self.G.nodes():
d = max(d, self.node_depth(node))
for node in self.G.nodes(): # pyright: ignore[reportUnknownVariableType]
d = max(d, self.node_depth(int(node))) # pyright: ignore[reportUnknownArgumentType]
return d

def node_depth(self, node_id: int, depth: int | None = None) -> int:
"""
Get/set the depth associated with the provided `node_id`. The depth can only increase.
If a smaller depth is provided, the larger value is retained.
"""
"""
if depth:
self.G.nodes[node_id]['depth'] = max(self.G.nodes[node_id]['depth'], depth)
self.G.nodes[node_id]['depth'] = max(self.G.nodes[node_id]['depth'], depth) # pyright: ignore[reportUnknownArgumentType]

return self.G.nodes[node_id]['depth']
return self.G.nodes[node_id]['depth'] # pyright: ignore[reportUnknownVariableType]

def node_space(self, node_id: int) -> dict[str, int]:
"""
Expand All @@ -84,7 +83,7 @@ def node_space(self, node_id: int) -> dict[str, int]:
Note that this is the space *after* percolation. Hence it can hold that
`|node_space(child)| < |node_space(parent)| + |stable_motif(parent, child)|`.
"""
return self.G.nodes[node_id]['fixed_vars']
return self.G.nodes[node_id]['fixed_vars'] # pyright: ignore[reportUnknownVariableType]

def stable_motif(self, parent_id: int, child_id: int) -> dict[str, int]:
"""
Expand All @@ -94,7 +93,7 @@ def stable_motif(self, parent_id: int, child_id: int) -> dict[str, int]:
This corresponds to the maximal trap space within the `parent_id` node that, after percolation,
yields the `child_id` node.
"""
return self.G.edges[parent_id, child_id]['motif']
return self.G.edges[parent_id, child_id]['motif'] # pyright: ignore[reportUnknownVariableType]

def is_minimal(self, node_id: int, strict: bool = True) -> bool:
"""
Expand All @@ -104,9 +103,8 @@ def is_minimal(self, node_id: int, strict: bool = True) -> bool:
You can set `strict = False` to check whether the node is a leaf node in general (i.e. it
is either minimal, or not expanded).
"""
# TODO: This is not very efficient because it has to allocate the list,
# but it does not appear in any performance critical code (yet).
return ((not strict) or node_id in self.expanded) and len(list(self.G.successors(node_id))) == 0
is_leaf: bool = self.G.out_degree(node_id) == 0 # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
return ((not strict) or node_id in self.expanded) and is_leaf # pyright: ignore[reportUnknownVariableType]

def expand_node(self, node_id: int, depth_limit: int | None = 0, node_limit: int | None = None) -> int:
"""
Expand All @@ -131,7 +129,7 @@ def expand_node(self, node_id: int, depth_limit: int | None = 0, node_limit: int
node in the diagram, but rather the distance from the initial `node_id`.
"""
bfs_queue = [(node_id, depth_limit)]
visited = set()
visited: set[int] = set()

total_expanded = 0

Expand Down Expand Up @@ -162,9 +160,9 @@ def expand_node(self, node_id: int, depth_limit: int | None = 0, node_limit: int

if (depth is None) or (depth > 0):
new_depth = None if depth is None else (depth - 1)
for s in self.G.successors(node):
for s in self.G.successors(node): # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
if s not in visited:
bfs_queue.append((s, new_depth))
bfs_queue.append((s, new_depth)) # pyright: ignore[reportUnknownArgumentType]

return total_expanded

Expand Down Expand Up @@ -209,7 +207,8 @@ def _expand_one(self, node_id: int):
print(f"Sub-spaces: {len(sub_spaces)}")

for sub_space in sub_spaces:
child_id = self.ensure_node(node_id, sub_space)
# TODO: use this for something or delete it
child_id = self.ensure_node(node_id, sub_space) # pyright: ignore[reportUnusedVariable]

#if DEBUG:
# print(f"[{node_id}] Found child {child_id}: {sub_space} => {self.node_space(child_id)}")
Expand Down Expand Up @@ -247,9 +246,11 @@ def ensure_node(self, parent_id: int | None, stable_motif: dict[str, int]) -> in
# Key is a binary encoding of the fixed_vars dictionary. Since Python has
# arbitrary-precision integers, this should work for any network and be
# reasonably fast (we are not doing any copies or string manipulation).
key = 0
key: int = 0
for (k, v) in fixed_vars.items():
var_index = self.network.find_variable(k).as_index() # type: ignore
var = self.network.find_variable(k)
assert var
var_index: int = var.as_index()
# Each variable is encoded as two bits, so the total length
# of the key is 2 * n and the offset of each variable is 2 * index.
# 00 - unknown; 10 - zero; 11 - one
Expand All @@ -259,18 +260,18 @@ def ensure_node(self, parent_id: int | None, stable_motif: dict[str, int]) -> in

if key not in self.node_indices:
new_id = self.G.number_of_nodes()
self.G.add_node(new_id, fixed_vars=fixed_vars, depth=depth)
self.G.add_node(new_id, fixed_vars=fixed_vars, depth=depth) # pyright: ignore[reportUnknownMemberType]
self.node_indices[key] = new_id
if parent_id is not None:
self.G.add_edge(parent_id, new_id, motif=stable_motif)
self.G.add_edge(parent_id, new_id, motif=stable_motif) # pyright: ignore[reportUnknownMemberType]
return new_id
else:
existing_id = self.node_indices[key]
self.node_depth(existing_id, depth)
if (parent_id is not None):
# In theory, if you abuse this, you can create multiple edges,
# but this shouldn't happen with proper usage.
self.G.add_edge(parent_id, existing_id, motif=stable_motif)
self.G.add_edge(parent_id, existing_id, motif=stable_motif) # pyright: ignore[reportUnknownMemberType]
return existing_id

def expand_attractors(self, node_id: int) -> list[dict[str, int]]:
Expand Down Expand Up @@ -308,7 +309,7 @@ def expand_attractors(self, node_id: int) -> list[dict[str, int]]:
if x not in retained_set:
retained_set[x] = 0

child_spaces = [self.node_space(child) for child in self.G.successors(node_id)]
child_spaces = [self.node_space(child) for child in self.G.successors(node_id)] # pyright: ignore

if len(retained_set) == self.network.num_vars() and len(child_spaces) == 0:
# There is only a single attractor remaining here,
Expand Down
48 changes: 25 additions & 23 deletions nfvsmotifs/aeon_utils.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
from __future__ import annotations

from biodivine_aeon.biodivine_aeon import RegulatoryGraph, BooleanNetwork # type: ignore
from biodivine_aeon import RegulatoryGraph, BooleanNetwork

def remove_static_constraints(network: BooleanNetwork) -> BooleanNetwork:
"""
A method that removes all information about regulation monotonicity and
essentiality from the given `BooleanNetwork`.

This is mostly done to allow handling of randomly generated or otherwise
machine pre-processed files that can contain subtle logical redundancies
that AEON would otherwise detect as warnings.
"""
rg = RegulatoryGraph([network.get_variable_name(var) for var in network.variables()])
for reg in network.graph().regulations():
rg.add_regulation({
'source': network.get_variable_name(reg['source']),
'target': network.get_variable_name(reg['target']),
'observable': False,
})
def remove_static_constraints(network: BooleanNetwork) -> BooleanNetwork:
"""
A method that removes all information about regulation monotonicity and
essentiality from the given `BooleanNetwork`.
bn = BooleanNetwork(rg)
for var in network.variables():
bn.set_update_function(
network.get_variable_name(var),
network.get_update_function(var)
)
This is mostly done to allow handling of randomly generated or otherwise
machine pre-processed files that can contain subtle logical redundancies
that AEON would otherwise detect as warnings.
"""
rg = RegulatoryGraph([network.get_variable_name(var)
for var in network.variables()])
for reg in network.graph().regulations():
rg.add_regulation({
'source': network.get_variable_name(reg['source']),
'target': network.get_variable_name(reg['target']),
'observable': False,
})

return bn
bn = BooleanNetwork(rg)
for var in network.variables():
bn.set_update_function(
network.get_variable_name(var),
network.get_update_function(var)
)

return bn
17 changes: 10 additions & 7 deletions nfvsmotifs/drivers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from __future__ import annotations

from biodivine_aeon.biodivine_aeon import BooleanNetwork # type: ignore
from biodivine_aeon import BooleanNetwork
from nfvsmotifs.space_utils import percolate_space


def find_single_node_LDOIs(bn: BooleanNetwork) -> dict[tuple[str, int], dict[str, int]]:
"""
finds LDOIs of every single node state
TODO: take an initial set of LDOIs (e.g., of the original system) as an argument for speed-up
"""
LDOIs = {}
LDOIs: dict[tuple[str, int], dict[str, int]] = {}
for var in bn.variables():
name = bn.get_variable_name(var)
function = bn.get_update_function(var)
Expand All @@ -18,13 +19,15 @@ def find_single_node_LDOIs(bn: BooleanNetwork) -> dict[tuple[str, int], dict[str
for i in range(2):
fix = (name, i)
space = {name: i}
LDOIs[fix] = percolate_space(bn,space)[0]
LDOIs[fix] = percolate_space(bn, space)[0]

return LDOIs

def find_single_drivers(target_subspace: dict[str, int],
bn: BooleanNetwork,
LDOIs: dict[tuple[str, int],dict[str, int]] | None = None

def find_single_drivers(target_subspace: dict[str, int],
bn: BooleanNetwork,
LDOIs: dict[tuple[str, int],
dict[str, int]] | None = None
) -> set[tuple[str, int]]:
"""
find all the single node drivers for a given target_subspace,
Expand All @@ -33,7 +36,7 @@ def find_single_drivers(target_subspace: dict[str, int],
if LDOIs is None:
LDOIs = find_single_node_LDOIs(bn)

drivers = set()
drivers: set[tuple[str, int]] = set()
for fix, LDOI in LDOIs.items():
if target_subspace.items() <= (LDOI.items() | {fix}):
drivers.add(fix)
Expand Down
Loading

1 comment on commit 490fef4

@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
nfvsmotifs
   SuccessionDiagram.py1352085%5–6, 55, 63–66, 96, 106–107, 153, 179, 189, 193, 203, 207, 287–290, 359
   interaction_graph_utils.py141795%5–7, 57, 69, 95–96
   motif_avoidant.py112496%17, 48, 57, 93
   petri_net_translation.py84693%21–22, 48, 59–60, 89
   pyeda_utils.py953464%10, 56–68, 92, 97, 100–114, 142–146
   space_utils.py1111487%13–14, 29–36, 45, 187, 202, 259
   state_utils.py681282%12, 48–59, 87, 94, 102
   terminal_restriction_space.py44393%5–6, 70
   trappist_core.py1641392%8–9, 67, 101, 191–193, 217, 228–229, 302, 369, 397
nfvsmotifs/FVSpython3
   FVS.py481079%90–91, 97, 133, 183–189
   FVS_localsearch_10_python.py90199%179
TOTAL118912490% 

Tests Skipped Failures Errors Time
220 0 💤 0 ❌ 0 🔥 2m 35s ⏱️

Please sign in to comment.