def generate_cids(model, prefix=(), **kwds): """Generate forward and reverse mappings between model components and deterministic, unique identifiers that are safe to serialize or use as dictionary keys.""" object_to_cid = pmo.ComponentMap() cid_to_object = collections.OrderedDict() if hasattr(pmo, "preorder_traversal"): # pragma:nocover fn = lambda *args, **kwds: pmo.preorder_traversal(model, *args, **kwds) else: # pragma:nocover fn = model.preorder_traversal try: fn(return_key=True) except TypeError: traversal = fn(**kwds) obj_ = six.next(traversal) assert obj_ is model object_to_cid[model] = prefix cid_to_object[prefix] = model for obj in traversal: parent = obj.parent key = obj.storage_key cid_ = object_to_cid[obj] = object_to_cid[parent] + (key, ) cid_to_object[cid_] = obj else: # pragma:nocover traversal = fn(return_key=True, **kwds) obj_ = six.next(traversal)[1] assert obj_ is model object_to_cid[model] = prefix cid_to_object[prefix] = model for key, obj in traversal: parent = obj.parent cid_ = object_to_cid[obj] = object_to_cid[parent] + (key, ) cid_to_object[cid_] = obj return object_to_cid, cid_to_object
def _branch_x(self, parent): N = range(len(self.W)) orig_bounds = pmo.ComponentMap() orig_bounds.update((yi, yi.bounds) for yi in self.model.y.components()) orig_bounds.update((xij, xij.bounds) for xij in self.model.x.components()) # do some simple preprocessing to reduce # the branch space for i in N: assert self.model.y[i].lb <= self.model.y[i].ub assert self.model.y[i].lb in (0,1) assert self.model.y[i].ub in (0,1) if self.model.y[i].ub == 0: for j in N: assert self.model.x[i,j].lb == 0 self.model.x[i,j].ub = 0 unassigned_items = [] for j in N: assigned = sum(self.model.x[i,j].lb for i in N) if assigned == 0: unassigned_items.append(j) else: assert assigned == 1 for i in N: if self.model.x[i,j].lb == 0: self.model.x[i,j].ub = 0 # find an item that is not already fixed into a bin bv = None for j in unassigned_items: for i in N: if (self.model.x[i,j].lb == 0) and \ (self.model.x[i,j].ub == 1): bv = self.model.x[i,j] break if bv is not None: break else: #pragma:nocover return () assert bv is not None children = [parent.new_child(), parent.new_child()] bv.lb = bv.ub = 1 self.save_state(children[0]) bv.lb = bv.ub = 0 self.save_state(children[1]) # reset bounds for var in orig_bounds: var.bounds = orig_bounds[var] return children
def _branch_y(self, parent): N = range(len(self.W)) for i in N: yi = self.model.y[i] assert yi.lb in (0,1), \ str(yi.name)+" "+str(yi.bounds) assert yi.ub in (0,1), \ str(yi.name)+" "+str(yi.bounds) if yi.lb == 0: if yi.ub == 1: break else: assert yi.ub == 0 else: assert yi.lb == 1 assert yi.lb == yi.ub else: # there is no branching left to do return () for k in range(i,len(self.W)): assert self.model.y[k].lb == 0 assert self.model.y[k].ub in (0,1) orig_bounds = pmo.ComponentMap() orig_bounds.update((yi, yi.bounds) for yi in self.model.y.components()) orig_bounds.update((xij, xij.bounds) for xij in self.model.x.components()) children = [parent.new_child(), parent.new_child()] # first branch: fix this bin on self.model.y[i].lb = self.model.y[i].ub = 1 self.save_state(children[0]) # second branch: fix this bin off, as well as all # bins following it for k in range(i,len(self.W)): self.model.y[k].lb = self.model.y[k].ub = 0 for j in N: assert self.model.x[k,j].lb == 0 self.model.x[k,j].ub = 0 self.save_state(children[1]) # reset bounds for var in orig_bounds: var.bounds = orig_bounds[var] return children
def __init__(self, V, W, pyomo_solver="ipopt", pyomo_solver_io="nl", integer_tolerance=1e-4): assert V > 0 assert integer_tolerance > 0 self.V = V self.W = W self._integer_tolerance = integer_tolerance N = range(len(self.W)) m = self.model = pmo.block() x = m.x = pmo.variable_dict() y = m.y = pmo.variable_dict() for i in N: y[i] = pmo.variable(domain=pmo.Binary) for j in N: x[i,j] = pmo.variable(domain=pmo.Binary) m.B = pmo.expression(sum(y.values())) m.objective = pmo.objective(m.B, sense=pmo.minimize) m.B_nontrivial = pmo.constraint(m.B >= 1) m.capacity = pmo.constraint_dict() for i in N: m.capacity[i] = pmo.constraint( sum(x[i,j]*self.W[j] for j in N) <= self.V*y[i]) m.assign_1 = pmo.constraint_dict() for j in N: m.assign_1[j] = pmo.constraint( sum(x[i,j] for i in N) == 1) # relax everything for the bound solves, # since the objective uses a simple heuristic self.true_domain_type = pmo.ComponentMap() for xij in self.model.x.components(): self.true_domain_type[xij] = xij.domain_type xij.domain_type = pmo.RealSet for yi in self.model.y.components(): self.true_domain_type[yi] = yi.domain_type yi.domain_type = pmo.RealSet self.opt = pmo.SolverFactory( pyomo_solver, solver_io=pyomo_solver_io)