Python: how to create a parameter grid with dynamic number of parameters

Viewed 298

Suppose that the range of parameters of interest are given a dictionary that contains the range for each parameter of interest:

G = {'a': [1,2], 'b': [3], 'c': [1, 2.5] }

The goal is to extract every parameter configuration on this grid. In the example above, there are 4 such, corresponding to 2 values of a, and two values of b:

G1 = {'a': 1, 'b': 3, 'c': 1 }
G2 = {'a': 2, 'b': 3, 'c': 1 }
G3 = {'a': 1, 'b': 3, 'c': 2.5 }
G4 = {'a': 2, 'b': 3, 'c': 2.5 }

It's straightforward to write two nested for loops to produce all such configurations, it becomes less trivial how to do it for a general case, when there are a variable number of lists in G.

The only solution that comes to my mind is to create a multi-index vector vec=[0,0] which is as long as the number of parameters, and increment to iterate over all possible configurations: [0,0] -> [1,0] -> [0,1] -> [1,1]:

G = {'a': [1,2], 'b': [3], 'c': [1, 2.5] }

def get_configs(G):
    keys = list(G.keys())
    lists = list(G.values())
    sizes = [len(l) for l in lists]
    num_confs = np.prod(sizes)
    index = [0]*(len(G)+1)
    configs = []
    while len(configs)<num_confs:
        configs.append( {keys[i]: lists[i][index[i]] for i in range(len(G))})
        index[0] += 1
        cur = 0
        while len(configs)<num_confs and index[cur]>=sizes[cur]:
             index[cur]=0
             cur += 1
             index[cur] += 1
        return configs

configs = get_configs(G)
print(configs)

However, the solution seems a bit over-complicated and ugly. Is there a clean solution using python?

1 Answers

Here is a generalizable implementation using itertools.product:

from itertools import product

def dict_configs(d):
    for vcomb in product(*d.values()):
        yield dict(zip(d.keys(), vcomb))

Usage:

>>> G = {'a': [1,2], 'b': [3], 'c': [1, 2.5] }
>>> for config in dict_configs(G):
...     print(config)
...
{'a': 1, 'b': 3, 'c': 1}
{'a': 1, 'b': 3, 'c': 2.5}
{'a': 2, 'b': 3, 'c': 1}
{'a': 2, 'b': 3, 'c': 2.5}
Related