Ticket #11099: trac_11099.patch

File trac_11099.patch, 5.6 KB (added by ncohen, 9 years ago)
  • sage/graphs/digraph_generators.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1301569743 -7200
    # Node ID c558180b026b850785dac5401b3cf6cccf0d4e33
    # Parent  8a0b4f90f1ca76dbdba159897c39209c5da85442
    trac 11099 -- Adding the digraph constructor digraphs.RandomDirectedGNM
    
    diff --git a/sage/graphs/digraph_generators.py b/sage/graphs/digraph_generators.py
    a b  
    4141                Random Directed Graphs:
    4242                    - RandomDirectedGN
    4343                    - RandomDirectedGNC
     44                    - RandomDirectedGNP
     45                    - RandomDirectedGNM
    4446                    - RandomDirectedGNR
    4547
    4648                Families of Graphs:
     
    459461                    D.add_edge(i,j)
    460462        return D
    461463
     464    def RandomDirectedGNM(self, n, m, loops = False):
     465        r"""
     466        Returns a random labelled digraph on `n` nodes and `m` arcs.
     467       
     468        INPUT:
     469
     470        - ``n`` (integer) -- number of vertices.
     471
     472        - ``m`` (integer) -- number of edges.
     473
     474        - ``loops`` (boolean) -- whether to allow loops (set to ``False`` by
     475          default).
     476       
     477        PLOTTING: When plotting, this graph will use the default spring-layout
     478        algorithm, unless a position dictionary is specified.
     479       
     480        EXAMPLE::
     481       
     482            sage: D = digraphs.RandomDirectedGNM(10, 5)
     483            sage: D.num_verts()
     484            10
     485            sage: D.edges(labels=False)
     486            [(0, 3), (1, 5), (5, 1), (7, 0), (8, 5)]
     487
     488        With loops::
     489
     490            sage: D = digraphs.RandomDirectedGNM(10, 100, loops = True)
     491            sage: D.num_verts()
     492            10
     493            sage: D.loops()
     494            [(0, 0, None), (1, 1, None), (2, 2, None), (3, 3, None), (4, 4, None), (5, 5, None), (6, 6, None), (7, 7, None), (8, 8, None), (9, 9, None)]
     495
     496        TESTS::
     497
     498            sage: digraphs.RandomDirectedGNM(10,-3)
     499            Traceback (most recent call last):
     500            ...
     501            ValueError: The number of edges must satisfy 0<= m <= n(n-1) when no loops are allowed, and 0<= m <= n^2 otherwise.
     502
     503            sage: digraphs.RandomDirectedGNM(10,100)
     504            Traceback (most recent call last):
     505            ...
     506            ValueError: The number of edges must satisfy 0<= m <= n(n-1) when no loops are allowed, and 0<= m <= n^2 otherwise.
     507        """
     508        n, m = int(n), int(m)
     509
     510        # The random graph is built by drawing randomly and uniformly two
     511        # integers u,v, and adding the corresponding edge if it does not exist,
     512        # as many times as necessary.
     513
     514        # When the graph is dense, we actually compute its complement. This will
     515        # prevent us from drawing the same pair u,v too many times.
     516
     517        from sage.misc.prandom import _pyrand
     518        rand = _pyrand()
     519        D = DiGraph(n, loops = loops)
     520
     521        # Ensuring the parameters n,m make sense.
     522        #
     523        # If the graph is dense, we actually want to build its complement. We
     524        # update m accordingly.
     525
     526        good_input = True
     527        is_dense = False
     528       
     529        if m < 0:
     530            good_input = False
     531
     532        if loops:
     533            if m > n*n:
     534                good_input = False
     535            elif m > n*n/2:
     536                is_dense = True
     537                m = n*n - m
     538
     539        else:
     540            if m > n*(n-1):
     541                good_input = False
     542            elif m > n*(n-1)/2:
     543                is_dense = True
     544                m = n*(n-1) - m
     545
     546        if not good_input:
     547            raise ValueError("The number of edges must satisfy 0<= m <= n(n-1) when no loops are allowed, and 0<= m <= n^2 otherwise.")
     548
     549        # When the given number of edges defines a density larger than 1/2, it
     550        # should be faster to compute the complement of the graph (less edges to
     551        # generate), then to return its complement. This being said, the
     552        # .complement() method for sparse graphs is very slow at the moment.
     553
     554        # Similarly, it is faster to test whether a pair belongs to a dictionary
     555        # than to test the adjacency of two vertices in a graph. For these
     556        # reasons, the following code mainly works on dictionaries.
     557
     558        adj = dict( (i, dict()) for i in range(n) )
     559
     560        # We fill the dictionary structure, but add the corresponding edge in
     561        # the graph only if is_dense is False. If it is true, we will add the
     562        # edges in a second phase.
     563
     564
     565        while m > 0:
     566
     567            # It is better to obtain random numbers this way than by calling the
     568            # randint or randrange method. This, because they are very expensive
     569            # when trying to compute MANY random integers, and because the
     570            # following lines is precisely what they do anyway, after checking
     571            # their parameters are correct.
     572
     573            u=int(rand.random()*n)
     574            v=int(rand.random()*n)
     575               
     576            if (u != v or loops) and (not v in adj[u]):
     577                adj[u][v] = 1
     578                m -= 1
     579                if not is_dense:
     580                    D.add_edge(u,v)
     581
     582        # If is_dense is True, it means the graph has not been built. We fill D
     583        # with the complement of the edges stored in the adj dictionary
     584
     585        if is_dense:
     586            for u in range(n):
     587                for v in range(n):
     588                    if ((u != v) or loops) and (not (v in adj[u])):
     589                        D.add_edge(u,v)
     590
     591        return D
     592
    462593    def RandomDirectedGNR(self, n, p, seed=None):
    463594        """
    464595        Returns a random GNR (growing network with redirection) digraph