Arithmetic Progression Graphs Michael J. Dinneen, mjd@cs.auckland.ac.nz July 2016
1 A Real-World Problem 2 Solution 1 Combinatorial 3 Solution 2 Solving Systems of Equations 4 Solution 3 Augmenting Paths Approach
Arithmetic Progression Graphs Determine which finite undirected graphs G = (V, E) that can be both vertex and edge labeled (i.e., L 1 : V Z + and L 2 : E Z + ) that satisfy the following two conditions for some positive integers a and d: 1 For all v V, L 1 (v) = u N(v) L 2(uv), that is, the vertex labels are the sum of its incident edge labels. 2 range(l 1 ) = {a, a + d,..., a + (n 1)d}, where n = V. We call such a graph an Arithmetic Progression Graph (APG) with parameters a and d.
Yes and No instances of the APG family 1 5 3 a 4 2 a + 2d? a + d 6 2 4 When a, d > 0, 3a + 3d a + 3d
Some known properties of APGs With n = V and m = E and arithmetic progression parameters a > 0 and d > 0: a δ(g), i.e., minimum vertex degree. s v = v V V 1(v) = 2 e E V 2(e) = 2s e. s v = na + (0 + 1 + 2 + + (n 1))d = na + n(n 1) 2 d. 2na + n(n 1)d is divisible by 4. s e = (2na + n(n 1)d)/4 m.
Three test cases (Are these APGs?) A few small graphs displayed using sage s Graph.show() method. Graph t1.alist Graph t2.alist Graph t3.alist n = 4, m = 4 n = 7, m = 11 n = 8, m = 11
Try all combinations approach We want to check all combinations of edge labels that sum up to s e = (2na + n(n 1)d)/4. This is the same as checking all integer partitions of s e with m parts as the edge labels. An integer partition is a non-increasing sequence of positive integers x 1 x 2... x m such that s e = m i=1 x i. The following theorem helps us enumerate just these cases: Theorem The number of integer partitions of s e with largest part x 1 = m is the same as the number of integer partitions of s e with m parts.
Try all combinations approach We want to check all combinations of edge labels that sum up to s e = (2na + n(n 1)d)/4. This is the same as checking all integer partitions of s e with m parts as the edge labels. An integer partition is a non-increasing sequence of positive integers x 1 x 2... x m such that s e = m i=1 x i. The following theorem helps us enumerate just these cases: Theorem The number of integer partitions of s e with largest part x 1 = m is the same as the number of integer partitions of s e with m parts.
Brute-Force Combinatorial Solution (part 1) Sage code (preliminary part) to decide if a graph is an APG. #!/usr/bin/env sage -python import networkx as nx from sage.all import * a=1; d=1 if len(sys.argv)>1: a=int(sys.argv[1]) if len(sys.argv)>2: d=int(sys.argv[2]) # command-line arguments def magic(l): # function to check if sorted L is an Arithmetic Prog. for i in range(len(l)-1): if L[i+1]-L[i]!=d: return 0 return 1 g=nx.read_adjlist(sys.stdin) # input graph from networkx package n=g.order(); m=g.size() print "Graph", [(int(u),int(v)) for (u,v) in g.edges()]
Brute-Force Combinatorial Solution (part 2) Sage code to decide (via exhaustive search) if a graph is an APG. s=(2*n*a+(n-1)*n*d)/4 # desired sum of edges for x in partitions_greatest_eq(s,m): for y in permutations(partition(x).conjugate()): label=[0]*n; i=0 for (u,v) in g.edges(): label[int(u)]+=y[i]; label[int(v)]+=y[i]; i+=1 if magic(sorted(label)): print label, y; sys.exit(0)
Sample runs of Program 1 $ prog1.sage < t1.alist Graph [(1, 0), (1, 3), (0, 3), (0, 2)] [4, 3, 1, 2] [2, 1, 1, 1] $ prog1.sage 2 3 < t1.alist Graph [(1, 0), (1, 3), (0, 3), (0, 2)] [11, 8, 2, 5] [6, 2, 3, 2] $ time prog1.sage 2 2 < t2.alist Graph [(1, 5), (1, 4), (1, 6), (0, 5), (0, 4), (0, 6), (3, 5), (3, 6), ( [4, 8, 2, 12, 10, 14, 6] [1, 6, 1, 1, 1, 2, 11, 1, 1, 1, 2] real=0m4.820s user=0m3.062s sys=0m1.050s $ time prog1.sage 3 4 < t3.alist Graph [(1, 5), (1, 7), (0, 5), (0, 6), (3, 7), (3, 6), (2, 7), (2, 6), ( [7, 27, 3, 19, 11, 31, 15, 23] [26, 1, 4, 3, 18, 1, 2, 1, 1, 1, 10] real=389m54.579s user=319m3.685s sys=3m42.613s
Using algebra to improve decision time Definition The incidence matrix of a graph is an n m matrix where each column 1 j m has two 1 s (in rows u and v) corresponding to the edge uv of index j. From Condition 1 of the definition of an APG it follows that: Fact If M is an incidence matrix of a connected graph and x is a positive integer vector of length m (corresponding to edge labels) then the product Mx is an positive integer vector b of length n (corresponding to vertex labels).
Using algebra to improve decision time Definition The incidence matrix of a graph is an n m matrix where each column 1 j m has two 1 s (in rows u and v) corresponding to the edge uv of index j. From Condition 1 of the definition of an APG it follows that: Fact If M is an incidence matrix of a connected graph and x is a positive integer vector of length m (corresponding to edge labels) then the product Mx is an positive integer vector b of length n (corresponding to vertex labels).
What is Integer Programming? Definition Let A be an m n matrix with integral coefficients, b Z m and c Z n. The problem min{c T x x Z n, Ax = b, x 0 component-wise} is called an instance of the Integer Programming (IP) problem. The IP problem is very hard; namely, the decision version is NP-complete. Sage has a good non-branch-and-bound IP solver implementation that works well in practice. Note: the Linear Programming variant (over reals R) is in P.
What is Integer Programming? Definition Let A be an m n matrix with integral coefficients, b Z m and c Z n. The problem min{c T x x Z n, Ax = b, x 0 component-wise} is called an instance of the Integer Programming (IP) problem. The IP problem is very hard; namely, the decision version is NP-complete. Sage has a good non-branch-and-bound IP solver implementation that works well in practice. Note: the Linear Programming variant (over reals R) is in P.
Using algebra to improve decision time (cont.) Let M be the incidence matrix of a graph G. Thus if we know what vertex labels (vector b) that is desired, we can try to solve the equation Mx = b. This vector b is just some permutation of the arithmetic progression a, a + d,..., a + (n 1)d. However (!!!) to apply integer programming to APG domain, our solution x needs to be strictly positive. This problem is fixed by offsetting the solution vector by a vector of 1s : Let x = x I. If x 0 then x 1. Since M(x + I ) = Mx + MI = b, the new b vector should be b MI when solving Mx = b.
Using algebra to improve decision time (cont.) Let M be the incidence matrix of a graph G. Thus if we know what vertex labels (vector b) that is desired, we can try to solve the equation Mx = b. This vector b is just some permutation of the arithmetic progression a, a + d,..., a + (n 1)d. However (!!!) to apply integer programming to APG domain, our solution x needs to be strictly positive. This problem is fixed by offsetting the solution vector by a vector of 1s : Let x = x I. If x 0 then x 1. Since M(x + I ) = Mx + MI = b, the new b vector should be b MI when solving Mx = b.
Using algebra to improve decision time (cont.) Let M be the incidence matrix of a graph G. Thus if we know what vertex labels (vector b) that is desired, we can try to solve the equation Mx = b. This vector b is just some permutation of the arithmetic progression a, a + d,..., a + (n 1)d. However (!!!) to apply integer programming to APG domain, our solution x needs to be strictly positive. This problem is fixed by offsetting the solution vector by a vector of 1s : Let x = x I. If x 0 then x 1. Since M(x + I ) = Mx + MI = b, the new b vector should be b MI when solving Mx = b.
Integer Programming Solution (singular version) Sage code to decide (via IP) if a graph is an APG. #... same initialization code as before, then... M=Graph(g).incidence_matrix() for r in range(0,n): for t in range(0,m): M[r,t]=abs(M[r,t]) # make undirected singular.lib("intprog.lib") singular.eval( intmat M[%s][%s]=%s %(n,m,str(m.list())[1:-1])) I=vector(ZZ,[1]*m); M2=singular("M"); C2=singular(( 0, *m)[:-1], intvec ) for perm in permutations(n): B=vector(ZZ,[a+(perm[i]-1)*d for i in range(n)]) E=B-(M*I) if min(e)<0: continue E2=singular(str(E.list())[1:-1], intvec ) N2=singular.solve_IP(M2,E2,C2, "pct" ) if N2: print vertices =,B, edges =,list(n2+i); sys.exit(0)
Integer Programming Solution (MIP version) Sage code to decide (via MIP) if a graph is an APG. B=[a+(perm[i]-1)*d for i in range(n)] p=mixedintegerlinearprogram() b=p.new_variable() for i in range(n): p.add_constraint(sum([b[(u,v)] for (u,v) in G.edges(labels=None) \ if i==int(u) or i==int(v)]),min=b[i],max=b[i]) for e in G.edges(labels=None): p.add_constraint(b[e],min=1) p.set_objective(sum([b[x] for x in G.edges(labels=None)])) # anything p.set_integer(b) try: p.solve(solver="coin") except sage.numerical.mip.mipsolverexception as e: pass else: print p.get_values(b).items(); sys.exit(0)
Sample runs of Program 2 $ prog2.sage < t1.alist Graph [(1, 0), (1, 3), (0, 3), (0, 2)] vertices = (4, 2, 1, 3) edges = [1, 1, 2, 1] $ time prog2.sage 2 2 < t2.alist Graph [(1, 5), (1, 4), (1, 6), (0, 5), (0, 4), (0, 6), (3, 5), (3, 6), ( vertices = (4, 6, 2, 8, 12, 10, 14) edges = [1, 1, 4, 1, 2, 1, 7, 1, 1, 1, 8] real=0m3.501s user=0m1.662s sys=0m1.081s $ time prog2.sage 3 4 < t3.alist Graph [(1, 5), (1, 7), (0, 5), (0, 6), (3, 7), (3, 6), (2, 7), (2, 6), ( vertices = (3, 11, 7, 15, 19, 23, 27, 31) edges = [8, 3, 2, 1, 1, 14, 1, 6, 13, 13, 6] real=0m31.200s user=0m3.168s sys=0m1.533s
Initial conclusions Running time of algorithm 1 is O(m!B(s, m)) has been improved to O(n!IP(n)), where B(s, m) is the number of integer partitions of s with m parts and IP(n)) is the running time of Sage/Singular s Integer Programming algorithm. Most connected graphs are in APG. Order n Yes No 1 0 1 2 0 1 3 2 0 4 5 1 5 20 1 6 101 11 7 849 4 8 11090 27
Initial conclusions Running time of algorithm 1 is O(m!B(s, m)) has been improved to O(n!IP(n)), where B(s, m) is the number of integer partitions of s with m parts and IP(n)) is the running time of Sage/Singular s Integer Programming algorithm. Most connected graphs are in APG. Order n Yes No 1 0 1 2 0 1 3 2 0 4 5 1 5 20 1 6 101 11 7 849 4 8 11090 27
Can we find a better algorithm? If we change the problem slightly does it help us? E.g. what if we fix the values of the vertices? Problem (FixedIncidentEdgeLabelable) Input: Connected undirected graph G = (V, E) with a vertex labeling f : V Z +. Question: Does there exist an edge labeling g : E Z + such that for all v V, f (v) = g(uv)? u N(v) Theorem There exists a pseudo polynomial-time algorithm to decide the problem FixedIncidentEdgeLabelable.
Can we find a better algorithm? If we change the problem slightly does it help us? E.g. what if we fix the values of the vertices? Problem (FixedIncidentEdgeLabelable) Input: Connected undirected graph G = (V, E) with a vertex labeling f : V Z +. Question: Does there exist an edge labeling g : E Z + such that for all v V, f (v) = g(uv)? u N(v) Theorem There exists a pseudo polynomial-time algorithm to decide the problem FixedIncidentEdgeLabelable.
Can we find a better algorithm? If we change the problem slightly does it help us? E.g. what if we fix the values of the vertices? Problem (FixedIncidentEdgeLabelable) Input: Connected undirected graph G = (V, E) with a vertex labeling f : V Z +. Question: Does there exist an edge labeling g : E Z + such that for all v V, f (v) = g(uv)? u N(v) Theorem There exists a pseudo polynomial-time algorithm to decide the problem FixedIncidentEdgeLabelable.
Augmenting Paths Algorithm Definition A vertex is unsaturated if the sum of its incident edges is less than its label. An improving walk satisfies the following conditions: We use an approach similar to the augmenting path techniques used in many maximal matching algorithms. If there is an odd length sequence of edges, starting and ending at a unsaturated vertices then we can improve the saturation level of the graph by adding, in an alternating fashion, +1 and -1 to the edges in this walk sequence. To ensure that each edge label stays positive we only apply this augmentation when all of the even-indexed edges have value at least 2. The saturation levels only increase by 1 for first/last vertex.
Using an improving walk to increase saturation 5 3 2 2 6 8 3 1 6 14 14 2 3 3 8 9 2 5 2 3 2 6 8 3 1 4 5 14 14 2 3 8 9 2 3 2 3 1 4 2 3 1 6 1 7 1 3 6 1 7 1 3
Pseudocode for Solution 3 We give a decision algorithm that runs in time that is bounded by a polynomial of n = V and the sum T = v V f (v). Procedure Membership(Graph G, Vertex labels f [1..n]) begin Edge labels g[1..m] = (1, 1,..., 1) Saturation values s[v] = uv E g[uv], for all v V if v, s[v] > f [v] return false L1: while v, s[v] f [v] do for each v such that s[v] f [v] do if there exists an improving walk starting at v do Note special case of ending at v if s[v] + 1 = f [v] Augment the edges of the improving walk by updating the values of g[] and s[] next L1 return false return true end
# Python code for solving the Fixed_Incident_Edge_Lablelable problem import networkx as nx import numpy as np n=0 # order of input graph STree=nx.DiGraph() # bipartite search graph unsat=set() # current nodes not saturated def set_search_tree(g,g): global STree STree=nx.DiGraph() STree.add_nodes_from(range(2*n)) for x in range(n): for y in G[x]: STree.add_edge(x,y+n) if g[min(x,y),max(x,y)]>1: STree.add_edge(y+n,x) return def improve_walk(v,loopflag): path=nx.single_source_shortest_path(stree,v) endpoint=unsat if LoopFlag: endpoint=unsat set([v]) for w in endpoint: if w+n in path: return [z%n for z in path[w+n]] return None
def membership(g,f): """ Check connected graph G has an edge labeling (g[]) such that the sum of incident edge labels correspond to the f[] vertex labeling. """ global n, unsat n=g.order() g=np.zeros((n,n),int) # current edge labels (adjacency matrix) for (u,v) in G.edges(): g[u,v]=1 s=np.zeros((n),int) # current saturation values (vector) for v in G: s[v]=len(g[v]) if s[v]>f[v]: return None unsat=set([i for i in range(n) if s[i]<f[i]]) while unsat: # line L1 of pseudocode set_search_tree(g,g) v=unsat.pop() W=improve_walk(v,s[v]!=f[v]-1) # 2nd argument detects our "special case" if W: for i in range(len(w)-1): # augment the edges g[] if W[i]<W[i+1]: g[w[i],w[i+1]]+=2*((i+1)%2)-1 else: g[w[i+1],w[i]]+=2*((i+1)%2)-1 w=w[-1]; s[v]+=1; s[w]+=1 # and update the saturations s[] if s[v]!=f[v]: unsat.add(v) if v!=w and s[w]==f[w]: unsat.remove(w) else: return None return [((u,v),g[u,v]) for (u,v) in G.edges()]
Analysis of Running Time The program terminates with at most T /2 iterations of the while loop (since saturation levels always increase by two). Finding an improving walk takes O(n 2 ) steps by building a search tree of at most 2n vertices. We need to consider whether each of the other vertices is reachable at only an odd distance (not all the distances) from the starting vertex. Thus, the total running time is bounded by O(n 3 T ). More information (and correctness proof): 2014: Michael J. Dinneen, Nan Rosemary Ke, and Masoud Khosravani. Arithmetic progression graphs, Universal J. of Applied Mathematics. http://www.cs.auckland.ac.nz/cdmtcs/researchreports/356dkk.pdf