def isMinSep(S, G): """Check whether S is a minimal separator of G. A set of vertices S is a minimal separator of G if and only if there are at least two full components associated with S in G. See Lemma 1 of [BT02Listing]. """ n_of_full_comps = 0 for (Sd, C) in pv.getBlocks(G, S): if Sd == S: n_of_full_comps += 1 if n_of_full_comps == 2: return True return False
def isPMC(P, G, boundVal): """Check whether P is a pmc in G. If yes, the number of nonedges in G[P] is also returned. See Theorem 8 of [BT02Listing]. """ nj = len(P) J = G.subgraph(P) fs = nj * (nj - 1) / 2 - J.number_of_edges() if fs > boundVal: return False, -1 for (N, C) in pv.getBlocks(G, P): if N == P: return False, -1 pv.cliquify(J, N) if nj * (nj - 1) == 2 * J.number_of_edges( ): #checking whether J became a clique. return True, fs return (False, -1)
def oneMoreVertex(G, a, S_cur, S_next, P_cur, boundVal): """See Algorithm ONE_MORE_VERTEX in [BT02Listing]. """ P_next = set() P_next_temp = set() for (pmc, dummy) in P_cur: if pmc in P_next_temp: continue ispmc, fs = isPMC(pmc, G, boundVal) if ispmc: P_next.add((pmc, fs)) P_next_temp.add(pmc) else: pmca = frozenset(pmc.union(set([a]))) if pmca in P_next_temp: continue ispmc, fs = isPMC(pmca, G, boundVal) if ispmc: P_next.add((pmca, fs)) P_next_temp.add(pmca) for s in S_next: sa = frozenset(s.union(set([a]))) if not sa in P_next_temp: ispmc, fs = isPMC(sa, G, boundVal) if ispmc: P_next.add((sa, fs)) P_next_temp.add(sa) if a not in s and not s in S_cur: blocks = list(pv.getBlocks(G, s)) for t in S_next: for (Sd, C) in blocks: if Sd == s: stc = frozenset(s.union(t.intersection(C))) if stc in P_next_temp: continue ispmc, fs = isPMC(stc, G, boundVal) if ispmc: P_next.add((stc, fs)) P_next_temp.add(stc) return P_next
def computeBPnPB(G, B, bids, P, S): """Computess BP and PB. B is the dictionary of blocks where bids is its indices sorted based on the block size, P is the list of pmcs and S is the dictionary of minimal separators. BP[i] is the dictionary of pmcs associated with the block B[i]. PB[(p,b)] is the dictionary of blocks which are associated to P[p] and which are subsets of B[b]. """ BP = {} PB = {} for i in xrange(0, len(B)): BP[i] = [] for p in xrange(0, len(P)): Pp = P[p][0] lenPp = len(Pp) b = len(B) - 1 pBlocks = list(pv.getBlocks(G, Pp)) while b >= 0: bb = bids[b] (s, C) = B[bb] Ss = S[s][0] lenSs = len(Ss) if lenPp <= lenSs: b -= 1 continue if Ss.issubset(Pp) and Pp.issubset(Ss.union(C)): BP[bb].append(p) PB[(p, bb)] = [] for (Sd, Cd) in pBlocks: SdCd = Sd.union(Cd) if len(SdCd) >= lenSs + len(C): continue if SdCd.issubset(Ss.union(C)): PB[(p, bb)].append(getBlockId(Sd, Cd, S, B, bids)) b = b - 1 return BP, PB
def computeSepBlocks(G): """Computes the following: 1. S <dictionary>: the minimal separators of G. S[i] = (s, blocks, fs), where s is the set of minimal separator, blocks are the ids of blocks associated with s, and fs is the fill-in size of s. 2. B <dictionary>: contains the full blocks associated with minimal separators. B[i] = (s, C) denotes the block where s is the index to S and C is the actual component. 4. bids <list>: block indices (in B) sorted in nondecreasing order based on the number of vertices in the blokcs. 5. Sim <set>: contains the inclusion-wise minimal separators (indices from S). See Algorithm AllMinSep in [BBC00Generating]. """ #INITIALIZATION step in the algorithm. S = {} #Minimal separators B = {} #Blocks S_temp = set() sid = 0 #separator id. bid = 0 #full block id. Sim = set() for v in G.nodes(): N = set([v]) N.update(G.neighbors(v)) for (Sd, Cd) in pv.getBlocks(G, N): if Sd in S_temp: continue fs = pv.fillSize(G, Sd) B[bid] = (sid, Cd) blocks = [bid] bid += 1 for (Td, Dd) in pv.getBlocks(G, Sd.union(Cd)): if Td != Sd: #we only need full blocks. continue B[bid] = (sid, Dd) blocks.append(bid) bid += 1 S[sid] = (Sd, blocks, fs) S_temp.add(frozenset(Sd)) updateSim(Sim, S, Sd, sid) sid += 1 #GENERATION step in the algorithm. counter = 0 while counter != len(S): (Sd, blocks_dummy, fs_dummy) = S[counter] for x in Sd: T = set(G.neighbors(x)).union(Sd) for (Td, Dd) in pv.getBlocks(G, T): if Td in S_temp: continue fs = pv.fillSize(G, Td) B[bid] = (sid, Dd) blocks = [bid] bid += 1 for Ud, Ed in pv.getBlocks(G, Td.union(Dd)): if Ud != Td: continue B[bid] = (sid, Ed) blocks.append(bid) bid += 1 S[sid] = (Td, blocks, fs) updateSim(Sim, S, Td, sid) S_temp.add(frozenset(Td)) sid += 1 counter += 1 bids = sorted([bid for bid in B.keys()], key=lambda x: len(S[B[x][0]][0]) + len(B[x][1])) return S, B, bids, Sim