pythonmultidimensional-cube

Funtion to Generate a Unit hypercube in any Dimesion (Python)


I need to write a python function that returns a list or tuple of coordinates for a unit hypercube, (square/box/tesseract etc.) based on starting coordinates that will be placed in the top left. I have a vector class that takes a list of any length, which I use for different unrelated parts of the project. The order of the points doesn't really matter, only that the starting position is the 'lowest point', ie [x, y, z ...] and that no other point is [x-1, y] or something like that. It needs to work for any number of dimensions, and each side is one unit long.

For a square, it would look like this:

def square(x, y):
  return [
    Vector([x, y]),
    Vector([x + 1, y]),
    Vector([x + 1, y + 1]),
    Vector([x, y + 1])
  ]

A cube would look like this:

def cube(x, y, z):
  return [
    Vector([x, y, z]),
    Vector([x + 1, y, z]),
    Vector([x + 1, y + 1, z]),
    Vector([x, y + 1, z]),
    Vector([x, y, z + 1]),
    Vector([x + 1, y, z + 1]),
    Vector([x + 1, y + 1, z + 1]),
    Vector([x, y + 1, z + 1]),
  ]

It keeps going like that, so I need to write a function that would look something like this:

def hypercube(start):
  points = [];

  #Add all the points to the list (need to figure out)

  return points

# And it will be used like so:

starts = [35, 12]
print(hypercube(starts))
# result: 
#[Vector(35, 12), Vector(36, 12), Vector(36, 13), Vector(35, 13)]


starts = [35, 12, 34, 17, 2]
print(hypercube(starts))
#result :
#[Vector(35, 12, 34, 17, 2), ... Vector(36, 13, 35, 18, 3)]

I understand that there is probably a recursive way to do this, I just can't think of it.


Solution

  • The itertools function combinations_with_replacement can give you all the needed combinations of "add 1" or "add nothing" for each axis in your cube.

    So, supposing your Vector class supports Vector addition:

    from itertolls import combinations_with_replacements
    
    from ... import Vector
    
    def hypercube(starts):
        dimensions = len(starts)
        return [starts + Vector(*combination) for combination in combinations_with_replacements((0, 1), dimensions)]
    

    And if your "Vector" does not support addition with the + operator yet, all you have to do is to include an __add__ method to it:

    
    class Vector:
    
        def __add__(self, other):
           return self.__class__([comp1 + comp2  for comp1, comp2 in zip(self, other)]) 
    
    

    (In this case, assuming your "Vector" inherits from Python Sequences like a list, or collections.abc.Sequence and is properly iterable - otherwise, just pass zip the Vector attribute that holds the sequence data)