Changeset 7493:ec2dbddf8eba


Ignore:
Timestamp:
12/01/07 23:27:41 (5 years ago)
Author:
R. L. Miller <rlmillster@…>
Branch:
default
Message:

reimplemented graph generation by adding edges

Location:
sage/graphs
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • sage/graphs/graph.py

    r7369 r7493  
    36533653        """ 
    36543654        L = self._nxg.edges() 
    3655         if sort: 
    3656             L.sort() 
    36573655        if labels: 
    3658             return L 
     3656            if sort: 
     3657                return sorted(L) 
     3658            else: 
     3659                return L 
    36593660        else: 
    3660             return [(u,v) for u,v,_ in L] 
    3661  
     3661            if sort: 
     3662                return sorted([tuple(sorted((u,v))) for u,v,_ in L]) 
     3663            else: 
     3664                return [(u,v) for u,v,_ in L] 
    36623665 
    36633666    def edge_boundary(self, vertices1, vertices2=None, labels=True): 
  • sage/graphs/graph_generators.py

    r7395 r7493  
    25802580################################################################################ 
    25812581     
    2582     def __call__(self, vertices, property=lambda x: True): 
    2583         """ 
    2584         Accesses the generator of isomorphism class representatives. 
    2585          
     2582    def __call__(self, vertices, property=lambda x: True, augment='edges'): 
     2583        """ 
     2584        Accesses the generator of isomorphism class representatives. Iterates 
     2585        over distinct, exhaustive representatives. 
     2586 
    25862587        INPUT: 
    2587             vertices -- the maximum number of vertices in the graphs to be 
    2588                 generated. 
     2588            vertices -- natural number 
    25892589            property -- any property to be tested on graphs before generation. 
    2590                 If for any graph G satisfying the property, every subgraph, 
    2591                 obtained from G by deleting one vertex and only edges incident 
    2592                 to that vertex satisfies the property, then this will generate 
    2593                 all graphs with that property. If this does not hold, then all 
    2594                 the graphs generated will satisfy the property, but there will 
    2595                 be some missing. 
    2596          
    2597         NOTE: 
    2598             There could be other implementations of the algorithm so that the 
    2599             restriction on 'property' was also different- the restriction is 
    2600             specific to this particular implementation. 
    2601          
     2590            augment -- choices: 
     2591                'vertices' -- augments by adding a vertex, and edges incident 
     2592                    to that vertex. 
     2593                    In this case, all graphs on up to n=vertices are generated. 
     2594                    If for any graph G satisfying the property, every subgraph, 
     2595                    obtained from G by deleting one vertex and only edges incident 
     2596                    to that vertex, satisfies the property, then this will generate 
     2597                    all graphs with that property. If this does not hold, then all 
     2598                    the graphs generated will satisfy the property, but there will 
     2599                    be some missing. 
     2600                'edges' -- augments a fixed number of vertices by adding one edge 
     2601                    In this case, all graphs on exactly n=vertices are generated. 
     2602                    If for any graph G satisfying the property, every subgraph, 
     2603                    obtained from G by deleting one edge but not the vertices 
     2604                    incident to that edge, satisfies the property, then this will 
     2605                    generate all graphs with that property. If this does not hold, 
     2606                    then all the graphs generated will satisfy the property, but 
     2607                    there will be some missing. 
     2608 
    26022609        EXAMPLES: 
    26032610        Print graphs on 3 or less vertices. 
    2604             sage: for G in graphs(3): 
     2611            sage: for G in graphs(3, augment='vertices'): 
    26052612            ...    print G 
    26062613            ... 
     
    26132620            Graph on 2 vertices 
    26142621            Graph on 3 vertices 
    2615          
    2616         Generate all graphs with up to 5 vertices and up to 4 edges. 
     2622 
     2623        Print graphs on 3 vertices. 
     2624            sage: for G in graphs(3): 
     2625            ...    print G 
     2626            ... 
     2627            Graph on 3 vertices 
     2628            Graph on 3 vertices 
     2629            Graph on 3 vertices 
     2630            Graph on 3 vertices 
     2631         
     2632        Generate all graphs with 5 vertices and up to 4 edges. 
    26172633            sage: L = list(graphs(5, lambda G: G.size() <= 4)) 
    26182634            sage: len(L) 
    2619             31 
     2635            13 
    26202636            sage: graphs_list.show_graphs(L)    # long time 
    26212637         
    26222638        Generate all graphs with degree at most 2, up to 6 vertices. 
    26232639            sage: property = lambda G: ( max([G.degree(v) for v in G] + [0]) <= 2 ) 
    2624             sage: L = list(graphs(6, property)) 
     2640            sage: L = list(graphs(6, property, augment='vertices')) 
    26252641            sage: len(L) 
    26262642            45 
    26272643         
    2628         Generate all bipartite graphs on up to 7, 8 vertices: 
    2629             sage: L = list( graphs(7, lambda G: G.is_bipartite()) ) 
     2644        Generate all bipartite graphs on up to 7 vertices: 
     2645            sage: L = list( graphs(7, lambda G: G.is_bipartite(), augment='vertices') ) 
    26302646            sage: len(L) 
    26312647            133 
    2632             sage: L = list( graphs(8, lambda G: G.is_bipartite()) ) # long time (30 secs) 
    2633             sage: len(L)                                            # long time 
    2634             354 
     2648 
     2649        Generate all bipartite graphs on exactly 8 vertices: 
     2650            sage: L = list( graphs(8, lambda G: G.is_bipartite()) ) 
     2651            sage: len(L) 
     2652            38 
    26352653         
    26362654        REFERENCE: 
     
    26382656            Algorithms Volume 26, Issue 2, February 1998, pages 306-324. 
    26392657        """ 
    2640         from sage.graphs.graph_fast import binary 
    26412658        from sage.graphs.graph import Graph 
    26422659        g = Graph() 
    2643         for gg in canaug_traverse(g, [], vertices, property): 
    2644             yield gg 
    2645  
    2646 def canaug_traverse(g, aut_gens, max_verts, property): 
     2660        if augment == 'vertices': 
     2661            for gg in canaug_traverse_vert(g, [], vertices, property): 
     2662                yield gg 
     2663        elif augment == 'edges': 
     2664            g.add_vertices(range(vertices)) 
     2665            gens = [] 
     2666            for i in range(vertices-1): 
     2667                gen = range(i) 
     2668                gen.append(i+1); gen.append(i) 
     2669                gen += range(i+2, vertices) 
     2670                gens.append(gen) 
     2671            for gg in canaug_traverse_edge(g, gens, property): 
     2672                yield gg 
     2673        else: 
     2674            raise NotImplementedError() 
     2675 
     2676def canaug_traverse_vert(g, aut_gens, max_verts, property): 
    26472677    """ 
    26482678    Main function for exhaustive generation. Recursive traversal of a 
     
    26572687     
    26582688    EXAMPLES: 
    2659         sage: from sage.graphs.graph_generators import canaug_traverse 
    2660         sage: list(canaug_traverse(Graph(), [], 3, lambda x: True)) 
     2689        sage: from sage.graphs.graph_generators import canaug_traverse_vert 
     2690        sage: list(canaug_traverse_vert(Graph(), [], 3, lambda x: True)) 
    26612691        [Graph on 0 vertices, ... Graph on 3 vertices] 
    26622692 
     
    26642694     
    26652695    Print graphs on 3 or less vertices. 
    2666         sage: for G in graphs(3): 
     2696        sage: for G in graphs(3, augment='vertices'): 
    26672697        ...    print G 
    26682698        ... 
     
    26772707     
    26782708    Generate all graphs with up to 5 vertices and up to 4 edges. 
    2679         sage: L = list(graphs(5, lambda G: G.size() <= 4)) 
     2709        sage: L = list(graphs(5, lambda G: G.size() <= 4, augment='vertices')) 
    26802710        sage: len(L) 
    26812711        31 
     
    26832713     
    26842714    Generate all bipartite graphs on up to 7 vertices: 
    2685         sage: L = list( graphs(7, lambda G: G.is_bipartite()) ) 
     2715        sage: L = list( graphs(7, lambda G: G.is_bipartite(), augment='vertices') ) 
    26862716        sage: len(L) 
    26872717        133     
     
    27452775            m_z = z.subgraph(sub_verts) 
    27462776             
    2747             perm = range(n+1) 
    2748             seen_perms = [perm] 
    27492777            if m_z == g: 
    2750                 for a in canaug_traverse(z, z_aut_gens, max_verts, property): 
     2778                for a in canaug_traverse_vert(z, z_aut_gens, max_verts, property): 
    27512779                    yield a 
    27522780            else: 
    27532781                for possibility in check_aut(z_aut_gens, cut_vert, n): 
    27542782                    if m_z.relabel(possibility, inplace=False) == g: 
    2755                         for a in canaug_traverse(z, z_aut_gens, max_verts, property): 
     2783                        for a in canaug_traverse_vert(z, z_aut_gens, max_verts, property): 
    27562784                            yield a 
    27572785                        break 
     
    27912819                    yield new_perm 
    27922820 
     2821def canaug_traverse_edge(g, aut_gens, property): 
     2822    """ 
     2823    Main function for exhaustive generation. Recursive traversal of a 
     2824    canonically generated tree of isomorph free graphs satisfying a given 
     2825    property. 
     2826     
     2827    INPUT: 
     2828        g -- current position on the tree. 
     2829        aut_gens -- list of generators of Aut(g), in list notation. 
     2830        property -- check before traversing below g. 
     2831     
     2832    EXAMPLES: 
     2833        sage: from sage.graphs.graph_generators import canaug_traverse_edge 
     2834        sage: list(canaug_traverse_edge(Graph(), [], lambda x: True)) 
     2835        [Graph on 3 vertices, ... Graph on 3 vertices] 
     2836 
     2837    The best way to access this function is through the graphs() iterator: 
     2838     
     2839    Print graphs on 3 or less vertices. 
     2840        sage: for G in graphs(3): 
     2841        ...    print G 
     2842        ... 
     2843        Graph on 3 vertices 
     2844        Graph on 3 vertices 
     2845        Graph on 3 vertices 
     2846        Graph on 3 vertices 
     2847     
     2848    Generate all graphs with 5 vertices and up to 4 edges. 
     2849        sage: L = list(graphs(5, lambda G: G.size() <= 4)) 
     2850        sage: len(L) 
     2851        13 
     2852        sage: graphs_list.show_graphs(L)              # long time 
     2853     
     2854    Generate all bipartite graphs on 7 vertices: 
     2855        sage: L = list( graphs(7, lambda G: G.is_bipartite()) ) 
     2856        sage: len(L) 
     2857        23     
     2858 
     2859    """ 
     2860    from sage.graphs.graph_fast import binary 
     2861    from sage.graphs.graph_isom import search_tree 
     2862    if not property(g): 
     2863        return 
     2864    yield g 
     2865    n = g.order() 
     2866    n_choose_2 = (n*(n-1))>>1 # >> 1 is just / 2 
     2867    if g.size() < n_choose_2: 
     2868         
     2869        # build a list representing C(g) - the edge to be added 
     2870        # is one of n*(n-1)/2 choices 
     2871        num_roots = n_choose_2 
     2872        children = [[(j-1,i) for i in range(j-1)] for j in range(1,n+1)] 
     2873         
     2874        # union-find C(g) under Aut(g) 
     2875        for gen in aut_gens: 
     2876            for i in xrange(n): 
     2877                for j in xrange(i): # i > j 
     2878                    if children[i][j] == (i,j): 
     2879                        y, x = sorted([gen[i], gen[j]]) 
     2880                        if x < i: 
     2881                            children[i][j] = (x, y) 
     2882                        elif x > i: 
     2883                            children[x][y] = (i, j) 
     2884                        elif y < j: 
     2885                            children[i][j] = (x, y) 
     2886                        elif y > j: 
     2887                            children[x][y] = (i, j) 
     2888                        else: 
     2889                            continue 
     2890                        num_roots -= 1 
     2891 
     2892        # find representatives of orbits of C(g) 
     2893        roots = [] 
     2894        found_roots = 0 
     2895        i = 0; j = 1 
     2896        while found_roots < num_roots: 
     2897            if children[j][i] == (j, i): 
     2898                found_roots += 1 
     2899                roots.append((i, j)) 
     2900            if j < n - 1: 
     2901                j += 1 
     2902            elif i < j: # j == n-1 
     2903                i += 1 
     2904                j = i + 1 
     2905         
     2906        for i, j in roots: 
     2907            if g.has_edge(i, j): 
     2908                continue 
     2909            # construct a z for each edge in roots... 
     2910            z = g.copy() 
     2911            z.add_edge(i, j) 
     2912 
     2913            z_aut_gens, _, canonical_relabeling = search_tree(z, [z.vertices()], certify=True) 
     2914            relabel_inverse = [0]*n 
     2915            for i in xrange(n): 
     2916                relabel_inverse[canonical_relabeling[i]] = i 
     2917            z_can = z.relabel(canonical_relabeling, inplace=False) 
     2918            cut_edge_can = z_can.edges(labels=False, sort=True)[-1] 
     2919            cut_edge = [relabel_inverse[cut_edge_can[0]], relabel_inverse[cut_edge_can[1]]] 
     2920            cut_edge = tuple(sorted(cut_edge)) 
     2921 
     2922            m_z = z.copy() 
     2923            m_z.delete_edge(cut_edge) 
     2924 
     2925            if m_z == g: 
     2926                for a in canaug_traverse_edge(z, z_aut_gens, property): 
     2927                    yield a 
     2928            else: 
     2929                for possibility in check_aut_edge(z_aut_gens, cut_edge, i, j, n): 
     2930                    if m_z.relabel(possibility, inplace=False) == g: 
     2931                        for a in canaug_traverse_edge(z, z_aut_gens, property): 
     2932                            yield a 
     2933                        break 
     2934 
     2935def check_aut_edge(aut_gens, cut_edge, i, j, n): 
     2936    """ 
     2937    Helper function for exhaustive generation. 
     2938     
     2939    At the start, check_aut_edge is given a set of generators for the automorphism 
     2940    group, aut_gens. We already know we are looking for an element of the auto- 
     2941    morphism group that sends cut_edge to \{i, j\}, and check_aut generates 
     2942    these for the canaug_traverse function. 
     2943     
     2944    EXAMPLE: 
     2945    Note that the last two entries indicate that none of the automorphism group 
     2946    has yet been searched - we are starting at the identity [0, 1, 2, 3] and so 
     2947    far that is all we have seen. We return automorphisms mapping 2 to 3. 
     2948        sage: from sage.graphs.graph_generators import check_aut 
     2949        sage: list( check_aut( [ [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3] ], 2, 3)) 
     2950        [[1, 0, 3, 2], [1, 2, 3, 0]] 
     2951 
     2952    """ 
     2953    from copy import copy 
     2954    perm = range(n) 
     2955    seen_perms = [perm] 
     2956    unchecked_perms = [perm] 
     2957    while len(unchecked_perms) != 0: 
     2958        perm = unchecked_perms.pop(0) 
     2959        for gen in aut_gens: 
     2960            new_perm = copy(perm) 
     2961            for i in xrange(n): 
     2962                new_perm[i] = gen[perm[i]] 
     2963            if new_perm not in seen_perms: 
     2964                seen_perms.append(new_perm) 
     2965                unchecked_perms.append(new_perm) 
     2966                if new_perm[cut_edge[0]] == i and new_perm[cut_edge[1]] == j: 
     2967                    yield new_perm 
     2968                if new_perm[cut_edge[0]] == j and new_perm[cut_edge[1]] == i: 
     2969                    yield new_perm 
     2970 
    27932971# Easy access to the graph generators from the command line: 
    27942972graphs = GraphGenerators() 
Note: See TracChangeset for help on using the changeset viewer.