Source code for pybnb.pyomo.misc

"""
Miscellaneous utilities used for development.

Copyright by Gabriel A. Hackebeil (gabe.hackebeil@gmail.com).
"""
import math
import collections
import hashlib

import pybnb

import six

import pyomo.kernel as pmo

if getattr(pmo, "version_info", (0,) * 3) < (5, 4, 3):  # pragma:nocover
    raise ImportError("Pyomo 5.4.3 or later is not available")


[docs]def hash_joblist(jobs): """Create a hash of a Python list by casting each entry to a string.""" x = hashlib.sha1() for entry in jobs: x.update(str(entry).encode()) return x.hexdigest()
[docs]def add_tmp_component(model, name, obj): """Add a temporary component to a model, adjusting the name as needed to make sure it is unique.""" while hasattr(model, name): name = "." + name + "." setattr(model, name, obj) return name
[docs]def correct_integer_lb(lb, integer_tolerance): """Converts a lower bound for an integer optimization variable to an integer equal to `ceil(ub)`, taking care not to move a non-integer bound away from an integer point already within a given tolerance.""" assert 0 <= integer_tolerance < 0.5 if lb - math.floor(lb) > integer_tolerance: return int(math.ceil(lb)) else: return int(math.floor(lb))
[docs]def correct_integer_ub(ub, integer_tolerance): """Converts an upper bound for an integer optimization variable to an integer equal to `floor(ub)`, taking care not to move a non-integer bound away from an integer point already within a given tolerance.""" assert 0 <= integer_tolerance < 0.5 if math.ceil(ub) - ub > integer_tolerance: return int(math.floor(ub)) else: return int(math.ceil(ub))
[docs]def create_optimality_bound(problem, pyomo_objective, best_objective_value): """Returns a constraint that bounds an objective function with a known best value. That is, the constraint will require the objective function to be better than the given value.""" optbound = pmo.constraint(body=pyomo_objective) if problem.sense() == pybnb.minimize: assert pyomo_objective.sense == pmo.minimize optbound.ub = best_objective_value else: assert problem.sense() == pybnb.maximize assert pyomo_objective.sense == pmo.maximize optbound.lb = best_objective_value return optbound
[docs]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