42

It is very convenient in numpy to use the .T attribute to get a transposed version of an ndarray. However, there is no similar way to get the conjugate transpose. Numpy's matrix class has the .H operator, but not ndarray. Because I like readable code, and because I'm too lazy to always write .conj().T, I would like the .H property to always be available to me. How can I add this feature? Is it possible to add it so that it is brainlessly available every time numpy is imported?

(A similar question could by asked about the .I inverse operator.)

Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
benpro
  • 4,325
  • 4
  • 19
  • 17

2 Answers2

30

You can subclass the ndarray object like:

from numpy import ndarray

class myarray(ndarray):    
    @property
    def H(self):
        return self.conj().T

such that:

a = np.random.rand(3, 3).view(myarray)
a.H

will give you the desired behavior.

Edit:

As suggested by @slek120, you can force to transpose only the last 2 axes with:

self.swapaxes(-2, -1).conj()

instead of self.conj().T.

Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
  • Thanks, but I was hoping for a monkey patching type solution where I could still use ndarray everywhere, e.g. `A = np.random.randn(3,3) + 1j*np.random.randn(3,3); B = A.H.dot(A)` – benpro Nov 14 '14 at 14:55
  • @benpro I see... but [this would be trickier](http://docs.scipy.org/doc/numpy/user/basics.subclassing.html#implications-for-subclassing) – Saullo G. P. Castro Nov 14 '14 at 15:03
  • 1
    I use `self.swapaxes(-2, -1).conj()` which only transposes the last 2 axes instead of all of them, which is useful for an array of matrices. – slek120 Apr 01 '22 at 20:08
  • 1
    @slek120, good hint. I will refer to your comment in the main answer – Saullo G. P. Castro Apr 02 '22 at 10:12
21

In general, the difficulty in this problem is that Numpy is a C-extension, which cannot be monkey patched...or can it? The forbiddenfruit module allows one to do this, although it feels a little like playing with knives.

So here is what I've done:

  1. Install the very simple forbiddenfruit package

  2. Determine the user customization directory:

    import site
    print site.getusersitepackages()
    
  3. In that directory, edit usercustomize.py to include the following:

    from forbiddenfruit import curse
    from numpy import ndarray
    from numpy.linalg import inv
    curse(ndarray,'H',property(fget=lambda A: A.conj().T))
    curse(ndarray,'I',property(fget=lambda A: inv(A)))
    
  4. Test it:

    python -c python -c "import numpy as np; A = np.array([[1,1j]]);  print A; print A.H"
    

    Results in:

    [[ 1.+0.j  0.+1.j]]
    [[ 1.-0.j]
     [ 0.-1.j]]
    
benpro
  • 4,325
  • 4
  • 19
  • 17