# Buggy code
def __add__(self, other):  # defines left addition for Qobj class
    """
    ADDITION with Qobj on LEFT [ ex. Qobj+4 ]
    """
    if _checkeseries(other) == "eseries":
        return other.__radd__(self)

    if not isinstance(other, Qobj):
        other = Qobj(other)

    if np.prod(other.shape) == 1 and np.prod(self.shape) != 1:
        # case for scalar quantum object
        dat = np.array(other.full())[0][0]
        if dat == 0:
            return self

        out = Qobj(type=self.type)

        if self.type in ["oper", "super"]:
            out.data = self.data + dat * sp.identity(
                self.shape[0], dtype=complex, format="csr"
            )
        else:
            out.data = self.data
            out.data.data = out.data.data + dat

        out.dims = self.dims
        out.shape = self.shape
        if isinstance(dat, (int, float)):
            out._isherm = self._isherm
        else:
            out._isherm = out.isherm

        return out.tidyup() if qset.auto_tidyup else out

    elif np.prod(self.shape) == 1 and np.prod(other.shape) != 1:
        # case for scalar quantum object
        dat = np.array(self.full())[0][0]
        if dat == 0:
            return other

        out = Qobj()
        if other.type in ["oper", "super"]:
            out.data = (
                dat * sp.identity(other.shape[0], dtype=complex, format="csr")
                + other.data
            )
        else:
            out.data = other.data
            out.data.data = out.data.data + dat
        out.dims = other.dims
        out.shape = other.shape

        if isinstance(dat, (int, float)):
            out._isherm = self._isherm
        else:
            out._isherm = out.isherm

        return out.tidyup() if qset.auto_tidyup else out

    elif self.dims != other.dims:
        raise TypeError("Incompatible quantum object dimensions")

    elif self.shape != other.shape:
        raise TypeError("Matrix shapes do not match")

    else:  # case for matching quantum objects
        out = Qobj(type=self.type)
        out.data = self.data + other.data
        out.dims = self.dims
        out.shape = self.shape

        if self.type in ["ket", "bra", "super"]:
            out._isherm = False
        elif self._isherm and self._isherm == other._isherm:
            out._isherm = True
        elif self._isherm and not other._isherm:
            out._isherm = False
        elif not self._isherm and other._isherm:
            out._isherm = False
        else:
            out._isherm = out.isherm

        return out.tidyup() if qset.auto_tidyup else out


# Traceback (TypeError)
rho_psi = operator_to_vector(Qobj(np.diag(np.array([0.9, 0.1], dtype=complex))))>>> E_psi = rho_psi.dag()
S = to_super(sigmax())
(E_psi * S) * rho_psi
Traceback (most recent call last):
File "<ipython-input-22-90cbfac2a43e>", line 1, in <module>
(E_psi * S) * rho_psi
File "qutip/qobj.py", line 416, in __mul__
raise TypeError("Incompatible Qobj shapes")
TypeError: Incompatible Qobj shapes

E_psi * (S * rho_psi)
Quantum object: dims = [[1], [1]], shape = [1, 1], type = oper, isherm = True
Qobj data =
[[ 0.18]]
E_psi
Quantum object: dims = [[1], [[2], [2]]], shape = [1, 4], type = bra
Qobj data =
[[ 0.9  0.   0.   0.1]]
rho_psi
Quantum object: dims = [[[2], [2]], [1]], shape = [4, 1], type = operator-vector
Qobj data =
[[ 0.9]
[ 0. ]
[ 0. ]
[ 0.1]]
S
Quantum object: dims = [[[2], [2]], [[2], [2]]], shape = [4, 4], type = super, isherm = True
Qobj data =
[[ 0.  0.  0.  1.]
[ 0.  0.  1.  0.]
[ 0.  1.  0.  0.]
[ 1.  0.  0.  0.]]

# Fixed code
def __add__(self, other):  # defines left addition for Qobj class
    """
    ADDITION with Qobj on LEFT [ ex. Qobj+4 ]
    """
    if _checkeseries(other) == "eseries":
        return other.__radd__(self)

    if not isinstance(other, Qobj):
        other = Qobj(other)

    if np.prod(other.shape) == 1 and np.prod(self.shape) != 1:
        # case for scalar quantum object
        dat = np.array(other.full())[0][0]
        if dat == 0:
            return self

        out = Qobj()

        if self.type in ["oper", "super"]:
            out.data = self.data + dat * sp.identity(
                self.shape[0], dtype=complex, format="csr"
            )
        else:
            out.data = self.data
            out.data.data = out.data.data + dat

        out.dims = self.dims
        out.shape = self.shape
        if isinstance(dat, (int, float)):
            out._isherm = self._isherm
        else:
            out._isherm = out.isherm

        return out.tidyup() if qset.auto_tidyup else out

    elif np.prod(self.shape) == 1 and np.prod(other.shape) != 1:
        # case for scalar quantum object
        dat = np.array(self.full())[0][0]
        if dat == 0:
            return other

        out = Qobj()
        if other.type in ["oper", "super"]:
            out.data = (
                dat * sp.identity(other.shape[0], dtype=complex, format="csr")
                + other.data
            )
        else:
            out.data = other.data
            out.data.data = out.data.data + dat
        out.dims = other.dims
        out.shape = other.shape

        if isinstance(dat, (int, float)):
            out._isherm = self._isherm
        else:
            out._isherm = out.isherm

        return out.tidyup() if qset.auto_tidyup else out

    elif self.dims != other.dims:
        raise TypeError("Incompatible quantum object dimensions")

    elif self.shape != other.shape:
        raise TypeError("Matrix shapes do not match")

    else:  # case for matching quantum objects
        out = Qobj()
        out.data = self.data + other.data
        out.dims = self.dims
        out.shape = self.shape

        if self.type in ["ket", "bra", "super"]:
            out._isherm = False
        elif self._isherm and self._isherm == other._isherm:
            out._isherm = True
        elif self._isherm and not other._isherm:
            out._isherm = False
        elif not self._isherm and other._isherm:
            out._isherm = False
        else:
            out._isherm = out.isherm

        return out.tidyup() if qset.auto_tidyup else out