4
$\begingroup$

I have the following function that has been vectorized so that for every element in input array t, an array is output:

@np.vectorize
def Ham(t):
    d=np.array([[np.cos(t),np.sqrt(t)],[0,1]],dtype=np.complex128)
    return d

I am getting an error: TypeError: only length-1 arrays can be converted to Python scalars. I believe this error happens when there is conflicts with numpy and python, but I can't see where that would be. Also, if the dtype is not given, the error is ValueError: setting an array element with a sequence. I'm guessing you can't assign arrays inside arrays in python, but how else can I do this?

$\endgroup$
7
$\begingroup$

The problem is that np.cos(t) and np.sqrt(t) generate arrays with the length of t, whereas the second row ([0,1]) maintains the same size. To use np.vectorize with your function, you have to define the output type, and np.vectorize isn't really meant as a decorator except for the simplest cases. In this way however you can generate the function with the right type:

def Ham(t):
    d=np.array([[np.cos(t),np.sqrt(t)],[0,1]],dtype=np.complex128)
    return d

HamVec = np.vectorize(Ham, otypes=[np.ndarray])

Now you can use HamVec as a function:

>>> x=np.array([1,2,3])
>>> HamVec(x)
array([ array([[ 0.54030231+0.j,  1.00000000+0.j],
       [ 0.00000000+0.j,  1.00000000+0.j]]),
       array([[-0.41614684+0.j,  1.41421356+0.j],
       [ 0.00000000+0.j,  1.00000000+0.j]]),
       array([[-0.98999250+0.j,  1.73205081+0.j],
       [ 0.00000000+0.j,  1.00000000+0.j]])], dtype=object)

Notes:

  1. The np.vectorize is just a convenience function, it doesn't actually make code run any faster.
  2. This question might have been more suitable for StackOverflow.

Edit: as an answer to the follow up question: the resulting values of the matrix are of type numpy.complex128:

>>> y = HamVec(x)
>>> type(y[0][0][0])
<type 'numpy.complex128'>

And you can do for example:

>>> y*np.complex('3+2j')
array([ array([[ 1.62090692+1.08060461j,  3.00000000+2.j        ],
       [ 0.00000000+0.j        ,  3.00000000+2.j        ]]),
       array([[-1.24844051-0.83229367j,  4.24264069+2.82842712j],
       [ 0.00000000+0.j        ,  3.00000000+2.j        ]]),
       array([[-2.96997749-1.97998499j,  5.19615242+3.46410162j],
       [ 0.00000000+0.j        ,  3.00000000+2.j        ]])], dtype=object)
$\endgroup$
  • $\begingroup$ That worked, thanks! I just have another question though. Is there a way to change the output to be of type cfloat? I tried converting it inside the function, but it always returns an array of dtype=object $\endgroup$ – Alex Jan 11 '16 at 17:14
  • $\begingroup$ Are you sure this matters? The values in the result matrix are in fact of type numpy.complex128. Also see this question. $\endgroup$ – agold Jan 11 '16 at 17:35
  • $\begingroup$ Hmm I thought the dtype=object meant that the result matrix was of object type. Is there a reason why it says that it is of type object and not complex128? $\endgroup$ – Alex Jan 11 '16 at 19:10
  • $\begingroup$ I have added an example to the answer. $\endgroup$ – agold Jan 11 '16 at 19:17
  • $\begingroup$ Okay sorry if I keep asking questions here, but I am trying to take numpy.linalg.eig of the resulting matrix, but since there is dtype=object in the matrix, I get an error. Is there a simple way of removing dtype in the output array? $\endgroup$ – Alex Jan 12 '16 at 1:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.