Cutwidth¶
This module implements several algorithms to compute the cutwidth of a graph and the corresponding ordering of the vertices. It also implements tests functions for evaluation the width of a linear ordering (or layout).
Given an ordering
of the vertices of
, its cost is defined as:
Where
The cutwidth of a graph is equal to the minimum cost of an ordering of its
vertices.
This module contains the following methods
cutwidth() |
Return the cutwidth of the graph and the corresponding vertex ordering. |
cutwidth_dyn() |
Compute the cutwidth of ![]() |
cutwidth_MILP() |
Compute the cutwidth of ![]() |
width_of_cut_decomposition() |
Return the width of the cut decomposition induced by the linear ordering ![]() ![]() |
Exponential algorithm for cutwidth¶
In order to find an optimal ordering of the vertices for the vertex separation,
this algorithm tries to save time by computing the function at most
once once for each of the sets
. These values are stored in
an array of size
where reading the value of
or updating it can be
done in constant time.
Assuming that we can compute the cost of a set and remember it, finding an
optimal ordering is an easy task. Indeed, we can think of the sequence
of vertices as a sequence of sets
, whose cost is precisely
. Hence, when considering the digraph on the
sets
where there is an arc from
to
if
for some
(that is, if the sets
and
can be consecutive in a
sequence), an ordering of the vertices of
corresponds to a path from
to
. In this setting, checking whether there exists
a ordering of cost less than
can be achieved by checking whether there
exists a directed path
to
using only sets of cost
less than
. This is just a depth-first-search, for each
.
Lazy evaluation of
In the previous algorithm, most of the time is actually spent on the computation
of for each set
– i.e.
computations of
neighborhoods. This can be seen as a huge waste of time when noticing that it is
useless to know that the value
for a set
is less than
if all the
paths leading to
have a cost greater than
. For this reason, the value of
is computed lazily during the depth-first search. Explanation :
When the depth-first search discovers a set of size less than , the costs of
its out-neighbors (the potential sets that could follow it in the optimal
ordering) are evaluated. When an out-neighbor is found that has a cost smaller
than
, the depth-first search continues with this set, which is explored with
the hope that it could lead to a path toward
. On the other
hand, if an out-neighbour has a cost larger than
it is useless to attempt to
build a cheap sequence going though this set, and the exploration stops
there. This way, a large number of sets will never be evaluated and a lot of
computational time is saved this way.
Besides, some improvement is also made by “improving” the values found by
. Indeed,
is a lower bound on the cost of a sequence containing the
set
, but if all out-neighbors of
have a cost of
then one
knows that having
in a sequence means a total cost of at least
. For this reason, for each set
we store the value of
, and replace
it by
(where
is the
minimum of the costs of the out-neighbors of
) once the costs of these
out-neighbors have been evaluated by the algorithm.
This algorithm and its implementation are very similar to
sage.graphs.graph_decompositions.vertex_separation.vertex_separation_exp()
.
The main difference is in the computation of . See the
vertex
separation module's documentation
for more details on this
algorithm.
Note
Because of its current implementation, this algorithm only works on graphs on strictly less than 32 vertices. This can be changed to 64 if necessary, but 32 vertices already require 4GB of memory.
MILP formulation for the cutwidth¶
We describe a mixed integer linear program (MILP) for determining an
optimal layout for the cutwidth of .
Variables:
– Variable set to 1 if vertex
is placed in the ordering at position
with
, and 0 otherwise.
– Variable set to 1 if one of
or
is at a position
and the other is at a position
, and so we have to count edge
at position
. Otherwise,
. The value of
is a xor of the values of
and
.
– Objective value to minimize. It is equal to the maximum over all position
of the number of edges with one extremity at position at most
and the other at position stricly more than
, that is
.
MILP formulation:
Constraints (1)-(3) ensure that all vertices have a distinct position.
Constraints (4)-(5) force variable to 1 if the edge is in the cut.
Constraint (6) count the number of edges starting at position at most
and
ending at a position stricly larger than
.
This formulation corresponds to method cutwidth_MILP()
.
Authors¶
- David Coudert (2015-06): Initial version
Methods¶
-
sage.graphs.graph_decompositions.cutwidth.
cutwidth
(G, algorithm='exponential', cut_off=0, solver=None, verbose=False)¶ Return the cutwidth of the graph and the corresponding vertex ordering.
INPUT:
G
– a Graph or a DiGraphalgorithm
– (default:"exponential"
) Specify the algorithm to use amongexponential
– Use an exponential time and space algorithm based on dynamic programming. This algorithm only works on graphs with strictly less than 32 vertices.MILP
– Use a mixed integer linear programming formulation. This algorithm has no size restriction but could take a very long time.
cut_off
– (default: 0) This parameter is used to stop the search as soon as a solution with width at mostcut_off
is found, if any. If this bound cannot be reached, the best solution found is returned.solver
– (default:None
) Specify a Linear Program (LP) solver to be used. If set toNone
, the default one is used. This parameter is used only whenalgorithm='MILP'
. For more information on LP solvers and which default solver is used, see the methodsolve
of the classMixedIntegerLinearProgram
.verbose
(boolean) – whether to display information on the computations.
OUTPUT:
A pair
(cost, ordering)
representing the optimal ordering of the vertices and its cost.EXAMPLES:
Cutwidth of a Complete Graph:
sage: from sage.graphs.graph_decompositions.cutwidth import cutwidth sage: G = graphs.CompleteGraph(5) sage: cw,L = cutwidth(G); cw 6 sage: K = graphs.CompleteGraph(6) sage: cw,L = cutwidth(K); cw 9 sage: cw,L = cutwidth(K+K); cw 9
The cutwidth of a
Grid Graph with
is
:
sage: from sage.graphs.graph_decompositions.cutwidth import cutwidth sage: G = graphs.Grid2dGraph(3,3) sage: cw,L = cutwidth(G); cw 4 sage: G = graphs.Grid2dGraph(3,5) sage: cw,L = cutwidth(G); cw 4
-
sage.graphs.graph_decompositions.cutwidth.
cutwidth_MILP
(G, lower_bound=0, solver=None, verbose=0)¶ MILP formulation for the cutwidth of a Graph.
This method uses a mixed integer linear program (MILP) for determining an optimal layout for the cutwidth of
. See the
module's documentation
for more details on this MILP formulation.INPUT:
G
– a Graphlower_bound
– (default: 0) the algorithm searches for a solution with cost larger or equal tolower_bound
. If the given bound is larger than the optimal solution the returned solution might not be optimal. If the given bound is too high, the algorithm might not be able to find a feasible solution.solver
– (default:None
) Specify a Linear Program (LP) solver to be used. If set toNone
, the default one is used. For more information on LP solvers and which default solver is used, see the methodsolve
of the classMixedIntegerLinearProgram
.verbose
– integer (default:0
). Sets the level of verbosity. Set to 0 by default, which means quiet.
OUTPUT:
A pair
(cost, ordering)
representing the optimal ordering of the vertices and its cost.EXAMPLES:
Cutwidth of a Cycle graph:
sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CycleGraph(5) sage: cw, L = cutwidth.cutwidth_MILP(G); cw 2 sage: cw == cutwidth.width_of_cut_decomposition(G, L) True sage: cwe, Le = cutwidth.cutwidth_dyn(G); cwe 2
Cutwidth of a Complete graph:
sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CompleteGraph(4) sage: cw, L = cutwidth.cutwidth_MILP(G); cw 4 sage: cw == cutwidth.width_of_cut_decomposition(G, L) True
Cutwidth of a Path graph:
sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.PathGraph(3) sage: cw, L = cutwidth.cutwidth_MILP(G); cw 1 sage: cw == cutwidth.width_of_cut_decomposition(G, L) True
-
sage.graphs.graph_decompositions.cutwidth.
cutwidth_dyn
(G, lower_bound=0)¶ Dynamic programming algorithm for the cutwidth of a Graph.
This function uses dynamic programming algorithm for determining an optimal layout for the cutwidth of
. See the
module's documentation
for more details on this method.INPUT:
G
– a Graphlower_bound
– (default: 0) the algorithm returns immediately if it finds a solution lower or equal tolower_bound
(in which case it may not be optimal).
OUTPUT:
A pair
(cost, ordering)
representing the optimal ordering of the vertices and its cost.Note
Because of its current implementation, this algorithm only works on graphs on strictly less than 32 vertices. This can be changed to 63 if necessary, but 32 vertices already require 4GB of memory.
-
sage.graphs.graph_decompositions.cutwidth.
width_of_cut_decomposition
(G, L)¶ Returns the width of the cut decomposition induced by the linear ordering
of the vertices of
.
If
is an instance of
Graph
, this function returns the widthof the cut decomposition induced by the linear ordering
of the vertices of
.
INPUT:
G
– a GraphL
– a linear ordering of the vertices ofG
EXAMPLES:
Cut decomposition of a Cycle graph:
sage: from sage.graphs.graph_decompositions import cutwidth sage: G = graphs.CycleGraph(6) sage: L = G.vertices() sage: cutwidth.width_of_cut_decomposition(G, L) 2
Cut decomposition of a Path graph:
sage: from sage.graphs.graph_decompositions import cutwidth sage: P = graphs.PathGraph(6) sage: cutwidth.width_of_cut_decomposition(P, [0, 1, 2, 3, 4, 5]) 1 sage: cutwidth.width_of_cut_decomposition(P, [5, 0, 1, 2, 3, 4]) 2 sage: cutwidth.width_of_cut_decomposition(P, [0, 2, 4, 1, 3, 5]) 5