| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| |
|
| | |
| |
|
| | from sys import exit, stdout |
| |
|
| | from os.path import splitext |
| |
|
| | from itertools import imap |
| |
|
| | from math import sqrt, log10, floor |
| |
|
| | from collections import deque |
| |
|
| | from argparse import ArgumentParser as argument_parser |
| |
|
| | from csv import DictReader as csv_dict_reader |
| | from csv import DictWriter as csv_dict_writer |
| |
|
| | from re import compile as regex_compile |
| |
|
| | |
| |
|
| | def unpack_tuple(f): |
| | """Return a unary function that calls `f` with its argument unpacked.""" |
| | return lambda args: f(*iter(args)) |
| |
|
| | def strip_dict(d): |
| | """Strip leading and trailing whitespace from all keys and values in `d`.""" |
| | d.update({key: value.strip() for (key, value) in d.items()}) |
| |
|
| | def merge_dicts(d0, d1): |
| | """Create a new `dict` that is the union of `dict`s `d0` and `d1`.""" |
| | d = d0.copy() |
| | d.update(d1) |
| | return d |
| |
|
| | def strip_list(l): |
| | """Strip leading and trailing whitespace from all values in `l`.""" |
| | for i, value in enumerate(l): l[i] = value.strip() |
| |
|
| | |
| |
|
| | def int_or_float(x): |
| | """Convert `x` to either `int` or `float`, preferring `int`. |
| | |
| | Raises: |
| | ValueError : If `x` is not convertible to either `int` or `float` |
| | """ |
| | try: |
| | return int(x) |
| | except ValueError: |
| | return float(x) |
| |
|
| | def try_int_or_float(x): |
| | """Try to convert `x` to either `int` or `float`, preferring `int`. `x` is |
| | returned unmodified if conversion fails. |
| | """ |
| | try: |
| | return int_or_float(x) |
| | except ValueError: |
| | return x |
| |
|
| | |
| |
|
| | def find_significant_digit(x): |
| | """Return the significant digit of the number x. The result is the number of |
| | digits after the decimal place to round to (negative numbers indicate rounding |
| | before the decimal place).""" |
| | if x == 0: return 0 |
| | return -int(floor(log10(abs(x)))) |
| |
|
| | def round_with_int_conversion(x, ndigits = None): |
| | """Rounds `x` to `ndigits` after the the decimal place. If `ndigits` is less |
| | than 1, convert the result to `int`. If `ndigits` is `None`, the significant |
| | digit of `x` is used.""" |
| | if ndigits is None: ndigits = find_significant_digit(x) |
| | x_rounded = round(x, ndigits) |
| | return int(x_rounded) if ndigits < 1 else x_rounded |
| |
|
| | |
| |
|
| | class measured_variable(object): |
| | """A meta-variable representing measured data. It is composed of three raw |
| | variables plus units meta-data. |
| | |
| | Attributes: |
| | quantity (`str`) : |
| | Name of the quantity variable of this object. |
| | uncertainty (`str`) : |
| | Name of the uncertainty variable of this object. |
| | sample_size (`str`) : |
| | Name of the sample size variable of this object. |
| | units (units class or `None`) : |
| | The units the value is measured in. |
| | """ |
| |
|
| | def __init__(self, quantity, uncertainty, sample_size, units = None): |
| | self.quantity = quantity |
| | self.uncertainty = uncertainty |
| | self.sample_size = sample_size |
| | self.units = units |
| |
|
| | def as_tuple(self): |
| | return (self.quantity, self.uncertainty, self.sample_size, self.units) |
| |
|
| | def __iter__(self): |
| | return iter(self.as_tuple()) |
| |
|
| | def __str__(self): |
| | return str(self.as_tuple()) |
| |
|
| | def __repr__(self): |
| | return str(self) |
| |
|
| | class measured_value(object): |
| | """An object that represents a value determined by multiple measurements. |
| | |
| | Attributes: |
| | quantity (scalar) : |
| | The quantity of the value, e.g. the arithmetic mean. |
| | uncertainty (scalar) : |
| | The measurement uncertainty, e.g. the sample standard deviation. |
| | sample_size (`int`) : |
| | The number of observations contributing to the value. |
| | units (units class or `None`) : |
| | The units the value is measured in. |
| | """ |
| |
|
| | def __init__(self, quantity, uncertainty, sample_size = 1, units = None): |
| | self.quantity = quantity |
| | self.uncertainty = uncertainty |
| | self.sample_size = sample_size |
| | self.units = units |
| |
|
| | def as_tuple(self): |
| | return (self.quantity, self.uncertainty, self.sample_size, self.units) |
| |
|
| | def __iter__(self): |
| | return iter(self.as_tuple()) |
| |
|
| | def __str__(self): |
| | return str(self.as_tuple()) |
| |
|
| | def __repr__(self): |
| | return str(self) |
| |
|
| | |
| |
|
| | def arithmetic_mean(X): |
| | """Computes the arithmetic mean of the sequence `X`. |
| | |
| | Let: |
| | |
| | * `n = len(X)`. |
| | * `u` denote the arithmetic mean of `X`. |
| | |
| | .. math:: |
| | |
| | u = \frac{\sum_{i = 0}^{n - 1} X_i}{n} |
| | """ |
| | return sum(X) / len(X) |
| |
|
| | def sample_variance(X, u = None): |
| | """Computes the sample variance of the sequence `X`. |
| | |
| | Let: |
| | |
| | * `n = len(X)`. |
| | * `u` denote the arithmetic mean of `X`. |
| | * `s` denote the sample standard deviation of `X`. |
| | |
| | .. math:: |
| | |
| | v = \frac{\sum_{i = 0}^{n - 1} (X_i - u)^2}{n - 1} |
| | |
| | Args: |
| | X (`Iterable`) : The sequence of values. |
| | u (number) : The arithmetic mean of `X`. |
| | """ |
| | if u is None: u = arithmetic_mean(X) |
| | return sum(imap(lambda X_i: (X_i - u) ** 2, X)) / (len(X) - 1) |
| | |
| | def sample_standard_deviation(X, u = None, v = None): |
| | """Computes the sample standard deviation of the sequence `X`. |
| | |
| | Let: |
| | |
| | * `n = len(X)`. |
| | * `u` denote the arithmetic mean of `X`. |
| | * `v` denote the sample variance of `X`. |
| | * `s` denote the sample standard deviation of `X`. |
| | |
| | .. math:: |
| | |
| | s &= \sqrt{v} |
| | &= \sqrt{\frac{\sum_{i = 0}^{n - 1} (X_i - u)^2}{n - 1}} |
| | |
| | Args: |
| | X (`Iterable`) : The sequence of values. |
| | u (number) : The arithmetic mean of `X`. |
| | v (number) : The sample variance of `X`. |
| | """ |
| | if u is None: u = arithmetic_mean(X) |
| | if v is None: v = sample_variance(X, u) |
| | return sqrt(v) |
| |
|
| | def combine_sample_size(As): |
| | """Computes the combined sample variance of a group of `measured_value`s. |
| | |
| | Let: |
| | |
| | * `g = len(As)`. |
| | * `n_i = As[i].samples`. |
| | * `n` denote the combined sample size of `As`. |
| | |
| | .. math:: |
| | |
| | n = \sum{i = 0}^{g - 1} n_i |
| | """ |
| | return sum(imap(unpack_tuple(lambda u_i, s_i, n_i, t_i: n_i), As)) |
| |
|
| | def combine_arithmetic_mean(As, n = None): |
| | """Computes the combined arithmetic mean of a group of `measured_value`s. |
| | |
| | Let: |
| | |
| | * `g = len(As)`. |
| | * `u_i = As[i].quantity`. |
| | * `n_i = As[i].samples`. |
| | * `n` denote the combined sample size of `As`. |
| | * `u` denote the arithmetic mean of the quantities of `As`. |
| | |
| | .. math:: |
| | |
| | u = \frac{\sum{i = 0}^{g - 1} n_i u_i}{n} |
| | """ |
| | if n is None: n = combine_sample_size(As) |
| | return sum(imap(unpack_tuple(lambda u_i, s_i, n_i, t_i: n_i * u_i), As)) / n |
| | |
| | def combine_sample_variance(As, n = None, u = None): |
| | """Computes the combined sample variance of a group of `measured_value`s. |
| | |
| | Let: |
| | |
| | * `g = len(As)`. |
| | * `u_i = As[i].quantity`. |
| | * `s_i = As[i].uncertainty`. |
| | * `n_i = As[i].samples`. |
| | * `n` denote the combined sample size of `As`. |
| | * `u` denote the arithmetic mean of the quantities of `As`. |
| | * `v` denote the sample variance of `X`. |
| | |
| | .. math:: |
| | |
| | v = \frac{(\sum_{i = 0}^{g - 1} n_i (u_i - u)^2 + s_i^2 (n_i - 1))}{n - 1} |
| | |
| | Args: |
| | As (`Iterable` of `measured_value`s) : The sequence of values. |
| | n (number) : The combined sample sizes of `As`. |
| | u (number) : The combined arithmetic mean of `As`. |
| | """ |
| | if n <= 1: return 0 |
| | if n is None: n = combine_sample_size(As) |
| | if u is None: u = combine_arithmetic_mean(As, n) |
| | return sum(imap(unpack_tuple( |
| | lambda u_i, s_i, n_i, t_i: n_i * (u_i - u) ** 2 + (s_i ** 2) * (n_i - 1) |
| | ), As)) / (n - 1) |
| |
|
| | def combine_sample_standard_deviation(As, n = None, u = None, v = None): |
| | """Computes the combined sample standard deviation of a group of |
| | `measured_value`s. |
| | |
| | Let: |
| | |
| | * `g = len(As)`. |
| | * `u_i = As[i].quantity`. |
| | * `s_i = As[i].uncertainty`. |
| | * `n_i = As[i].samples`. |
| | * `n` denote the combined sample size of `As`. |
| | * `u` denote the arithmetic mean of the quantities of `As`. |
| | * `v` denote the sample variance of `X`. |
| | * `s` denote the sample standard deviation of `X`. |
| | |
| | .. math:: |
| | |
| | s &= \sqrt{v} |
| | &= \sqrt{\frac{(\sum_{i = 0}^{g - 1} n_i (u_i - u)^2 + s_i^2 (n_i - 1))}{n - 1}} |
| | |
| | Args: |
| | As (`Iterable` of `measured_value`s) : The sequence of values. |
| | n (number) : The combined sample sizes of `As`. |
| | u (number) : The combined arithmetic mean of `As`. |
| | v (number) : The combined sample variance of `As`. |
| | """ |
| | if n <= 1: return 0 |
| | if n is None: n = combine_sample_size(As) |
| | if u is None: u = combine_arithmetic_mean(As, n) |
| | if v is None: v = combine_sample_variance(As, n, u) |
| | return sqrt(v) |
| |
|
| | |
| |
|
| | def process_program_arguments(): |
| | ap = argument_parser( |
| | description = ( |
| | "Aggregates the results of multiple runs of benchmark results stored in " |
| | "CSV format." |
| | ) |
| | ) |
| |
|
| | ap.add_argument( |
| | "-d", "--dependent-variable", |
| | help = ("Treat the specified three variables as a dependent variable. The " |
| | "1st variable is the measured quantity, the 2nd is the uncertainty " |
| | "of the measurement and the 3rd is the sample size. The defaults " |
| | "are the dependent variables of Thrust's benchmark suite. May be " |
| | "specified multiple times."), |
| | action = "append", type = str, dest = "dependent_variables", |
| | metavar = "QUANTITY,UNCERTAINTY,SAMPLES" |
| | ) |
| |
|
| | ap.add_argument( |
| | "-p", "--preserve-whitespace", |
| | help = ("Don't trim leading and trailing whitespace from each CSV cell."), |
| | action = "store_true", default = False |
| | ) |
| |
|
| | ap.add_argument( |
| | "-o", "--output-file", |
| | help = ("The file that results are written to. If `-`, results are " |
| | "written to stdout."), |
| | action = "store", type = str, default = "-", |
| | metavar = "OUTPUT" |
| | ) |
| |
|
| | ap.add_argument( |
| | "input_files", |
| | help = ("Input CSV files. The first two rows should be a header. The 1st " |
| | "header row specifies the name of each variable, and the 2nd " |
| | "header row specifies the units for that variable."), |
| | type = str, nargs = "+", |
| | metavar = "INPUTS" |
| | ) |
| |
|
| | return ap.parse_args() |
| |
|
| | |
| |
|
| | def filter_comments(f, s = "#"): |
| | """Return an iterator to the file `f` which filters out all lines beginning |
| | with `s`.""" |
| | return filter(lambda line: not line.startswith(s), f) |
| |
|
| | |
| |
|
| | class io_manager(object): |
| | """Manages I/O operations and represents the input data as an `Iterable` |
| | sequence of `dict`s. |
| | |
| | It is `Iterable` and an `Iterator`. It can be used with `with`. |
| | |
| | Attributes: |
| | preserve_whitespace (`bool`) : |
| | If `False`, leading and trailing whitespace is stripped from each CSV cell. |
| | writer (`csv_dict_writer`) : |
| | CSV writer object that the output is written to. |
| | output_file (`file` or `stdout`) : |
| | The output `file` object. |
| | readers (`list` of `csv_dict_reader`s) : |
| | List of input files as CSV reader objects. |
| | input_files (list of `file`s) : |
| | List of input `file` objects. |
| | variable_names (`list` of `str`s) : |
| | Names of the variables, in order. |
| | variable_units (`list` of `str`s) : |
| | Units of the variables, in order. |
| | """ |
| |
|
| | def __init__(self, input_files, output_file, preserve_whitespace = True): |
| | """Read input files and open the output file and construct a new `io_manager` |
| | object. |
| | |
| | If `preserve_whitespace` is `False`, leading and trailing whitespace is |
| | stripped from each CSV cell. |
| | |
| | Raises |
| | AssertionError : |
| | If `len(input_files) <= 0` or `type(preserve_whitespace) != bool`. |
| | """ |
| | assert len(input_files) > 0, "No input files provided." |
| |
|
| | assert type(preserve_whitespace) == bool |
| |
|
| | self.preserve_whitespace = preserve_whitespace |
| |
|
| | self.readers = deque() |
| |
|
| | self.variable_names = None |
| | self.variable_units = None |
| |
|
| | self.input_files = deque() |
| |
|
| | for input_file in input_files: |
| | input_file_object = open(input_file) |
| | reader = csv_dict_reader(filter_comments(input_file_object)) |
| |
|
| | if not self.preserve_whitespace: |
| | strip_list(reader.fieldnames) |
| |
|
| | if self.variable_names is None: |
| | self.variable_names = reader.fieldnames |
| | else: |
| | |
| | assert self.variable_names == reader.fieldnames, \ |
| | "Input file (`" + input_file + "`) variable schema `" + \ |
| | str(reader.fieldnames) + "` does not match the variable schema `" + \ |
| | str(self.variable_names) + "`." |
| |
|
| | |
| | variable_units = reader.next() |
| |
|
| | if not self.preserve_whitespace: |
| | strip_dict(variable_units) |
| |
|
| | if self.variable_units is None: |
| | self.variable_units = variable_units |
| | else: |
| | |
| | assert self.variable_units == variable_units, \ |
| | "Input file (`" + input_file + "`) units schema `" + \ |
| | str(variable_units) + "` does not match the units schema `" + \ |
| | str(self.variable_units) + "`." |
| |
|
| | self.readers.append(reader) |
| | self.input_files.append(input_file_object) |
| | |
| | if output_file == "-": |
| | self.output_file = stdout |
| | else: |
| | self.output_file = open(output_file, "w") |
| |
|
| | self.writer = csv_dict_writer( |
| | self.output_file, fieldnames = self.variable_names |
| | ) |
| |
|
| | def __enter__(self): |
| | """Called upon entering a `with` statement.""" |
| | return self |
| |
|
| | def __exit__(self, *args): |
| | """Called upon exiting a `with` statement.""" |
| | if self.output_file is stdout: |
| | self.output_file = None |
| | elif self.output_file is not None: |
| | self.output_file.__exit__(*args) |
| |
|
| | for input_file in self.input_files: |
| | input_file.__exit__(*args) |
| |
|
| | |
| | |
| |
|
| | def __iter__(self): |
| | """Return an iterator to the input sequence. |
| | |
| | This is a requirement for the `Iterable` protocol. |
| | """ |
| | return self |
| |
|
| | def next(self): |
| | """Consume and return the next record (a `dict` representing a CSV row) in |
| | the input. |
| | |
| | This is a requirement for the `Iterator` protocol. |
| | |
| | Raises: |
| | StopIteration : If there is no more input. |
| | """ |
| | if len(self.readers) == 0: |
| | raise StopIteration() |
| |
|
| | try: |
| | row = self.readers[0].next() |
| | if not self.preserve_whitespace: strip_dict(row) |
| | return row |
| | except StopIteration: |
| | |
| | |
| | self.readers.popleft() |
| | self.input_files.popleft().close() |
| | return self.next() |
| |
|
| | |
| | |
| |
|
| | def write_header(self): |
| | """Write the header for the output CSV file.""" |
| | |
| | self.writer.writeheader() |
| |
|
| | |
| | self.writer.writerow(self.variable_units) |
| |
|
| | def write(self, d): |
| | """Write a record (a `dict`) to the output CSV file.""" |
| | self.writer.writerow(d) |
| |
|
| | |
| |
|
| | class dependent_variable_parser(object): |
| | """Parses a `--dependent-variable=AVG,STDEV,TRIALS` command line argument.""" |
| |
|
| | |
| | |
| |
|
| | |
| | variable_name_rule = r'[^,]+' |
| |
|
| | |
| | dependent_variable_rule = r'(' + variable_name_rule + r')' \ |
| | + r',' \ |
| | + r'(' + variable_name_rule + r')' \ |
| | + r',' \ |
| | + r'(' + variable_name_rule + r')' |
| |
|
| | engine = regex_compile(dependent_variable_rule) |
| |
|
| | |
| |
|
| | def __call__(self, s): |
| | """Parses the string `s` with the form "AVG,STDEV,TRIALS". |
| | |
| | Returns: |
| | A `measured_variable`. |
| | |
| | Raises: |
| | AssertionError : If parsing fails. |
| | """ |
| |
|
| | match = self.engine.match(s) |
| |
|
| | assert match is not None, \ |
| | "Dependent variable (-d) `" +s+ "` is invalid, the format is " + \ |
| | "`AVG,STDEV,TRIALS`." |
| |
|
| | return measured_variable(match.group(1), match.group(2), match.group(3)) |
| |
|
| | |
| |
|
| | class record_aggregator(object): |
| | """Consumes and combines records and represents the result as an `Iterable` |
| | sequence of `dict`s. |
| | |
| | It is `Iterable` and an `Iterator`. |
| | |
| | Attributes: |
| | dependent_variables (`list` of `measured_variable`s) : |
| | A list of dependent variables provided on the command line. |
| | dataset (`dict`) : |
| | A mapping of distinguishing (e.g. control + independent) values (`tuple`s |
| | of variable-quantity pairs) to `list`s of dependent values (`dict`s from |
| | variables to lists of cells). |
| | in_order_dataset_keys : |
| | A list of unique dataset keys (e.g. distinguishing variables) in order of |
| | appearance. |
| | """ |
| |
|
| | parse_dependent_variable = dependent_variable_parser() |
| |
|
| | def __init__(self, raw_dependent_variables): |
| | """Parse dependent variables and construct a new `record_aggregator` object. |
| | |
| | Raises: |
| | AssertionError : If parsing of dependent variables fails. |
| | """ |
| | self.dependent_variables = [] |
| |
|
| | if raw_dependent_variables is not None: |
| | for variable in raw_dependent_variables: |
| | self.dependent_variables.append(self.parse_dependent_variable(variable)) |
| |
|
| | self.dataset = {} |
| |
|
| | self.in_order_dataset_keys = deque() |
| |
|
| | |
| | |
| |
|
| | def append(self, record): |
| | """Add `record` to the dataset. |
| | |
| | Raises: |
| | ValueError : If any `str`-to-numeric conversions fail. |
| | """ |
| | |
| | |
| | |
| | |
| | dependent_values = {} |
| |
|
| | |
| | |
| | |
| | sample_size_variables = [] |
| |
|
| | |
| | |
| | for variable in self.dependent_variables: |
| | quantity, uncertainty, sample_size, units = variable.as_tuple() |
| |
|
| | dependent_values[quantity] = [int_or_float(record.pop(quantity))] |
| | dependent_values[uncertainty] = [int_or_float(record.pop(uncertainty))] |
| | dependent_values[sample_size] = [int(record[sample_size])] |
| |
|
| | sample_size_variables.append(sample_size) |
| |
|
| | |
| | for sample_size_variable in sample_size_variables: |
| | |
| | record.pop(sample_size_variable, None) |
| |
|
| | |
| | distinguishing_values = tuple(record.items()) |
| |
|
| | if distinguishing_values in self.dataset: |
| | |
| | |
| | |
| | |
| | for variable, columns in dependent_values.iteritems(): |
| | self.dataset[distinguishing_values][variable] += columns |
| | else: |
| | |
| | |
| | self.dataset[distinguishing_values] = dependent_values |
| | self.in_order_dataset_keys.append(distinguishing_values) |
| |
|
| | |
| | |
| |
|
| | def combine_dependent_values(self, dependent_values): |
| | """Takes a mapping of dependent variables to lists of cells and returns |
| | a new mapping with the cells combined. |
| | |
| | Raises: |
| | AssertionError : If class invariants were violated. |
| | """ |
| | combined_dependent_values = dependent_values.copy() |
| |
|
| | for variable in self.dependent_variables: |
| | quantity, uncertainty, sample_size, units = variable.as_tuple() |
| |
|
| | quantities = dependent_values[quantity] |
| | uncertainties = dependent_values[uncertainty] |
| | sample_sizes = dependent_values[sample_size] |
| |
|
| | if type(sample_size) is list: |
| | |
| | assert len(quantities) == len(uncertainties) \ |
| | and len(uncertainties) == len(sample_sizes), \ |
| | "Length of quantities list `(" + str(len(quantities)) + ")`, " + \ |
| | "length of uncertainties list `(" + str(len(uncertainties)) + \ |
| | "),` and length of sample sizes list `(" + str(len(sample_sizes)) + \ |
| | ")` are not the same." |
| | else: |
| | |
| | |
| | assert len(quantities) == len(uncertainties), \ |
| | "Length of quantities list `(" + str(len(quantities)) + ")` and " + \ |
| | "length of uncertainties list `(" + str(len(uncertainties)) + \ |
| | ")` are not the same." |
| |
|
| | |
| | measured_values = [] |
| |
|
| | for i in range(len(quantities)): |
| | mv = measured_value( |
| | quantities[i], uncertainties[i], sample_sizes[i], units |
| | ) |
| |
|
| | measured_values.append(mv) |
| |
|
| | |
| | combined_sample_size = combine_sample_size( |
| | measured_values |
| | ) |
| |
|
| | combined_arithmetic_mean = combine_arithmetic_mean( |
| | measured_values, combined_sample_size |
| | ) |
| |
|
| | combined_sample_standard_deviation = combine_sample_standard_deviation( |
| | measured_values, combined_sample_size, combined_arithmetic_mean |
| | ) |
| |
|
| | |
| | |
| | sigdig = find_significant_digit(combined_sample_standard_deviation) |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | combined_dependent_values[quantity] = combined_arithmetic_mean |
| | combined_dependent_values[uncertainty] = combined_sample_standard_deviation |
| | combined_dependent_values[sample_size] = combined_sample_size |
| |
|
| | return combined_dependent_values |
| |
|
| | |
| | |
| |
|
| | def __iter__(self): |
| | """Return an iterator to the output sequence of separated distinguishing |
| | variables and dependent variables (a tuple of two `dict`s). |
| | |
| | This is a requirement for the `Iterable` protocol. |
| | """ |
| | return self |
| |
|
| | def records(self): |
| | """Return an iterator to the output sequence of CSV rows (`dict`s of |
| | variables to values). |
| | """ |
| | return imap(unpack_tuple(lambda dist, dep: merge_dicts(dist, dep)), self) |
| |
|
| | def next(self): |
| | """Produce the components of the next output record - a tuple of two |
| | `dict`s. The first `dict` is a mapping of distinguishing variables to |
| | distinguishing values, the second `dict` is a mapping of dependent |
| | variables to combined dependent values. Combining the two dicts forms a |
| | CSV row suitable for output. |
| | |
| | This is a requirement for the `Iterator` protocol. |
| | |
| | Raises: |
| | StopIteration : If there is no more output. |
| | AssertionError : If class invariants were violated. |
| | """ |
| | assert len(self.dataset.keys()) == len(self.in_order_dataset_keys), \ |
| | "Number of dataset keys (`" + str(len(self.dataset.keys())) + \ |
| | "`) is not equal to the number of keys in the ordering list (`" + \ |
| | str(len(self.in_order_dataset_keys)) + "`)." |
| |
|
| | if len(self.in_order_dataset_keys) == 0: |
| | raise StopIteration() |
| |
|
| | |
| | raw_distinguishing_values = self.in_order_dataset_keys.popleft() |
| | distinguishing_values = dict(raw_distinguishing_values) |
| |
|
| | dependent_values = self.dataset.pop(raw_distinguishing_values) |
| |
|
| | combined_dependent_values = self.combine_dependent_values(dependent_values) |
| |
|
| | return (distinguishing_values, combined_dependent_values) |
| |
|
| | |
| |
|
| | args = process_program_arguments() |
| |
|
| | if args.dependent_variables is None: |
| | args.dependent_variables = [ |
| | "STL Average Walltime,STL Walltime Uncertainty,STL Trials", |
| | "STL Average Throughput,STL Throughput Uncertainty,STL Trials", |
| | "Thrust Average Walltime,Thrust Walltime Uncertainty,Thrust Trials", |
| | "Thrust Average Throughput,Thrust Throughput Uncertainty,Thrust Trials" |
| | ] |
| |
|
| | |
| | with io_manager(args.input_files, |
| | args.output_file, |
| | args.preserve_whitespace) as iom: |
| | |
| | ra = record_aggregator(args.dependent_variables) |
| |
|
| | |
| | for record in iom: |
| | ra.append(record) |
| |
|
| | iom.write_header() |
| |
|
| | |
| | for record in ra.records(): |
| | iom.write(record) |
| |
|
| |
|