In [2]:
import numpy as np
from qutip import *
In [6]:
# prototype density matrix (i.e. nonsense)
rho = Qobj([[1,2],[3,4]])
rho
Out[6]:
In [31]:
rho_v = operator_to_vector(rho)
rho_v
Out[31]:
This is where I got confused. By hand I write this as 1,2,3,4 in order from top to bottom, based on the notation: $$\rho = \sum_{i,j}\rho_{ij}|i\rangle\langle j| \rightarrow |\rho\rangle\rangle = \sum_{i,j}\rho_{ij}|i\rangle \otimes |j\rangle$$
I'll let $$|1\rangle = \begin{pmatrix}1\\0\end{pmatrix}$$ and $$|2\rangle = \begin{pmatrix}0\\1\end{pmatrix}$$ so $i=j=1,2$ in the sums. The outer products are: $$|1\rangle\langle 1| = \begin{pmatrix}1&0\\0&0\end{pmatrix}$$ $$|1\rangle\langle 2| = \begin{pmatrix}0&1\\0&0\end{pmatrix}$$ $$|2\rangle\langle 1| = \begin{pmatrix}0&0\\1&0\end{pmatrix}$$ $$|2\rangle\langle 2| = \begin{pmatrix}0&0\\0&1\end{pmatrix}$$ And the tensor products are: $$|1\rangle \otimes |1\rangle = \begin{pmatrix}1\\0\\0\\0\end{pmatrix}$$ $$|1\rangle \otimes |2\rangle = \begin{pmatrix}0\\1\\0\\0\end{pmatrix}$$ $$|2\rangle \otimes |1\rangle = \begin{pmatrix}0\\0\\1\\0\end{pmatrix}$$ $$|2\rangle \otimes |2\rangle = \begin{pmatrix}0\\0\\0\\1\end{pmatrix}$$
I see the code for operator_to_vector
takes the transpose, but I'm not sure why that is? Maybe to align to the underlying Fortran-style column-major data in the underlying implementation?
So, the bottom line is: Either trust and use the QuTiP functions or roll your own. Mixing and matching builds you a world that will be ripe with transpose errors :-)
In [17]:
one = Qobj([[1],[0]])
one
Out[17]:
In [19]:
two = Qobj([[0],[1]])
two
Out[19]:
In [24]:
rho == 1*one*one.dag() + 2*one*two.dag() + 3*two*one.dag() + 4*two*two.dag()
Out[24]:
So this is consistent with my prototype $\rho$
In [28]:
tensor(one,one)
Out[28]:
In [25]:
tensor(one,two)
Out[25]:
In [26]:
tensor(two,one)
Out[26]:
In [27]:
tensor(two,two)
Out[27]:
These are also consistent with "by hand" notation. So everything individually works as it would "by hand" but the operator_to_vector takes a transpose first... presumably to align the numpy arrays?
Ok, so knowing that, it's a bit hard to compare to by-hand results, but we can check a few. First, the left-multiplication should be the same as spre
. Defined as $\mathcal{L}(A) = A\otimes I$:
In [70]:
spre(destroy(2))
Out[70]:
In [76]:
tensor(destroy(2),identity(2))
Out[76]:
In [78]:
tensor(identity(2),destroy(2))
Out[78]:
But this is instead showing that left-multiplication is $\mathcal{L}(A) = I\otimes A$, doesn't match the expected definition.
I think this is generally known, as we're mixing notation with a particular (matrix) representation. MATLAB does a similar thing (I suspect for the same Fortran-roots reason): https://physics.stackexchange.com/questions/163546/finding-the-matrix-representation-of-a-superoperator
In [ ]: