I'm running an experiment with python simulation, and need to create a list of input cases.
Each case is an instance taken from a list of list of parameters, For example:
heights = [100,110,120]
alphas = [0.1,0.01,0.001]
C = [0.1,0.2,0.5,0.9]
B = [1,2]
and the list of lists is:
params = [heights,alphas,C,B]
The original amount is bigger (~30x100) so it's not efficient to address each list directly.
Eventually each input case is a tuple/namedtuple/dictionary of one parameter from each category, for example:
instance = {'height':100, 'alpha':0.1,'C:0.1, 'B':1}
I would like to iterate the parameter space in order to create a list of instances - but here is the catch:
Instead of making a cartesian product of all of them, per each parameter I want to iterate all the options, while the rest of categories are set to a default value (the first). For example:
params = [[1,2,3],[4,5][7,8]]
the expected set of instances (with no repeat) is:
[(1,4,7),(2,4,7),(3,4,7),(1,5,7)(1,4,8)]
where 1 is the default of first index, 4 is the default of the second index and 7 is the default of the 3rd.
Making a cartesian product is quite easy with itertools
:
from itertools import product
params = [[1,2,3],[4,5],[7,8]]
list(product(*params))
[(1, 4, 7), (1, 4, 8), (1, 5, 7), (1, 5, 8), (2, 4, 7), (2, 4, 8), (2, 5, 7), (2, 5, 8), (3, 4, 7), (3, 4, 8), (3, 5, 7), (3, 5, 8)]
then I can filter out unnecessary instances, but it sounds ineficient to generate them at first place. Is there any elegant way to build this iteration?
params = [[1, 2, 3], [4, 5], [7, 8]]
default = [par[0] for par in params]
instances = set()
for ii, pp in enumerate(params):
for value in pp:
new_instance = default[:ii] + [value] + default[ii + 1:]
instances.add(tuple(new_instance))