A simple and efficient way to do this is to make a np.float32 view of the array, and then tweak the view to have shape (m, n, 2), where (m, n) is the shape of inp_array. By using a view, the output array actually uses the same memory as inp_array.
Here's your array inp_array.
In [158]: inp_array = np.array([[1,2+3.j,3,4], [5,6,7+1.j,8], [9,10,11,12]], dtype=np.complex64)
In [159]: inp_array
Out[159]:
array([[ 1.+0.j, 2.+3.j, 3.+0.j, 4.+0.j],
[ 5.+0.j, 6.+0.j, 7.+1.j, 8.+0.j],
[ 9.+0.j, 10.+0.j, 11.+0.j, 12.+0.j]], dtype=complex64)
Make a view of the array with type np.float32. If (m, n) is the shape of inp_array, then v will have shape (m, 2*n).
In [160]: v = inp_array.view(np.float32)
In [161]: v
Out[161]:
array([[ 1., 0., 2., 3., 3., 0., 4., 0.],
[ 5., 0., 6., 0., 7., 1., 8., 0.],
[ 9., 0., 10., 0., 11., 0., 12., 0.]], dtype=float32)
Now reshape to (m, n, 2). (w is what you called out_array.)
In [162]: w = v.reshape(inp_array.shape + (2,))
In [163]: w
Out[163]:
array([[[ 1., 0.],
[ 2., 3.],
[ 3., 0.],
[ 4., 0.]],
[[ 5., 0.],
[ 6., 0.],
[ 7., 1.],
[ 8., 0.]],
[[ 9., 0.],
[10., 0.],
[11., 0.],
[12., 0.]]], dtype=float32)
In [164]: inp_array[1,2]
Out[164]: (7+1j)
In [165]: w[1,2]
Out[165]: array([7., 1.], dtype=float32)
A couple notes:
- This method assumes that
inp_arrayis "C contiguous". That is, the data in the array is stored in contiguous block of memory in "C" order. This might not be the case ifinp_arraywas created, for example, as a slice of a bigger array. inp_array,vandware all views of the same block of memory. If you change one in-place, they all change:In [171]: w[0, 0, 0] = 99 In [172]: inp_array Out[172]: array([[99.+0.j, 2.+3.j, 3.+0.j, 4.+0.j], [ 5.+0.j, 6.+0.j, 7.+1.j, 8.+0.j], [ 9.+0.j, 10.+0.j, 11.+0.j, 12.+0.j]], dtype=complex64)
A simple and efficient way to do this is to make a np.float32 view of the array, and then tweak the view to have shape (m, n, 2), where (m, n) is the shape of inp_array. By using a view, the output array actually uses the same memory as inp_array.
Here's your array inp_array.
In [158]: inp_array = np.array([[1,2+3.j,3,4], [5,6,7+1.j,8], [9,10,11,12]], dtype=np.complex64)
In [159]: inp_array
Out[159]:
array([[ 1.+0.j, 2.+3.j, 3.+0.j, 4.+0.j],
[ 5.+0.j, 6.+0.j, 7.+1.j, 8.+0.j],
[ 9.+0.j, 10.+0.j, 11.+0.j, 12.+0.j]], dtype=complex64)
Make a view of the array with type np.float32. If (m, n) is the shape of inp_array, then v will have shape (m, 2*n).
In [160]: v = inp_array.view(np.float32)
In [161]: v
Out[161]:
array([[ 1., 0., 2., 3., 3., 0., 4., 0.],
[ 5., 0., 6., 0., 7., 1., 8., 0.],
[ 9., 0., 10., 0., 11., 0., 12., 0.]], dtype=float32)
Now reshape to (m, n, 2). (w is what you called out_array.)
In [162]: w = v.reshape(inp_array.shape + (2,))
In [163]: w
Out[163]:
array([[[ 1., 0.],
[ 2., 3.],
[ 3., 0.],
[ 4., 0.]],
[[ 5., 0.],
[ 6., 0.],
[ 7., 1.],
[ 8., 0.]],
[[ 9., 0.],
[10., 0.],
[11., 0.],
[12., 0.]]], dtype=float32)
In [164]: inp_array[1,2]
Out[164]: (7+1j)
In [165]: w[1,2]
Out[165]: array([7., 1.], dtype=float32)
A couple notes:
- This method assumes that
inp_arrayis "C contiguous". That is, the data in the array is stored in contiguous block of memory in "C" order. This might not be the case ifinp_arraywas created, for example, as a slice of a bigger array. inp_array,vandware all views of the same block of memory. If you change one in-place, they all change:In [171]: w[0, 0, 0] = 99 In [172]: inp_array Out[172]: array([[99.+0.j, 2.+3.j, 3.+0.j, 4.+0.j], [ 5.+0.j, 6.+0.j, 7.+1.j, 8.+0.j], [ 9.+0.j, 10.+0.j, 11.+0.j, 12.+0.j]], dtype=complex64)
The imaginary parts are there in your output_array, but the dimensions are not in the order you would like.
Try replacing the final line with:
out_array = np.stack([np.real(inp_array), np.imag(inp_array)], axis=-1)
or you could use .transpose:
out_array = np.array([np.real(inp_array), np.imag(inp_array)]).transpose(1, 2, 0)
Both should give output:
> out_array
array([[[ 1., 0.],
[ 2., 3.],
[ 3., 0.],
[ 4., 0.]],
[[ 5., 0.],
[ 6., 0.],
[ 7., 1.],
[ 8., 0.]],
[[ 9., 0.],
[ 10., 0.],
[ 11., 0.],
[ 12., 0.]]], dtype=float32)
Actually, none of the proposed solutions worked in my case (Python 2.7.6, NumPy 1.8.2).
But I've found out, that change of dtype from complex (standard Python library) to numpy.complex_ may help:
>>> import numpy as np
>>> x = 1 + 2 * 1j
>>> C = np.zeros((2,2),dtype=np.complex_)
>>> C
array([[ 0.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j]])
>>> C[0,0] = 1+1j + x
>>> C
array([[ 2.+3.j, 0.+0.j],
[ 0.+0.j, 0.+0.j]])
To insert complex x or x + something into C, you apparently need to treat it as if it were an array, so either index into x or assign it to a slice of C:
>>> C
array([[ 0.+0.j, 0.+0.j],
[ 0.+0.j, 0.+0.j]])
>>> C[0, 0:1] = x
>>> C
array([[ 0.47229555+0.7957525j, 0.00000000+0.j ],
[ 0.00000000+0.j , 0.00000000+0.j ]])
>>> C[1, 1] = x[0] + 1+1j
>>> C
array([[ 0.47229555+0.7957525j, 0.00000000+0.j ],
[ 0.00000000+0.j , 1.47229555+1.7957525j]])
It looks like NumPy isn't handling this case correctly. Consider submitting a bug report.
I also deal with lots of complex integer data, generally basebanded data.
I use
dtype = np.dtype([('re', np.int16), ('im', np.int16)])
It's not perfect, but it adequately describes the data. I use it for loading into memory without doubling the size of the data. It also has the advantage of being able to load and store transparently with HDF5.
DATATYPE H5T_COMPOUND {
H5T_STD_I16LE "re";
H5T_STD_I16LE "im";
}
Using it is straightforward and is just different.
x = np.zeros((3,3),dtype)
x[0,0]['re'] = 1
x[0,0]['im'] = 2
x
>> array([[(1, 2), (0, 0), (0, 0)],
>> [(0, 0), (0, 0), (0, 0)],
>> [(0, 0), (0, 0), (0, 0)]],
>> dtype=[('re', '<i2'), ('im', '<i2')])
To do math with it, I convert to a native complex float type. The obvious approach doesn't work, but it's also not that hard.
y = x.astype(np.complex64) # doesn't work, only gets the real part
y = x['re'] + 1.j*x['im'] # works, but slow and big
y = x.view(np.int16).astype(np.float32).view(np.complex64)
y
>> array([[ 1.+2.j, 0.+0.j, 0.+0.j],
>> [ 0.+0.j, 0.+0.j, 0.+0.j],
>> [ 0.+0.j, 0.+0.j, 0.+0.j]], dtype=complex64)
This last conversion approach was inspired by an answer to What's the fastest way to convert an interleaved NumPy integer array to complex64?
Consider using matrices of the form [[a,-b],[b,a]] as a stand-in for the complex numbers.
Ordinary multiplication and addition of matrices corresponds to addition an multiplication of complex numbers (this subring of the collection of 2x2 matrices is isomorphic to the complex numbers).
I think Python can handle integer matrix algebra.