3

I have a question about NumPy's advanced indexing.

I found this question, but I guess my question is slightly different.

In the example below x_array is the expected result. But when I tried the same with a list the result is different.

From the numpy doc:

Advanced indexing is triggered when the selection object, obj, is a non-tuple sequence object, an ndarray (of data type integer or bool), or a tuple with at least one sequence object or ndarray (of data type integer or bool). There are two types of advanced indexing: integer and Boolean.

import numpy as np

vertices = np.arange(9).reshape((3,3))

idx_list = [[0, 1, 2],
            [0, 2, 1]]

x_list = vertices[idx_list]

print('list')

print(x_list)

#this works as expected
idx_array = np.array(idx_list)
x_array = vertices[idx_array]

print('array')
print(x_array)

idx_list should trigger advanced indexing as it is a "non-tuple sequence object?" Or is a list and a tuple the same here and it is "a tuple with at least one sequence object"

Using the list yields the same as when passing the two list entries separated by a comma within the square brackets (one for each dimension).

x_list_2 = vertices[idx_list[0], idx_list[1]] 

This is also the behaviour I expect.

Joe
  • 6,758
  • 2
  • 26
  • 47
  • 2
    This is an inconsistency that hasn't been cleaned up for historical reasons; there may be old code that expects this behavior. – hpaulj Aug 14 '17 at 13:46
  • So it is the same issue than in the link mentioned above? – Joe Aug 14 '17 at 14:25
  • Some ways down my answer in the link is a quote from the code (via `@Eric`) about a `sequence with ... sequences embedded`. The example is like yours. `vertices[idx_list], :]` tells it, explicitly, to apply `idx_list` to the 1st dimension, otherwise it is treating it as an `indexing tuple`. – hpaulj Aug 14 '17 at 17:05
  • So does the `Sequences` in `Sequences < NPY_MAXDIMS` refer to `len(idx_list)` or to the number of arguments within the square brackets like `x[arg1, arg2]` ? – Joe Aug 15 '17 at 05:51
  • It's always OK to post an answer to your own question. – uhoh Jan 11 '18 at 02:15

2 Answers2

0

In the end it comes down to what is mentioned in https://stackoverflow.com/a/40599589/7919597

From numpy's indexing documentation:

In order to remain backward compatible with a common usage in Numeric, basic slicing is also initiated if the selection object is any non-ndarray sequence (such as a list) containing slice objects, the Ellipsis object, or the newaxis object, but not for integer arrays or other embedded sequences.

The example with the list triggers an undocumented part of the backward compatibility logic, as described in a comment in the source code:

/*
 * Sequences < NPY_MAXDIMS with any slice objects
 * or newaxis, Ellipsis or other arrays or sequences
 * embedded, are considered equivalent to an indexing
 * tuple. (`a[[[1,2], [3,4]]] == a[[1,2], [3,4]]`)
 */
Joe
  • 6,758
  • 2
  • 26
  • 47
0

Your answer doesn't explain anything. Here are the ideas:

First, since your idx_list is of dimension 2, something is done in the background:

idx_list = [[0, 1, 2],
            [0, 2, 1]]

x_list = vertices[tuple(idx_list)]  # wrapping with a `tuple()`

If you do this explicitly, you can get rid of the (annoying) FutureWarning:

FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.

(this answers your OP) Second, your expected behaviour(x_array, shape(2,3,3)):

[[[0 1 2]
  [3 4 5]
  [6 7 8]]

 [[0 1 2]
  [6 7 8]
  [3 4 5]]]

can be done in either (as your OP):

vertices[np.array(idx_list)]

or by list, too:

vertices[tuple([list])]
# or this shorthand with warning
# vertices[[list]]

Notice that I've wrapped one additional bracket([list]) to make sure that the first component of the resulting tuple is of dimension 2, which results in the same meaning as np.array(idx_list)

NeoZoom.lua
  • 2,269
  • 4
  • 30
  • 64