Source code for icarus.results.readwrite

"""Functions for reading and writing results
"""
import collections
import copy
import json
try:
    import cPickle as pickle
except ImportError:
    import pickle
from icarus.util import Tree
from icarus.registry import register_results_reader, register_results_writer


__all__ = [
    'ResultSet',
    'write_results_pickle',
    'read_results_pickle'
           ]

[docs]class ResultSet(object): """This class can be used to store results from different experiments, accessed and filtered. A result set is basically a list of results, one per each experiment. Each entry of the resultset is a 2-tuple referring to a single experiment. In this 2-tuple: * the first element is a tree with all parameters of the experiment * the second element is a tree with all results of the experiment All operations that write data are thread-safe so that this object can be shared by different processes. """ def __init__(self, attr=None): """Constructor Parameters ---------- attr : dict, optional Dictionary of common attributes to all experiments """ self._results = collections.deque() # Dict of global attributes common to all experiments self.attr = attr if attr is not None else {} def __len__(self): """Returns the number of results in the resultset Returns ------- len : int The length of the resultset """ return len(self._results) def __iter__(self): """Returns iterator over the resultset Returns ------- iter : iterator Iterator over the resultset """ return iter(self._results) def __getitem__(self, i): """Returns a specified item of the resultset Parameters ---------- i : int The index of the result Returns ------- result : tuple Result """ return self._results[i] def __add__(self, resultset): """Merges two resultsets. Parameters ---------- resultset : ResultSet The result set to merge Returns ------- resultset : ResultSet The resultset containing results from this resultset and the one passed as argument """ if self.attr != resultset.attr: raise ValueError('The resultsets cannot be merged because ' 'they have different global attributes') rs = copy.deepcopy(self) for i in iter(resultset): rs.add(*i) return rs
[docs] def add(self, parameters, results): """Add a result to the result set. Parameters ---------- parameters : Tree Tree of experiment parameters results : Tree Tree of experiment results Notes ----- If parameters and results are dictionaries, this method will attempt to convert them to trees and storing them anyway. It is necessary that parameters and results are saved as trees so that plotting functions can search correctly in them. """ if not isinstance(parameters, Tree): parameters = Tree(parameters) if not isinstance(results, Tree): results = Tree(results) self._results.append((parameters, results))
[docs] def dump(self): """Dump all results in a list Returns ------- results : list A list of 2-value tuples where the first value is the dictionary of experiment parameters and the second value is the dictionary of experiment results. """ return list(self._results)
[docs] def json(self, indent=None): """Return a JSON representation of the resultset Parameters ---------- indent : int, optional If non-negative, pretty print the output with specified indentation Returns ------- json : str String containing the JSON representation of the object """ d = [(k.dict(str_keys=True), v.dict(str_keys=True)) for k, v in self.dump()] return json.dumps(d, indent=indent)
[docs] def prettyprint(self): """Return a human-readable text representation of the resultset. Return ------ prettyprint : str Human-readable string representation of the resultset """ output = "" n = len(self) for i, (experiment, results) in enumerate(self): output += "EXPERIMENT {}/{}:\n".format(i + 1, n) output += " CONFIGURATION:\n" for k, v in experiment.items(): if isinstance(v, dict): s = " * {} ->".format(k) if 'name' in v: s += " name: {},".format(v.pop('name')) for group, value in v.items(): s += " {}: {},".format(group, value) output += s.rstrip(",") + "\n" else: output += " * {} -> {}\n".format(k, v) output += " RESULTS:\n" for collector, data in results.items(): if isinstance(data, dict): output += " {}\n".format(collector) for metric, value in data.items(): output += " * {}: {}\n".format(metric, value) else: output += " * {}: {}\n".format(collector, data) output += "\n" return output
[docs] def filter(self, condition): """Return subset of results matching specific conditions Parameters ---------- condition : dict Dictionary listing all parameters and values to be matched in the results set. Each parameter, i.e., each key of the dictionary must be an iterable object containing the path in the parameters tree to the required parameter Returns ------- filtered_results : ResultSet List of 2-tuples of filtered results, where the first element is a tree of all experiment parameters and the second value is a tree with experiment results. """ filtered_resultset = ResultSet() for parameters, results in self._results: parameters = Tree(parameters) if parameters.match(condition): filtered_resultset.add(parameters, results) return filtered_resultset
[docs]@register_results_writer('PICKLE') def write_results_pickle(results, path): """Write a resultset to a pickle file Parameters ---------- results : ResultSet The set of results path : str The path of the file to which write """ with open(path, 'wb') as pickle_file: pickle.dump(results, pickle_file)
[docs]@register_results_reader('PICKLE') def read_results_pickle(path): """Reads a resultset from a pickle file. Parameters ---------- path : str The file path from which results are read Returns ------- results : ResultSet The read result set """ with open(path, 'rb') as pickle_file: return pickle.load(pickle_file)