python - all permutations of +-r, +-s -


given 2 numbers r , s, list of permutations of n +-r , m +-s. example (with r=3.14 , s=2.71),

n = 1 m = 1 out = [     (+r, +s), (+r, -s), (-r, +s), (-r, -s),      (+s, +r), (+s, -r), (-s, +r), (-s, -r)     ] 
n = 1 m = 2 out = [     (+r, +s, +s), (+r, -s, +s), (-r, +s, +s), (-r, -s, +s), ...     (+s, +r, +s), (-s, +r, +s), (+s, -r, +s), (-s, -r, +s), ...     ...     ] 

with itertools.product([+r, -r], repeat=n) can list of rs , ss separately, , i'd need intertwine them, i'm not sure if right thing do.

efficiency not overly important, wouldn't mind solution produces many repeated results make them unique afterwards.

update: general solution added.

here solution bit more complicated in code not produce repeated elements , can evaluated lazily:

from itertools import combinations, product, chain  r = 3.14 s = 2.71 n = 1 m = 2 idx = combinations(range(n + m), n) vs = ((r if j in else s j in range(n + m)) in idx) res = chain.from_iterable(product(*((+vij, -vij) vij in vi)) vi in vs) print("\n".join(map(str, res))) 

output:

(3.14, 2.71, 2.71) (3.14, 2.71, -2.71) (3.14, -2.71, 2.71) (3.14, -2.71, -2.71) (-3.14, 2.71, 2.71) (-3.14, 2.71, -2.71) (-3.14, -2.71, 2.71) (-3.14, -2.71, -2.71) (2.71, 3.14, 2.71) (2.71, 3.14, -2.71) (2.71, -3.14, 2.71) (2.71, -3.14, -2.71) (-2.71, 3.14, 2.71) (-2.71, 3.14, -2.71) (-2.71, -3.14, 2.71) (-2.71, -3.14, -2.71) (2.71, 2.71, 3.14) (2.71, 2.71, -3.14) (2.71, -2.71, 3.14) (2.71, -2.71, -3.14) (-2.71, 2.71, 3.14) (-2.71, 2.71, -3.14) (-2.71, -2.71, 3.14) (-2.71, -2.71, -3.14) 

explanation

we can think of output permutations containing n +/- r elements , m +/- s elements, or, in other words, tuples of n + m elements n +/- r , rest +/- s. idx contains tuples possible positions +/- r elements; example, first result (0,).

then, each of these tuples i create "template" tuples in vs, tuples of size n + m indices in i r , rest s. so, tuple (0,) in idx (r, s, s). if n + m big consider previous step idx = map(set, idx) faster in operation, i'm not sure @ point worth it.

finally, each of these templates vi in v need consider possibilities using positive , negative value each of elements. cartesian product of (+vi[0], -vi[0]), (+vi[1], -vi[1]), .... , need chain each of generator of each of these products final result.

general solution

to build general solution problem arbitrary number of different elements, need consider partitions of set of indices. example, n = 3 , m = 5, possible ways can split {0, 1, 2, 3, 4, 5, 6, 7} in 2 parts of sizes 3 , 5. here implementation that:

from itertools import chain, repeat, permutations, product   def partitions(*sizes):     if not sizes or all(s <= 0 s in sizes):         yield ()     i_size, size in enumerate(sizes):         if size <= 0:             continue         next_sizes = sizes[:i_size] + (sizes[i_size] - 1,) + sizes[i_size + 1:]         p in partitions(*next_sizes):             yield (i_size,) + p   def signed_permutations(*elems):     values, sizes = zip(*elems)     templates = partitions(*sizes)     return chain.from_iterable(         product(*((+values[ti], -values[ti]) ti in t)) t in templates)   r = 3.14 s = 2.71 n = 1 m = 2 res = signed_permutations((r, n), (s, m)) print("\n".join(map(str, res))) 

the idea same, build "templates" (this time contain indices of values instead of values themselves) , cartesian products them.


Comments

Popular posts from this blog

python - Selenium remoteWebDriver (& SauceLabs) Firefox moseMoveTo action exception -

html - How to custom Bootstrap grid height? -

transpose - Maple isnt executing function but prints function term -