Skip to content

Commit

Permalink
made succession skipping optional
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrozum committed Sep 28, 2024
1 parent 90b2b04 commit d978daa
Showing 1 changed file with 39 additions and 30 deletions.
69 changes: 39 additions & 30 deletions biobalm/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,16 +317,17 @@ def successions_to_target(
succession_diagram: SuccessionDiagram,
target: BooleanSpace,
expand_diagram: bool = True,
skip_feedforward_successions: bool = False,
) -> list[SubspaceSuccession]:
"""Find lists of nested trap spaces (successions) that lead to the
specified target subspace.
Generally, it is not necessary to call this function directly, as it is
automatically invoked by
:func:`succession_control<biobalm.control.succession_control>`. It is primarily
provided in the public API for testing and benchmarking purposes, or in the
case that the user wants to implement a custom strategy to identify
succession drivers rather than relying on
:func:`succession_control<biobalm.control.succession_control>`. It is
primarily provided in the public API for testing and benchmarking purposes,
or in the case that the user wants to implement a custom strategy to
identify succession drivers rather than relying on
:func:`drivers_of_succession<biobalm.control.drivers_of_succession>`.
Parameters
Expand All @@ -338,6 +339,12 @@ def successions_to_target(
expand_diagram: bool
Whether to ensure that the succession diagram is expanded enough to
capture all paths to the target (default: True).
skip_feedforward_successions: bool
Whether to skip redundant successions (default: False). Skipping these
can reduce the number of interventions to test, yielding performance
improvements, but can also cause the algorithm to miss some valid
interventions, particularly in cases when the order of intervention
application is important.
Returns
-------
Expand All @@ -346,10 +353,10 @@ def successions_to_target(
nested trap spaces that specify the target.
"""
successions: list[SubspaceSuccession] = []
# Tracks the combined perturbation that needs to be applied
# for the whole succession to take effect. We use this to detect
# which successions are redundant when they can be replaced by
# a succession with a subset signature.
# Tracks the combined perturbation that needs to be applied for the whole
# succession to take effect. We use this to detect which successions are
# redundant when they can be replaced by a succession with a subset
# signature. Used when skip_feedforward_successions is True
succession_signatures: list[BooleanSpace] = []

# expand the succession_diagram toward the target
Expand All @@ -376,8 +383,9 @@ def successions_to_target(
for s in succession_diagram.node_ids():
# a node is a valid end point if all
# 1) its descendents (including itself) are not "hot lava"
# 2) it has a parent that is or can reach "hot lava" (otherwise, we can just control to the parent)
# note that all nodes are either cold lava or hot lava, but not both or neither
# 2) it has a parent that is or can reach "hot lava" (otherwise, we can
# just control to the parent) note that all nodes are either cold lava
# or hot lava, but not both or neither
if descendant_map[s] & hot_lava_nodes:
continue
found_valid_target_node = True
Expand All @@ -399,27 +407,28 @@ def successions_to_target(
succession_diagram.edge_stable_motif(x, y, reduced=True)
for x, y in zip(path[:-1], path[1:])
]
signature = reduce(lambda x, y: x | y, succession)
# First, check if any existing successions can be eliminated
# because they are redundant w.r.t. to this succession.
# (`reversed` is important here, because that way a delete
# only impacts indices that we already processed)
skip_completely = False
for i in reversed(range(len(succession_signatures))):
existing_signature = succession_signatures[i]
if is_subspace(signature, existing_signature):
# The current `path` is already superseded by a path in successions.
skip_completely = True
break
if is_subspace(existing_signature, signature):
# A path in successions is made redundant by the current path.
del succession_signatures[i]
del successions[i]
if skip_completely:
pass

if skip_feedforward_successions:
signature = reduce(lambda x, y: x | y, succession)
# First, check if any existing successions can be eliminated
# because they are redundant w.r.t. to this succession.
# (`reversed` is important here, because that way a delete
# only impacts indices that we already processed)
skip_completely = False
for i in reversed(range(len(succession_signatures))):
existing_signature = succession_signatures[i]
if is_subspace(signature, existing_signature):
# The current `path` is already superseded by a path in successions.
skip_completely = True
break
if is_subspace(existing_signature, signature):
# A path in successions is made redundant by the current path.
del succession_signatures[i]
del successions[i]
if skip_completely:
continue

succession_signatures.append(signature)
successions.append(succession)
succession_signatures.append(signature)

if found_valid_target_node and len(successions) == 0:
successions = [[]]
Expand Down

1 comment on commit d978daa

@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
biobalm
   _pint_reachability.py615018%24, 40–54, 69–93, 101–146
   control.py1472881%108, 120, 126, 130, 135, 144–160, 173, 411–430, 552, 555, 568
   interaction_graph_utils.py52688%11–13, 151–152, 222–223
   petri_net_translation.py1491292%22–26, 79, 136, 234, 308–309, 333–334, 343, 452
   space_utils.py1322085%26–28, 104–110, 133–139, 347–350, 414, 462
   succession_diagram.py4399279%6, 128, 218–223, 236, 283–290, 394–401, 418–419, 429, 435, 551, 638–644, 760, 763, 858–872, 903–921, 953, 963, 1006, 1013, 1064, 1082, 1204, 1395–1423, 1441, 1474, 1505, 1516, 1524, 1567, 1579, 1584
   symbolic_utils.py32584%10, 39–44, 100, 128
   trappist_core.py1842388%14–18, 55, 57, 92, 215, 217, 219, 254–256, 276–282, 340, 342, 372, 420, 422
biobalm/_sd_algorithms
   expand_attractor_seeds.py60788%6, 28, 42, 109–114, 119
   expand_bfs.py28196%6
   expand_dfs.py30197%6
   expand_minimal_spaces.py68691%6, 36, 49, 64, 101, 116
   expand_source_SCCs.py1111686%11–13, 50, 69, 77, 82, 103, 112, 120, 131, 140, 143, 167, 179, 242–243
   expand_source_blocks.py1231985%10, 31, 43–46, 68, 75, 83, 142, 168, 177, 208, 216–217, 221, 231, 237, 246
   expand_to_target.py31390%6, 38, 43
biobalm/_sd_attractors
   attractor_candidates.py2809168%13–15, 27–28, 94, 102, 108–109, 153, 162, 184, 219, 225–236, 255, 271–352, 357, 361, 367, 373, 388, 415, 420, 424, 430, 432–470, 543, 614–615, 716
   attractor_symbolic.py2244082%6–7, 39–40, 54–68, 77, 95, 102, 107, 112, 193, 206–210, 221, 230, 262, 298, 328–330, 349, 359–361, 371, 380, 422, 442, 449
TOTAL224242081% 

Tests Skipped Failures Errors Time
361 0 💤 0 ❌ 0 🔥 1m 0s ⏱️

Please sign in to comment.