Ticket #8922: trac_8922.patch
File trac_8922.patch, 12.8 KB (added by , 11 years ago) |
---|
-
sage/graphs/base/dense_graph.pxd
# HG changeset patch # User Nathann Cohen <nathann.cohen@gmail.com> # Date 1273258872 14400 # Node ID 5a688fdc03a3cede3566d5335d68eddd317c5099 # Parent decbd57f6680a443348813d94c3eb7d94ae6e199 Trac 8922 : induced_subgraph_search in Graph diff -r decbd57f6680 -r 5a688fdc03a3 sage/graphs/base/dense_graph.pxd
a b 21 21 cdef int radix_mod_mask 22 22 cdef int num_longs 23 23 cdef unsigned long *edges 24 cdef int * adjacency_sequence(self, int n, int * vertices, int vertex) 24 25 25 26 # Method declarations inherited from CGraph: 26 27 # cdef int add_arc_unsafe(self, int, int) -
sage/graphs/base/dense_graph.pyx
diff -r decbd57f6680 -r 5a688fdc03a3 sage/graphs/base/dense_graph.pyx
a b 456 456 self.check_vertex(u) 457 457 self.check_vertex(v) 458 458 self.del_arc_unsafe(u,v) 459 460 cdef int * adjacency_sequence(self, int n, int * vertices, int vertex): 461 r""" 462 Returns the adjacency sequence corresponding to a list of 463 vertices, and a vertex 464 465 INPUT: 466 467 - ``n`` -- number of elements in ``vertices`` 468 - ``vertices`` -- list of vertices 469 - ``vertex`` 470 471 OUTPUT: 472 473 Returns a list of ``n`` integers, whose i th element 474 is set to 1 iif vertex is adjacent to vertices[i] 475 """ 476 477 cdef int i = 0 478 cdef int * line 479 line = <int *> sage_malloc(n*sizeof(int)) 480 for 0 <= i < n: 481 line[i] = 1 if self.has_arc_unsafe(vertices[i],vertex) else 0 482 483 return line 459 484 460 485 ################################### 461 486 # Neighbor functions -
sage/graphs/generic_graph.py
diff -r decbd57f6680 -r 5a688fdc03a3 sage/graphs/generic_graph.py
a b 4210 4210 Same test with the Linear Program formulation:: 4211 4211 4212 4212 sage: g = graphs.PappusGraph() 4213 sage: g.matching(algorithm="LP", value_only=True) 4213 sage: g.matching(algorithm="LP", value_only=True) # optional - requires GLPK CBC or CPLEX 4214 4214 9.0 4215 4215 4216 4216 TESTS: … … 6911 6911 G.delete_edges(edges_to_delete) 6912 6912 if not inplace: 6913 6913 return G 6914 6915 def induced_subgraph_search(self, G): 6916 r""" 6917 Returns an induced copy of `G` in self. 6918 6919 INPUT: 6920 6921 - ``G`` -- the graph whose copy we are looking for in ``self`` 6922 6923 ALGORITHM: 6924 6925 Brute-force 6926 6927 EXAMPLES: 6928 6929 A Petersen Graph contains a `P_5` :: 6930 6931 sage: g = graphs.PetersenGraph() 6932 sage: h1 = g.induced_subgraph_search(graphs.PathGraph(5)) 6933 sage: h1 6934 Subgraph of (Petersen graph): Graph on 5 vertices 6935 sage: h1.vertices() 6936 [0, 1, 2, 3, 8] 6937 6938 It also contains a Claw (`K_{1,3}`):: 6939 6940 sage: h2 = g.induced_subgraph_search(graphs.ClawGraph()) 6941 sage: h2 6942 Subgraph of (Petersen graph): Graph on 4 vertices 6943 sage: h2.vertices() 6944 [0, 1, 4, 5] 6945 6946 Of course both copies are isomorphic to the graphs we were looking 6947 for :: 6948 6949 sage: h1.is_isomorphic(graphs.PathGraph(5)) 6950 True 6951 sage: h2.is_isomorphic(graphs.ClawGraph()) 6952 True 6953 6954 However, as it contains no induced subgraphs isomorphic to 6955 `P_6`, an exception is raised in this case :: 6956 6957 sage: g.induced_subgraph_search(graphs.PathGraph(6)) 6958 Traceback (most recent call last): 6959 ... 6960 ValueError: No induced copy of the graph exists 6961 """ 6962 from sage.graphs.generic_graph_pyx import subgraph_search 6963 6964 H = subgraph_search(self, G, induced = True) 6965 6966 if H == []: 6967 raise ValueError('No induced copy of the graph exists') 6968 6969 return self.subgraph(H) 6970 6971 def subgraph_search(self, G): 6972 r""" 6973 Returns an of `G` included in self. 6974 6975 INPUT: 6976 6977 - ``G`` -- the graph whose copy we are looking for in ``self`` 6978 6979 ALGORITHM: 6980 6981 Brute-force 6982 6983 EXAMPLES: 6984 6985 A Petersen Graph contains a `P_5` :: 6986 6987 sage: g = graphs.PetersenGraph() 6988 sage: h1 = g.subgraph_search(graphs.PathGraph(5)) 6989 sage: h1 6990 Subgraph of (Petersen graph): Graph on 5 vertices 6991 sage: h1.vertices() 6992 [0, 1, 2, 3, 4] 6993 6994 It also contains a Claw (`K_{1,3}`):: 6995 6996 sage: h2 = g.subgraph_search(graphs.ClawGraph()) 6997 sage: h2 6998 Subgraph of (Petersen graph): Graph on 4 vertices 6999 sage: h2.vertices() 7000 [0, 1, 4, 5] 7001 7002 However, as it contains no subgraph isomorphic to 7003 `K_3`, an exception is raised in this case :: 7004 7005 sage: g.subgraph_search(graphs.CompleteGraph(3)) 7006 Traceback (most recent call last): 7007 ... 7008 ValueError: No copy of the graph exists 7009 """ 7010 from sage.graphs.generic_graph_pyx import subgraph_search 7011 7012 H = subgraph_search(self, G) 7013 7014 if H == []: 7015 raise ValueError('No copy of the graph exists') 7016 7017 return self.subgraph(H) 6914 7018 6915 7019 def random_subgraph(self, p, inplace=False): 6916 7020 """ -
sage/graphs/generic_graph_pyx.pyx
diff -r decbd57f6680 -r 5a688fdc03a3 sage/graphs/generic_graph_pyx.pyx
a b 4 4 AUTHORS: 5 5 -- Robert L. Miller (2007-02-13): initial version 6 6 -- Robert W. Bradshaw (2007-03-31): fast spring layout algorithms 7 -- Nathann Cohen : exhaustive search 7 8 """ 8 9 9 10 #***************************************************************************** … … 17 18 include "../ext/interrupt.pxi" 18 19 include '../ext/cdefs.pxi' 19 20 include '../ext/stdsage.pxi' 21 22 from sage.graphs.base.dense_graph cimport DenseGraph 20 23 from random import random 21 24 22 25 cdef extern from *: … … 450 453 return m[:n*n] 451 454 452 455 456 # Exhaustive search in graphs 453 457 458 cpdef subgraph_search(G,H, induced = False): 459 r""" 460 Returns a set of vertices in G representing a copy of H 454 461 462 ALGORITHM: 455 463 464 This algorithm is a brute-force search. 465 Let `V(H)=\{h_1,\dots,h_k\}`. It first tries 466 to find in `G` a possible representant of `h_1`, then a 467 representant of `h_2` compatible with `h_1`, then 468 a representant of `h_3` compatible with the first 469 two, etc ... 456 470 471 This way, most of the times we need to test far less than 472 `\binom k!{|V(G)|}{k}` subsets, and hope this brute-force 473 technique can sometimes be useful. 457 474 475 INPUT: 458 476 477 - ``G``, ``H`` -- graphs 459 478 479 - ``induced`` (boolean) -- whether to require that the subgraph 480 is an induced subgraph 460 481 482 OUTPUT: 483 484 A list of vertices inducing a copy of ``H``. If none is found, 485 an empty list is returned. 486 487 EXAMPLE: 488 489 A Petersen Graph contains an induced `P_5` :: 490 491 sage: from sage.graphs.generic_graph_pyx import subgraph_search 492 sage: g = graphs.PetersenGraph() 493 sage: subgraph_search(g, graphs.PathGraph(5), induced = True) 494 [0, 1, 2, 3, 8] 495 496 It also contains a Claw (`K_{1,3}`):: 497 498 sage: subgraph_search(g, graphs.ClawGraph()) 499 [0, 1, 4, 5] 500 501 Though it contains no induced `P_6` :: 502 503 sage: subgraph_search(g, graphs.PathGraph(6), induced = True) 504 [] 505 """ 506 507 cdef int ng = G.order() 508 cdef int nh = H.order() 509 cdef int i, j, k 510 cdef int * tmp_array 511 512 cdef (int) (*is_admissible) (int, int *, int *) 513 514 if induced: 515 is_admissible = vectors_equal 516 else: 517 is_admissible = vectors_inferior 518 519 # Static copies of the two graphs for 520 # more efficient operations 521 522 cdef DenseGraph g = DenseGraph(ng) 523 cdef DenseGraph h = DenseGraph(nh) 524 525 # Copying the matrices 526 527 i = 0 528 for l in G.adjacency_matrix(): 529 j = 0 530 for k in l: 531 if k: 532 g.add_arc(i,j) 533 j=j+1 534 i=i+1 535 536 i = 0 537 for l in H.adjacency_matrix(): 538 j = 0 539 for k in l: 540 if k: 541 h.add_arc(i,j) 542 j=j+1 543 i=i+1 544 545 # A vertex is said to be busy if it is already part 546 # of the partial copy of H in G 547 cdef int * busy 548 busy = <int *> sage_malloc(ng*sizeof(int)) 549 memset(busy, 0, ng*sizeof(int)) 550 551 # 0 is the first vertex we use, so it is at first 552 # busy 553 busy[0] = 1 554 555 # stack 556 # 557 # List of the vertices which are part of the 558 # partial copy of H in G 559 # 560 # stack[i] is the integer corresponding 561 # to the vertex of G representing 562 # the i th vertex of H 563 # 564 # stack[i] = -1 means that i is not represented 565 # ... yet ! 566 567 cdef int * stack 568 stack = <int *> sage_malloc(nh*sizeof(int)) 569 stack[0] = 0 570 stack[1] = -1 571 572 # number of representants we have already 573 # found 574 575 # set to 1 as vertex 0 is already part of the partial 576 # copy of H ... 577 cdef int active = 1 578 579 # vertices is equal to range(nh), as an int * variable 580 cdef int * vertices 581 vertices = <int *> sage_malloc(nh*sizeof(int)) 582 for 0<= i < nh: 583 vertices[i] = i 584 585 # line_h[i] represents the adjacency sequence of vertex i 586 # in h relatively to vertices 0...i-1 587 cdef int ** line_h 588 line_h = <int **> sage_malloc(nh * sizeof(int *)) 589 for 0<= i < nh: 590 line_h[i] = <int *> h.adjacency_sequence( i, vertices, i) 591 592 # the sequence of vertices to be returned 593 value = [] 594 595 _sig_on 596 597 # as long as there is a non-void partial copy of H in G 598 while active: 599 600 # If we are here and found nothing yet 601 # we try the next possible vertex 602 # as a representant of the active th 603 # vertex of H 604 i = stack[active] +1 605 606 # Looking for a vertex which is not busy 607 # and compatible with the partial copy we have of H 608 while i < ng: 609 if busy[i] == 1: 610 i = i + 1 611 else: 612 tmp_array = g.adjacency_sequence(active, stack, i) 613 614 if is_admissible(active, tmp_array, line_h[active]): 615 free(tmp_array) 616 break 617 else: 618 free(tmp_array) 619 i = i + 1 620 621 # if we found none, it means that we can not extend the current copy of H 622 # so we update the status of stack[active] 623 # and prepare to change the previous vertex 624 if i >= ng: 625 if stack[active] != -1: 626 busy[stack[active]] = 0 627 stack[active] = -1 628 active=active-1 629 630 631 # If we have found a good representant of H's i^{th} vertex in G 632 else: 633 634 if stack[active] != -1: 635 busy[stack[active]]=0 636 stack[active] = i 637 busy[stack[active]]=1 638 639 active = active + 1 640 641 # We have found our copy !!! 642 if active == nh: 643 g_vertices = G.vertices() 644 value = [g_vertices[stack[i]] for i in xrange(nh)] 645 break 646 647 else: 648 # we begin the search of the next vertex at 0 649 stack[active] = -1 650 651 _sig_off 652 653 # Free the memory 654 sage_free(busy) 655 sage_free(stack) 656 sage_free(vertices) 657 for 0<= i < nh: 658 sage_free(line_h[i]) 659 sage_free(line_h) 660 661 return value 662 663 664 cdef int vectors_equal(int n, int * a, int * b): 665 r""" 666 Tests whether two vectors given in argument are equal 667 668 INPUT: 669 670 - ``n`` -- length of the vectors 671 - ``a``,``b`` -- the two vectors 672 """ 673 674 cdef int i =0 675 for 0<= i < n: 676 if a[i] != b[i]: 677 return False 678 return True 679 680 cdef int vectors_inferior(int n, int * a, int * b): 681 r""" 682 Tests whether the second vector of integer is larger than the first 683 684 INPUT: 685 686 - ``n`` -- length of the vectors 687 - ``a``,``b`` -- the two vectors 688 """ 689 690 cdef int i =0 691 for 0<= i < n: 692 if a[i] < b[i]: 693 return False 694 return True 695 -
sage/graphs/graph.py
diff -r decbd57f6680 -r 5a688fdc03a3 sage/graphs/graph.py
a b 2113 2113 rs_dict[h] = [v for v in self if rs[h][v]==1] 2114 2114 2115 2115 return rs_dict 2116 2116 2117 2117 2118 2118 ### Centrality 2119 2119