# Buggy code
def __mul__(self, other):
    """
    MULTIPLICATION with Qobj on LEFT [ ex. Qobj*4 ]
    """
    if isinstance(other, Qobj):
        if self.shape[1] == other.shape[0] and self.dims[1] == other.dims[0]:
            out = Qobj()
            out.data = self.data * other.data
            dims = [self.dims[0], other.dims[1]]
            out.dims = dims
            if not isinstance(dims[0][0], list):
                r = range(len(dims[0]))
                mask = [dims[0][n] == dims[1][n] == 1 for n in r]
                out.dims = [
                    max([1], [dims[0][n] for n in r if not mask[n]]),
                    max([1], [dims[1][n] for n in r if not mask[n]]),
                ]
            else:
                out.dims = dims
            out.shape = [self.shape[0], other.shape[1]]
            out.type = _typecheck(out)
            out._isherm = out.isherm
            return out.tidyup() if qset.auto_tidyup else out

        elif self.shape[0] == 1 and self.shape[1] == 1:
            out = Qobj(other)
            out.data *= self.data[0, 0]
            return out.tidyup() if qset.auto_tidyup else out

        elif other.shape[0] == 1 and other.shape[1] == 1:
            out = Qobj(self)
            out.data *= other.data[0, 0]
            return out.tidyup() if qset.auto_tidyup else out

        else:
            raise TypeError("Incompatible Qobj shapes")

    elif isinstance(other, (list, np.ndarray)):
        # if other is a list, do element-wise multiplication
        return np.array([self * item for item in other])

    elif _checkeseries(other) == "eseries":
        return other.__rmul__(self)

    elif isinstance(other, (int, float, complex, np.int64)):
        out = Qobj(type=self.type)
        out.data = self.data * other
        out.dims = self.dims
        out.shape = self.shape
        if isinstance(other, complex):
            out._isherm = out.isherm
        else:
            out._isherm = self._isherm

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

    else:
        raise TypeError("Incompatible object for multiplication")


# 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 __mul__(self, other):
    """
    MULTIPLICATION with Qobj on LEFT [ ex. Qobj*4 ]
    """
    if isinstance(other, Qobj):
        if self.shape[1] == other.shape[0] and self.dims[1] == other.dims[0]:
            out = Qobj()
            out.data = self.data * other.data
            dims = [self.dims[0], other.dims[1]]
            out.dims = dims
            if not isinstance(dims[0][0], list) and not isinstance(dims[1][0], list):
                r = range(len(dims[0]))
                mask = [dims[0][n] == dims[1][n] == 1 for n in r]
                out.dims = [
                    max([1], [dims[0][n] for n in r if not mask[n]]),
                    max([1], [dims[1][n] for n in r if not mask[n]]),
                ]
            else:
                out.dims = dims
            out.shape = [self.shape[0], other.shape[1]]
            out.superrep = self.superrep  # XXX
            out._isherm = out.isherm
            return out.tidyup() if qset.auto_tidyup else out

        elif np.prod(self.shape) == 1:
            out = Qobj(other)
            out.data *= self.data[0, 0]
            return out.tidyup() if qset.auto_tidyup else out

        elif np.prod(other.shape):
            out = Qobj(self)
            out.data *= other.data[0, 0]
            return out.tidyup() if qset.auto_tidyup else out

        else:
            raise TypeError("Incompatible Qobj shapes")

    elif isinstance(other, (list, np.ndarray)):
        # if other is a list, do element-wise multiplication
        return np.array([self * item for item in other])

    elif _checkeseries(other) == "eseries":
        return other.__rmul__(self)

    elif isinstance(other, (int, float, complex, np.int64)):
        out = Qobj()
        out.data = self.data * other
        out.dims = self.dims
        out.shape = self.shape
        if isinstance(other, complex):
            out._isherm = out.isherm
        else:
            out._isherm = self._isherm

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

    else:
        raise TypeError("Incompatible object for multiplication")