Ticket #8640: trac_8640-bipartite.patch

File trac_8640-bipartite.patch, 39.7 KB (added by Minh Van Nguyen, 13 years ago)
  • doc/en/reference/graphs.rst

    # HG changeset patch
    # User Minh Van Nguyen <nguyenminh2@gmail.com>
    # Date 1272661471 25200
    # Node ID 19e6f9b02fe7093a3ca7899da71c801b13dd6650
    # Parent  0c26d57cfc5ca87137186f07391b2bd02d60fb13
    #8640: add BipartiteGraph to the reference manual
    
    diff --git a/doc/en/reference/graphs.rst b/doc/en/reference/graphs.rst
    a b  
    44.. toctree::
    55   :maxdepth: 2
    66
     7   sage/graphs/generic_graph
    78   sage/graphs/graph
    89   sage/graphs/digraph
    9    sage/graphs/generic_graph
     10   sage/graphs/bipartite_graph
    1011
    1112   sage/graphs/cliquer
    1213   sage/graphs/graph_coloring
  • sage/graphs/bipartite_graph.py

    diff --git a/sage/graphs/bipartite_graph.py b/sage/graphs/bipartite_graph.py
    a b  
    44This module implements bipartite graphs.
    55
    66AUTHORS:
    7     -- Robert L. Miller (2008-01-20): initial version
    8     -- Ryan W. Hinton (2010-03-04): overrides for adding and deleting vertices
    9        and edges
    107
    11 TESTS:
     8- Robert L. Miller (2008-01-20): initial version
    129
    13     sage: B = graphs.CompleteBipartiteGraph(7,9)
     10- Ryan W. Hinton (2010-03-04): overrides for adding and deleting vertices
     11  and edges
     12
     13TESTS::
     14
     15    sage: B = graphs.CompleteBipartiteGraph(7, 9)
    1416    sage: loads(dumps(B)) == B
    1517    True
    1618
    1719::
    1820
    19     sage: B=BipartiteGraph(graphs.CycleGraph(4))
     21    sage: B = BipartiteGraph(graphs.CycleGraph(4))
    2022    sage: B == B.copy()
    2123    True
    2224    sage: type(B.copy())
    2325    <class 'sage.graphs.bipartite_graph.BipartiteGraph'>
    24 
    2526"""
    2627
    2728#*****************************************************************************
     
    4041    INPUT:
    4142
    4243    - ``data`` -- can be any of the following:
    43             1.  Empty or None (creates an empty graph).
    44             2.  An arbitrary graph (finds a bipartition).
    45             3.  A graph and a bipartition.
    46             4.  A reduced adjacency matrix.
    47             5.  A file in alist format.
    48             6.  From a NetworkX bipartite graph.
     44
     45      #. Empty or ``None`` (creates an empty graph).
     46      #. An arbitrary graph (finds a bipartition).
     47      #. A graph and a bipartition.
     48      #. A reduced adjacency matrix.
     49      #. A file in alist format.
     50      #. From a NetworkX bipartite graph.
    4951
    5052    A reduced adjacency matrix contains only the non-redundant portion of the
    5153    full adjacency matrix for the bipartite graph.  Specifically, for zero
    52     matrices of the appropriate size, for the reduced adjacency matrix H, the
    53     full adjacency matrix is [[0, H'], [H, 0]].
     54    matrices of the appropriate size, for the reduced adjacency matrix ``H``,
     55    the full adjacency matrix is ``[[0, H'], [H, 0]]``.
    5456
    5557    The alist file format is described at
    56         http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
     58    http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html
    5759
    5860    EXAMPLES:
    59    
    60     1.  No inputs or None for the input creates an empty graph::
     61
     62    1. No inputs or ``None`` for the input creates an empty graph::
    6163
    6264        sage: B = BipartiteGraph()
    6365        sage: type(B)
     
    6971
    7072    2. From a graph: without any more information, finds a bipartition::
    7173
    72         sage: B = BipartiteGraph( graphs.CycleGraph(4) )
    73         sage: B = BipartiteGraph( graphs.CycleGraph(5) )
     74        sage: B = BipartiteGraph(graphs.CycleGraph(4))
     75        sage: B = BipartiteGraph(graphs.CycleGraph(5))
    7476        Traceback (most recent call last):
    7577        ...
    7678        TypeError: Input graph is not bipartite!
     
    9193        set([4, 5, 6])
    9294
    9395    3. From a graph and a partition. Note that if the input graph is not
    94     bipartite, then Sage will raise an error. However, if one specifies check =
    95     False, the offending edges are simply deleted (along with those vertices
    96     not appearing in either list).  We also lump creating one bipartite graph
    97     from another into this category::
     96       bipartite, then Sage will raise an error. However, if one specifies
     97       ``check=False``, the offending edges are simply deleted (along with
     98       those vertices not appearing in either list).  We also lump creating
     99       one bipartite graph from another into this category::
    98100
    99101        sage: P = graphs.PetersenGraph()
    100102        sage: partition = [range(5), range(5,10)]
     
    108110        set([0, 1, 2, 3, 4])
    109111        sage: B.show()
    110112
    111     ::
     113      ::
    112114
    113115        sage: G = Graph({0:[5,6], 1:[4,5], 2:[4,6], 3:[4,5,6]})
    114116        sage: B = BipartiteGraph(G)
     
    121123        sage: B3 == B2
    122124        True
    123125
    124     ::
     126      ::
    125127
    126128        sage: G = Graph({0:[], 1:[], 2:[]})
    127129        sage: part = (range(2), [2])
     
    132134
    133135    4. From a reduced adjacency matrix::
    134136
    135         sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), \
    136                           (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
     137        sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),
     138        ...               (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
    137139        sage: M
    138140        [1 1 1 0 0 0 0]
    139141        [1 0 0 1 1 0 0]
     
    156158         (5, 9, None),
    157159         (6, 10, None)]
    158160
    159     ::
     161      ::
    160162
    161163        sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)])
    162164        sage: B = BipartiteGraph(M, multiedges=True, sparse=True)
     
    176178         (4, 6, None),
    177179         (4, 7, None)]
    178180
    179     ::
     181      ::
    180182
    181183         sage: F.<a> = GF(4)
    182184         sage: MS = MatrixSpace(F, 2, 3)
     
    206208        sage: G = graphs.OctahedralGraph()
    207209        sage: N = networkx.make_clique_bipartite(G.networkx_graph())
    208210        sage: B = BipartiteGraph(N)
    209 
    210211    """
    211212
    212213    def __init__(self, *args, **kwds):
    213214        """
    214         Create a bipartite graph. See documentation: BipartiteGraph?
    215        
    216         EXAMPLE:
     215        Create a bipartite graph. See documentation ``BipartiteGraph?`` for
     216        detailed information.
     217
     218        EXAMPLE::
     219
    217220            sage: P = graphs.PetersenGraph()
    218221            sage: partition = [range(5), range(5,10)]
    219222            sage: B = BipartiteGraph(P, partition, check=False)
    220 
    221223        """
    222224        if len(args) == 0:
    223225            Graph.__init__(self)
    224             self.left = set(); self.right = set()
     226            self.left = set()
     227            self.right = set()
    225228            return
    226229
    227230        # need to turn off partition checking for Graph.__init__() adding
    228231        # vertices and edges; methods are restored ad the end of big "if"
    229232        # statement below
    230233        import types
    231         self.add_vertex = types.MethodType(Graph.add_vertex, self, BipartiteGraph)
    232         self.add_vertices = types.MethodType(Graph.add_vertices, self, BipartiteGraph)
     234        self.add_vertex = types.MethodType(Graph.add_vertex,
     235                                           self,
     236                                           BipartiteGraph)
     237        self.add_vertices = types.MethodType(Graph.add_vertices,
     238                                             self,
     239                                             BipartiteGraph)
    233240        self.add_edge = types.MethodType(Graph.add_edge, self, BipartiteGraph)
    234241
    235242        arg1 = args[0]
     
    237244        from sage.structure.element import is_Matrix
    238245        if isinstance(arg1, BipartiteGraph):
    239246            Graph.__init__(self, arg1, *args, **kwds)
    240             self.left, self.right = set(arg1.left), set(arg1.right)
     247            self.left = set(arg1.left)
     248            self.right = set(arg1.right)
    241249        elif isinstance(arg1, str):
    242250            Graph.__init__(self, *args, **kwds)
    243251            # will call self.load_afile after restoring add_vertex() instance
     
    246254            self.right = set()
    247255        elif is_Matrix(arg1):
    248256            # sanity check for mutually exclusive keywords
    249             if kwds.get('multiedges',False) and kwds.get('weighted',False):
    250                 raise TypeError, "Weighted multi-edge bipartite graphs from reduced adjacency matrix not supported."
     257            if kwds.get("multiedges", False) and kwds.get("weighted", False):
     258                raise TypeError(
     259                    "Weighted multi-edge bipartite graphs from reduced " +
     260                    "adjacency matrix not supported.")
    251261            Graph.__init__(self, *args, **kwds)
    252262            ncols = arg1.ncols()
    253263            nrows = arg1.nrows()
    254             self.left, self.right = set(xrange(ncols)), set(xrange(ncols, nrows+ncols))
    255             if kwds.get('multiedges',False):
     264            self.left = set(xrange(ncols))
     265            self.right = set(xrange(ncols, nrows + ncols))
     266            if kwds.get("multiedges", False):
    256267                for ii in range(ncols):
    257268                    for jj in range(nrows):
    258269                        if arg1[jj][ii] != 0:
    259                             self.add_edges([(ii,jj+ncols)] * arg1[jj][ii])
    260             elif kwds.get('weighted',False):
     270                            self.add_edges([(ii, jj + ncols)] * arg1[jj][ii])
     271            elif kwds.get("weighted", False):
    261272                for ii in range(ncols):
    262273                    for jj in range(nrows):
    263274                        if arg1[jj][ii] != 0:
    264                             self.add_edge((ii, jj+ncols, arg1[jj][ii]))
     275                            self.add_edge((ii, jj + ncols, arg1[jj][ii]))
    265276            else:
    266277                for ii in range(ncols):
    267278                    for jj in range(nrows):
    268279                        if arg1[jj][ii] != 0:
    269                             self.add_edge((ii, jj+ncols))
    270         elif isinstance(arg1, Graph) and \
    271              len(args) > 0 and isinstance(args[0], (list,tuple)) and \
    272              len(args[0]) == 2 and isinstance(args[0][0], (list,tuple)):
    273                 # Assume that args[0] is a bipartition
    274                 from copy import copy
    275                 left, right = args[0]; left = copy(left); right = copy(right)
    276                 verts = set(left)|set(right)
    277                 if set(arg1.vertices()) != verts:
    278                     arg1 = arg1.subgraph(list(verts))
    279                 Graph.__init__(self, arg1, *(args[1:]), **kwds)
    280                 if not kwds.has_key('check') or kwds['check']:
    281                     while len(left) > 0:
    282                         a = left.pop(0)
    283                         if len( set( arg1.neighbors(a) ) & set(left) ) != 0:
    284                             raise TypeError("Input graph is not bipartite with " + \
    285                              "respect to the given partition!")
    286                     while len(right) > 0:
    287                         a = right.pop(0)
    288                         if len( set( arg1.neighbors(a) ) & set(right) ) != 0:
    289                             raise TypeError("Input graph is not bipartite with " + \
    290                              "respect to the given partition!")
    291                 else:
    292                     while len(left) > 0:
    293                         a = left.pop(0)
    294                         a_nbrs = set( arg1.neighbors(a) ) & set(left)
    295                         if len( a_nbrs ) != 0:
    296                             self.delete_edges([(a, b) for b in a_nbrs])
    297                     while len(right) > 0:
    298                         a = right.pop(0)
    299                         a_nbrs = set( arg1.neighbors(a) ) & set(right)
    300                         if len( a_nbrs ) != 0:
    301                             self.delete_edges([(a, b) for b in a_nbrs])
    302                 self.left, self.right = set(args[0][0]), set(args[0][1])
     280                            self.add_edge((ii, jj + ncols))
     281        elif (isinstance(arg1, Graph) and
     282              len(args) > 0 and isinstance(args[0], (list, tuple)) and
     283              len(args[0]) == 2 and isinstance(args[0][0], (list, tuple))):
     284            # Assume that args[0] is a bipartition
     285            from copy import copy
     286            left, right = args[0]
     287            left = copy(left)
     288            right = copy(right)
     289            verts = set(left) | set(right)
     290            if set(arg1.vertices()) != verts:
     291                arg1 = arg1.subgraph(list(verts))
     292            Graph.__init__(self, arg1, *(args[1:]), **kwds)
     293            if "check" not in kwds or kwds["check"]:
     294                while len(left) > 0:
     295                    a = left.pop(0)
     296                    if len(set(arg1.neighbors(a)) & set(left)) != 0:
     297                        raise TypeError(
     298                            "Input graph is not bipartite with " +
     299                            "respect to the given partition!")
     300                while len(right) > 0:
     301                    a = right.pop(0)
     302                    if len(set(arg1.neighbors(a)) & set(right)) != 0:
     303                        raise TypeError(
     304                            "Input graph is not bipartite with " +
     305                            "respect to the given partition!")
     306            else:
     307                while len(left) > 0:
     308                    a = left.pop(0)
     309                    a_nbrs = set(arg1.neighbors(a)) & set(left)
     310                    if len(a_nbrs) != 0:
     311                        self.delete_edges([(a, b) for b in a_nbrs])
     312                while len(right) > 0:
     313                    a = right.pop(0)
     314                    a_nbrs = set(arg1.neighbors(a)) & set(right)
     315                    if len(a_nbrs) != 0:
     316                        self.delete_edges([(a, b) for b in a_nbrs])
     317            self.left, self.right = set(args[0][0]), set(args[0][1])
    303318        elif isinstance(arg1, Graph):
    304319            Graph.__init__(self, arg1, *args, **kwds)
    305320            try:
     
    310325            import networkx
    311326            Graph.__init__(self, arg1, *args, **kwds)
    312327            if isinstance(arg1, (networkx.MultiGraph, networkx.Graph)):
    313                 if hasattr(arg1, 'node_type'):
     328                if hasattr(arg1, "node_type"):
    314329                    # Assume the graph is bipartite
    315330                    self.left = set()
    316331                    self.right = set()
    317332                    for v in arg1.nodes_iter():
    318                         if arg1.node_type[v] == 'Bottom':
     333                        if arg1.node_type[v] == "Bottom":
    319334                            self.left.add(v)
    320                         elif arg1.node_type[v] == 'Top':
     335                        elif arg1.node_type[v] == "Top":
    321336                            self.right.add(v)
    322337                        else:
    323                             raise TypeError("NetworkX node_type defies bipartite assumption (is not 'Top' or 'Bottom')")
     338                            raise TypeError(
     339                                "NetworkX node_type defies bipartite " +
     340                                "assumption (is not 'Top' or 'Bottom')")
    324341            # make sure we found a bipartition
    325             if not (hasattr(self, 'left') and hasattr(self, 'right')):
     342            if not (hasattr(self, "left") and hasattr(self, "right")):
    326343                try:
    327344                    self.left, self.right = self.bipartite_sets()
    328345                except:
    329346                    raise TypeError("Input graph is not bipartite!")
    330347
    331348        # restore vertex partition checking
    332         self.add_vertex = types.MethodType(BipartiteGraph.add_vertex, self, BipartiteGraph)
    333         self.add_vertices = types.MethodType(BipartiteGraph.add_vertices, self, BipartiteGraph)
    334         self.add_edge = types.MethodType(BipartiteGraph.add_edge, self, BipartiteGraph)
     349        self.add_vertex = types.MethodType(BipartiteGraph.add_vertex,
     350                                           self,
     351                                           BipartiteGraph)
     352        self.add_vertices = types.MethodType(BipartiteGraph.add_vertices,
     353                                             self,
     354                                             BipartiteGraph)
     355        self.add_edge = types.MethodType(BipartiteGraph.add_edge,
     356                                         self,
     357                                         BipartiteGraph)
    335358
    336359        # post-processing
    337360        if isinstance(arg1, str):
     
    343366        r"""
    344367        Returns a short string representation of self.
    345368
    346         EXAMPLE:
     369        EXAMPLE::
     370
    347371            sage: B = BipartiteGraph(graphs.CycleGraph(16))
    348372            sage: B
    349373            Bipartite cycle graph: graph on 16 vertices
    350 
    351374        """
    352375        s = Graph._repr_(self).lower()
    353         if 'bipartite' in s:
     376        if "bipartite" in s:
    354377            return s.capitalize()
    355378        else:
    356             return 'Bipartite ' + s
    357 
     379            return "".join(["Bipartite ", s])
    358380
    359381    def add_vertex(self, name=None, left=False, right=False):
    360382        """
    361383        Creates an isolated vertex. If the vertex already exists, then
    362384        nothing is done.
    363        
     385
    364386        INPUT:
    365        
    366         - ``name`` - Name of the new vertex.  If no name is specified, then the
    367            vertex will be represented by the least non-negative integer not
    368            already representing a vertex.  Name must be an immutable object,
    369            and cannot be None.
    370387
    371         - ``left`` - if True, puts the new vertex in the left partition.
     388        - ``name`` -- (default: ``None``) name of the new vertex.  If no name
     389          is specified, then the vertex will be represented by the least
     390          non-negative integer not already representing a vertex.  Name must
     391          be an immutable object and cannot be ``None``.
    372392
    373         - ``right`` - if True, puts the new vertex in the right partition.
     393        - ``left`` -- (default: ``False``) if ``True``, puts the new vertex
     394          in the left partition.
     395
     396        - ``right`` -- (default: ``False``) if ``True``, puts the new vertex
     397          in the right partition.
    374398
    375399        Obviously, ``left`` and ``right`` are mutually exclusive.
    376        
     400
    377401        As it is implemented now, if a graph `G` has a large number
    378         of vertices with numeric labels, then G.add_vertex() could
    379         potentially be slow, if name is None.
    380        
     402        of vertices with numeric labels, then ``G.add_vertex()`` could
     403        potentially be slow, if name is ``None``.
     404
    381405        EXAMPLES::
    382        
     406
    383407            sage: G = BipartiteGraph()
    384408            sage: G.add_vertex(left=True)
    385409            sage: G.add_vertex(right=True)
     
    390414            sage: G.right
    391415            set([1])
    392416
    393         TEST::
     417        TESTS:
    394418
    395           Exactly one of ``left`` and ``right`` must be true::
     419        Exactly one of ``left`` and ``right`` must be true::
    396420
    397421            sage: G = BipartiteGraph()
    398422            sage: G.add_vertex()
     
    404428            ...
    405429            RuntimeError: Only one partition may be specified.
    406430
    407           Adding the same vertex must specify the same partition::
    408          
     431        Adding the same vertex must specify the same partition::
     432
    409433            sage: bg = BipartiteGraph()
    410434            sage: bg.add_vertex(0, right=True)
    411435            sage: bg.add_vertex(0, right=True)
     
    415439            Traceback (most recent call last):
    416440            ...
    417441            RuntimeError: Cannot add duplicate vertex to other partition.
    418            
    419 
    420442        """
    421443        # sanity check on partition specifiers
    422444        if left and right:
    423             raise RuntimeError('Only one partition may be specified.')
     445            raise RuntimeError("Only one partition may be specified.")
    424446        if not (left or right):
    425             raise RuntimeError('Partition must be specified (e.g. left=True).')
     447            raise RuntimeError("Partition must be specified (e.g. left=True).")
    426448
    427449        # do nothing if we already have this vertex (idempotent)
    428450        if (name is not None) and (name in self):
    429             if ((name in self.left) and left) or ((name in self.right) and right):
     451            if (((name in self.left) and left) or
     452                ((name in self.right) and right)):
    430453                return
    431454            else:
    432                 raise RuntimeError('Cannot add duplicate vertex to other partition.')
     455                raise RuntimeError(
     456                    "Cannot add duplicate vertex to other partition.")
    433457
    434458        # add the vertex
    435459        if name is not None:
     
    450474
    451475        return
    452476
    453 
    454477    def add_vertices(self, vertices, left=False, right=False):
    455478        """
    456479        Add vertices to the bipartite graph from an iterable container of
    457480        vertices.  Vertices that already exist in the graph will not be added
    458481        again.
    459        
     482
    460483        INPUTS:
    461484
    462           - ``vertices`` - sequence of vertices to add.
     485        - ``vertices`` -- sequence of vertices to add.
    463486
    464           - ``left`` - either True or sequence of same length as ``vertices``
    465             with True/False elements.
     487        - ``left`` -- (default: ``False``) either ``True`` or sequence of
     488          same length as ``vertices`` with ``True``/``False`` elements.
    466489
    467           - ``right`` - either True or sequence of the same length as
    468             ``vertices`` with True/False elements.
     490        - ``right`` -- (default: ``False``) either ``True`` or sequence of
     491          the same length as ``vertices`` with ``True``/``False`` elements.
    469492
    470493        Only one of ``left`` and ``right`` keywords should be provided.  See
    471494        the examples below.
    472495
    473496        EXAMPLES::
    474        
     497
    475498            sage: bg = BipartiteGraph()
    476499            sage: bg.add_vertices([0,1,2], left=True)
    477500            sage: bg.add_vertices([3,4,5], left=[True, False, True])
     
    481504            set([0, 1, 2, 3, 5, 7])
    482505            sage: bg.right
    483506            set([4, 6, 8, 9, 10, 11])
    484            
    485507
    486508        TEST::
    487509
     
    504526            RuntimeError: Cannot add duplicate vertex to other partition.
    505527            sage: (bg.left, bg.right)
    506528            (set([0, 1, 2]), set([]))
    507 
    508529        """
    509530        # sanity check on partition specifiers
    510531        if left and right:  # also triggered if both lists are specified
    511             raise RuntimeError('Only one partition may be specified.')
     532            raise RuntimeError("Only one partition may be specified.")
    512533        if not (left or right):
    513             raise RuntimeError('Partition must be specified (e.g. left=True).')
     534            raise RuntimeError("Partition must be specified (e.g. left=True).")
    514535
    515536        # handle partitions
    516         if left and (not hasattr(left, '__iter__')):
     537        if left and (not hasattr(left, "__iter__")):
    517538            new_left = set(vertices)
    518539            new_right = set()
    519         elif right and (not hasattr(right, '__iter__')):
     540        elif right and (not hasattr(right, "__iter__")):
    520541            new_left = set()
    521542            new_right = set(vertices)
    522543        else:
     
    525546                left = map(lambda tf: not tf, right)
    526547            new_left = set()
    527548            new_right = set()
    528             for tf,vv in zip(left, vertices):
     549            for tf, vv in zip(left, vertices):
    529550                if tf:
    530551                    new_left.add(vv)
    531552                else:
     
    533554
    534555        # check that we're not trying to add vertices to the wrong sets
    535556        # or that a vertex is to be placed in both
    536         if (new_left & self.right) or (new_right & self.left) or (new_right & new_left):
    537             raise RuntimeError('Cannot add duplicate vertex to other partition.')
     557        if ((new_left & self.right) or
     558            (new_right & self.left) or
     559            (new_right & new_left)):
     560            raise RuntimeError(
     561                "Cannot add duplicate vertex to other partition.")
    538562
    539563        # add vertices
    540564        Graph.add_vertices(self, vertices)
     
    547571        """
    548572        Deletes vertex, removing all incident edges. Deleting a non-existent
    549573        vertex will raise an exception.
    550        
     574
    551575        INPUT:
    552        
    553         - ``in_order`` - (default ``False``) If ``True``, this deletes the `i`th vertex
    554            in the sorted list of vertices, i.e.  ``G.vertices()[i]``
    555        
     576
     577        - ``vertex`` -- a vertex to delete.
     578
     579        - ``in_order`` -- (default ``False``) if ``True``, this deletes the
     580          `i`-th vertex in the sorted list of vertices,
     581          i.e. ``G.vertices()[i]``.
     582
    556583        EXAMPLES::
    557        
     584
    558585            sage: B = BipartiteGraph(graphs.CycleGraph(4))
    559586            sage: B
    560587            Bipartite cycle graph: graph on 4 vertices
     
    606633            try:
    607634                self.right.remove(vertex)
    608635            except:
    609                 raise RuntimeError("Vertex (%s) not found in partitions"%vertex)
     636                raise RuntimeError(
     637                    "Vertex (%s) not found in partitions" % vertex)
    610638
    611639    def delete_vertices(self, vertices):
    612640        """
    613641        Remove vertices from the bipartite graph taken from an iterable
    614642        sequence of vertices. Deleting a non-existent vertex will raise an
    615643        exception.
    616        
     644
     645        INPUT:
     646
     647        - ``vertices`` -- a sequence of vertices to remove.
     648
    617649        EXAMPLES::
    618        
     650
    619651            sage: B = BipartiteGraph(graphs.CycleGraph(4))
    620652            sage: B
    621653            Bipartite cycle graph: graph on 4 vertices
     
    632664            Traceback (most recent call last):
    633665            ...
    634666            RuntimeError: Vertex (0) not in the graph.
    635 
    636667        """
    637668        # remove vertices from the graph
    638669        Graph.delete_vertices(self, vertices)
    639        
     670
    640671        # now remove vertices from partition lists (exception already thrown
    641672        # for non-existant vertices)
    642673        for vertex in vertices:
     
    646677                try:
    647678                    self.right.remove(vertex)
    648679                except:
    649                     raise RuntimeError("Vertex (%s) not found in partitions"%vertex)
     680                    raise RuntimeError(
     681                        "Vertex (%s) not found in partitions" % vertex)
    650682
    651683    def add_edge(self, u, v=None, label=None):
    652684        """
    653         Adds an edge from u and v.
     685        Adds an edge from ``u`` and ``v``.
    654686
    655         INPUT: The following forms are all accepted:
    656        
    657         - G.add_edge( 1, 2 )
    658         - G.add_edge( (1, 2) )
    659         - G.add_edges( [ (1, 2) ])
    660         - G.add_edge( 1, 2, 'label' )
    661         - G.add_edge( (1, 2, 'label') )
    662         - G.add_edges( [ (1, 2, 'label') ] )
    663        
    664         See Graph.add_edge for more detail.  This method simply checks that the
    665         edge endpoints are in different partitions.
     687        INPUT:
     688
     689        - ``u`` -- the tail of an edge.
     690
     691        - ``v`` -- (default: ``None``) the head of an edge. If ``v=None``, then
     692          attempt to add the edge ``(u, u)``.
     693
     694        - ``label`` -- (default: ``None``) the label of the edge ``(u, v)``.
     695
     696        The following forms are all accepted:
     697
     698        - ``G.add_edge(1, 2)``
     699        - ``G.add_edge((1, 2))``
     700        - ``G.add_edges([(1, 2)])``
     701        - ``G.add_edge(1, 2, 'label')``
     702        - ``G.add_edge((1, 2, 'label'))``
     703        - ``G.add_edges([(1, 2, 'label')])``
     704
     705        See ``Graph.add_edge`` for more detail.  This method simply checks
     706        that the edge endpoints are in different partitions.
    666707
    667708        TEST::
    668709
     
    673714            Traceback (most recent call last):
    674715            ...
    675716            RuntimeError: Edge vertices must lie in different partitions.
    676 
    677717        """
    678718        # logic for getting endpoints copied from generic_graph.py
    679719        if label is None:
     
    688728                u, v = u
    689729
    690730        # check for endpoints in different partitions
    691         if self.left.issuperset((u,v)) or self.right.issuperset((u,v)):
    692             raise RuntimeError('Edge vertices must lie in different partitions.')
     731        if self.left.issuperset((u, v)) or self.right.issuperset((u, v)):
     732            raise RuntimeError(
     733                "Edge vertices must lie in different partitions.")
    693734
    694735        # add the edge
    695736        Graph.add_edge(self, u, v, label)
     
    699740        """
    700741        Return an undirected Graph (without bipartite constraint) of the given
    701742        object.
    702        
     743
    703744        EXAMPLES::
    704        
     745
    705746            sage: BipartiteGraph(graphs.CycleGraph(6)).to_undirected()
    706747            Cycle graph: Graph on 6 vertices
    707748        """
     
    711752        r"""
    712753        Returns the underlying bipartition of the bipartite graph.
    713754
    714         EXAMPLE:
    715             sage: B = BipartiteGraph( graphs.CycleGraph(4) )
     755        EXAMPLE::
     756
     757            sage: B = BipartiteGraph(graphs.CycleGraph(4))
    716758            sage: B.bipartition()
    717759            (set([0, 2]), set([1, 3]))
    718 
    719760        """
    720761        return (self.left, self.right)
    721762
    722763    def project_left(self):
    723764        r"""
    724         Projects self onto left vertices: edges are 2-paths in the original.
     765        Projects ``self`` onto left vertices. Edges are 2-paths in the
     766        original.
    725767
    726         EXAMPLE:
     768        EXAMPLE::
    727769
    728770            sage: B = BipartiteGraph(graphs.CycleGraph(20))
    729771            sage: G = B.project_left()
    730772            sage: G.order(), G.size()
    731773            (10, 10)
    732 
    733774        """
    734775        G = Graph()
    735776        G.add_vertices(self.left)
    736777        for v in G:
    737778            for u in self.neighbor_iterator(v):
    738                 G.add_edges([(v,w) for w in self.neighbor_iterator(u)])
     779                G.add_edges([(v, w) for w in self.neighbor_iterator(u)])
    739780        return G
    740781
    741782    def project_right(self):
    742783        r"""
    743         Projects self onto right vertices: edges are 2-paths in the original.
     784        Projects ``self`` onto right vertices. Edges are 2-paths in the
     785        original.
    744786
    745         EXAMPLE:
     787        EXAMPLE::
    746788
    747789            sage: B = BipartiteGraph(graphs.CycleGraph(20))
    748790            sage: G = B.project_right()
    749791            sage: G.order(), G.size()
    750792            (10, 10)
    751 
    752793        """
    753794        G = Graph()
    754795        G.add_vertices(self.left)
    755796        for v in G:
    756797            for u in self.neighbor_iterator(v):
    757                 G.add_edges([(v,w) for w in self.neighbor_iterator(u)])
     798                G.add_edges([(v, w) for w in self.neighbor_iterator(u)])
    758799        return G
    759800
    760801    def plot(self, *args, **kwds):
    761802        r"""
    762803        Overrides Graph's plot function, to illustrate the bipartite nature.
    763804
    764         EXAMPLE:
     805        EXAMPLE::
    765806
    766807            sage: B = BipartiteGraph(graphs.CycleGraph(20))
    767808            sage: B.plot()
    768 
    769809        """
    770         if 'pos' not in kwds.keys():
    771             kwds['pos'] = None
    772         if kwds['pos'] is None:
     810        if "pos" not in kwds:
     811            kwds["pos"] = None
     812        if kwds["pos"] is None:
    773813            pos = {}
    774814            left = list(self.left)
    775815            right = list(self.right)
     
    781821                pos[left[0]] = [-1, 0]
    782822            elif l_len > 1:
    783823                i = 0
    784                 d = 2./(l_len-1)
     824                d = 2.0 / (l_len - 1)
    785825                for v in left:
    786                     pos[v] = [-1, 1-i*d]
     826                    pos[v] = [-1, 1 - i*d]
    787827                    i += 1
    788828            if r_len == 1:
    789829                pos[right[0]] = [1, 0]
    790830            elif r_len > 1:
    791831                i = 0
    792                 d = 2./(r_len-1)
     832                d = 2.0 / (r_len - 1)
    793833                for v in right:
    794                     pos[v] = [1, 1-i*d]
     834                    pos[v] = [1, 1 - i*d]
    795835                    i += 1
    796             kwds['pos'] = pos
     836            kwds["pos"] = pos
    797837        return Graph.plot(self, *args, **kwds)
    798838
    799839    def load_afile(self, fname):
     
    801841        Loads into the current object the bipartite graph specified in the
    802842        given file name.  This file should follow David MacKay's alist format,
    803843        see
    804             http://www.inference.phy.cam.ac.uk/mackay/codes/data.html
     844        http://www.inference.phy.cam.ac.uk/mackay/codes/data.html
    805845        for examples and definition of the format.
    806        
    807         EXAMPLE:
     846
     847        EXAMPLE::
     848
    808849            sage: file_name = SAGE_TMP + 'deleteme.alist.txt'
    809850            sage: fi = open(file_name, 'w')
    810851            sage: fi.write("7 4 \n 3 4 \n 3 3 1 3 1 1 1 \n 3 3 3 4 \n\
     
    833874             sage: B2 == B
    834875             True
    835876        """
    836 
    837877        # open the file
    838878        try:
    839             fi = open(fname, 'r')
     879            fi = open(fname, "r")
    840880        except IOError:
    841881            print("Unable to open file <<" + fname + ">>.")
    842882            return None
     
    850890        # sanity checks on header info
    851891        if len(col_degrees) != num_cols:
    852892            print("Invalid Alist format: ")
    853             print("Number of column degree entries does not match number of columns.")
     893            print("Number of column degree entries does not match number " +
     894                  "of columns.")
    854895            return None
    855896        if len(row_degrees) != num_rows:
    856897            print("Invalid Alist format: ")
    857             print("Number of row degree entries does not match number of rows.")
     898            print("Number of row degree entries does not match number " +
     899                  "of rows.")
    858900            return None
    859901
    860902        # clear out self
    861903        self.clear()
    862904        self.add_vertices(range(num_cols), left=True)
    863         self.add_vertices(range(num_cols, num_cols+num_rows), right=True)
     905        self.add_vertices(range(num_cols, num_cols + num_rows), right=True)
    864906
    865907        # read adjacency information
    866908        for cidx in range(num_cols):
     
    869911                if ridx > 0:
    870912                    self.add_edge(cidx, num_cols + ridx - 1)
    871913
    872         #NOTE:: we could read in the row adjacency information as well to double-check....
    873         #NOTE:: we could check the actual node degrees against the reported node degrees....
     914        #NOTE:: we could read in the row adjacency information as well to
     915        #       double-check....
     916        #NOTE:: we could check the actual node degrees against the reported
     917        #       node degrees....
    874918
    875         # now we have all the edges in our graph, just fill in the bipartite partitioning
     919        # now we have all the edges in our graph, just fill in the
     920        # bipartite partitioning
    876921        self.left = set(xrange(num_cols))
    877922        self.right = set(xrange(num_cols, num_cols + num_rows))
    878923
     
    881926
    882927    def save_afile(self, fname):
    883928        r"""
    884         Save the graph to file in alist format. 
     929        Save the graph to file in alist format.
    885930
    886         Saves this graph to file in David MacKay's alist format, see 
    887             http://www.inference.phy.cam.ac.uk/mackay/codes/data.html
     931        Saves this graph to file in David MacKay's alist format, see
     932        http://www.inference.phy.cam.ac.uk/mackay/codes/data.html
    888933        for examples and definition of the format.
    889        
    890         EXAMPLE:
    891             sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), \
    892                               (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
     934
     935        EXAMPLE::
     936
     937            sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),
     938            ...               (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
    893939            sage: M
    894940            [1 1 1 0 0 0 0]
    895941            [1 0 0 1 1 0 0]
     
    902948            sage: b == b2
    903949            True
    904950
    905         TESTS:
     951        TESTS::
     952
    906953            sage: file_name = SAGE_TMP + 'deleteme.alist.txt'
    907954            sage: for order in range(3, 13, 3):
    908955            ...       num_chks = int(order / 3)
     
    914961            ...               b = BipartiteGraph(g, partition, check=False)
    915962            ...               b.save_afile(file_name)
    916963            ...               b2 = BipartiteGraph(file_name)
    917             ...               if b != b2: 
     964            ...               if b != b2:
    918965            ...                   print "Load/save failed for code with edges:"
    919966            ...                   print b.edges()
    920967            ...           except:
     
    922969            ...               print "with edges: "
    923970            ...               g.edges()
    924971            ...               raise
    925        
    926972        """
    927 
    928973        # open the file
    929974        try:
    930             fi = open(fname, 'w')
     975            fi = open(fname, "w")
    931976        except IOError:
    932977            print("Unable to open file <<" + fname + ">>.")
    933978            return
     
    9681013        Translate an edge to its reduced adjacency matrix position.
    9691014
    9701015        Returns (row index, column index) for the given pair of vertices.
    971        
    972         EXAMPLE:
     1016
     1017        EXAMPLE::
     1018
    9731019            sage: P = graphs.PetersenGraph()
    9741020            sage: partition = [range(5), range(5,10)]
    9751021            sage: B = BipartiteGraph(P, partition, check=False)
    9761022            sage: B._BipartiteGraph__edge2idx(2,7,range(5),range(5,10))
    9771023            (2, 2)
    978 
    9791024        """
    9801025        try:
    9811026            if v1 in self.left:  # note uses attribute for faster lookup
     
    9831028            else:
    9841029                return (right.index(v1), left.index(v2))
    9851030        except ValueError:
    986             raise ValueError("Tried to map invalid edge (%d,%d) to vertex indices" \
    987                                  % (v1, v2))
     1031            raise ValueError(
     1032                "Tried to map invalid edge (%d,%d) to vertex indices" %
     1033                (v1, v2))
    9881034
    9891035    def reduced_adjacency_matrix(self, sparse=True):
    9901036        r"""
    9911037        Return the reduced adjacency matrix for the given graph.
    9921038
    993         A reduced adjacency matrix contains only the non-redundant portion of the
    994         full adjacency matrix for the bipartite graph.  Specifically, for zero
    995         matrices of the appropriate size, for the reduced adjacency matrix H, the
    996         full adjacency matrix is [[0, H'], [H, 0]].
     1039        A reduced adjacency matrix contains only the non-redundant portion of
     1040        the full adjacency matrix for the bipartite graph.  Specifically, for
     1041        zero matrices of the appropriate size, for the reduced adjacency
     1042        matrix ``H``, the full adjacency matrix is ``[[0, H'], [H, 0]]``.
    9971043
    9981044        This method supports the named argument 'sparse' which defaults to
    999         True.  When enabled, the returned matrix will be sparse.
     1045        ``True``.  When enabled, the returned matrix will be sparse.
    10001046
    10011047        EXAMPLES:
    10021048
    1003         Bipartite graphs that are not weighted will return a matrix over ZZ.
    1004             sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0), \
    1005                               (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
     1049        Bipartite graphs that are not weighted will return a matrix over ZZ::
     1050
     1051            sage: M = Matrix([(1,1,1,0,0,0,0), (1,0,0,1,1,0,0),
     1052            ...               (0,1,0,1,0,1,0), (1,1,0,1,0,0,1)])
    10061053            sage: B = BipartiteGraph(M)
    10071054            sage: N = B.reduced_adjacency_matrix()
    10081055            sage: N
     
    10151062            sage: N[0,0].parent()
    10161063            Integer Ring
    10171064
    1018         Multi-edge graphs also return a matrix over ZZ.
    1019             sage: M = Matrix([(1, 1, 2, 0, 0), (0, 2, 1, 1, 1), (0, 1, 2, 1, 1)])
     1065        Multi-edge graphs also return a matrix over ZZ::
     1066
     1067            sage: M = Matrix([(1,1,2,0,0), (0,2,1,1,1), (0,1,2,1,1)])
    10201068            sage: B = BipartiteGraph(M, multiedges=True, sparse=True)
    10211069            sage: N = B.reduced_adjacency_matrix()
    10221070            sage: N == M
     
    10251073            Integer Ring
    10261074
    10271075        Weighted graphs will return a matrix over the ring given by their
    1028         (first) weights.
     1076        (first) weights::
     1077
    10291078            sage: F.<a> = GF(4)
    10301079            sage: MS = MatrixSpace(F, 2, 3)
    10311080            sage: M = MS.matrix([[0, 1, a+1], [a, 1, 1]])
     
    10361085            sage: N[0,0].parent()
    10371086            Finite Field in a of size 2^2
    10381087
    1039         TESTS:
     1088        TESTS::
     1089
    10401090            sage: B = BipartiteGraph()
    10411091            sage: B.reduced_adjacency_matrix()
    10421092            []
     
    10491099            True
    10501100        """
    10511101        if self.multiple_edges() and self.weighted():
    1052             raise NotImplementedError, "Don't know how to represent weights for a multigraph."
     1102            raise NotImplementedError(
     1103                "Don't know how to represent weights for a multigraph.")
    10531104        if self.is_directed():
    1054             raise NotImplementedError, "Reduced adjacency matrix does not exist for directed graphs."
     1105            raise NotImplementedError(
     1106                "Reduced adjacency matrix does not exist for directed graphs.")
    10551107
    10561108        # create sorted lists of left and right edges
    10571109        left = list(self.left)
     
    10691121            # if we're normal or multi-edge, just create the matrix over ZZ
    10701122            for (v1, v2, name) in self.edge_iterator():
    10711123                idx = self.__edge2idx(v1, v2, left, right)
    1072                 if D.has_key(idx):
     1124                if idx in D:
    10731125                    D[idx] = 1 + D[idx]
    10741126                else:
    10751127                    D[idx] = 1