def _build_decomposition_tree(self): # TODO: fix this. Add default empty separators set. s = self._s + [set()] # TODO: check connectivity order. prev_model = self._model.slice(self._u[-1], s[-2] | self._m[-1] | s[-1]) tree = DecompositionTree(self._model) tree.add_node(prev_model) tree.set_root(prev_model) for i in xrange(len(self._u) - 2, -1, -1): model = self._model.slice(self._u[i], s[i + 1] | self._m[i] | s[i]) tree.add_node(model) tree.add_edge(prev_model, model, [self.get_model().get_columns_names()[i] for i in s[i + 1]]) prev_model = model self._decomposition_tree = tree
def modify(self): list_of_models = [] names = [] tmpbool = True for node in self._tree.get_nodes(): m = node.get_model() names.append(node.get_name()) kmodel = knapsack_model.KnapsackModel(m) kmodel.mp_model_to_knapsack(m) new_model = mp_model_builder.MPModelBuilder().build_from_scratch(kmodel.get_profits(), [kmodel.get_weights()], ['L'], [kmodel.get_max_weight()], ["new_model"], [0 for j in range(m.get_num_columns())], [1 for j in range(m.get_num_columns())], m.columns_names) new_model.set_objective(kmodel.get_profits()) new_model.set_name(m.get_name()) list_of_models.append(new_model) G = nx.DiGraph(self._tree) for edge in dfs_edges(G, self._tree.get_root()): fnode = edge[0] snode = edge[1] for i in range(len(names)): if names[i] == fnode: fmodel = list_of_models[i] elif names[i] == snode: smodel = list_of_models[i] if tmpbool: new_tree = DecompositionTree(self._tree._model) root = Node(fmodel) new_tree.set_root(root) tmpbool = False fbool = False if not fmodel in new_tree.get_models(): new_tree.add_node(fmodel) fbool = True if not smodel in new_tree.get_models(): new_tree.add_node(smodel) fbool = True if fbool: shared_vars_names = [] fvars = fmodel.columns_names svars = smodel.columns_names for p in fvars: if p in svars: shared_vars_names.append(p) new_tree.add_edge(fmodel, smodel, shared_vars_names) return new_tree
def decompose(self, initial_cols=[0], max_separator_size=0, merge_empty_blocks=True): '''Decomposes model into submodels starting by initial cols. By default starts from column 0. Default max separator size is 11. :param initial_cols: A list of integers. :param max_separator_size: An integer that represents max available separator size. :param merge_empty_blocks: ``True`` or ``False``, whether or not we need to merge empty blocks. ''' if max_separator_size: raise NotImplementedError() logging.info('Decompose model %s', self._model.get_name()) self._used=[] self._used2=[] self._p=[] m = self._model.get_rows_coefficients() j_to_i_mapping = {} for j in range(m.shape[1]): j_to_i_mapping[j] = set() # TODO(d2rk): use interaction graph? g = networkx.Graph() g.add_nodes_from(range(m.shape[1])) for i in xrange(m.shape[0]): J_ = _get_indices(m, i) for j in range(len(J_) - 1): j_to_i_mapping[J_[j]].add(i) for j_ in range(j + 1, len(J_)): g.add_edge(J_[j], J_[j_]) j_to_i_mapping[J_[-1]].add(i) def get_neighbors(nodes): neighbors = set() for node in nodes: neighbors.update(g.neighbors(node)) neighbors.update(nodes) return neighbors def U(m_): u_=set() for i in xrange(m.shape[0]): ok = True K_ = _get_indices(m, i) for j in K_: ok &= j in m_ if ok: u_.add(i) return u_ self._m = [set(initial_cols) | get_neighbors(set(initial_cols))] self._s = [set()] self._u = [set()] i = len(self._m) J = get_neighbors(self._m[i - 1]) while True: M_ = J - self._m[i - 1] - self._s[i - 1] if not len(M_): break T = get_neighbors(M_) J_ = T - M_ self._m.append(M_) self._u.append(set()) self._s.append(J_ & J) self._m[i - 1] -= self._s[i] J = T i += 1 for j in range(i): current= self._m[j] | self._s[j] if j+1 < i: current.update(self._s[j+1]) self._u[j] = U(current) tree = DecompositionTree(self._model) for j in range(m.shape[1]): self._p.append(j) self._used.append(0) self._used2.append(0) self._layers=[] self._layermodel=[] for j in range(i): self._layers.append([]) self._layermodel.append([]) for j in range(i-1,-1,-1): current=self._m[j] | self._s[j] separator=set() | self._s[j] if j+1<i: current.update(self._s[j+1]) separator.update(self._s[j+1]) for k in current: self._used[k]=1 for k in current - separator: T=get_neighbors([k]) for _k in T: if self._used[_k]: self.unite_components(k,_k) for k in current: if not self._used2[k]: self._layers[j].append(set()) for _k in current: if self.get_component(k)==self.get_component(_k): self._layers[j][-1].add(_k) self._used2[_k]=1 u=U(self._layers[j][-1]) self._layermodel[j].append(self._model.slice(u, self._layers[j][-1])) tree.add_node(self._layermodel[j][-1]) if j!=i-1: for _k in range(len(self._layers[j+1])): if len( self._layers[j][-1] & self._layers[j+1][_k] )>0: tree.add_edge(self._layermodel[j][-1], self._layermodel[j+1][_k], [self.get_model().get_columns_names()[i] for i in self._layers[j][-1] & self._layers[j+1][_k]]) for k in separator: T=get_neighbors([k]) for _k in T: if self._used[_k]: self.unite_components(k,_k) tree.set_root(self._layermodel[0][0]) self._decomposition_tree = tree