Minimum Path Cover
1. Definition
The Minimum Path Cover problem on a directed acyclic graph (DAG) is defined as follows:
-
INPUT: A directed graph \(G = (V,E)\).
-
OUTPUT: A minimum number \(k\) of source-to-sink paths, \(P_1,\dots,P_k\) such that every edge \(e \in E\) appears in at least one \(P_i\).
Note
- This class support also covers of nodes. Set the parameter
cover_type = "node"
. For details on how these are handled internally, see Handling graphs with flows / weights on nodes. - The graph may have more than one source or sink nodes, in which case the solution paths are just required to start in any source node, and end in any sink node.
2. Solving the problem
We create the graph as a networkx DiGraph. In real project, you will likely have a method that transforms your graph to a DiGraph. We also give an attribute flow
for every edge storing its flow value.
import flowpaths as fp
import networkx as nx
graph = nx.DiGraph()
graph.add_edge("s", "a")
graph.add_edge("s", "b")
graph.add_edge("a", "b")
graph.add_edge("a", "c")
graph.add_edge("b", "c")
graph.add_edge("c", "d")
graph.add_edge("c", "t")
graph.add_edge("d", "t")
mpc_model = fp.MinPathCover(graph)
mpc_model.solve()
The solution of MinPathCover
is a dictionary, with an key 'paths'
containing the solution paths:
if mpc_model.is_solved():
solution = mpc_model.get_solution()
print(solution)
# {'paths': [
# ['s', 'b', 'c', 't'],
# ['s', 'a', 'b', 'c', 'd', 't'],
# ['s', 'a', 'c', 't']]}
We can also support subpath constraints:
subpath_constraints=[[("a", "c"),("c", "t")]]
mpc_model_sc = fp.MinPathCover(
graph,
subpath_constraints=subpath_constraints,
)
mpc_model_sc.solve()
MinPathCover
MinPathCover(
G: DiGraph,
cover_type: str = "edge",
subpath_constraints: list = [],
subpath_constraints_coverage: float = 1.0,
subpath_constraints_coverage_length: float = None,
length_attr: str = None,
elements_to_ignore: list = [],
additional_starts: list = [],
additional_ends: list = [],
optimization_options: dict = {},
solver_options: dict = {},
)
Bases: AbstractPathModelDAG
This class finds a minimum number of paths covering the edges of a directed acyclic graph (DAG) – and generalizations of this problem, see the parameters below.
Parameters
-
G: nx.DiGraph
The input directed acyclic graph, as networkx DiGraph.
-
cover_type: str
, optionalThe elements of the graph to cover. Default is
"edge"
. Options:"edge"
: cover the edges of the graph. This is the default."node"
: cover the nodes of the graph.
-
subpath_constraints: list
, optionalList of subpath constraints. Default is an empty list. Each subpath constraint is a list of edges that must be covered by some solution path, according to the
subpath_constraints_coverage
orsubpath_constraints_coverage_length
parameters (see below). -
subpath_constraints_coverage: float
, optionalCoverage fraction of the subpath constraints that must be covered by some solution paths.
Defaults to
1.0
, meaning that 100% of the edges (or nodes, ifflow_attr_origin
is"node"
) of the constraint need to be covered by some solution path). See subpath constraints documentation -
subpath_constraints_coverage_length: float
, optionalCoverage length of the subpath constraints. Default is
None
. If set, this overridessubpath_constraints_coverage
, and the coverage constraint is expressed in terms of the subpath constraint length.subpath_constraints_coverage_length
is then the fraction of the total length of the constraint (specified vialength_attr
) needs to appear in some solution path. See subpath constraints documentation -
length_attr: str
, optionalThe attribute name from where to get the edge lengths (or node length, if
flow_attr_origin
is"node"
). Defaults toNone
.- If set, then the subpath lengths (above) are in terms of the edge/node lengths specified in the
length_attr
field of each edge/node. - If set, and an edge/node has a missing edge length, then it gets length 1.
- If set, then the subpath lengths (above) are in terms of the edge/node lengths specified in the
-
elements_to_ignore: list
, optionalList of graph elements to ignore when adding constrains on flow explanation by the weighted paths. These elements are either edges or nodes, depending on the
cover_type
parameter. Default is an empty list. See ignoring edges documentation -
additional_starts: list
, optionalList of additional start nodes of the paths. Default is an empty list. See additional start/end nodes documentation.
-
additional_ends: list
, optionalList of additional end nodes of the paths. Default is an empty list. See additional start/end nodes documentation.
-
optimization_options: dict
, optionalDictionary with the optimization options. Default is
None
. See optimization options documentation. -
solver_options: dict
, optionalDictionary with the solver options. Default is
None
. See solver options documentation.
Source code in flowpaths/minpathcover.py
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
|
get_solution
Get the solution of the Min Path Cover model, as dict with unique key "paths"
.
kPathCover
kPathCover(
G: DiGraph,
k: int,
cover_type: str = "edge",
subpath_constraints: list = [],
subpath_constraints_coverage: float = 1.0,
subpath_constraints_coverage_length: float = None,
length_attr: str = None,
elements_to_ignore: list = [],
additional_starts: list = [],
additional_ends: list = [],
optimization_options: dict = {},
solver_options: dict = {},
)
Bases: AbstractPathModelDAG
This class finds, if possible, k
paths covering the edges of a directed acyclic graph (DAG) – and generalizations of this problem, see the parameters below.
Parameters
-
G : nx.DiGraph
The input directed acyclic graph, as networkx DiGraph.
-
k: int
The number of paths to decompose in.
-
cover_type : str
, optionalThe elements of the graph to cover. Default is
"edge"
. Options:"edge"
: cover the edges of the graph. This is the default."node"
: cover the nodes of the graph.
-
subpath_constraints: list
, optionalList of subpath constraints. Default is an empty list. Each subpath constraint is a list of edges that must be covered by some solution path, according to the
subpath_constraints_coverage
orsubpath_constraints_coverage_length
parameters (see below). -
subpath_constraints_coverage: float
, optionalCoverage fraction of the subpath constraints that must be covered by some solution paths.
Defaults to
1.0
, meaning that 100% of the edges (or nodes, ifflow_attr_origin
is"node"
) of the constraint need to be covered by some solution path). See subpath constraints documentation -
subpath_constraints_coverage_length: float
, optionalCoverage length of the subpath constraints. Default is
None
. If set, this overridessubpath_constraints_coverage
, and the coverage constraint is expressed in terms of the subpath constraint length.subpath_constraints_coverage_length
is then the fraction of the total length of the constraint (specified vialength_attr
) needs to appear in some solution path. See subpath constraints documentation -
length_attr: str
, optionalThe attribute name from where to get the edge lengths (or node length, if
flow_attr_origin
is"node"
). Defaults toNone
.- If set, then the subpath lengths (above) are in terms of the edge/node lengths specified in the
length_attr
field of each edge/node. - If set, and an edge/node has a missing edge length, then it gets length 1.
- If set, then the subpath lengths (above) are in terms of the edge/node lengths specified in the
-
elements_to_ignore: list
, optionalList of edges (or nodes, if
flow_attr_origin
is"node"
) to ignore when adding constrains on flow explanation by the weighted paths. Default is an empty list. See ignoring edges documentation -
additional_starts: list
, optionalList of additional start nodes of the paths. Default is an empty list. See additional start/end nodes documentation.
-
additional_ends: list
, optionalList of additional end nodes of the paths. Default is an empty list. See additional start/end nodes documentation.
-
optimization_options : dict
, optionalDictionary with the optimization options. Default is
None
. See optimization options documentation. -
solver_options : dict
, optionalDictionary with the solver options. Default is
None
. See solver options documentation.
Source code in flowpaths/kpathcover.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
|
get_solution
Retrieves the solution for the k-path cover problem.
Returns
-
solution: dict
A dictionary containing the solution paths, under key
"paths"
.
Raises
exception
If model is not solved.
Source code in flowpaths/kpathcover.py
is_valid_solution
Checks if the solution is valid, meaning it covers all required edges.
Raises
- ValueError: If the solution is not available (i.e., self.solution is None).
Returns
- bool: True if the solution is valid, False otherwise.
Notes
- get_solution() must be called before this method.