Source code for trilearn.graph.greenthomas

import numpy as np
import scipy.special as sp

import trilearn.auxiliary_functions as aux


[docs] def disconnect_select_subsets(tree, c): # 2. choose sets M = np.random.randint(2, high=len(c)+1) N = np.random.randint(1, high=M) X = frozenset(np.random.choice(list(c), size=N, replace=False)) Y = frozenset(np.random.choice(list(c-X), size=M-N, replace=False)) #print "X: " + str(X) #print "Y: " + str(Y) return (X, Y)
[docs] def disconnect_get_neighbors(tree, C, X, Y): # 3. define neighbors NX = set() NY = set() N = set() for n in tree.neighbors(C): # n interects both X and Y if len(n & X) > 0 and len(n & Y) > 0: # TODO #print str(n) + " interects both " + str(X) + " and "+str(Y) return False # neighbors intersecting X if len(n & X) > 0 and len(n & Y) == 0: NX.add(n) # neighbors intersectin Y elif len(n & X) == 0 and len(n & Y) > 0: NY.add(n) # neighbors not intersecting eithor of X or Y else: N.add(n) return (NX, NY, N)
[docs] def disconnect_get_CXCY(C, X, Y, NX, NY): S = C - (X | Y) CX = None CY = None XS = X | S YS = Y | S if NX is not None: for n in NX: if XS <= n: CX = n break if NY is not None: for n in NY: if YS <= n: CY = n break return (CX, CY)
[docs] def connect_a(tree, S, X, Y, CX, CY): XYS = X | Y | S # print "a)" # print "added node: " + str(XYS) # print "removed node: " + str(CX) # print "removed node: " + str(CY) # print "removed edge: " + str((CX, CY)) tree.remove_edge(CX, CY) XSneigh = set(tree.neighbors(CX)) YSneigh = set(tree.neighbors(CY)) tree.add_node(XYS) tree.add_edges_from([(XYS, n) for n in tree.neighbors(CX)]) tree.add_edges_from([(XYS, n) for n in tree.neighbors(CY)]) # print "added edges: " + str([(XYS, n) for n in tree.neighbors(CX)]) # print "added edges: " + str([(XYS, n) for n in tree.neighbors(CY)]) tree.remove_node(CY) tree.remove_node(CX) CX_disconn = None CY_disconn = None return (CX_disconn, CY_disconn, XSneigh, YSneigh)
[docs] def disconnect_a(tree, c, X, Y, CX, CY, XSneig, YSneig): S = c - (X | Y) XS = X | S YS = Y | S tree.add_node(XS) tree.add_node(YS) tree.add_edge(XS, YS) tree.add_edges_from([(XS, n) for n in XSneig]) tree.add_edges_from([(YS, n) for n in YSneig]) # print "a)" # print "removed node: " + str(c) # print "added edges: " + str([(XS, n) for n in XSneig]) # print "added edges: " + str([(YS, n) for n in YSneig]) # print "added edge: (" + str((XS, YS)) + ")" # print "removed edges: " + str([(c, n) for n in tree.neighbors(c)]) tree.remove_node(c) CX_conn = XS CY_conn = YS return (CX_conn, CY_conn)
[docs] def disconnect_b(tree, c, X, Y, CX, CY): S = c - (X | Y) YS = Y | S # print "b) disconnect" # print "added node: " + str(YS) # print "removed node: " + str(c) # replace c=XYS by YS tree.add_node(YS) tree.add_edges_from([(YS, n) for n in tree.neighbors(c)]) # print "added edges: " + str([(YS, n) for n in tree.neighbors(c)]) # print "removed edges: " + str([(c, n) for n in tree.neighbors(c)]) tree.remove_node(c) CX_conn = CX CY_conn = YS return (CX_conn, CY_conn)
[docs] def disconnect_c(tree, c, X, Y, CX, CY): S = c - (X | Y) XS = X | S # print "c)" # print "added node: " + str(XS) # print "removed node: " + str(c) # print "added edges: " + str([(XS, n) for n in tree.neighbors(c)]) # print "removed edges: " + str([(c, n) for n in tree.neighbors(c)]) # replace c=XYS by XS tree.add_node(XS) tree.add_edges_from([(XS, n) for n in tree.neighbors(c)]) tree.remove_node(c) CX_conn = XS CY_conn = CY return (CX_conn, CY_conn)
[docs] def disconnect_d(tree, c, X, Y, CX, CY): # print "d)" # print "added edge: " + str((CX, CY)) # print "removed node: " + str(c) # print "removed edges: " + str([(c, n) for n in tree.neighbors(c)]) tree.add_edge(CX, CY) tree.remove_node(c) CX_conn = CX CY_conn = CY return (CX_conn, CY_conn)
[docs] def disconnect_move(tree): C = np.random.choice(list(tree.nodes())) if len(C) < 2: #print "|C| < 2" return False (X, Y) = disconnect_select_subsets(tree, C) neigs = disconnect_get_neighbors(tree, C, X, Y) if neigs is False: #print "Some neighbor intersects both X and Y" return False else: (NX, NY, N) = neigs (CX, CY) = disconnect_get_CXCY(C, X, Y, NX, NY) S = C - (X | Y) # print "Disconnnect nodes: " + str(list(X)) + " and " + str(list(Y)) + " in " + str(C) # print "CX: " + str(CX) # print "CY: " + str(CY) num_cliques = tree.order() # case a if CX is None and CY is None: if N is not None: # this should be taken out NXS = aux.random_subset(N) # part of neigs N that will be assigned to XS NYS = N - NXS # part of neigs N that will be assigned to YS # print "NXS: " + str(NXS) # print "NYS: " + str(NYS) XSneig = NX | NXS # CX_disconn_neig YSneig = NY | NYS # CY_disconn_neig (CX_conn, CY_conn) = disconnect_a(tree, C, X, Y, CX, CY, XSneig, YSneig) logprob = disconnect_logprob_a(num_cliques, X, Y, S, N) return ("a", logprob, X, Y, S, CX_conn, CY_conn) # case b elif CX is not None and CY is None: if len(NX) == 1: # contains only CX (CX_conn, CY_conn) = disconnect_b(tree, C, X, Y, CX, CY) logprob = disconnect_logprob_bcd(num_cliques, X, Y, S) return ("b", logprob, X, Y, S, CX_conn, CY_conn) else: #print "NX contains more that one clique so nothing is done" return False # case c elif CX is None and CY is not None: if len(NY) == 1: # contains only CX (CX_conn, CY_conn) = disconnect_c(tree, C, X, Y, CX, CY) logprob = disconnect_logprob_bcd(num_cliques, X, Y, S) return ("c", logprob, X, Y, S, CX_conn, CY_conn) else: #print "NY contains more that one clique so nothing is done" return False # case d elif CX is not None and CY is not None: if len(N) == 0 and len(NY) == 1 and len(NX) == 1: (CX_conn, CY_conn) = disconnect_d(tree, C, X, Y, CX, CY) logprob = disconnect_logprob_bcd(num_cliques, X, Y, S) return ("d", logprob, X, Y, S, CX_conn, CY_conn) else: #print "len(N) == 0 and len(NY) == 1 and len(NX) == 1 id False so nothing is changes" return False
[docs] def disconnect_logprob_a(num_cliques, X, Y, S, N): return disconnect_logprob_bcd(num_cliques, X, Y, S) - len(N) * np.log(2)
[docs] def disconnect_logprob_bcd(num_cliques, X, Y, S): C = X | Y | S M = len(X | Y) N = len(X) m = len(C) logprob = 0.0 logprob += -np.log(num_cliques) logprob += np.log(2) - np.log((m - 1) * (M - 1)) logprob += sp.gammaln(N+1) + sp.gammaln(M-N+1) + sp.gammaln(m - M+1) - sp.gammaln(m+1) return logprob
[docs] def connect_move(tree): num_seps = tree.size() if num_seps == 0: return False (X, Y, CX, CY) = connect_select_subsets(tree) logprob = connect_logprob(num_seps, X, Y, CX, CY) S = CX & CY XS = X | S YS = Y | S CX_disconn, CY_disconn = None, None # print "Connnect: " + str(list(X)) + " and " + str(list(Y)) + " in " + str((CX, CY)) # print "XS: " + str(XS) # print "CX: " + str(CX) # print "YS: " + str(YS) # print "CY: " + str(CY) # a) if XS == CX and YS == CY: (CX_disconn, CY_disconn, XSneig, YSneig) = connect_a(tree, S, X, Y, CX, CY) return ("a", logprob, X, Y, S, CX_disconn, CY_disconn, XSneig, YSneig) # b) elif XS < CX and YS == CY: (CX_disconn, CY_disconn) = connect_b(tree, S, X, Y, CX, CY) return ("b", logprob, X, Y, S, CX_disconn, CY_disconn) # c) elif XS == CX and YS < CY: (CX_disconn, CY_disconn) = connect_c(tree, S, X, Y, CX, CY) return ("c", logprob, X, Y, S, CX_disconn, CY_disconn) # d) elif XS < CX and YS < CY: (CX_disconn, CY_disconn) = connect_d(tree, S, X, Y, CX, CY) return ("d", logprob, X, Y, S, CX_disconn, CY_disconn)
[docs] def connect_select_subsets(tree): # 1. choose separator SJ = tree.size() edgeind = np.random.randint(tree.size()) edge = list(tree.edges())[edgeind] S = edge[0] & edge[1] CX = edge[0] CY = edge[1] NumX = np.random.randint(len(CX - S)) + 1 NumY = np.random.randint(len(CY - S)) + 1 X = frozenset(np.random.choice(list(CX - S), NumX, replace=False)) Y = frozenset(np.random.choice(list(CY - S), NumY, replace=False)) return (X, Y, CX, CY)
[docs] def connect_b(tree, S, X, Y, CX, CY): XYS = X | Y | S # print "b) connect" # print "added node: " + str(XYS) # print "removed node: " + str(CY) # print "removed edges: " + str([(CY, n) for n in tree.neighbors(CY)]) # print "added edges: " + str([(XYS, n) for n in tree.neighbors(CY)]) tree.add_node(XYS) tree.add_edges_from([(XYS, n) for n in tree.neighbors(CY)]) tree.remove_node(CY) CX_disconn = CX CY_disconn = None return (CX_disconn, CY_disconn)
[docs] def connect_c(tree, S, X, Y, CX, CY): XYS = X | Y | S # print "c)" # print "added node: " + str(XYS) # print "removed node: " + str(CX) # print "removed edges: " + str([(CX, n) for n in tree.neighbors(CX)]) # print "added edges: " + str([(XYS, n) for n in tree.neighbors(CX)]) tree.add_node(XYS) tree.add_edges_from([(XYS, n) for n in tree.neighbors(CX)]) tree.remove_node(CX) CX_disconn = None CY_disconn = CY return (CX_disconn, CY_disconn)
[docs] def connect_d(tree, S, X, Y, CX, CY): XYS = X | Y | S # print "d)" # print "added node: " + str(XYS) # print "added edge: " + str((XYS, CX)) # print "added edge: " + str((XYS, CY)) # print "removed edge: " + str((CX, CY)) tree.add_node(XYS) tree.add_edge(XYS, CX) tree.add_edge(XYS, CY) tree.remove_edge(CX, CY) CX_disconn = CX CY_disconn = CY return (CX_disconn, CY_disconn)
[docs] def connect_logprob(num_seps, X, Y, CX, CY): S = CX & CY logprob = 0.0 s = len(S) SJ = num_seps NX = len(X) NY = len(Y) mX = len(CX) mY = len(CY) logprob += -np.log(SJ) logprob += -np.log(mX - s) logprob += sp.gammaln(NX + 1) + sp.gammaln(mX - s - NX + 1) - sp.gammaln(mX - s + 1) logprob += -np.log(mY - s) logprob += sp.gammaln(NY + 1) + sp.gammaln(mY - s - NY + 1) - sp.gammaln(mY - s + 1) return logprob