diff --git a/Makefile b/Makefile index 772fc2c33e25be28119b86269816862d6f0e86ce..a1430e1b1f689df8a3c048523e8c888246c03f3b 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ default: groupConnectivity.so clean_obj -groupConnectivity.so: groupConnectivity.pyx group-connectivity.h setup.py compileTimeOptions.h generateCompileTimeOptions.sh rings.h fast-array.h twoCuts.h parmap.py +groupConnectivity.so: groupConnectivity.pyx group-connectivity.h setup.py compileTimeOptions.h generateCompileTimeOptions.sh rings.h fast-array.h twoCuts.h parmap.py groupConnectivityNaive.py ./generateCompileTimeOptions.sh > options.h python setup.py build_ext cp build/lib*/groupConnectivity.so . diff --git a/groupConnectivity.pyx b/groupConnectivity.pyx index edcf2a1a2557971398e295f4eb44267429a0b9de..f0f0eae5d2b60ba2f3bfb371d59597de3fb04ff5 100644 --- a/groupConnectivity.pyx +++ b/groupConnectivity.pyx @@ -1,8 +1,11 @@ from libcpp.vector cimport vector from libcpp cimport bool from libcpp.utility cimport pair -from sage.graphs.graph import Graph +from sage.graphs.graph import Graph, DiGraph + +# include because we don't want it to became external dependecy include "parmap.py" +include "groupConnectivityNaive.py" cdef extern from "group-connectivity.h" namespace "Ring": cdef cppclass Z4[T]: @@ -28,6 +31,7 @@ cdef extern from "group-connectivity.h": def pathToEdges(G, path): + """Transform list of vertices into list of edges.""" ret = [] u = path[0] for v in path[1:]: @@ -39,10 +43,7 @@ def pathToEdges(G, path): def theOtherNeighbour(G, v, w): - """ - Given vertex v of degree 2 returns neighbour - of v not equal to w. - """ + """Return neighbour of v in G not equal to w given v has degree 2.""" N = G.neighbors(v) if N[0] == w: return N[1] diff --git a/groupConnectivityNaive.py b/groupConnectivityNaive.py new file mode 100644 index 0000000000000000000000000000000000000000..e72f7c3387fb6fdf6ad95c31d46e4e33538844d7 --- /dev/null +++ b/groupConnectivityNaive.py @@ -0,0 +1,100 @@ +def flowEnumerator(G, group): + """Enumerate all flows of given graph. + + Graph G must be directed and it edges labeled with numbers 0 to |E(G)|. + """ + + m = G.num_edges() + + assert(G.is_directed()) + assert(set(x for _, _, x in G.edges()) == set(range(m))) + + def to_elem_vector(cycle): + vec = [ group.zero() ] * m + for (u, v, x) in cycle: + if u > v: + vec[x] = -group.one() + else: + vec[x] = group.one() + return vec + + elemVecs = map(to_elem_vector, Graph(G).cycle_basis(output = "edge")) + + def combine(vec, i): + if i >= len(elemVecs): + yield vec + return + + for e in group: + for v in combine(map(lambda x: x[0] + e * x[1], zip(vec, elemVecs[i])), i + 1): + yield v + + for v in combine([group.zero()] * m, 0): + yield v + + +def testGroupConnectivityNaive(G_, group, forb_spanning_tree = False, list_all = False): + E = [ (u, v, i) for i, (u, v, _) in enumerate(G_.edges()) ] + G = DiGraph([G_.vertices(), E], format='vertices_and_edges') + m = G.num_edges() + info = { 'graph': G, 'edges': E } + + if forb_spanning_tree: + T = G.min_spanning_tree() + else: + T = G.edges() + + info['span_tree'] = T + + T = [ x for _, _, x in T ] + + flows = list(flowEnumerator(G, group)) + info['all_flows'] = flows + + mask = [group.zero()] * m + for e in T: + mask[e] = None + + def is_compatible(f, x): + for i in range(m): + if f[i] == x[i]: + return False + return True + + flows = [ f for f in flows if is_compatible(f, mask) ] + info['compatible_flows'] = flows + + Elems = [ x for x in group ] + forb = [ group.zero() ] * m + + def forb_iter(e): + if e >= len(T): + yield True + return + + for v in Elems: + forb[T[e]] = v + for r in forb_iter(e + 1): + yield r + + def find_flow(): + for f in flows: + if is_compatible(f, forb): + return True + return False + + ret = [] + + for _ in forb_iter(0): + if not find_flow(): + if not list_all: + return (False, info, [forb]) + ret.append(list(forb)) + + return (len(ret) == 0, info, ret) + +def labelsFromArray(G, E, labels): + for (u, v, i) in E: + G.set_edge_label(u, v, labels[i]) + +