def isoBFS(G): table = {} isoTool.setGraph(G) todo = [ (0,0,[]) ] best = bestKnown bestList = [] hitTotal = 0 def end(signal=None, func=None): print print "Considered:", hitTotal print best print '\n'.join(str(x) for x in bestList) print hitCount if signal: import sys sys.exit() import signal signal.signal(signal.SIGINT, end) sortCount = 0 # Main BFS loop while len(todo) > 0: hitTotal += 1 #print todo (cost, depth, cons) = heappop(todo) #(cost, depth, cons) = todo.pop() #print todo #print c #print triList #verb = False #if getConsList(cons) == ['m', 'm', '1bec f08dccc 707af4d', '[]']: # print "yep" # print cons # print calcSize(cons) # verb = True # #exit() #print "cons:", c # Add in all of the edges needed for G c = cons while c!= []: ta = c[1] addEdge(G, (ta[1],ta[2])) c = c[3] #th = isoTool.getHash() # doesn't have a performance impact th = 1 #print "considering:", cons currentSize, usedSet = calcSize(cons) #if best != -1 and calcSize(cons)[0] > best: if best != -1 and currentSize > best: # strip off the edges added at this stage of the BFS c = cons while c!= []: ta = c[1] delEdge(G, (ta[1],ta[2])) c = c[3] continue edgeCache = {} # loop across all of the tripples to check where to continue the search for t in getAllTripples(G): e1 = sortPair([t[0], t[2]]) e2 = sortPair([t[1], t[2]]) #print "tripple:", t, e1, e2 #print "calling left:" if edgeCache.has_key(e1): h1, leafList1 = edgeCache[e1] else: addEdge(G,e1) h1 = isoTool.getHash() leafList1 = extraLeafCheck(G,topDepth,e1) #leaf1, cons1 = leafCheck(G) edgeCache[e1] = h1, leafList1 delEdge(G,e1) #print "calling right:" if edgeCache.has_key(e2): h2, leafList2 = edgeCache[e2] else: addEdge(G,e2) h2 = isoTool.getHash() #if h1 != h2: leafList2 = extraLeafCheck(G,topDepth,e2) #leaf2, cons2 = leafCheck(G) edgeCache[e2] = h2, leafList2 delEdge(G,e2) #print "leafList1:", leafList1 #print "leafList2:", leafList2 #for leaf1, cons1 in leafList1: # for leaf2, cons2 in leafList2: for leafNode1 in leafList1: for leafNode2 in leafList2: haveCons = False #if h1 == h2 or (leafNode1[0] and leafNode1[0] == leafNode2[0]): if h1 == h2: leftBranch = ('m', [], [], []) #if leafNode1[0] in ('4', '5', 'h'): if leafNode1[0]: rightBranch = leafNode1 haveCons = True h = h1, h2 #h = False else: rightBranch = [] h = h1 # uhm. Not sure about this. Seems like a big change: #nt = t[:] nt = t[1], t[0], t[2] elif leafNode1[0] and leafNode2[0]: leftBranch = leafNode1 rightBranch = leafNode2 nt = t[:] haveCons = True h = sortPair((h1,h2)) #h = False elif leafNode1[0]: leftBranch = leafNode1 rightBranch = [] nt = t[:] h = h2 elif leafNode2[0]: leftBranch = leafNode2 rightBranch = [] nt = t[1], t[0], t[2] h = h1 else: continue newCons = insertBranch(cons,[False, nt, leftBranch, rightBranch]) #newSize, used = calcSize(newCons) newSize, used = calcSize([False, nt, leftBranch, rightBranch], usedSet) newSize = newSize + currentSize - 1 #if newSize2+currentSize-1 != newSize or used != used2: # print "fail" # print cons # print newCons # print [False, nt, leftBranch, rightBranch] # print # print currentSize, usedSet # print newSize, used # print newSize2, used2 # exit() score = newSize #score = 1.0/newSize #score = (depth+1)/(newSize**2*1.0) #score = (newSize**2*1.0)/(depth+1) #print newCons #print getConsList(newCons) #print "result:", (h,used,newSize) #print "in table:", (h,used,newSize) in table if (h,used,newSize) not in table: table[(h,used,newSize)] = True print "remaining:", len(todo), "best:", best, "size:", newSize, "score:", score, "cons:", getConsList(newCons) if haveCons: # we have a construction if best == -1 or newSize < best: best = newSize bestList = [] if newSize == best: #bestList.append((c, t, code, (leaf1, leaf2), (cons1, cons2),used)) bestList.append(newCons) elif best == -1 or newSize <= best: heappush(todo, (score,depth+1,newCons)) #todo.append((score,depth+1,newCons)) #todo.insert(0, (score,depth+1,newCons)) # strip off the edges added at this stage of the BFS c = cons while c!= []: ta = c[1] delEdge(G, (ta[1],ta[2])) c = c[3] #table[th] = True end()
def isoBFS(G): table = {} isoTool.setGraph(G) todo = [(0, 0, [])] best = bestKnown bestList = [] hitTotal = 0 def end(signal=None, func=None): print print "Considered:", hitTotal print best print '\n'.join(str(x) for x in bestList) print hitCount if signal: import sys sys.exit() import signal signal.signal(signal.SIGINT, end) sortCount = 0 # Main BFS loop while len(todo) > 0: hitTotal += 1 #print todo (cost, depth, cons) = heappop(todo) #(cost, depth, cons) = todo.pop() #print todo #print c #print triList #verb = False #if getConsList(cons) == ['m', 'm', '1bec f08dccc 707af4d', '[]']: # print "yep" # print cons # print calcSize(cons) # verb = True # #exit() #print "cons:", c # Add in all of the edges needed for G c = cons while c != []: ta = c[1] addEdge(G, (ta[1], ta[2])) c = c[3] #th = isoTool.getHash() # doesn't have a performance impact th = 1 #print "considering:", cons currentSize, usedSet = calcSize(cons) #if best != -1 and calcSize(cons)[0] > best: if best != -1 and currentSize > best: # strip off the edges added at this stage of the BFS c = cons while c != []: ta = c[1] delEdge(G, (ta[1], ta[2])) c = c[3] continue edgeCache = {} # loop across all of the tripples to check where to continue the search for t in getAllTripples(G): e1 = sortPair([t[0], t[2]]) e2 = sortPair([t[1], t[2]]) #print "tripple:", t, e1, e2 #print "calling left:" if edgeCache.has_key(e1): h1, leafList1 = edgeCache[e1] else: addEdge(G, e1) h1 = isoTool.getHash() leafList1 = extraLeafCheck(G, topDepth, e1) #leaf1, cons1 = leafCheck(G) edgeCache[e1] = h1, leafList1 delEdge(G, e1) #print "calling right:" if edgeCache.has_key(e2): h2, leafList2 = edgeCache[e2] else: addEdge(G, e2) h2 = isoTool.getHash() #if h1 != h2: leafList2 = extraLeafCheck(G, topDepth, e2) #leaf2, cons2 = leafCheck(G) edgeCache[e2] = h2, leafList2 delEdge(G, e2) #print "leafList1:", leafList1 #print "leafList2:", leafList2 #for leaf1, cons1 in leafList1: # for leaf2, cons2 in leafList2: for leafNode1 in leafList1: for leafNode2 in leafList2: haveCons = False #if h1 == h2 or (leafNode1[0] and leafNode1[0] == leafNode2[0]): if h1 == h2: leftBranch = ('m', [], [], []) #if leafNode1[0] in ('4', '5', 'h'): if leafNode1[0]: rightBranch = leafNode1 haveCons = True h = h1, h2 #h = False else: rightBranch = [] h = h1 # uhm. Not sure about this. Seems like a big change: #nt = t[:] nt = t[1], t[0], t[2] elif leafNode1[0] and leafNode2[0]: leftBranch = leafNode1 rightBranch = leafNode2 nt = t[:] haveCons = True h = sortPair((h1, h2)) #h = False elif leafNode1[0]: leftBranch = leafNode1 rightBranch = [] nt = t[:] h = h2 elif leafNode2[0]: leftBranch = leafNode2 rightBranch = [] nt = t[1], t[0], t[2] h = h1 else: continue newCons = insertBranch( cons, [False, nt, leftBranch, rightBranch]) #newSize, used = calcSize(newCons) newSize, used = calcSize( [False, nt, leftBranch, rightBranch], usedSet) newSize = newSize + currentSize - 1 #if newSize2+currentSize-1 != newSize or used != used2: # print "fail" # print cons # print newCons # print [False, nt, leftBranch, rightBranch] # print # print currentSize, usedSet # print newSize, used # print newSize2, used2 # exit() score = newSize #score = 1.0/newSize #score = (depth+1)/(newSize**2*1.0) #score = (newSize**2*1.0)/(depth+1) #print newCons #print getConsList(newCons) #print "result:", (h,used,newSize) #print "in table:", (h,used,newSize) in table if (h, used, newSize) not in table: table[(h, used, newSize)] = True print "remaining:", len( todo ), "best:", best, "size:", newSize, "score:", score, "cons:", getConsList( newCons) if haveCons: # we have a construction if best == -1 or newSize < best: best = newSize bestList = [] if newSize == best: #bestList.append((c, t, code, (leaf1, leaf2), (cons1, cons2),used)) bestList.append(newCons) elif best == -1 or newSize <= best: heappush(todo, (score, depth + 1, newCons)) #todo.append((score,depth+1,newCons)) #todo.insert(0, (score,depth+1,newCons)) # strip off the edges added at this stage of the BFS c = cons while c != []: ta = c[1] delEdge(G, (ta[1], ta[2])) c = c[3] #table[th] = True end()
def extraLeafCheck(G, depth, ne = None, nKiteEdges=None): global hitCount # do a depth limited search for a construction. # So we take both edges of a triple, and both of the resulting graphs are leafs # depth is how many more times we can recurse before finding a leaf. # bigTable is a global cache of graphs and depths, but we can only cache negative results. # caching on graph isomorphism here doesn't work. # You cache a result. Then you pull that result from the cache later for a new graph. # But the indicies are wrong, so your construction is wrong when you sum the graphs. # To make this work, you would have to map back and forth between # the canonical indicies and your working indices. #h1 = -1 # depth is part of the hash because just because a graph isn't a leaf at depth 4, doesn't mean it's not a leaf at depth 3 h1 = isoTool.getHash() if (h1, depth) in bigTable: # print "Cache hit:", h1, bigTable[h1] hitCount += 1 return bigTable[(h1, depth)] # test if this graph is a leaf. I.E. contains a 4-clique, 5-wheel, or h graph l = leafCheck(G,ne,nKiteEdges) # return if we have a leaf, or we have hit our depth limit. if l[0] or depth <= 2: # leafCheck takes care of depth <= 2 #bigTable[h1] = [l] # FIXME I think we can cache the negative result here for depth return [l] # edgeCache caches a result for when an edge participates in multiple tripples. edgeCache = {} retList = [] # we need to return all possible solutions usedSets = [] # a list of sets of graphs used for each of the solutions in retLest kiteEdges = getKiteEdges(G) # performance optimization for t in getAllTripples(G): e1 = sortPair([t[0], t[2]]) e2 = sortPair([t[1], t[2]]) #print "elc tripple:", t, e1, e2 # Basic recursive check on the edges if edgeCache.has_key(e1): r1 = edgeCache[e1] else: addEdge(G,e1) r1 = extraLeafCheck(G,depth-1,e1,kiteEdges) delEdge(G,e1) edgeCache[e1] = r1 if edgeCache.has_key(e2): r2 = edgeCache[e2] else: addEdge(G,e2) r2 = extraLeafCheck(G,depth-1,e2,kiteEdges) delEdge(G,e2) edgeCache[e2] = r2 # to make this arbitrary depth: # leaf1 and leaf2 become lists # is that it? # Oh, and we are going to need edges for all returns # loop across the results for l1 in r1: for l2 in r2: # Found a pair of results that are good. # non-good results are in the ret-list? We don't just return empty? if l1[0] and l2[0]: #print "t:", t #print "derp1:", l1 #print "derp2:", l2 #print G #print "big1:", r1 #print "big2:", r2 #exit() # get the subgraph generated by the hajos sum of the leaf graphs # r is presumably our standard search node quad. Whatever that is. # this reduces our found construction to a subgraph construction r = getCombinedCons(G, t, l1, l2) # might be able to optimize the above. We always call it, so we might # not need to recurse. In fact, it's kind of goofy that this gets called recursively. #if r[0] == '1bec e0328 4f4d838': # print r # exit() # Do some optimzation to reduce the size of our results # use calcSize to get the set of graphs used in the construction used = calcSize(r)[1] # calcSize doesn't include the root graph in the set, so add it used = used.union([r[0]]) # Check if we have already seen a result that uses a subset of the # graphs that we are using. okay = True for s in usedSets: if s.issubset(used): okay = False break # now the other side of the above. Go through the list, and kill any previous results that # are supersets of the current result. if okay: #this is going to be hacky. #filter the retList if the new construction is a subset of # any of the constructions in the retlist. newUsed = [] newRet = [] for i in xrange(len(retList)): s = usedSets[i] if not used.issubset(s): newUsed.append(s) newRet.append(retList[i]) retList = newRet usedSets = newUsed retList.append(r) usedSets.append(used) #print "elc ret:", retList if retList: return retList # we have a result, we can return it. # unfortunately, our search node format does not cover returning usedSets as well. else: bigTable[(h1,depth)] = [(False,)] # only cache on failure return [(False,)]
def extraLeafCheck(G, depth, ne=None, nKiteEdges=None): global hitCount # do a depth limited search for a construction. # So we take both edges of a triple, and both of the resulting graphs are leafs # depth is how many more times we can recurse before finding a leaf. # bigTable is a global cache of graphs and depths, but we can only cache negative results. # caching on graph isomorphism here doesn't work. # You cache a result. Then you pull that result from the cache later for a new graph. # But the indicies are wrong, so your construction is wrong when you sum the graphs. # To make this work, you would have to map back and forth between # the canonical indicies and your working indices. #h1 = -1 # depth is part of the hash because just because a graph isn't a leaf at depth 4, doesn't mean it's not a leaf at depth 3 h1 = isoTool.getHash() if (h1, depth) in bigTable: # print "Cache hit:", h1, bigTable[h1] hitCount += 1 return bigTable[(h1, depth)] # test if this graph is a leaf. I.E. contains a 4-clique, 5-wheel, or h graph l = leafCheck(G, ne, nKiteEdges) # return if we have a leaf, or we have hit our depth limit. if l[0] or depth <= 2: # leafCheck takes care of depth <= 2 #bigTable[h1] = [l] # FIXME I think we can cache the negative result here for depth return [l] # edgeCache caches a result for when an edge participates in multiple tripples. edgeCache = {} retList = [] # we need to return all possible solutions usedSets = [ ] # a list of sets of graphs used for each of the solutions in retLest kiteEdges = getKiteEdges(G) # performance optimization for t in getAllTripples(G): e1 = sortPair([t[0], t[2]]) e2 = sortPair([t[1], t[2]]) #print "elc tripple:", t, e1, e2 # Basic recursive check on the edges if edgeCache.has_key(e1): r1 = edgeCache[e1] else: addEdge(G, e1) r1 = extraLeafCheck(G, depth - 1, e1, kiteEdges) delEdge(G, e1) edgeCache[e1] = r1 if edgeCache.has_key(e2): r2 = edgeCache[e2] else: addEdge(G, e2) r2 = extraLeafCheck(G, depth - 1, e2, kiteEdges) delEdge(G, e2) edgeCache[e2] = r2 # to make this arbitrary depth: # leaf1 and leaf2 become lists # is that it? # Oh, and we are going to need edges for all returns # loop across the results for l1 in r1: for l2 in r2: # Found a pair of results that are good. # non-good results are in the ret-list? We don't just return empty? if l1[0] and l2[0]: #print "t:", t #print "derp1:", l1 #print "derp2:", l2 #print G #print "big1:", r1 #print "big2:", r2 #exit() # get the subgraph generated by the hajos sum of the leaf graphs # r is presumably our standard search node quad. Whatever that is. # this reduces our found construction to a subgraph construction r = getCombinedCons(G, t, l1, l2) # might be able to optimize the above. We always call it, so we might # not need to recurse. In fact, it's kind of goofy that this gets called recursively. #if r[0] == '1bec e0328 4f4d838': # print r # exit() # Do some optimzation to reduce the size of our results # use calcSize to get the set of graphs used in the construction used = calcSize(r)[1] # calcSize doesn't include the root graph in the set, so add it used = used.union([r[0]]) # Check if we have already seen a result that uses a subset of the # graphs that we are using. okay = True for s in usedSets: if s.issubset(used): okay = False break # now the other side of the above. Go through the list, and kill any previous results that # are supersets of the current result. if okay: #this is going to be hacky. #filter the retList if the new construction is a subset of # any of the constructions in the retlist. newUsed = [] newRet = [] for i in xrange(len(retList)): s = usedSets[i] if not used.issubset(s): newUsed.append(s) newRet.append(retList[i]) retList = newRet usedSets = newUsed retList.append(r) usedSets.append(used) #print "elc ret:", retList if retList: return retList # we have a result, we can return it. # unfortunately, our search node format does not cover returning usedSets as well. else: bigTable[(h1, depth)] = [(False, )] # only cache on failure return [(False, )]