def _two(self, g, s1, cut1, val1): ''' solves 2-decomposition ''' # get root. root = g.graph['root'] # greedy graph constraction. logging.info("two contracting") psz = len(g.nodes()) while 1 == 1: test = False for e in g.edges(): # graph active sets. sa = g.node[e[0]]['set'] sb = g.node[e[1]]['set'] # check if we cant merge. if len(sa) + len(sb) > self._cutoff: continue # dont touch root. if e[0] == root or e[1] == root: continue # make new node info. n = "%s_%s" % (str(e[0]), str(e[1])) s = g.node[e[0]]['set'].union(g.node[e[1]]['set']) # insert into graph. g.add_node(n, {'set':s, 'graph':None}) # rehook edges. for q in g.neighbors(e[0]): if q == e[1]: continue cut = g[e[0]][q]['cut'] g.remove_edge(e[0], q) g.add_edge(n, q, {'cut':cut}) for q in g.neighbors(e[1]): if q == e[0]: continue cut = g[e[1]][q]['cut'] g.remove_edge(e[1], q) g.add_edge(n, q, {'cut':cut}) # do contraction. g.remove_edge(e[0], e[1]) g.remove_node(e[0]) g.remove_node(e[1]) # break and reset. test = True break # check if there was no mod. if test == False: break logging.info("two contracted: %i to %i" % (psz, len(g.nodes()))) # solve bottom up. logging.info("solving two (bottom): %d" % len(s1)) for p, q, kids in self._dfs_gen(g, root, order=False): # grab active set. s2 = g.node[p]['set'] # if its the root just solve. if q == -1: # just solve. self._load(s2) if cut1 in s2: self._force(cut1, val1) sol, val = self._solve() self._clear() # save to root. g.node[p]['sol'] = sol g.node[p]['val'] = val else: # get cuts. cuts = g[p][q]['cut'] # solve 4 combinations of orientations. for x, y in itertools.product([0,1], repeat=2): # solve. self._load(s2) if cut1 in s2: self._force(cut1, val1) self._force(cuts[0], x) self._force(cuts[1], y) sol, val = self._solve() self._clear() # save info. g.node[p]['sol_%i_%i' % (x,y)] = sol g.node[p]['val_%i_%i' % (x,y)] = val # prepare a partial solution. nlist = build_nlist(self._nodes, s1) blist = build_blist(self._bundles, s1) tlist = build_tlist(self._bundles, s1) partial = PartialSolution(nlist.size, blist.size) val = 0.0 # apply solution top down. logging.info("applying two (top): %d" % len(s1)) for p, q, kids in self._dfs_gen(g, root, order=True): # grab active set. s2 = g.node[p]['set'] # just apply root. if q == -1: partial.merge(g.node[p]['sol']) val += g.node[p]['val'] continue # determine what the parent did. cuts = g[p][q]['cut'] oa = partial.get_orien(cuts[0]) ob = partial.get_orien(cuts[1]) # apply that solution. partial.merge(g.node[p]['sol_%i_%i' % (oa, ob)]) val += g.node[p]['val_%i_%i' % (oa, ob)] # return the solution. return partial, val
def _one(self, g, s0): ''' solves one component ''' # greedy graph constraction. logging.info("one contracting") psz = len(g.nodes()) while 1 == 1: test = False for e in g.edges(): # graph active sets. sa = g.node[e[0]]['set'] sb = g.node[e[1]]['set'] # check if we cant merge. if len(sa) + len(sb) > self._cutoff: continue # make new node info. n = "%s_%s" % (str(e[0]), str(e[1])) s = g.node[e[0]]['set'].union(g.node[e[1]]['set']) # insert into graph. g.add_node(n, {'set':s, 'graph':None}) # rehook edges. for q in g.neighbors(e[0]): if q == e[1]: continue cut = g[e[0]][q]['cut'] g.remove_edge(e[0], q) g.add_edge(n, q, {'cut':cut}) for q in g.neighbors(e[1]): if q == e[0]: continue cut = g[e[1]][q]['cut'] g.remove_edge(e[1], q) g.add_edge(n, q, {'cut':cut}) # do contraction. g.remove_edge(e[0], e[1]) g.remove_node(e[0]) g.remove_node(e[1]) # break and reset. test = True break # check if there was no mod. if test == False: break logging.info("one contracted: %i to %i" % (psz, len(g.nodes()))) # choose root. root = g.nodes()[0] # solve bottom up. logging.info("solving one (bottom): %d" % len(s0)) for p, q, kids in self._dfs_gen(g, root, order=False): # grab active set. s1 = g.node[p]['set'] g1 = g.node[p]['graph'] large = len(s1) > self._cutoff # if its the root just solve. if q == -1: # just solve (hope its not a 2-component). if large == False: # solve normal. self._load(s1) sol, val = self._solve() self._clear() else: # solve 2 decomp. print "NOT WRITTEN" sys.exit() # save to root. g.node[p]['sol'] = sol g.node[p]['val'] = val else: # get cut. cut = g[p][q]['cut'] # solve 2 combinations of orientations. logging.info("solving one: %d" % len(s1)) for x in [0, 1]: # switch on solve. if large == False: # solve normal. self._load(s1) self._force(cut, x) sol, val = self._solve() self._clear() else: # solve decompose. sol, val = self._two(g1, s1, cut, x) # save info. g.node[p]['sol_%i' % x] = sol g.node[p]['val_%i' % x] = val # prepare a partial solution. nlist = build_nlist(self._nodes, s0) blist = build_blist(self._bundles, s0) tlist = build_tlist(self._bundles, s0) partial = PartialSolution(nlist.size, blist.size) val = 0.0 # apply solution top down. logging.info("applying one (top): %d" % len(s0)) for p, q, kids in self._dfs_gen(g, root, order=True): # grab active set. s1 = g.node[p]['set'] # just apply root. if q == -1: partial.merge(g.node[p]['sol']) val += g.node[p]['val'] continue # determine what the parent did. cut = g[p][q]['cut'] o = partial.get_orien(cut) # apply that solution. partial.merge(g.node[p]['sol_%i' % o]) val += g.node[p]['val_%i' % o] # return solution. return partial, val