1

The Problem:

Consider a d-dimensional simple cubic lattice.

If the lattice has width L, then the number of lattice sites is Ld. I want to create a list that contains all the positions of the lattice sites, for a general d and L.

For example, when L = 2 and d = 2 this would be [(0, 0), (1, 0), (0, 1), (1, 1)].

My Attempt:

Whilst I can do this for general L, I have not been able to generalise the dimension d.

Below is my solution for d = 3 using three for loops.

def Positions(L):
    PositionList = []
    for i in range(L):
        for j in range(L):
            for k in range(L):
                PositionList.append([k, j, i])
    return PositionList

It's easy to see how I would change it to increase or decrease the dimension d as I could simply add or remove the for loops, but obviously it is very tedious to write this out for large d.

I thought about using a recursive for loop, so I would only be using one for loop for any d, but I don't know how to do this whilst preserving the indexing I need to write out the positions.

In Conclusion:

Is it possible to have a variable number of for loops, each one having a distinct index to solve this problem?

Or is there a better solution without using for loops?

trincot
  • 317,000
  • 35
  • 244
  • 286

3 Answers3

1

Recursion is indeed the way to go

The idea is:

If you assume your function works for d-1 dimensions, then you can take that result and append to each of the results the value of i (the loop variable), and do that repeatedly for each value of i.

The base case is when d=0, in that case you have just a single, empty result.

Here is how that can be coded:

def Positions(L, d):
    if d == 0:  # base case
        return [[]]
    return [
        [i] + res  # prepend i to the results coming from recursion
            for i in range(L)
                for res in Positions(L, d-1)
    ]

If you are not familiar with the list-comprehension syntax used in the final statement, then here is how you would do it without that syntax:

def Positions(L, d):
    if d == 0:  # base case
        return [[]]
    positions = []
    for i in range(L):
        for res in Positions(L, d-1):
            positions.append([i] + res)
    return positions
trincot
  • 317,000
  • 35
  • 244
  • 286
  • that's FP way. and its major drawback is, all this interim storage can't be good, for any non-negligible output size. but it can all be avoided by appending by one tuple at a time into the final result list *in the innermost loop* (innermost among the `d` nested loops built through recursion), building up the tuple on the way down. then the space requirement is just one d-size tuple (besides the output of course -- and it can be just print out, instead, for no-space output; impossible with the FP approach). can it be done in python? – Will Ness Oct 20 '20 at 18:41
  • @WillNess, with `yield`. – trincot Oct 20 '20 at 19:49
  • aha, and each function (besides the bottom-most) would use `yield from`? isn't there some costs for that `d`-long chain of re-yieldings? in e.g. C we'd just link-in each tuple, if the output were a linked list, say. I was wondering if _that_ was possible in Python. – Will Ness Oct 20 '20 at 20:23
  • sure that is also possible. – trincot Oct 20 '20 at 20:54
0

you use recursion. the first part is the base case and the second part is to add every number from 0 to L-1 for every term in the lattice for the lower dimension

def positions(L,d):
  if d==0:
    return [()]
  else:
    return [(x,)+positions(L,d-1)[y] for x in range(L) for y in range(len(positions(L,d-1)))]
tiger li
  • 13
  • 6
0

One easy way is using itertools cartesian product:

from itertools import product 
L, D = 2, 2 
print(list(product(list(range(L)), repeat = D)))

Result

[(0, 0), (0, 1), (1, 0), (1, 1)]
Seyi Daniel
  • 2,259
  • 2
  • 8
  • 18
  • You beat me to it @Seyi Daniel. I was just thinking about using a combinatorial function to solve this problem in one line when I was reminded of the `itertools` library. Thank you anyway, hopefully this will be helpful for the next person to have this problem – Quantum James Oct 20 '20 at 16:57