Reputation: 151
I want to generate all tuples (m, n)
such that m+2n <= 2nmax - 1
in python 3.9. It is easily done via
nmax = 4
a = [(m, n) for n in range(0, nmax) for m in range(0, 2*(nmax-n))]
>>> [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (0, 2), (1, 2), (2, 2), (3, 2), (0, 3), (1, 3)]
However I noticed that if I instead do
nmax = 4
b = [(m, n) for n in range(0, nmax+1) for m in range(0, 2*(nmax-n))]
>>> [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (0, 2), (1, 2), (2, 2), (3, 2), (0, 3), (1, 3)]
(n
goes to nmax+1
instead of nmax
) then
a == b
>>> True
I first thought it was an edge case for the nmax
I was picking, but I get the same behaviour for all nmax<100
. I do not quite understand why there is an ambiguity here. Is it because of the range of m
depends on n
? If so, what would be the "correct" bounds?
Upvotes: 1
Views: 179
Reputation: 25489
In the last iteration of your second case, n
is equal to nmax
. This makes 2 * (nmax - n)
zero. range(0, 0)
is an empty iterator, so there is no inner loop for the last outer loop of n
, so nothing gets added to the list comprehension, and it's as if the last loop never happened. So you get a == b
is True
.
You want m <= 2(nmax - n) - 1
, i.e. m < 2(nmax - n)
, which is what you already get from your first loop.
When n == nmax
, this condition gives m <= -1
. Using m in range(0, ...)
automatically means m >= 0
. It's fairly obvious that both these conditions can never be true, so no pair of (m, n)
will satisfy m, n >= 0; m + 2n <= 2 nmax - 1
when n == nmax
Upvotes: 2
Reputation: 54148
Is it because of the range of m depends on n
Yes.
Outer range(0, nmax)
means last value is nmax-1
that means inner loop final bounds is
2 * (nmax - n)
2 * (nmax - nmax + 1)
2 * 1
2
Outer range(0, nmax + 1)
means last value is nmax
that means inner loop final bounds is
2 * (nmax - nmax)
2 * (0)
0
So the round you add for n
creates an empty range
for m
Detail by the values
for n in range(0, nmax + 1):
values = list(range(0, 2 * (nmax - n)))
print(f"{n=} {2*(nmax-n)=} {values=}")
n=0 2*(nmax-n)=8 values=[0, 1, 2, 3, 4, 5, 6, 7]
n=1 2*(nmax-n)=6 values=[0, 1, 2, 3, 4, 5]
n=2 2*(nmax-n)=4 values=[0, 1, 2, 3]
n=3 2*(nmax-n)=2 values=[0, 1]
n=4 2*(nmax-n)=0 values=[] # generated by the +1 in the 'n' range
Upvotes: 2