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
Post a Comment