0

I have a simple problem. The numerous tutorials I've looked at show everything but this common situation. I want to do an element by element vector-vector multiply, where one of the vectors is a slice of a matrix.

I have not been able to duplicate this problem interactively with the shell, so I don't understand it. The following is just the portion of code which illustrates the problem.

    Ordr = 2  # these values set higher up in the code
    nx = 5
    dx = np.empty((Ordr-1,nx),dtype=float)
    # vector dpx and dx calculated in other code here
    print('shapes dpx,dx',dpx.shape,dx.shape)
    ap.arrayprint('root calc:',dpx,np.transpose(dx)) # not shown originally
    dtmp = dpx*dx[0,:]
    print('shape dtmp',dtmp.shape)
results are:
  shapes dpx,dx (5,) (1, 5)
  shape dtmp (5,5)

I expected dtmp to be shape (5,) It seems an outer product is being calculated, although I have not checked the actual numbers. It doesn't make any difference if I reverse the order, i.e. dpx[0,:]*dx As I say, I haven't been able to replicate the problem in the shell, so I'm wondering what gives. I am running version 3.6.8 on Cygwin. The same result occurs under Windows version 3.7.3rc1.

New addition to post on July 18,2019: Further checks revealed that a call to a function to do tabular printing was causing the problem. The function prints vectors as columns together with two dimensional arrays. This is accomplished by reshaping the vectors by something like: a.shape = (n,1)
After the function call, this reshape is passed back to the calling routine. Since dp is then (5,1) the multiply is a (5,1) matrix by a (5,) vector. Broadcasting is invoked resulting in a (5,5) result.

I am a new python programmer and I thought (erroneously) that this modification to the inputs would not pass back to the caller. Is it an error to modify the function inputs in this way? Should this have been flagged as an error in the function? I understand C pass by value and Fortran pass by reference, but do not understand how Python passes parameters to functions. Can someone point me to an explanation of calling conventions in Python?

Based on this discovery, the title of the post is completely wrong. My question now is - Why does Python allow me to change the inputs to the function? Would it be worth posting this under a different title?

L. Young
  • 113
  • 9

1 Answers1

0

Trying to recreate your example:

In [104]: dpx=np.arange(5); dpx.shape                                                                        
Out[104]: (5,)
In [105]: dx = np.zeros((1,5)); dx.shape                                                                     
Out[105]: (1, 5)
In [106]: dpx*dx[0,:]                                                                                        
Out[106]: array([0., 0., 0., 0., 0.])
In [107]: _.shape                                                                                            
Out[107]: (5,)

Regarding your new info.

a.shape = (n,1)

this action changes the shape of a itself, where as np.reshape(a, (n,1)) or a.reshape(n1,1) makes a new array with the new shape (but usually a view, shared data buffer).

When passed to a function:

def foo(a, b):
    a.shape = (n,1)
    b = b.reshape(n,1)

foo(A,B)

A and B are both passed to foo by reference. That is the object referenced by A in the outer namespace is referenced by a in the inner one. The a.shape changes that object in-place, and this change then appears in the same object referenced by A.

But B is not changed. b gets a new object assignment, and becomes local. The link between B and b is broken.

In general Python does not make automatic copies of objects, at least not by simply passing them to functions (and back). You have to make them yourself, or use functions that make new objects.

I'm not sure the terminology is exactly right, but this answer fits my understanding:

https://stackoverflow.com/a/33066581/901925

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • As I mentioned, I could not recreate the problem in the shell. So are you saying the results I was expecting are the correct results. There must be something else going on which causes the problem. Could this be a compiler bug? – L. Young Jul 17 '19 at 23:18
  • Can you duplicate it in a script? – hpaulj Jul 17 '19 at 23:31
  • No. If there is nothing wrong with the piece of code in the original post, then it looks like I need to work with my original code to generate an example. I replaced the code with a loop and at the end got an array of shape (5,1). Crazy. I'll try whittling down the code, to get a small example which demonstrates the problem. – L. Young Jul 17 '19 at 23:51
  • See additions to post on July 18, 2019 – L. Young Jul 18 '19 at 23:59
  • Thanks, for the information. It is good to know the differences between shape and reshape. It's nice that Python gives both alternatives as opposed to rigid languages like Fortran. Thanks also for the link discussing argument passing. This is one of those subtleties not discussed in most descriptions. It looks like this topic has been well covered. – L. Young Jul 19 '19 at 14:18