How to generate (enumerate) 2**N tuples representing all vertices of unit hypercube in N-dimensional

D

Dr. Colombes

I'm looking for a good Python way to generate (enumerate) the 2**N
tuples representing all vertices of the unit hypercube in N-dimensional
hyperspace.

For example, for N=4 the Python code should generate the following 2**N
= 16 tuples:

(1,1,1,1), (1,1,1,-1),
(1,1,-1, 1), (1,1,-1,-1),
(1,-1,1,1), (1,-1,1,-1),
(1,-1,-1, 1), (1,-1,-1,-1),
(-1,1,1,1), (-1,1,1,-1),
(-1,1,-1, 1), (-1,1,-1,-1),
(-1,-1,1,1), (-1,-1,1,-1),
(-1,-1,-1, 1), (-1,-1,-1,-1)

Maybe converting each integer in the range(2**N) to binary, then
converting to bit string, then applying the "tuple" function to each
bit string?

Thanks for your help.
 
P

Paul Rubin

Dr. Colombes said:
I'm looking for a good Python way to generate (enumerate) the 2**N
tuples representing all vertices of the unit hypercube in N-dimensional
hyperspace.
For example, for N=4 the Python code should generate the following 2**N
= 16 tuples:

Here's a recursive generator:

def hypercube(ndims):
if ndims == 0:
yield ()
return
for h in 1, -1:
for y in hypercube(ndims-1):
return (h,)+y


[(1, 1, 1, 1), (1, 1, 1, -1), (1, 1, -1, 1), (1, 1, -1, -1), (1, -1,
1, 1), (1, -1, 1, -1), (1, -1, -1, 1), (1, -1, -1, -1), (-1, 1, 1, 1),
(-1, 1, 1, -1), (-1, 1, -1, 1), (-1, 1, -1, -1), (-1, -1, 1, 1), (-1,
-1, 1, -1), (-1, -1, -1, 1), (-1, -1, -1, -1)]
Maybe converting each integer in the range(2**N) to binary, then
converting to bit string, then applying the "tuple" function to each
bit string?

Yeah you could do that too.
 
H

Heiko Wundram

Dr. Colombes said:
Maybe converting each integer in the range(2**N) to binary, then
converting to bit string, then applying the "tuple" function to each
bit string?

A direct translation of that:

def perm(n):
rv = []
for i in xrange(2L**n):
cur = []
for j in range(n):
cur.append(1-2*(bool(i & (1<<j))))
# cur is in reversed order LSB first, but as you seemingly don't
# care about order of the returned tuples, this is irrelevant.
rv.append(tuple(cur))
return rv

