My problem:
I have, e.g., 4 numbers
a, b, c, d = np.random.rand(4)
and I need all of the possible sums a + b - c
, a + b -d
, b + c - d
, b + c -a
etc etc
I have found that I can proceed like this
from itertools import permutations
p = np.array(list(set(permutations([1, 1, -1, 0])))).T
sums = np.random.rand(4) @ p
and so far so good, I've vectorized my problem... what hurts my feelings is the use of permutations(…)
because the number of permutations, for n
numbers to combine, is of course n!
while the filter operated by set
reduces the number of the significant permutations to a few percent.
My question:
Is it possible to obtain, e.g.,
p = np.array(list(set(permutations([1]*5 + [-1]*4 + [0]*6)))).T
without computing all the 1,307,674,368,000 (mostly identical) permutations?
Following the advice of Lukas Thaler and of Chris_Rands I have checked the possible use of sympy.utilities.iterables.multiset_permutations
In [1]: from itertools import permutations
In [2]: from sympy.utilities.iterables import multiset, multiset_permutations
In [3]: for n in (2,3):
...: l = [1]*n +[2]*n + [3]*n
...: ms = multiset(l)
...: print(n*3)
...: %timeit list(multiset_permutations(ms))
...: %timeit set(permutations(l))
...:
6
568 µs ± 3.71 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
91.3 µs ± 571 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
9
9.32 ms ± 209 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
58.3 ms ± 323 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
It seems to me that
- for negligible amounts of computation it doesn't matter anyway
- when the things stiffen, the pure Python implementation in Sympy easily overcomes the brute force approach using
set
anditertools.permutations
so that I conclude that my question is a duplicate of the question referenced by Chris and I vote to close it.