def write(self, stream, prefix="", pretty=False): """Writes results in YAML format to a stream or file. Parameters ---------- stream : file-like object or string A file-like object or a filename where results should be written to. prefix : string, optional A string to use as a prefix for each line that is written. (default: '') pretty : bool, optional Indicates whether or not certain recognized attributes should be formatted for more human-readable output. (default: False) """ with as_stream(stream) as stream: attrs = vars(self) names = sorted(list(attrs.keys())) first = ('solution_status', 'termination_condition', 'objective', 'bound', 'absolute_gap', 'relative_gap', 'nodes', 'wall_time') for cnt, name in enumerate(first): if not hasattr(self, name): continue names.remove(name) val = getattr(self, name) if val is not None: if pretty: if name == 'wall_time': val = time_format(val, digits=2) elif name in ('objective','bound', 'absolute_gap','relative_gap'): val = "%.7g" % (val) if name in ("solution_status", "termination_condition"): val = val.value stream.write(prefix+'%s: %s\n' % (name, val)) for name in names: stream.write(prefix+'%s: %s\n' % (name, getattr(self, name)))
def write(self, stream, prefix="", pretty=False): # type: (Union[IO, str], str, bool) -> None """Writes results in YAML format to a stream or file. Changing the parameter values from their defaults may result in the output becoming non-compatible with the YAML format. Parameters ---------- stream : file-like object or string A file-like object or a filename where results should be written to. prefix : string, optional A string to use as a prefix for each line that is written. (default: '') pretty : bool, optional Indicates whether or not certain recognized attributes should be formatted for more human-readable output. (default: False) Example ------- >>> import six >>> import pybnb >>> results = pybnb.SolverResults() >>> results.best_node = pybnb.Node() >>> results.best_node.objective = 123 >>> out = six.StringIO() >>> # the best_node is serialized >>> results.write(out) >>> del results >>> import yaml >>> results_dict = yaml.safe_load(out.getvalue()) >>> # de-serialize the best_node >>> best_node = pybnb.node.loads(results_dict['best_node']) >>> assert best_node.objective == 123 """ with as_stream(stream) as out: attrs = vars(self) names = sorted(list(attrs.keys())) first = ( "solution_status", "termination_condition", "objective", "bound", "absolute_gap", "relative_gap", "nodes", "wall_time", "best_node", ) for cnt, name in enumerate(first): if not hasattr(self, name): continue names.remove(name) val = getattr(self, name) if val is not None: if name in ("solution_status", "termination_condition"): if type(val) in (SolutionStatus, TerminationCondition): val = val.value elif pretty: if name == "wall_time": val = time_format(val, digits=2) elif name in ( "objective", "bound", "absolute_gap", "relative_gap", ): val = "%.7g" % (val) elif name == "best_node": assert isinstance(val, Node) if val.objective is not None: val = "Node(objective=%.7g)" % (val.objective) else: val = "Node(objective=None)" else: if name == "best_node": val = dumps(val) if not six.PY2: val = base64.encodebytes(val).decode("ascii") else: val = base64.encodestring(val).decode("ascii") val = "\n ".join(val.splitlines()) val = "!!binary |\n %s" % (val) else: val_ = "%r" % (val) if type(val) is float: if val_ == "inf": val_ = ".inf" elif val_ == "-inf": val_ = "-.inf" elif val_ == "nan": val_ = ".nan" val = val_ del val_ if pretty or (val is not None): out.write(prefix + "%s: %s\n" % (name, val)) else: assert val is None out.write(prefix + "%s: null\n" % (name)) for name in names: val = getattr(self, name) if pretty: out.write(prefix + "%s: %r\n" % (name, val)) else: if val is None: out.write(prefix + "%s: null\n" % (name)) else: val_ = "%r" % (val) if type(val) is float: if val_ == "inf": val_ = ".inf" elif val_ == "-inf": val_ = "-.inf" elif val_ == "nan": val_ = ".nan" val = val_ del val_ out.write(prefix + "%s: %s\n" % (name, val))
def test_time_format(self): assert time_format(None) == "<unknown>" assert time_format(0.0) == "0.0 s" assert time_format(0.0, align_unit=True) == "0.0 s " assert time_format(0.0, digits=2) == "0.00 s" assert time_format(24.9) == "24.9 s" assert time_format(93.462, digits=3) == "1.558 m" assert time_format(93.462, digits=4) == "1.5577 m" assert time_format(93.462, digits=4, align_unit=True) == "1.5577 m " assert time_format(5607.72, digits=3) == "1.558 h" assert time_format(5607.72, digits=4) == "1.5577 h" assert time_format(5607.72, digits=4, align_unit=True) == "1.5577 h " assert time_format(134585.28, digits=3) == "1.558 d" assert time_format(134585.28, digits=4) == "1.5577 d" assert time_format(134585.28, digits=4, align_unit=True) == "1.5577 d " assert time_format(0.23334, digits=1) == "233.3 ms" assert time_format(0.23334, digits=2) == "233.34 ms" assert time_format(0.00023334, digits=1) == "233.3 us" assert time_format(0.00023334, digits=2) == "233.34 us" assert time_format(0.0009999, digits=1) == "999.9 us" assert time_format(0.00099999, digits=1) == "1.0 ms" assert time_format(0.00099999, digits=2) == "999.99 us" assert time_format(0.000999999, digits=2) == "1.00 ms" assert time_format(0.000999999, digits=3) == "999.999 us" assert time_format(0.0009999999, digits=3) == "1.000 ms" assert time_format(0.0009999999, digits=4) == "999.9999 us" assert time_format(0.00099999999, digits=4) == "1.0000 ms" assert time_format(0.00099999999, digits=5) == "999.99999 us" assert time_format(0.000999999999, digits=5) == "1.00000 ms" assert time_format(0.000999999999, digits=6) == "999.999999 us"
def summarize_worker_statistics(stats, stream=sys.stdout): """Writes a summary of workers statistics to an output stream. Parameters ---------- stats : dict A dictionary of worker statistics returned from a call to :func:`collect_worker_statistics`. stream : file-like object, or string, optional A file-like object or a filename where results should be written to. (default: ``sys.stdout``) """ import numpy wall_time = numpy.array(stats['wall_time'], dtype=float) queue_time = numpy.array(stats['queue_time'], dtype=float) queue_count = numpy.array(stats['queue_call_count'], dtype=int) objective_time = numpy.array(stats['objective_time'], dtype=float) objective_count = numpy.array(stats['objective_call_count'], dtype=int) bound_time = numpy.array(stats['bound_time'], dtype=float) bound_count = numpy.array(stats['bound_call_count'], dtype=int) branch_time = numpy.array(stats['branch_time'], dtype=float) branch_count = numpy.array(stats['branch_call_count'], dtype=int) load_state_time = numpy.array(stats['load_state_time'], dtype=float) load_state_count = numpy.array(stats['load_state_call_count'], dtype=int) explored_nodes_count = numpy.array(stats['explored_nodes_count'], dtype=int) work_time = wall_time - queue_time with as_stream(stream) as stream: stream.write("Number of Workers: %6d\n" % (len(wall_time))) div = max(1.0,numpy.mean(explored_nodes_count)) numerator = numpy.max(explored_nodes_count) - \ numpy.min(explored_nodes_count) if explored_nodes_count.sum() == 0: stream.write("Load Imbalance: %6.2f%%\n" % (0.0)) else: stream.write("Load Imbalance: %6.2f%%\n" % (numerator/div*100.0)) stream.write(" - min: %d\n" % (numpy.min(explored_nodes_count))) stream.write(" - max: %d\n" % (numpy.max(explored_nodes_count))) stream.write("Average Worker Timing:\n") queue_count_str = "%d" % queue_count.sum() tmp = "%"+str(len(queue_count_str))+"d" bound_count_str = tmp % bound_count.sum() objective_count_str = tmp % objective_count.sum() branch_count_str = tmp % branch_count.sum() load_state_count_str = tmp % load_state_count.sum() div1 = numpy.copy(wall_time) div1[div1 == 0] = 1 div2 = numpy.copy(queue_count) div2[div2 == 0] = 1 stream.write(" - queue: %6.2f%% [avg time: %8s, count: %s]\n" % (numpy.mean(queue_time/div1)*100.0, time_format(numpy.mean(queue_time/div2), align_unit=True), queue_count_str)) div2 = numpy.copy(load_state_count) div2[div2==0] = 1 stream.write(" - load_state:%6.2f%% [avg time: %8s, count: %s]\n" % (numpy.mean((load_state_time/div1))*100.0, time_format(numpy.mean(load_state_time/div2), align_unit=True), load_state_count_str)) div2 = numpy.copy(bound_count) div2[div2==0] = 1 stream.write(" - bound: %6.2f%% [avg time: %8s, count: %s]\n" % (numpy.mean((bound_time/div1))*100.0, time_format(numpy.mean(bound_time/div2), align_unit=True), bound_count_str)) div2 = numpy.copy(objective_count) div2[div2==0] = 1 stream.write(" - objective: %6.2f%% [avg time: %8s, count: %s]\n" % (numpy.mean((objective_time/div1))*100.0, time_format(numpy.mean(objective_time/div2), align_unit=True), objective_count_str)) div2 = numpy.copy(branch_count) div2[div2==0] = 1 stream.write(" - branch: %6.2f%% [avg time: %8s, count: %s]\n" % (numpy.mean((branch_time/div1))*100.0, time_format(numpy.mean(branch_time/div2), align_unit=True), branch_count_str)) other_time = work_time - objective_time - bound_time - branch_time - load_state_time div2 = numpy.copy(queue_count) div2[div2 == 0] = 1 stream.write(" - other: %6.2f%% [avg time: %8s, count: %s]\n" % (numpy.mean(other_time/div1)*100.0, time_format(numpy.mean(other_time/div2), align_unit=True), queue_count_str))