Skip to content

Commit 5aa5f2f

Browse files
Fixed bug in mingenset lowerbound
1 parent f895076 commit 5aa5f2f

File tree

9 files changed

+68
-11
lines changed

9 files changed

+68
-11
lines changed

examples/min_gen_set.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,23 @@ def example2():
3232
mgs_solver.solve()
3333
process_solution(mgs_solver)
3434

35+
def example3():
36+
numbers = [2,4,6,7,9]
37+
total=13
38+
partition_constraints = []
39+
40+
mgs_solver = fp.MinGenSet(
41+
numbers,
42+
total=total,
43+
weight_type=int,
44+
partition_constraints=partition_constraints,
45+
# remove_sums_of_two=False,
46+
# remove_complement_values=False,
47+
)
48+
49+
mgs_solver.solve()
50+
process_solution(mgs_solver)
51+
3552
def process_solution(model: fp.MinGenSet):
3653
if model.is_solved():
3754
print(model.get_solution())
@@ -41,4 +58,5 @@ def process_solution(model: fp.MinGenSet):
4158

4259
if __name__ == "__main__":
4360
example1()
44-
example2()
61+
example2()
62+
example3()

flowpaths/kflowdecomp.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,8 @@ def __init__(
164164

165165
# Call the constructor of the parent class AbstractPathModelDAG
166166
super().__init__(
167-
self.G,
168-
self.k,
167+
G=self.G,
168+
k=self.k,
169169
subpath_constraints=self.subpath_constraints,
170170
subpath_constraints_coverage=self.subpath_constraints_coverage,
171171
subpath_constraints_coverage_length=self.subpath_constraints_coverage_length,
@@ -188,7 +188,7 @@ def __init__(
188188
# The given weights optimization
189189
self.__encode_given_weights()
190190

191-
utils.logger.info(f"{__name__}: initialized with graph id = {id(G)}, k = {self.k}")
191+
utils.logger.info(f"{__name__}: initialized with graph id = {utils.fpid(G)}, k = {self.k}")
192192

193193
def __encode_flow_decomposition(self):
194194

flowpaths/kleastabserrors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def __init__(
186186
# This method is called from the current class to add the objective function
187187
self.__encode_objective()
188188

189-
utils.logger.info(f"{__name__}: initialized with graph id = {id(G)}, k = {self.k}")
189+
utils.logger.info(f"{__name__}: initialized with graph id = {utils.fpid(G)}, k = {self.k}")
190190

191191
def __encode_leastabserrors_decomposition(self):
192192

flowpaths/kminpatherror.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ def __init__(
222222
# This method is called from the current class to add the objective function
223223
self.__encode_objective()
224224

225-
utils.logger.info(f"{__name__}: initialized with graph id = {id(G)}, k = {self.k}")
225+
utils.logger.info(f"{__name__}: initialized with graph id = {utils.fpid(G)}, k = {self.k}")
226226

227227
def __encode_minpatherror_decomposition(self):
228228

flowpaths/minerrorflow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def __init__(
102102

103103
self.__encode_objective()
104104

105-
utils.logger.info(f"{__name__}: initialized with graph id = {id(G)}")
105+
utils.logger.info(f"{__name__}: initialized with graph id = {utils.fpid(G)}")
106106

107107
def __create_solver(self):
108108

flowpaths/minflowdecomp.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,9 @@ def __init__(
129129
self.__generating_set = None
130130
self.__all_subgraph_weights = None
131131
self.__given_weights_model = None
132+
self.__source_flow = None
132133

133-
utils.logger.info(f"{__name__}: initialized with graph id = {id(G)}")
134+
utils.logger.info(f"{__name__}: initialized with graph id = {utils.fpid(G)}")
134135

135136
def solve(self) -> bool:
136137
"""
@@ -236,6 +237,21 @@ def __solve_with_given_weights(self) -> bool:
236237
self.__given_weights_model = given_weights_kfd_solver
237238
sol = self.__given_weights_model.get_solution(remove_empty_paths=True)
238239
utils.logger.info(f"{__name__}: found an MFD solution with given weights in {len(sol['paths'])} paths weights {sol['weights']}")
240+
else:
241+
utils.logger.info(f"{__name__}: did NOT found an MFD solution with given weights")
242+
243+
def __get_source_flow(self):
244+
if self.__source_flow is None:
245+
self.__source_flow = 0
246+
for v in self.G.nodes():
247+
if self.G.in_degree(v) == 0:
248+
for _, _, data in self.G.out_edges(v, data=True):
249+
if self.flow_attr in data:
250+
self.__source_flow += data[self.flow_attr]
251+
utils.logger.debug(f"{__name__}: source_flow = {self.__source_flow}")
252+
return self.__source_flow
253+
else:
254+
return self.__source_flow
239255

240256
def __get_partition_constraints_for_min_gen_set(
241257
self,
@@ -271,7 +287,7 @@ def __get_partition_constraints_for_min_gen_set(
271287
for i in range(level[u], level[v]):
272288
level_edges[i].append((u, v))
273289

274-
source_flow = sum(self.G.nodes[n].get(self.flow_attr, 0) for n in self.G.nodes() if self.G.in_degree(n) == 0)
290+
source_flow = self.__get_source_flow()
275291

276292
# Now we create the partition constraints
277293
for i in range(max_level):
@@ -306,7 +322,10 @@ def __get_lowerbound_with_min_gen_set(self) -> int:
306322

307323
start_time = time.time()
308324
all_weights = list(set({self.G.edges[e][self.flow_attr] for e in self.G.edges() if self.flow_attr in self.G.edges[e]}))
309-
source_flow = sum(self.G.nodes[n].get(self.flow_attr, 0) for n in self.G.nodes() if self.G.in_degree(n) == 0)
325+
# Get the source_flow as the sum of the flow values on all the edges exiting the source nodes
326+
# (i.e., nodes with in-degree 0)
327+
source_flow = self.__get_source_flow()
328+
# source_flow = sum(self.G.nodes[n].get(self.flow_attr, 0) for n in self.G.nodes() if self.G.in_degree(n) == 0)
310329
current_lowerbound_k = self.__lowerbound_k if self.__lowerbound_k is not None else 1
311330
min_gen_set_lowerbound = None
312331

@@ -332,6 +351,9 @@ def __get_lowerbound_with_min_gen_set(self) -> int:
332351
self.__generating_set = mingenset_model.get_solution()
333352
min_gen_set_lowerbound = len(self.__generating_set)
334353
utils.logger.info(f"{__name__}: found a min gen set solution with {min_gen_set_lowerbound} elements ({self.__generating_set})")
354+
else:
355+
utils.logger.info(f"{__name__}: did NOT find a min gen set solution")
356+
exit(0)
335357

336358
self.solve_statistics["min_gen_set_solve_time"] = time.time() - start_time
337359

flowpaths/mingenset.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import flowpaths.utils.solverwrapper as sw
2+
import flowpaths.utils as utils
23
import time
34

45
class MinGenSet():
@@ -65,8 +66,10 @@ def __init__(
6566
"""
6667

6768
self.numbers = list(numbers) # Make a copy of the list
69+
utils.logger.debug(f"{__name__}: Initial numbers: {self.numbers}")
6870
self.initial_numbers = numbers
6971
self.total = total
72+
utils.logger.debug(f"Total: {self.total}")
7073
self.weight_type = weight_type
7174
self.lowerbound = lowerbound
7275
self.partition_constraints = partition_constraints
@@ -98,6 +101,8 @@ def __init__(
98101

99102
self.numbers = list(set(self.numbers) - elements_to_remove)
100103

104+
utils.logger.debug(f"{__name__}: Numbers after removing values: {self.numbers}")
105+
101106
def __create_solver(self, k):
102107

103108
self.solver = sw.SolverWrapper()

flowpaths/utils/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from .graphutils import max_bottleneck_path
33
from .graphutils import check_flow_conservation
44
from .graphutils import draw_solution
5+
from .graphutils import fpid
56
from .logging import configure_logging
67
from .logging import logger
78

@@ -12,4 +13,5 @@
1213
"draw_solution",
1314
"configure_logging",
1415
"logger",
16+
"fpid"
1517
]

flowpaths/utils/graphutils.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33

44
bigNumber = 1 << 32
55

6+
def fpid(G) -> str:
7+
"""
8+
Returns a unique identifier for the given graph.
9+
"""
10+
if isinstance(G, nx.DiGraph):
11+
if "id" in G.graph:
12+
return G.graph["id"]
13+
14+
return str(id(G))
15+
616
def read_graph(graph_raw) -> nx.DiGraph:
717
# Input format is: ['#Graph id\n', 'n\n', 'u_1 v_1 w_1\n', ..., 'u_k v_k w_k\n']
818
id = graph_raw[0].strip("# ").strip()
@@ -22,7 +32,7 @@ def read_graph(graph_raw) -> nx.DiGraph:
2232
# print(elements)
2333
u = elements[0].strip()
2434
v = elements[1].strip()
25-
w = int(elements[2].strip(" \n"))
35+
w = float(elements[2].strip(" \n"))
2636
# print(u, v, w)
2737
G.add_edge(u, v, flow=w)
2838

0 commit comments

Comments
 (0)