Source code for pybnb.node

"""
Branch-and-bound node implementation.

Copyright by Gabriel A. Hackebeil (gabe.hackebeil@gmail.com).
"""
import uuid
import zlib

from pybnb.configuration import config

import six

if not six.PY2:
    import pickle
else:
    import cPickle as pickle

_serializer_modules = {}
_serializer_modules["pickle"] = pickle
_serializer_modules["dill"] = None

def _get_dill():
    assert config.SERIALIZER == "dill"
    import dill
    _serializer_modules["dill"] = dill
    return dill

[docs]def dumps(obj): """Return the serialized representation of the object as a bytes object, using the serialization module set in the current configuration.""" try: mod = _serializer_modules[config.SERIALIZER] except KeyError: raise ValueError("Invalid serializer '%s'. " "Valid choices are: ['pickle', 'dill']" % (config.SERIALIZER)) if mod is None: mod = _get_dill() data = mod.dumps( obj, protocol=config.SERIALIZER_PROTOCOL_VERSION) if config.COMPRESSION: data = zlib.compress(data) return data
[docs]def loads(data): """Read and return an object from the given serialized data, using the serialization module set in the current configuration.""" try: mod = _serializer_modules[config.SERIALIZER] except KeyError: raise ValueError("Invalid serializer '%s'. " "Valid choices are: ['pickle', 'dill']" % (config.SERIALIZER)) if mod is None: mod = _get_dill() if config.COMPRESSION: data = zlib.decompress(data) return mod.loads(data)
class _SerializedNode(object): """A helper object used by the distributed dispatcher for lightweight handling of serialized nodes.""" __slots__ = ("objective", "bound", "tree_depth", "queue_priority", "_uuid", "data") def __init__(self, slots): (self.objective, self.bound, self.tree_depth, self.queue_priority, self._uuid, self.data) = slots def _generate_uuid(self): self._uuid = uuid.uuid4().hex @property def slots(self): return (self.objective, self.bound, self.tree_depth, self.queue_priority, self._uuid, self.data) @staticmethod def to_slots(node): return (node.objective, node.bound, node.tree_depth, node.queue_priority, node._uuid, dumps(node.state)) @classmethod def from_node(cls, node): return cls(cls.to_slots(node)) @staticmethod def restore_node(slots): node = Node() (node.objective, node.bound, node.tree_depth, node.queue_priority, node._uuid, node.state) = slots node.state = loads(node.state) return node
[docs]class Node(object): """A branch-and-bound node that stores problem state. Attributes ---------- objective : float The objective value for the node. bound : float The bound value for the node. tree_depth : int The tree depth of the node (0-based). queue_priority : float or tuple of floats The queue priority of the node. state The user specified node state. """ __slots__ = ("objective", "bound", "tree_depth", "queue_priority", "_uuid", "state") def __init__(self): self.objective = None self.bound = None self.tree_depth = None self.queue_priority = None self._uuid = None self.state = None def _generate_uuid(self): self._uuid = uuid.uuid4().hex def resize(self, *args, **kwds): raise NotImplementedError( "It is no longer necessary to call " "node.resize(...). Simply assign any object " "to the node.state attribute. It no longer " "needs to be a numpy array. The node state " "must be serialize-able using pickle or dill " "in order to be compatible with the MPI-based " "parallel solver.") def __str__(self): out = \ ("Node(objective=%s,\n" " bound=%s,\n" " tree_depth=%s)" % (self.objective, self.bound, self.tree_depth)) return out def new_child(self): child = Node() child.objective = self.objective child.bound = self.bound child.tree_depth = self.tree_depth + 1 assert child.queue_priority is None assert child.state is None return child