0

Here is a piece of code:

np.concatenate(([3], [0]*5, np.arange(-1, 1.002, 2/9.0)))

# the above outputs 
array([ 3.        ,  0.        ,  0.        ,  0.        ,  0.        ,
        0.        , -1.        , -0.77777778, -0.55555556, -0.33333333,
       -0.11111111,  0.11111111,  0.33333333,  0.55555556,  0.77777778,
        1.        ])

Although this is verbose, it's pretty understandable. And here's another way to get the same output using an (ab)used notation, with complex number as step size.

np.r_[3, [0]*5, -1:1:10j]

# the above outputs
array([ 3.        ,  0.        ,  0.        ,  0.        ,  0.        ,
        0.        , -1.        , -0.77777778, -0.55555556, -0.33333333,
       -0.11111111,  0.11111111,  0.33333333,  0.55555556,  0.77777778,
        1.        ])

I'm trying to understand how the step size in the first approach is equivalent to the complex number step size (10j) in the second approach.

2/9.0  == 10j  # how?

I have read in scipy reference documentation that -1:1:10j means we want to produce 10 values between -1:1, both sides inclusive. But, how does that 10j translate to 0.2222?

  • Any intuitive ideas or explanations?
  • Also, what are other useful NumPy examples that we can do with this sort of expression?

P.S. I have already looked at range-builder-r-slice-with-complex-but-not-imaginary-step-magnitude but that doesn't offer much ideas.

kmario23
  • 57,311
  • 13
  • 161
  • 150

2 Answers2

2

The relevant part of the r_ docs is:

However, if step is an imaginary number (i.e. 100j) then its integer portion is interpreted as a number-of-points desired and the start and stop are inclusive. In other words start:stop:stepj is interpreted as np.linspace(start, stop, step, endpoint=1) inside of the brackets.

This is a notational trick used in a couple of the classes in numpy/lib/index_tricks.py (mgrid is another). This isn't a general numpy or python trick. The use of class definition (not function) and custom __getitem__ method is key.

As for the numeric details, check the code for np.linspace. (MATLAB has a function with the same name).

Maybe this comparison with arange will help give an intuitive feel.

In [65]: np.arange(-1,1.01,.2)                                                  
Out[65]: 
array([-1.00000000e+00, -8.00000000e-01, -6.00000000e-01, -4.00000000e-01,
       -2.00000000e-01, -2.22044605e-16,  2.00000000e-01,  4.00000000e-01,
        6.00000000e-01,  8.00000000e-01,  1.00000000e+00])
In [66]: _.shape                                                                
Out[66]: (11,)
In [67]: np.linspace(-1,1,11)                                                   
Out[67]: array([-1. , -0.8, -0.6, -0.4, -0.2,  0. ,  0.2,  0.4,  0.6,  0.8,  1. ])

The arange produced 11 values, so we had to use the same size number in linspace. Note that linspace handling of the end point is nicer, resulting in a cleaner display of the float values (which are not exact in either case).

If we use 10 instead, the spacing is correct (.2222...*9=1.9999....). To get 10 values we have to step 9 times. Or divide the range into 9 intervals.

In [68]: np.linspace(-1,1,10)                                                   
Out[68]: 
array([-1.        , -0.77777778, -0.55555556, -0.33333333, -0.11111111,
        0.11111111,  0.33333333,  0.55555556,  0.77777778,  1.        ])

arange with floats is messier than the equivalent starting with integers:

In [70]: np.arange(-10,11,2)/10                                                 
Out[70]: array([-1. , -0.8, -0.6, -0.4, -0.2,  0. ,  0.2,  0.4,  0.6,  0.8,  1. ])
hpaulj
  • 221,503
  • 14
  • 230
  • 353
1

When you have start, stop (both included), and size, then step is calculated as follows:

step = (stop - start) / (size - 1)

With start = -1, stop = 1, size = 2 you will get step = 2 and array [-1, 1]

With start = -1, stop = 1, size = 3 you will get step = 1 and array [-1, 0, 1]

With start = -1, stop = 1, size = 10 from the slice -1:1:10j you will get step = 2/9 and array

[-1.        , -0.77777778, -0.55555556, -0.33333333, -0.11111111,
  0.11111111,  0.33333333,  0.55555556,  0.77777778,  1.        ]

Note: For a complex number such as 10j, np.abs(10j) would be calculated first to get a real number.

kmario23
  • 57,311
  • 13
  • 161
  • 150
sanyassh
  • 8,100
  • 13
  • 36
  • 70