# Ticket #12716: trac_12716_linear_ordering.patch

File trac_12716_linear_ordering.patch, 35.7 KB (added by dcoudert, 9 years ago)
• ## doc/en/reference/graphs.rst

# HG changeset patch
# User dcoudert <david.coudert@inria.fr>
# Date 1332092768 -3600
# Node ID 46f64db1dee735774b0c1a40399cf43ff66a13e1
diff --git a/doc/en/reference/graphs.rst b/doc/en/reference/graphs.rst
diff --git a/sage/graphs/graph_decompositions/linear_ordering.py b/sage/graphs/graph_decompositions/linear_ordering.py
new file mode 100644
 - r""" Linear orderings of graphs and digraphs This module implements several algorithms for computing and evaluating linear vertex ordering of graphs and digraphs. The of a linear ordering is one of the following values. +--------------+----------------------------+ | short name   |  long name                 | +==============+============================+ | vs           | vertex_separation          | +--------------+----------------------------+ | pw           | pathwidth                  | +--------------+----------------------------+ | tw           | treewidth                  | +--------------+----------------------------+ | bw           | bandwidth                  | +--------------+----------------------------+ | pn           | process_number             | +--------------+----------------------------+ | cw           | cutwidth                   | +--------------+----------------------------+ | mcw          | modified_cutwidth          | +--------------+----------------------------+ | ola          | optimal_linear_arrangement | +--------------+----------------------------+ | sc           | sum_cut                    | +--------------+----------------------------+ | mfi          | minimun_fill_in            | +--------------+----------------------------+ Some of these widths are defined for both graphs and digraphs, and others only for graphs or for digraphs. We follow the formulations proposed in [Bod98]_ and [BFK+11]_ for the evaluation of the widths induced by a linear vertex ordering L=[v_1, ..., v_n] of the vertices of a (di)graph G=(V,E).  Thus, we consider that we have a function f associating an integer to each 3-tuple, consisting of a (di)graph G=(V,E), a vertex set S\subseteq V, and a vertex v\in V. Let L[:i]=[v_1, ..., v_i] be a prefix of the ordering and so a subset of V. We consider the problems that can be formulated as the computation of: .. MATH:: \text{cost}(G, L) = \max_{0\leq i<|V(G)|} f(G, L[:i]\setminus\{v\}, v) or .. MATH:: \text{cost}(G, L) = \sum_{0\leq i<|V(G)|} f(G, L[:i]\setminus\{v\}, v) Given an ordering v_1, ..., v_n of the vertices of V(G), its *cost* is defined as: **Vertex separation** The vertex separation of a linear ordering L of the vertices of a digraph D is measured as the maximum number of out-neighbors with position k>i in the ordering of the vertices with position j<=i in the ordering. That is, .. MATH:: vs_L(D) =  \max_{1\leq i\leq |V|-1} |\{N^+(L[:i])\setminus L[:i]\}| **Path decomposition** The cost of a path decomposition induced by a linear ordering L of the vertices of a graph G is measured as the maximum number of neighbors with position k>i in the ordering of the vertices with position j<=i in the ordering. That is, .. MATH:: pw_L(G) =  \max_{1\leq i\leq |V|-1} |\{N(L[:i])\setminus L[:i]\}| **Tree decomposition** The value tw_L(G) of the tree decomposition induced by the ordering L of the vertices of G. The cost of a tree decomposition is mesured by the maximum number of vertices with position j > i in the vertex ordering that can be reached from a vertex v at position i through a path with internal vertices at positions <= i. Let Z(i) be the set of vertices that can be reached from the vertex at position i. We have .. MATH:: tw_L(G) =  \max_{1\leq i\leq |V|-1} | Z( i ) | **Bandwidth** The bandwidth minimization problem is to find a linear vertex ordering that minimizes the maximum dilation among all the edges, where the dilatation of an edge is the distance between its endpoints in the vertex ordering. We can extend the notion to digraphs where the dilatation of an arc (u,v) is the distance between its endpoints if v has a higher index that u in the ordering, and 0 otherwise. So, the bandwidth bw_L(G) of a graph G=(V,E), or the bandwidth bw_L(D) for a digraph D=(V,A), induced by a given vertex ordering L are measured as follows, .. MATH:: bw_L(G) =  \max_{\{u,v\}\in E} | L[u] - L[v] | bw_L(D) =  \max_{\{u,v\}\in A} max( 0, L[v] - L[u] ) **Process number** The process number of a linear ordering L of the vertices of a digraph D is measured as the maximum number of out-neighbors with position k>=i (i included) in the ordering of the vertices with position j<=i (i included) in the ordering. Thus, loops on vertices of the digraph are also taken into account. This notion can also be formulated for undirected graphs (see [CoSe11]_ for more details on this notion). We have, .. MATH:: pn_L(D) =  \max_{1\leq i\leq |V|} |\{N^+(L[:i])\setminus L[:i-1]\}| pn_L(G) =  \max_{1\leq i\leq |V|} |\{N(L[:i])\setminus L[:i-1]\}| **Cutwidth and modified cutwidth** The cutwidth minimization problem is to find an ordering that minimizes the maximum number of edges between vertices with index j<=i in the ordering and vertices with index k>i in the ordering. When considering digraphs, only arcs from j<=i to k>i are considered.  For the modified cutwidth, only edges (or arcs) from vertices with indexes ji are considered. So we count the number of edges (or arcs) passing over the vertex with index i. So, the cutwidth cw_L(G) of a graph G=(V,E), or the cutwidth cw_L(D) for a digraph D=(V,A), or the modified cutwidth mcw_L(G) of a graph G=(V,E), or the modified cutwidth mcw_L(D) for a digraph D=(V,A), induced by a given vertex ordering L are measured as follows, .. MATH:: cw_L(D) =  \max_{1\leq i\leq |V|-1}|\{(u,v)\in A,\ L[u]\leq ii in the ordering. When considering digraphs, only arcs from j<=i to k>i are considered. So, the cost of a linear arrangement ola_L(G) of a graph G=(V,E), or ola_L(D) for a digraph D=(V,A), induced by a given vertex ordering L are measured as follows, .. MATH:: ola_L(G) = \sum_{1\leq i\leq |V|-1} |\{(u,v)\in E,\ L[u]\leq i i in the vertex ordering that can be reached from a vertex v at position i through a path with internal vertices at positions <= i (see tree decompositions). Let Z(i) be the set of vertices that can be reached from the vertex at position i. We have .. MATH:: mfi_L(G) =  \sum_{1\leq i\leq |V|-1} | Z( i ) | REFERENCES: .. [BFK+06] *On exact algorithms for treewidth*, Hans L. Bodlaender, Fedor V. Fomin, Arie M.C.A. Koster, Dieter Kratsch, and Dimitrios M. Thilikos, Proceedings 14th Annual European Symposium on Algorithms (ESA), volume 4168 of Lecture Notes in Computer Science, pages 672-683. Springer, 2006. .. [BFK+11] *A note on exact algorithms for vertex ordering problems on graphs*, Hans L. Bodlaender, Fedor V. Fomin, Arie M.C.A. Koster, Dieter Kratsch, and Dimitrios M. Thilikos, Theory of Computing Systems, 2011 to appear. http://dx.doi.org/10.1007/s00224-011-9312-0. .. [Bod98] *A partial k-arboretum of graphs with bounded treewidth*, Hans L. Bodlaender, Theoretical Computer Science, Volume 209, Issues 1-2, Pages 1-45, 6 December 1998 .. [CoSe11] *Characterization of graphs and digraphs with small process number*, D. Coudert and J-S. Sereni, Discrete Applied Mathematics (DAM), 159(11):1094-1109, July 2011. .. [Kin92] *The vertex separation number of a graph equals its path-width*, Nancy G. Kinnersley, Information Processing Letters, Volume 42, Issue 6, Pages 345-350, 24 July 1992. AUTHORS: - David Coudert (2012-03-20): initial version .. TODO:: * implement methods for computing linear orderings Methods ------- """ #***************************************************************************** #          Copyright (C) 2012 David Coudert # # Distributed  under  the  terms  of  the  GNU  General  Public  License (GPL) #                         http://www.gnu.org/licenses/ #***************************************************************************** class LinearOrdering(): r""" Class gathering methods for manipulating linear orderings of (di)graphs. This module implements several algorithms for computing and evaluating linear vertex ordering of graphs and digraphs. The of a linear ordering is one of the following values. """ def _repr_(self): r""" Returns a string representation of the class LinearOrdering. """ return "Linear Ordering Class" def _latex_(self): r""" Returns the LaTeX representation of the class LinearOrdering. """ return 'Linear Ordering Class' ########################################################## # Function for testing the validity of a vertex ordering # ########################################################## def is_valid(self, G, L): r""" Test if a given linear ordering L is valid for a given (di)graph G. Returns True if L is a valid vertex ordering for G, that is if all vertices of G are in L, and L contains no other vertex and no duplicated vertices. INPUT: - G -- a graph or a digraph - L -- an ordering of the vertices of G OUTPUT: Returns True if L is a valid vertex ordering for G, and False oterwise. EXAMPLE: Path decomposition of a cycle:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = graphs.CycleGraph(6) sage: L = [u for u in G.vertices()] sage: LO.is_valid(G, L) True sage: LO.is_valid(G, [1,2]) False TEST: Giving anything else than a Graph or a DiGraph:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: LO.is_valid(2, []) Traceback (most recent call last): ... ValueError: The input parameter must be a Graph or a DiGraph. """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph if not isinstance(G, Graph) and not isinstance(G, DiGraph): raise ValueError("The input parameter must be a Graph or a DiGraph.") A = set( G.vertices() ) B = set( L ) return len( A.symmetric_difference(B) ) == 0 ############################################################################ # Front end function for the evaluation of linear vertex orderings with    # # different widths                                                         # ############################################################################ def width_of(self, G, L, width = 'vertex_separation'): r""" Returns the of the linear ordering L for G. This function returns the of the vertex ordering L, where width is one of the following values +--------------+----------------------------+ | short name   | long name                  | +==============+============================+ | vs           | vertex_separation          | +--------------+----------------------------+ | pw           | pathwidth                  | +--------------+----------------------------+ | tw           | treewidth                  | +--------------+----------------------------+ | bw           | bandwidth                  | +--------------+----------------------------+ | pn           | process_number             | +--------------+----------------------------+ | cw           | cutwidth                   | +--------------+----------------------------+ | mcw          | modified_cutwidth          | +--------------+----------------------------+ | ola          | optimal_linear_arrangement | +--------------+----------------------------+ | sc           | sum_cut                    | +--------------+----------------------------+ | mfi          | minimun_fill_in            | +--------------+----------------------------+ See the module's documentation for more details on these widths. INPUT: - G -- a graph or a digraph (possibly with multi-edges) - L -- an ordering of the vertices of G - width -- is the graph invariant to consider (vertex_separation by default) OUTPUT: The value of the measured graph invariants for this vertex ordering. NOTES: All width are defined for undirected graphs. For directed graphs, only vertex_separation, bandwidth, process_number, cutwidth, modified_cutwidth, optimal_linear_arrangement, and sum_cut are defined.  Measurements are performed using arcs from u=L[i] to v=L[j], with i<=j. EXAMPLE: Path decomposition of a cycle:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = graphs.CycleGraph(6) sage: LO.width_of(G, [0, 1, 2, 3, 4, 5], 'pw') 2 sage: LO.width_of(G, [0, 2, 4, 1, 5, 3], 'pw') 3 TEST: Giving anything else than a Graph or a DiGraph:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: LO.width_of(2, [], 'pw') Traceback (most recent call last): ... ValueError: The input parameter must be a Graph or a DiGraph. Giving a vertex ordering on a different set of vertices:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = graphs.CycleGraph(6) sage: LO.width_of(G, [1, 2, 3], 'pw') Traceback (most recent call last): ... ValueError: The input parameter is not a valid vertex ordering. Giving a not implemented width parameter:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = graphs.CycleGraph(6) sage: L = [u for u in G.vertices()] sage: LO.width_of(G, L, 'frite') Traceback (most recent call last): ... ValueError: The desired width evaluation function has not been implemented so far.  Feel free to add it. """ from sage.graphs.graph import Graph from sage.graphs.digraph import DiGraph if not isinstance(G, Graph) and not isinstance(G, DiGraph): raise ValueError("The input parameter must be a Graph or a DiGraph.") if not self.is_valid(G, L): raise ValueError("The input parameter is not a valid vertex ordering.") if width in ['pathwidth','pw']: return self.width_of_path_decomposition(G, L) elif width in ['vertex_separation','vs']: return self.width_of_vertex_separation(G, L) elif width in ['process_number','pn']: return self.width_of_process_number(G, L) elif width in ['treewidth','tw']: return self.width_of_tree_decomposition(G, L) elif width in ['cutwidth','cw']: return self.width_of_cutwidth(G, L) elif width in ['modified_cutwidth','mcw']: return self.width_of_modified_cutwidth(G, L) elif width in ['bandwidth','bw']: return self.width_of_bandwidth(G, L) elif width in ['sum_cut','sc']: return self.width_of_sum_cut(G, L) elif width in ['minimum_fill_in','mfi']: return self.width_of_fill_in(G, L) elif width in ['optimal_linear_arrangement','ola']: return self.width_of_linear_arrangement(G, L) else: raise ValueError("The desired width evaluation function has not been implemented so far.  Feel free to add it.") ############################################### # Methods for pathwidth and vertex separation # ############################################### def width_of_path_decomposition(self, G, L): r""" Returns the value pw_L(G) of the path decomposition induced by the vertex ordering L for G, where ..MATH:: pw_L(G) =  \max_{0\leq i< |V|-1} | N(L[:i])\setminus L[:i] | INPUT: - G -- a Graph - L -- an ordering of the vertices of G OUTPUT: The value pw_L(G) of the path decomposition induced by the ordering L of the vertices of G. EXAMPLE: Path decomposition of a cycle:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = graphs.CycleGraph(6) sage: LO.width_of_path_decomposition(G, [0, 1, 2, 3, 4, 5]) 2 sage: LO.width_of_path_decomposition(G, [0, 2, 4, 1, 5, 3]) 3 TEST: Giving anything else than a Graph:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = digraphs.Circuit(4) sage: LO.width_of_path_decomposition(G, []) Traceback (most recent call last): ... ValueError: The input parameter must be a Graph. Giving a vertex ordering on a different set of vertices:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = graphs.CycleGraph(6) sage: LO.width_of_path_decomposition(G, [1, 2, 3]) Traceback (most recent call last): ... ValueError: The input parameter is not a valid vertex ordering. """ # Path decompositions are defined only for graphs from sage.graphs.graph import Graph if not isinstance(G, Graph): raise ValueError("The input parameter must be a Graph.") if not self.is_valid(G, L): raise ValueError("The input parameter is not a valid vertex ordering.") pwL = 0 S = [] neighbors_of_S_in_V_minus_S = [] for u in L: # We remove u from the list of neighbors of S if u in neighbors_of_S_in_V_minus_S: neighbors_of_S_in_V_minus_S.remove(u) # We add vertex u to the set S S += [u] # We add the neighbors of u to the list of neighbors of S for v in G.neighbors(u): if (not v in S) and (not v in neighbors_of_S_in_V_minus_S): neighbors_of_S_in_V_minus_S += [v] # We update the cost of the path decomposition pwL = max( pwL, len(neighbors_of_S_in_V_minus_S) ) return pwL def width_of_vertex_separation(self, G, L): r""" Returns the value vs_L(G) of the vertex separation induced by the vertex ordering L for G, where ..MATH:: vs_L(G) =  \max_{0\leq i< |V|-1} | N^+(L[:i])\setminus L[:i] | INPUT: - G -- a graph or a digraph - L -- an ordering of the vertices of G OUTPUT: The value vs_L(G) of the vertex separation induced by the ordering L of the vertices of G. NOTES: The vertex separation is defined for both graphs and digraphs. The vertex separation of a graph is also the cost of the path decomposition induced by the vertex ordering (see the module's documentation). EXAMPLE: Vertex separation of a cycle:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = graphs.CycleGraph(6) sage: L = [u for u in G.vertices()] sage: LO.width_of_vertex_separation(G, L) 2 Vertex separation of a cicuit:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = digraphs.Circuit(6) sage: L = [u for u in G.vertices()] sage: LO.width_of_vertex_separation(G, L) 1 TEST: Giving anything else than a Graph or a DiGraph:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: LO.width_of_vertex_separation(2, []) Traceback (most recent call last): ... ValueError: The input parameter must be a Graph or a DiGraph. Giving a vertex ordering on a different set of vertices:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: G = digraphs.Circuit(6) sage: LO.width_of_vertex_separation(G, [1, 2, 3]) Traceback (most recent call last): ... ValueError: The input parameter is not a valid vertex ordering. """ # If G is a graph, we instead evaluate the path decomposition from sage.graphs.graph import Graph if isinstance(G, Graph): return self.width_of_path_decomposition(G, L) if not self.is_valid(G, L): raise ValueError("The input parameter is not a valid vertex ordering.") vsL = 0 S = [] neighbors_of_S_in_V_minus_S = [] for u in L: # We remove u from the list of neighbors of S if u in neighbors_of_S_in_V_minus_S: neighbors_of_S_in_V_minus_S.remove(u) # We add vertex u to the set S S += [u] # We add the out-neighbors of u to the list of neighbors of S for v in G.neighbors_out(u): if (not v in S) and (not v in neighbors_of_S_in_V_minus_S): neighbors_of_S_in_V_minus_S += [v] # We update the cost of the vertex separation vsL = max( vsL, len(neighbors_of_S_in_V_minus_S) ) return vsL def __vertex_separation_MILP__(self, D, integrality = False, verbosity = 0): r""" Implements an MILP for the vertex separation INPUTS: - D -- a digraph OUTPUT: A pair (cost, ordering) representing the optimal ordering of the vertices and its cost. VARIABLES: x[v,t] = 1 if and only if the working lightpath of connection v is torn down at epoch t So if an agent is put on vertex v at step t y[v,t] = 1 if and only if the new lightpath of connection v is set up at epoch t So if v is processed at step t u[v,t] = 1 if and only if the connection corresponding to v is disrupted at epoch t So if there is an agent on v at step t z          Objective = max number of concurrently disrupted connections CONSTANT: T         maximum number of epoch/steps. T <= 2.N TERMINOLOGY: An epoch is the period of time between the establishment of 2 new lightpaths So between the processing of 2 nodes => 1 epoch per connection => #epochs = T = N CONSTRAINTS: (1) Minimize z (2) x[v][t] <= x[v][t+1] for all v in V, and for t:=0..T-2 (3) y[v][t] <= y[v][t+1]        for all v in V, and for t:=0..T-2 (miss)  y[v][t] <= x[v][t]     for all v in V, and for all t:=0..T-1 to ensure that once a vertex is processed, it has already been covered.... (4) y[v][t] <= x[w][t]  for all v in V, for all w in N^+(v), and for all t:=0..T-1 (5) sum_{v in V} y[v][0] <= 1 (6) sum_{v in V} y[v][t+1] <= sum_{v in V} y[v][t] + 1  for t:=0..T-2 (7) sum_{v in V} y[v][T-1] = |V| (8) u[v][t] >= x[v][t]-y[v][t]    for all v in V, and for all t:=0..T-1 (9) z >= sum_{v in V} u[v][t]   for all t:=0..T-1 (10) 0 <= x[v][t] and u[v][t] <= 1 Meaning both are between 0 and 1 (11) y[v][t] in {0,1} (12) 0 <= z <= |V| """ from sage.numerical.mip import MixedIntegerLinearProgram, Sum, MIPSolverException p = MixedIntegerLinearProgram( maximization = False ) if integrality: x = p.new_variable( integer = True, dim = 2 ) u = p.new_variable( integer = True, dim = 2 ) else: x = p.new_variable( dim = 2 ) u = p.new_variable( dim = 2 ) y = p.new_variable( integer = True, dim = 2 ) z = p.new_variable( integer = True, dim = 1 ) N = D.num_verts() T=N #  (2) x[v][t] <= x[v][t+1] for all v in V, and for t:=0..T-2 #  (3) y[v][t] <= y[v][t+1]        for all v in V, and for t:=0..T-2 for v in D.vertices(): for t in xrange(T-1): p.add_constraint( x[v][t] - x[v][t+1], max = 0 ) p.add_constraint( y[v][t] - y[v][t+1], max = 0 ) # (miss)  y[v][t] <= x[v][t]     for all v in V, and for all t:=0..T-1 # for v in D.vertices(): #     for t in range(T): #        p.add_constraint(y[v][t]-x[v][t],max=0) # #  (4) y[v][t] <= x[w][t]  for all v in V, for all w in N^+(v), and for all t:=0..T-1 for v in D.vertices(): for w in D.neighbors_out(v): for t in xrange(T): p.add_constraint( y[v][t] - x[w][t], max = 0 ) #  (5) sum_{v in V} y[v][0] <= 1 p.add_constraint( Sum( y[v][0] for v in D.vertices() ), max = 1 ) #  (6) sum_{v in V} y[v][t+1] <= sum_{v in V} y[v][t] + 1  for t:=0..T-2 for t in xrange(T-1): p.add_constraint( Sum( y[v][t+1] - y[v][t] for v in D.vertices() ), max = 1 ) #  (7) sum_{v in V} y[v][T-1] = |V| p.add_constraint( Sum( y[v][T-1] for v in D.vertices() ), min = N ) p.add_constraint( Sum( y[v][T-1] for v in D.vertices() ), max = N ) #  (8) u[v][t] >= x[v][t]-y[v][t]    for all v in V, and for all t:=0..T-1 for v in D.vertices(): for t in xrange(T): p.add_constraint( x[v][t] - y[v][t] - u[v][t], max = 0 ) #  (9) z >= sum_{v in V} u[v][t]   for all t:=0..T-1 for t in xrange(T): p.add_constraint( Sum( u[v][t] for v in D.vertices() ) - z['z'], max = 0 ) # (10) 0 <= x[v][t] and u[v][t] <= 1 # (11) y[v][t] in {0,1} for v in D.vertices(): for t in xrange(T): p.add_constraint( x[v][t], min = 0 ) p.add_constraint( x[v][t], max = 1 ) p.add_constraint( u[v][t], min = 0 ) p.add_constraint( u[v][t], max = 1 ) p.set_binary( y[v][t] ) # (12) 0 <= z <= |V| p.add_constraint( z['z'], min = 0 ) p.add_constraint( z['z'], max = N ) #  (1) Minimize z p.set_objective( z['z'] ) try: obj = p.solve( log=verbosity ) taby = p.get_values( y ) tabz = p.get_values( z ) # since exactly one vertex is processed per epoch, we can reconstruct the sequence seq = [] for t in xrange(T): for v in D.vertices(): if (taby[v][t] > 0) and (not v in seq): seq += [v] vs = int(round( tabz['z'] )); except MIPSolverException: print "VSC NOT working with fractional stuff\n",D.edges(labels=False) print " => try with integral version" (vs,seq)=self.__vertex_separation_MILP__(D, True, verbosity) print vs,seq raise ValueError("Unbounded or unexpected error") del p return vs,seq; def vertex_separation(self, G, method = 'exp'): r""" Returns an optimal ordering of the vertices and its cost for vertex-separation. INPUT: - G -- a digraph - method (string) -- the method to use - 'exp' (default) -- Uses an algorithm with time and space complexity in 2^n. Because of its current implementation, this algorithm only works on graphs on less than 32 vertices. This can be changed to 54 if necessary, but 32 vertices already require 4GB of memory. - 'MILP' -- Uses an MILP implementation. OUTPUT: A pair (cost, ordering) representing the optimal ordering of the vertices and its cost. EXAMPLE: The vertex separation of a circuit is equal to 1:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: g = digraphs.Circuit(6) sage: LO.vertex_separation(g) (1, [0, 1, 2, 3, 4, 5]) TEST: Given anything else than a DiGraph:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: g = graphs.CycleGraph(6) sage: LO.vertex_separation(g) Traceback (most recent call last): ... ValueError: The input parameter must be a DiGraph. """ from sage.graphs.graph import DiGraph if not isinstance(G, DiGraph): raise ValueError("The input parameter must be a DiGraph.") if method == 'MILP': return self.__vertex_separation_MILP__(G) else: # default method from sage.graphs.graph_decompositions import vertex_separation return vertex_separation.vertex_separation(G) def path_decomposition(self, G, method = 'exp'): r""" Returns the pathwidth of the given graph and the ordering of the vertices resulting in a corresponding path decomposition. INPUT: - G -- a graph - method (string) -- the method to use - 'exp' (default) -- Uses an algorithm with time and space complexity in 2^n. Because of its current implementation, this algorithm only works on graphs on less than 32 vertices. This can be changed to 54 if necessary, but 32 vertices already require 4GB of memory. - 'MILP' -- Uses an MILP implementation. OUTPUT: A pair (cost, ordering) representing the optimal ordering of the vertices and its cost. EXAMPLE: The pathwidth of a circuit is equal to 2:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: g = graphs.CycleGraph(6) sage: LO.path_decomposition(g) (2, [0, 1, 2, 3, 4, 5]) TEST: Given anything else than a Graph:: sage: from sage.graphs.graph_decompositions.linear_ordering import LinearOrdering sage: LO = LinearOrdering() sage: g = digraphs.Circuit(6) sage: LO.path_decomposition(g) Traceback (most recent call last): ... ValueError: The input parameter must be a Graph. """ from sage.graphs.graph import Graph if not isinstance(G, Graph): raise ValueError("The input parameter must be a Graph.") if method == 'MILP': from sage.graphs.graph import DiGraph D = DiGraph( G.edges(labels = None) + [(v,u) for u,v in G.edges(labels = None)] ) return self.__vertex_separation_MILP__(D) else: # default method from sage.graphs.graph_decompositions import vertex_separation return vertex_separation.path_decomposition(G)