-2

Can I use numpy to generate repeating patterns of indices for example.

0, 1, 2, 3, 4, 5, 0, 6, 7, 8, 9, 10, 0, 11, 12, 13, 14, 15

or

0,1,2,1,2,3,4,5,6,5,6,7

Is there a method in numpy i can use to generate these lists between a range ?

currently I am doing this using lists in python but I was curious if I could use numpy to speed things up.

I am not sure what methods to even look into other than numpy.arange.

Just to further clarify I am generating indices to triangles in opengl in various patterns.

so for traingles in a circle I have some code like this.

    for fan_set in range(0, len(self.vertices) / vertex_length, triangle_count):
        for i in range(fan_set + 1, fan_set + 8):
            self.indices.append(fan_set)
            self.indices.append(i)
            self.indices.append(i + 1)
Oly
  • 370
  • 5
  • 16
  • The second example doesn't make much sense, can you explain it? – Ashwini Chaudhary May 18 '15 at 17:36
  • Have you come across a need for something faster than (x)range? There's things like linspace and mgrid that you could probably bend to your purpose, but I don't think they'll be much faster than using xrange. – a p May 18 '15 at 17:37
  • Also, if you could show us what you have right now (you say you're currently using python lists), we might be able to give you some pointers on speeding it up. – a p May 18 '15 at 17:38
  • how does `0,1,2,1,2,3,4,5,6,5,6,7` come about? – Padraic Cunningham May 18 '15 at 17:46
  • I have amended the question above to give some idea of what i am doing – Oly May 18 '15 at 17:47
  • If your list can be reshaped into a rectangle, then it can be generated with array operations. But if the repetitions differ in length, e.g. [[0],[0,1],[0,1,2]...]`, then list operations are better. And for small cases, lists have less overhead than arrays. – hpaulj May 18 '15 at 17:53
  • I could reshape the final array needs to be flat but its always repeating lengths, like 0,1,2,1,2,3 for the first quad and 4,5,6,5,6,7 for the second quad. the other example it repeats in sets of 9 points so maybe that could work. – Oly May 18 '15 at 17:57

3 Answers3

0

I'm not sure I understand exactly what you mean, but the following is what I use to generate unique indices for 3D points;

def indexate(points):
    """
    Convert a numpy array of points into a list of indices and an array of
    unique points.

    Arguments:
        points: A numpy array of shape (N, 3).

    Returns:
        An array of indices and an (M, 3) array of unique points.
    """
    pd = {}
    indices = [pd.setdefault(tuple(p), len(pd)) for p in points]
    pt = sorted([(v, k) for k, v in pd.items()], key=lambda x: x[0])
    unique = np.array([i[1] for i in pt])
    return np.array(indices, np.uint16), unique

You can find this code in my stltools package on github.

It works like this;

In [1]: import numpy as np

In [2]: points = np.array([[1,0,0], [0,0,1], [1,0,0], [0,1,0]])

In [3]: pd = {}

In [4]: indices = [pd.setdefault(tuple(p), len(pd)) for p in points]

In [5]: indices
Out[5]: [0, 1, 0, 2]

In [6]: pt = sorted([(v, k) for k, v in pd.items()], key=lambda x: x[0])

In [7]: pt
Out[7]: [(0, (1, 0, 0)), (1, (0, 0, 1)), (2, (0, 1, 0))]

In [8]: unique = np.array([i[1] for i in pt])

In [9]: unique
Out[9]: 
array([[1, 0, 0],
       [0, 0, 1],
       [0, 1, 0]])

The key point (if you'll pardon the pun) is to use a tuple of the point (because a tuple is immutable and thus hashable) as the key in a dictionary with the setdefault method, while the length of the dict is the value. In effect, the value is the first time this exact point was seen.

Roland Smith
  • 42,427
  • 3
  • 64
  • 94
  • this is what i am after but not in sequential order, in a repeating order but not one after the other because that repeats indices and points. also you could probably us np.arrange and skip generating the list if you putting them in order in this way. – Oly May 18 '15 at 18:00
  • @Oly I'm sorry but I cannot understand your comment. This codes returns a list of *unique* points and an array of indices of all points into the array of unique points. – Roland Smith May 18 '15 at 18:11
  • Smith my bad I did not fully understand it, i find it a bit confusing because its using dicts tuples and arrays, nice example but not quite what i was looking for. – Oly May 19 '15 at 08:15
0

I am not 100% certain this is what you're after, I think you can achieve this using pair of range values and increment n times 3 (the gap between each group), then use numpy.concatenate to concatenate the final array, like this:

import numpy as np

def gen_list(n):
    return np.concatenate([np.array(range(i, i+3) + range(i+1, i+4)) + i*3 
                           for i in xrange(n)])

Usage:

gen_list(2)
Out[16]: array([0, 1, 2, 1, 2, 3, 4, 5, 6, 5, 6, 7])

gen_list(3)
Out[17]: 
array([ 0,  1,  2,  1,  2,  3,  4,  5,  6,  5,  6,  7,  8,  9, 10,  9, 10,
       11])

list(gen_list(2))
Out[18]: [0, 1, 2, 1, 2, 3, 4, 5, 6, 5, 6, 7]

In my sample I only use n as how many groups you want to generate, you may change this to suit your triangle-ish requirements.

Anzel
  • 19,825
  • 5
  • 51
  • 52
  • thanks for the example its an interesting way of doing it, I will have a play around with it and look into concatenate a bit more as I dont know much about that method. – Oly May 19 '15 at 08:18
  • @Oly, yes have a play around and I hope this helps, `numpy.concatenate` basically with join a sequence of arrays together. – Anzel May 19 '15 at 08:39
0

Your first example can be produced via numpy methods as:

In [860]: np.concatenate((np.zeros((3,1),int),np.arange(1,16).reshape(3,5)),axis=1).ravel()
Out[860]: 
array([ 0,  1,  2,  3,  4,  5,  0,  6,  7,  8,  9, 10,  0, 11, 12, 13, 14,
       15])

That's because I see this 2d repeated pattern

array([[ 0,  1,  2,  3,  4,  5],
       [ 0,  6,  7,  8,  9, 10],
       [ 0, 11, 12, 13, 14, 15]])

The second pattern can be produced by ravel of this 2d array (produced by broadcasting 2 arrays):

In [863]: np.array([0,1,4,5])[:,None]+np.arange(3)
Out[863]: 
array([[0, 1, 2],
       [1, 2, 3],
       [4, 5, 6],
       [5, 6, 7]])

I can produce the 1st pattern with a variation on the 2nd (the initial column of 0s disrupts the pattern)

I=np.array([0,5,10])[:,None]+np.arange(0,6)
I[:,0]=0

I think your double loop can be expressed as a list comprehension as

In [872]: np.array([ [k,i,i+1] for k in range(0,1,1) for i in range(k+1,k+8)]).ravel()
Out[872]: array([0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 7, 0, 7, 8])

or without the ravel:

array([[0, 1, 2],
       [0, 2, 3],
       [0, 3, 4],
       [0, 4, 5],
       [0, 5, 6],
       [0, 6, 7],
       [0, 7, 8]])

though I don't know what parameters produce your examples.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • thats great i thought there might have been something simpler in numpy but this is what I was after a numpy solution. This also give me a direction to research about the various methods. – Oly May 19 '15 at 08:13