Skip to content

Commit f6daaec

Browse files
Refactor variable value retrieval and timing in flow models
Replaces use of get_variable_values with get_values for direct variable access in flow model classes, improving reliability and type safety. Adds solve_time_start initialization for accurate timing in all k-cycle model classes. Updates variable name parsing and retrieval logic in SolverWrapper to be more robust and removes internal prefix collision tracking, making prefix management the caller's responsibility. Also updates cycles_demo.py to activate more test cases and adjusts optimization options.
1 parent a3d78f6 commit f6daaec

File tree

7 files changed

+322
-168
lines changed

7 files changed

+322
-168
lines changed

examples/cycles_demo.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ def test_min_flow_decomp(filename: str):
2828
optimization_options={
2929
"optimize_with_safe_sequences": True, # set to false to deactivate the safe sequences optimization
3030
"optimize_with_safe_sequences_allow_geq_constraints": True,
31-
"optimize_with_safe_sequences_fix_via_bounds": True,
32-
"optimize_with_safe_sequences_fix_zero_edges": False,
31+
"optimize_with_safe_sequences_fix_via_bounds": False,
32+
"optimize_with_safe_sequences_fix_zero_edges": True,
3333
},
3434
solver_options={
3535
"external_solver": "highs", # we can try also "highs" at some point
@@ -152,10 +152,10 @@ def process_solution(model):
152152
print("avg_size_of_non_trivial_SCC:", solve_statistics['avg_size_of_non_trivial_SCC']) # size = number of edges
153153

154154
def main():
155-
# test_min_flow_decomp(filename = "tests/cyclic_graphs/gt3.kmer15.(130000.132000).V23.E32.cyc100.graph")
155+
test_min_flow_decomp(filename = "tests/cyclic_graphs/gt3.kmer15.(130000.132000).V23.E32.cyc100.graph")
156156
test_min_flow_decomp(filename = "tests/cyclic_graphs/gt5.kmer27.(1300000.1400000).V809.E1091.mincyc1000.graph")
157-
# test_least_abs_errors(filename = "tests/cyclic_graphs/gt5.kmer27.(655000.660000).V18.E27.mincyc4.e0.75.graph")
158-
# test_min_path_error(filename = "tests/cyclic_graphs/gt5.kmer27.(655000.660000).V18.E27.mincyc4.e0.75.graph")
157+
test_least_abs_errors(filename = "tests/cyclic_graphs/gt5.kmer27.(655000.660000).V18.E27.mincyc4.e0.75.graph")
158+
test_min_path_error(filename = "tests/cyclic_graphs/gt5.kmer27.(655000.660000).V18.E27.mincyc4.e0.75.graph")
159159

160160
if __name__ == "__main__":
161161
# Configure logging

flowpaths/abstractwalkmodeldigraph.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,10 @@ def __init__(
164164
)
165165

166166
self._is_solved = False
167-
167+
168+
if not hasattr(self, "solve_time_start") or self.solve_time_start is None:
169+
self.solve_time_start = time.perf_counter()
170+
168171
def create_solver_and_walks(self):
169172
"""
170173
Creates a solver instance and encodes the walks in the graph.
@@ -611,6 +614,7 @@ def solve(self) -> bool:
611614
start_time = time.perf_counter()
612615
self.solver.optimize()
613616
self.solve_statistics[f"solve_time_ilp"] = time.perf_counter() - start_time
617+
self.solve_statistics[f"solve_time"] = time.perf_counter() - self.solve_time_start
614618
self.solve_statistics[f"model_status"] = self.solver.get_model_status()
615619
self.solve_statistics[f"number_of_nontrivial_SCCs"] = self.G.get_number_of_nontrivial_SCCs()
616620
self.solve_statistics[f"avg_size_of_non_trivial_SCC"] = self.G.get_avg_size_of_non_trivial_SCC()
@@ -672,9 +676,7 @@ def get_solution_walks(self) -> list:
672676
"""
673677

674678
if self.edge_vars_sol == {}:
675-
self.edge_vars_sol = self.solver.get_variable_values(
676-
"edge", [str, str, int]
677-
)
679+
self.edge_vars_sol = self.solver.get_values(self.edge_vars)
678680
# utils.logger.debug(f"{__name__}: Getting solution walks with self.edge_vars_sol = {self.edge_vars_sol}")
679681

680682
# self.distance_vars_sol = self.solver.get_variable_values("distance", [str, int])

flowpaths/kflowdecompcycles.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import flowpaths.utils as utils
55
import flowpaths.nodeexpandeddigraph as nedg
66
import copy
7-
7+
import time
88

99
class kFlowDecompCycles(walkmodel.AbstractWalkModelDiGraph):
1010
def __init__(
@@ -161,6 +161,7 @@ def __init__(
161161
self._lowerbound_k = None
162162

163163
self.solve_statistics = {}
164+
self.solve_time_start = time.perf_counter()
164165

165166
self.optimization_options["trusted_edges_for_safety"] = self.G.get_non_zero_flow_edges(flow_attr=self.flow_attr, edges_to_ignore=self.edges_to_ignore)
166167

@@ -202,9 +203,7 @@ def __init__(
202203

203204
def _encode_flow_decomposition(self):
204205

205-
# print("edge_upper_bounds", self.edge_upper_bounds)
206206
# pi vars
207-
# edge_ubs = [self.edge_upper_bounds[(u, v)] for (u, v, i) in self.edge_indexes]
208207
self.pi_vars = self.solver.add_variables(
209208
self.edge_indexes,
210209
name_prefix="pi",
@@ -326,7 +325,7 @@ def get_solution(self, remove_empty_walks=True):
326325

327326
self.check_is_solved()
328327

329-
weights_sol_dict = self.solver.get_variable_values("weights", [int])
328+
weights_sol_dict = self.solver.get_values(self.path_weights_vars)
330329

331330
utils.logger.debug(f"{__name__}: weights_sol_dict = {weights_sol_dict}")
332331

flowpaths/kleastabserrorscycles.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import flowpaths.nodeexpandeddigraph as nedg
66
import copy
77
import numpy as np
8+
import time
89

910
class kLeastAbsErrorsCycles(walkmodel.AbstractWalkModelDiGraph):
1011
def __init__(
@@ -216,6 +217,7 @@ def __init__(
216217
self._lowerbound_k = None
217218

218219
self.solve_statistics = {}
220+
self.solve_time_start = time.perf_counter()
219221

220222
# If we get subset constraints, and the coverage fraction is 1
221223
# then we know their edges must appear in the solution, so we add their edges to the trusted edges for safety
@@ -371,7 +373,7 @@ def get_solution(self, remove_empty_walks=True):
371373

372374
self.check_is_solved()
373375

374-
weights_sol_dict = self.solver.get_variable_values("weights", [int])
376+
weights_sol_dict = self.solver.get_values(self.path_weights_vars)
375377

376378
utils.logger.debug(f"{__name__}: weights_sol_dict = {weights_sol_dict}")
377379

@@ -383,7 +385,7 @@ def get_solution(self, remove_empty_walks=True):
383385
)
384386
for i in range(self.k)
385387
]
386-
self.edge_errors_sol = self.solver.get_variable_values("ee", [str, str])
388+
self.edge_errors_sol = self.solver.get_values(self.edge_errors_vars)
387389
for (u,v) in self.edge_indexes_basic:
388390
self.edge_errors_sol[(u,v)] = round(self.edge_errors_sol[(u,v)]) if self.weight_type == int else float(self.edge_errors_sol[(u,v)])
389391

flowpaths/kminpatherrorcycles.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import flowpaths.nodeexpandeddigraph as nedg
66
import copy
77
import numpy as np
8-
8+
import time
99

1010
class kMinPathErrorCycles(walkmodel.AbstractWalkModelDiGraph):
1111
def __init__(
@@ -197,7 +197,8 @@ def __init__(
197197
self._lowerbound_k = None
198198

199199
self.solve_statistics = {}
200-
200+
self.solve_time_start = time.perf_counter()
201+
201202
if trusted_edges_for_safety_percentile is not None:
202203
# Select edges where the flow_attr value is >= trusted_edges_for_safety_percentile (using self.G)
203204
flow_values = [self.G.edges[edge][flow_attr] for edge in self.G.edges() if flow_attr in self.G.edges[edge]]
@@ -399,7 +400,7 @@ def get_solution(self, remove_empty_walks=True):
399400

400401
self.check_is_solved()
401402

402-
weights_sol_dict = self.solver.get_variable_values("weights", [int])
403+
weights_sol_dict = self.solver.get_values(self.path_weights_vars)
403404
self.path_weights_sol = [
404405
(
405406
round(weights_sol_dict[i])
@@ -408,7 +409,7 @@ def get_solution(self, remove_empty_walks=True):
408409
)
409410
for i in range(self.k)
410411
]
411-
slacks_sol_dict = self.solver.get_variable_values("slack", [int])
412+
slacks_sol_dict = self.solver.get_values(self.path_slacks_vars)
412413
self.path_slacks_sol = [
413414
(
414415
round(slacks_sol_dict[i])

flowpaths/kpathcovercycles.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import flowpaths.utils as utils
55
import flowpaths.nodeexpandeddigraph as nedg
66
from copy import deepcopy
7+
import time
78

89
class kPathCoverCycles(walkmodel.AbstractWalkModelDiGraph):
910
def __init__(
@@ -128,6 +129,7 @@ def __init__(
128129
self._lowerbound_k = None
129130

130131
self.solve_statistics = {}
132+
self.solve_time_start = time.perf_counter()
131133
self.optimization_options = optimization_options.copy() if optimization_options else {}
132134
self.optimization_options["trusted_edges_for_safety"] = set(e for e in self.G.edges() if e not in self.edges_to_ignore)
133135

0 commit comments

Comments
 (0)