Source code for paramcomparison
# Copyright (c) 2015 Hong Xu <hong@topbug.net>
# This file is part of ParamComparison.
# ParamComparison is free software: you can redistribute it and/or modify it under the terms of the
# GNU Lesser General Public License as published by the Free Software Foundation, either version 3
# of the License, or (at your option) any later version.
# ParamComparison is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public License along with
# ParamComparison. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
import copy
import itertools
import os
import sys
__version__ = '0.2.1'
[docs]class ParamComparison:
"""
A class to initiate the generation of pages
:type grid: dict: str -> (val0, val1, ...)
:param grid: A dictionary whose keys are strings of variable names and values are sequences of
values to be tried for the corresponding variable.
:type reader: :class:`readers.Reader` (or its subclass) object
:param reader: The Reader class to load and process data.
:raise TypeError: When ``reader`` is not an instance of :class:`readers.Reader`.
"""
def __init__(self, grid, reader):
# assure reader is valid
from .readers import Reader
if not isinstance(reader, Reader):
raise TypeError('Invalid reader. Must be an instance of paramcomparison.writers.Reader')
self.names = tuple(grid.keys())
self.name_idx = dict() # reverse look up (name --> index)
for i in range(0, len(self.names)):
self.name_idx[self.names[i]] = i
self.grid = dict()
for i in grid.items():
v = i[1]
self.grid[i[0]] = tuple(map(str, v))
self.results = dict()
# store all results to a dictionary to be used for further looking up
for params in itertools.product(*grid.values()):
func_params = dict(zip(self.names, params))
result = str(reader.read(func_params))
values = tuple(map(str, params))
self.results[values] = result
[docs] def generate_pages(self, outdir, writer, row_field, col_field):
"""
Generate a set of pages
:type outdir: str
:param outdir: The directory to write files to.
:type writer: :class:`writers.Writer` (or its subclass) object
:param writer: The writer to be used.
:type row_field: str
:param row_field: The field to be used in rows.
:type col_field: str
:param col_field: The field to be used in columns.
:return: None
:raise TypeError: When ``writer`` is not an instance of :class:`writers.Writer`.
"""
# make sure writer is valid
from .writers import Writer
if not isinstance(writer, Writer):
raise TypeError('Invalid writer. Must be an instance of paramcomparison.writers.Writer')
try:
os.mkdir(outdir)
except:
pass
prefix = outdir
if prefix[-1] != os.path.sep:
prefix += os.path.sep
# the index of the row and column field
try:
row_field_idx = self.names.index(row_field)
except ValueError:
raise ValueError('Field "{}" does not exist'.format(row_field))
try:
col_field_idx = self.names.index(col_field)
except ValueError:
raise ValueError('Field "{}" does not exist'.format(col_field))
if len(self.names) == 2: # we only have 2 fields, just generate a table
values = dict()
params = [None, None]
for r in self.grid[row_field]:
params[row_field_idx] = r
for c in self.grid[col_field]:
params[col_field_idx] = c
values[(r, c)] = self.results[tuple(params)]
with open(prefix + writer.get_file_name('main'), 'w') as f:
f.write(writer.write_title('main'))
f.write(writer.write_table(self.names, (None, None),
row_field_idx, self.grid[row_field],
col_field_idx, self.grid[col_field], values))
return
# i is the 3rd field
for i in range(len(self.names)):
# i is the index of the 3rd field
if i == row_field_idx or i == col_field_idx:
continue
with open(prefix + writer.get_file_name(self.names[i]), 'w') as f:
# write title first
f.write(writer.write_title(self.names[i]))
# subgrid with i, row_field_idx and col_field_idx removed
subgrid = copy.deepcopy(self.grid)
for j in (i, row_field_idx, col_field_idx):
subgrid.pop(self.names[j])
# Iterate all fields except row_field and col_field. Field i is always iterated in
# the last level. List the tables of the row field and column field for them.
num_iterable = sum(1 for x in itertools.product(*subgrid.values()))
x_idx = 0
for x in itertools.product(*subgrid.values()):
x_idx += 1
params = [None for j in range(len(self.names))]
subgrid_keys = tuple(subgrid.keys())
for j in range(len(subgrid_keys)):
params[self.name_idx[subgrid_keys[j]]] = x[j]
for v in self.grid[self.names[i]]:
params[i] = v
# a dictionary for only row and column fields
values = dict()
for r in self.grid[row_field]:
params[row_field_idx] = r
for c in self.grid[col_field]:
params[col_field_idx] = c
values[(r, c)] = self.results[tuple(params)]
params[row_field_idx] = None
params[col_field_idx] = None
f.write(writer.write_table(self.names, tuple(params),
row_field_idx, self.grid[row_field],
col_field_idx, self.grid[col_field],
values))
# don't write the separator for the last section
if x_idx < num_iterable:
f.write(writer.write_separator())