modelnine@phoenix ~ $ python
Python 2.4.2 (#1, Dec 22 2005, 17:27:39)
[GCC 4.0.2 (Gentoo 4.0.2-r2, pie-8.7.8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.[(1, 1, 1, 1, 1), (-1, 1, 1, 1, 1), (1, -1, 1, 1, 1), (-1, -1, 1, 1, 1), (1,
1, -1, 1, 1), (-1, 1, -1, 1, 1), (1, -1, -1, 1, 1), (-1, -1, -1, 1, 1), (1,
1, 1, -1, 1), (-1, 1, 1, -1, 1), (1, -1, 1, -1, 1), (-1, -1, 1, -1, 1), (1,
1, -1, -1, 1), (-1, 1, -1, -1, 1), (1, -1, -1, -1, 1), (-1, -1, -1, -1, 1),
(1, 1, 1, 1, -1), (-1, 1, 1, 1, -1), (1, -1, 1, 1, -1), (-1, -1, 1, 1, -1),
(1, 1, -1, 1, -1), (-1, 1, -1, 1, -1), (1, -1, -1, 1, -1), (-1, -1, -1, 1,
-1), (1, 1, 1, -1, -1), (-1, 1, 1, -1, -1), (1, -1, 1, -1, -1), (-1, -1, 1,
-1, -1), (1, 1, -1, -1, -1), (-1, 1, -1, -1, -1), (1, -1, -1, -1, -1), (-1,
-1, -1, -1, -1)]modelnine@phoenix ~ $

--- Heiko.
 
P

Paul Rubin

Heiko Wundram said:
def perm(n):
rv = []
for i in xrange(2L**n):
cur = []
for j in range(n):
cur.append(1-2*(bool(i & (1<<j))))
# cur is in reversed order LSB first, but as you seemingly don't
# care about order of the returned tuples, this is irrelevant.
rv.append(tuple(cur))
return rv

def perm(n):
return [tuple([(1,-1)[(t>>i)%2] for i in xrange(n)])
for t in xrange(2L**n)]
[(1, 1, 1, 1), (-1, 1, 1, 1), (1, -1, 1, 1), (-1, -1, 1, 1), (1, 1,
-1, 1), (-1, 1, -1, 1), (1, -1, -1, 1), (-1, -1, -1, 1), (1, 1, 1,
-1), (-1, 1, 1, -1), (1, -1, 1, -1), (-1, -1, 1, -1), (1, 1, -1, -1),
(-1, 1, -1, -1), (1, -1, -1, -1), (-1, -1, -1, -1)]
 
H

Heiko Wundram

Paul said:
def perm(n):
return [tuple([(1,-1)[(t>>i)%2] for i in xrange(n)])
for t in xrange(2L**n)]

or replace that with:

def perm(n):
return (tuple(((1,-1)[(t>>i)%2] for i in xrange(n)))
for t in xrange(2L**n))

to get a generator like in Paul's first example. Only works with Python 2.4+
though.

--- Heiko.
 
C

Claudio Grondi

Heiko said:
Paul said:
def perm(n):
return [tuple([(1,-1)[(t>>i)%2] for i in xrange(n)])
for t in xrange(2L**n)]


or replace that with:

def perm(n):
return (tuple(((1,-1)[(t>>i)%2] for i in xrange(n)))
for t in xrange(2L**n))

to get a generator like in Paul's first example. Only works with Python 2.4+
though.

--- Heiko.

Isn't this kind of coding beeing the result of suffering from the
post-pyContest illness syndrom?

Or is there another reason behind writing it that way sacrificing
readability like usage of less CPU time to run the code?

Or am I alone having trouble to read this kind of code because not
experienced enough in writing Python scripts?

Claudio
 
B

bonono

Dr. Colombes said:
I'm looking for a good Python way to generate (enumerate) the 2**N
tuples representing all vertices of the unit hypercube in N-dimensional
hyperspace.

For example, for N=4 the Python code should generate the following 2**N
= 16 tuples:

(1,1,1,1), (1,1,1,-1),
(1,1,-1, 1), (1,1,-1,-1),
(1,-1,1,1), (1,-1,1,-1),
(1,-1,-1, 1), (1,-1,-1,-1),
(-1,1,1,1), (-1,1,1,-1),
(-1,1,-1, 1), (-1,1,-1,-1),
(-1,-1,1,1), (-1,-1,1,-1),
(-1,-1,-1, 1), (-1,-1,-1,-1)

Maybe converting each integer in the range(2**N) to binary, then
converting to bit string, then applying the "tuple" function to each
bit string?

Thanks for your help.

Is this just a special case for the list of list combine() function
posted not long ago ?

def combine_lol(seq):
return reduce(lambda x,y: (a+(b,) for a in x for b in y), seq,
[()])

list(combine_lol([(1,-1)]*4))
 
H

Heiko Wundram

Claudio said:
Heiko said:
def perm(n):
return (tuple(((1,-1)[(t>>i)%2] for i in xrange(n)))
for t in xrange(2L**n))

Isn't this kind of coding beeing the result of suffering from the
post-pyContest illness syndrom?

I don't think what Paul Rubin posted is the sign of pyContest illness, as I
use two-level generator expressions such as this quite often in my code.
Why I didn't give this as the reponse to the OP was because it seems that
he's not that familiar with Python to be able to read this efficiently and
grap the concept behind the implementation immediately, that's why I
thought an explicit loop was in order.

But for any sufficiently advanced Python coder, I don't think this is
unreadable in the least.

--- Heiko.
 
D

Dr. Colombes

Paul, Heiko:

Thank you for the quality, parsimony and promptness of your
excellent suggestions.

I wasn't familiar with the Python "yield" function.

Dr. Colombes
 
C

Claudio Grondi

Heiko said:
Claudio said:
Heiko said:
def perm(n):
return (tuple(((1,-1)[(t>>i)%2] for i in xrange(n)))
for t in xrange(2L**n))

Isn't this kind of coding beeing the result of suffering from the
post-pyContest illness syndrom?


I don't think what Paul Rubin posted is the sign of pyContest illness, as I
use two-level generator expressions such as this quite often in my code.
Why I didn't give this as the reponse to the OP was because it seems that
he's not that familiar with Python to be able to read this efficiently and
grap the concept behind the implementation immediately, that's why I
thought an explicit loop was in order.

But for any sufficiently advanced Python coder, I don't think this is
unreadable in the least.

--- Heiko.
List comprehension is a nice thing when standalone.
I am usually able to read it from the left to the right and understand
directly.
But with nested list comprehensions I don't see directly what is going
on, because there are more than one identifier I don't know about at the
time of reading the expression and I am forced to read the entire
nestings with eventually some more code spread over it. The trouble is,
that there are no visual hints toward understanding of the used
algorithm like it is the case in the non-list-comprehension version and
I usually have to re-read the nested list comprehension from the right
to the the left in order to get the idea. I don't want to be forced to
read from the right to the left as I am used to read left-right,
top-down and I expect any text (also source code) to be that way.
Similar critics comes sometimes up when someone learns the German
language, because you are forced to read also a very, very long sentence
up to its end, before it is clear what is the action. I consider it as a
problem which would be nice to get rid of if possible, but it is much
easier to try to influence coding style than the usage of a language.

Can usage of deep (i.e. more than two levels) nested list comprehensions
be considered bad coding style?

Claudio
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,123
Latest member
Layne6498
Top