Path: blob/master/src/sage/graphs/generators/intersection.py
8815 views
# -*- coding: utf-8 -*-1r"""2Intersection graphs34The methods defined here appear in :mod:`sage.graphs.graph_generators`.5"""67###########################################################################8#9# Copyright (C) 2006 Robert L. Miller <[email protected]>10# and Emily A. Kirkman11# Copyright (C) 2009 Michael C. Yurko <[email protected]>12#13# Distributed under the terms of the GNU General Public License (GPL)14# http://www.gnu.org/licenses/15###########################################################################1617# import from Sage library18from sage.graphs.graph import Graph1920def IntervalGraph(intervals, points_ordered = False):21r"""22Returns the graph corresponding to the given intervals.2324An interval graph is built from a list `(a_i,b_i)_{1\leq i \leq n}` of25intervals : to each interval of the list is associated one vertex, two26vertices being adjacent if the two corresponding (closed) intervals27intersect.2829INPUT:3031- ``intervals`` -- the list of pairs `(a_i,b_i)` defining the graph.3233- ``points_ordered`` -- states whether every interval `(a_i,b_i)` of34`intervals` satisfies `a_i<b_i`. If satisfied then setting35``points_ordered`` to ``True`` will speed up the creation of the graph.3637.. NOTE::3839* The vertices are named 0, 1, 2, and so on. The intervals used40to create the graph are saved with the graph and can be recovered41using ``get_vertex()`` or ``get_vertices()``.4243EXAMPLE:4445The following line creates the sequence of intervals46`(i, i+2)` for i in `[0, ..., 8]`::4748sage: intervals = [(i,i+2) for i in range(9)]4950In the corresponding graph ::5152sage: g = graphs.IntervalGraph(intervals)53sage: g.get_vertex(3)54(3, 5)55sage: neigh = g.neighbors(3)56sage: for v in neigh: print g.get_vertex(v)57(1, 3)58(2, 4)59(4, 6)60(5, 7)6162The is_interval() method verifies that this graph is an interval graph. ::6364sage: g.is_interval()65True6667The intervals in the list need not be distinct. ::6869sage: intervals = [ (1,2), (1,2), (1,2), (2,3), (3,4) ]70sage: g = graphs.IntervalGraph(intervals,True)71sage: g.clique_maximum()72[0, 1, 2, 3]73sage: g.get_vertices()74{0: (1, 2), 1: (1, 2), 2: (1, 2), 3: (2, 3), 4: (3, 4)}7576The endpoints of the intervals are not ordered we get the same graph77(except for the vertex labels). ::7879sage: rev_intervals = [ (2,1), (2,1), (2,1), (3,2), (4,3) ]80sage: h = graphs.IntervalGraph(rev_intervals,False)81sage: h.get_vertices()82{0: (2, 1), 1: (2, 1), 2: (2, 1), 3: (3, 2), 4: (4, 3)}83sage: g.edges() == h.edges()84True85"""8687n = len(intervals)88g = Graph(n)8990if points_ordered:91for i in xrange(n-1):92li,ri = intervals[i]93for j in xrange(i+1,n):94lj,rj = intervals[j]95if ri < lj or rj < li: continue96g.add_edge(i,j)97else:98for i in xrange(n-1):99I = intervals[i]100for j in xrange(i+1,n):101J = intervals[j]102if max(I) < min(J) or max(J) < min(I): continue103g.add_edge(i,j)104105rep = dict( zip(range(n),intervals) )106g.set_vertices(rep)107108return g109110def PermutationGraph(second_permutation, first_permutation = None):111r"""112Builds a permutation graph from one (or two) permutations.113114General definition115116A Permutation Graph can be encoded by a permutation `\sigma`117of `1, ..., n`. It is then built in the following way :118119Take two horizontal lines in the euclidean plane, and mark points `1, ...,120n` from left to right on the first of them. On the second one, still from121left to right, mark point in the order in which they appear in `\sigma`.122Now, link by a segment the two points marked with 1, then link together123the points marked with 2, and so on. The permutation graph defined by the124permutation is the intersection graph of those segments : there exists a125point in this graph for each element from `1` to `n`, two vertices `i, j`126being adjacent if the segments `i` and `j` cross each other.127128The set of edges of the resulting graph is equal to the set of inversions of129the inverse of the given permutation.130131INPUT:132133- ``second_permutation`` -- the permutation from which the graph should be134built. It corresponds to the ordering of the elements on the second line135(see previous definition)136137- ``first_permutation`` (optional) -- the ordering of the elements on the138*first* line. This is useful when the elements have no natural ordering,139for instance when they are strings, or tuples, or anything else.140141When ``first_permutation == None`` (default), it is set to be equal to142``sorted(second_permutation)``, which just yields the expected143ordering when the elements of the graph are integers.144145.. SEEALSO:146147- Recognition of Permutation graphs in the :mod:`comparability module148<sage.graphs.comparability>`.149150- Drawings of permutation graphs as intersection graphs of segments is151possible through the152:meth:`~sage.combinat.permutation.Permutation.show` method of153:class:`~sage.combinat.permutation.Permutation` objects.154155The correct argument to use in this case is ``show(representation =156"braid")``.157158- :meth:`~sage.combinat.permutation.Permutation.inversions`159160EXAMPLE::161162sage: p = Permutations(5).random_element()163sage: edges = graphs.PermutationGraph(p).edges(labels =False)164sage: set(edges) == set(p.inverse().inversions())165True166167TESTS::168169sage: graphs.PermutationGraph([1, 2, 3], [4, 5, 6])170Traceback (most recent call last):171...172ValueError: The two permutations do not contain the same set of elements ...173"""174if first_permutation == None:175first_permutation = sorted(second_permutation)176else:177if set(second_permutation) != set(first_permutation):178raise ValueError("The two permutations do not contain the same "+179"set of elements ! It is going to be pretty "+180"hard to define a permutation graph from that !")181182vertex_to_index = {}183for i, v in enumerate(first_permutation):184vertex_to_index[v] = i+1185186from sage.combinat.permutation import Permutation187p2 = Permutation(map(lambda x:vertex_to_index[x], second_permutation))188p1 = Permutation(map(lambda x:vertex_to_index[x], first_permutation))189p2 = p2 * p1.inverse()190p2 = p2.inverse()191192g = Graph(name="Permutation graph for "+str(second_permutation))193g.add_vertices(second_permutation)194195for u,v in p2.inversions():196g.add_edge(first_permutation[u-1], first_permutation[v-1])197198return g199200def ToleranceGraph(tolrep):201r"""202Returns the graph generated by the tolerance representation ``tolrep``.203204The tolerance representation ``tolrep`` is described by the list205`((l_0,r_0,t_0), (l_1,r_1,t_1), ..., (l_k,r_k,t_k))` where `I_i = (l_i,r_i)`206denotes a closed interval on the real line with `l_i < r_i` and `t_i` a207positive value, called tolerance. This representation generates the208tolerance graph with the vertex set {0,1, ..., k} and the edge set `{(i,j):209|I_i \cap I_j| \ge \min{t_i, t_j}}` where `|I_i \cap I_j|` denotes the210length of the intersection of `I_i` and `I_j`.211212INPUT:213214- ``tolrep`` -- list of triples `(l_i,r_i,t_i)` where `(l_i,r_i)` denotes a215closed interval on the real line and `t_i` a positive value.216217.. NOTE::218219The vertices are named 0, 1, ..., k. The tolerance representation used220to create the graph is saved with the graph and can be recovered using221``get_vertex()`` or ``get_vertices()``.222223EXAMPLE:224225The following code creates a tolerance representation ``tolrep``, generates226its tolerance graph ``g``, and applies some checks::227228sage: tolrep = [(1,4,3),(1,2,1),(2,3,1),(0,3,3)]229sage: g = graphs.ToleranceGraph(tolrep)230sage: g.get_vertex(3)231(0, 3, 3)232sage: neigh = g.neighbors(3)233sage: for v in neigh: print g.get_vertex(v)234(1, 2, 1)235(2, 3, 1)236sage: g.is_interval()237False238sage: g.is_weakly_chordal()239True240241The intervals in the list need not be distinct ::242243sage: tolrep2 = [(0,4,5),(1,2,1),(2,3,1),(0,4,5)]244sage: g2 = graphs.ToleranceGraph(tolrep2)245sage: g2.get_vertices()246{0: (0, 4, 5), 1: (1, 2, 1), 2: (2, 3, 1), 3: (0, 4, 5)}247sage: g2.is_isomorphic(g)248True249250Real values are also allowed ::251252sage: tolrep = [(0.1,3.3,4.4),(1.1,2.5,1.1),(1.4,4.4,3.3)]253sage: g = graphs.ToleranceGraph(tolrep)254sage: g.is_isomorphic(graphs.PathGraph(3))255True256257TEST:258259Giving negative third value::260261sage: tolrep = [(0.1,3.3,-4.4),(1.1,2.5,1.1),(1.4,4.4,3.3)]262sage: g = graphs.ToleranceGraph(tolrep)263Traceback (most recent call last):264...265ValueError: Invalid tolerance representation at position 0; third value must be positive!266"""267n = len(tolrep)268269for i in xrange(n):270if tolrep[i][2] <= 0:271raise ValueError("Invalid tolerance representation at position "+str(i)+"; third value must be positive!")272273g = Graph(n)274275for i in xrange(n-1):276li,ri,ti = tolrep[i]277for j in xrange(i+1,n):278lj,rj,tj = tolrep[j]279if min(ri,rj) - max(li,lj) >= min(ti,tj):280g.add_edge(i,j)281282rep = dict( zip(range(n),tolrep) )283g.set_vertices(rep)284285return g286287288