Repository: qutip/qutip

Issue:
ENR basis not working with steady state solver (normal and floquet based) in 5.0.0
### Bug Description

Using a Hamiltonian that is constructed using operators returned from the `enr_destroy` function, does not work with the steady state solver in Quito 5.0.0. It does however work with Qutip 4.7 (have not checked any other versions). 

The error given is a dimension mismatch essentially, which seems to stem from an "expected dimension" of the Hamiltonian based on the number of modes. In the example below, the dimension mismatch is between 65536 (which is 2^16, the entire Hilbert space of my problem) vs 17, which is the excitation number restricted subspace. 

### Code to Reproduce the Bug

```shell
N = 16 ## number of resonators including tapers
max_excitation = 1 ## maximum excitation
num_levels = 2
dims = [num_levels] * N

ann_operators = enr_destroy(dims, excitations = max_excitation)
w_r = 2 * np.pi * 5
w = np.array([w_r] * N)

J_r = 2 * np.pi * 0.4
J_t2 = 1.353 * J_r
J_t1 = 1.035 * J_r

J = np.array([J_t2, J_t1] + [J_r] * (N-5) + [J_t1, J_t2])

kappa = 2.92 * J_r
drive_amp = 2 * np.pi * 0.0001
t = []

detuning_list = 2 * np.pi * np.linspace(-1, 1, 100)

for detuning in detuning_list:
    drive_w = (w_r - detuning)

    H_r = 0
    for i, a in enumerate(ann_operators):
        H_r += (w[i] - drive_w) * a.dag() * a

    H_int = 0
    for i in range(len(ann_operators)-1):
        H_int += J[i] * (ann_operators[i].dag() * ann_operators[i+1] + ann_operators[i+1].dag() * ann_operators[i])

    H_d = -1j * drive_amp * (ann_operators[0] - ann_operators[0].dag())

    H = H_r + H_int + H_d

    c_ops = [np.sqrt(kappa)*ann_operators[0], np.sqrt(kappa)*ann_operators[-1]]

    rho_ss = steadystate(H, c_ops)

    a_out = np.sqrt(kappa) * expect(ann_operators[-1], rho_ss)
    t.append(np.sqrt(kappa) * a_out/drive_amp)

print("J = ", np.array(J)/(2 * np.pi))
print("w = ", np.array(w)/(2 * np.pi))
print("kappa = ", kappa/2/np.pi)
t = np.array(t)
plt.plot(detuning_list/2/np.pi, 20 * np.log10(np.abs(t)))
plt.xlabel("Detuning (GHz)")
plt.ylabel("|S21|(dB)")
plt.ylim(-10,0.01)
# plt.xlim(-2, 2)
plt.grid()
```


### Code Output

```shell
{
	"name": "ValueError",
	"message": "Provided dimensions do not match the data: (65536, 65536) vs (17, 17)",
	"stack": "---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[2], line 39
     35 H = H_r + H_int + H_d
     37 c_ops = [np.sqrt(kappa)*ann_operators[0], np.sqrt(kappa)*ann_operators[-1]]
---> 39 rho_ss = steadystate(H, c_ops)
     41 a_out = np.sqrt(kappa) * expect(ann_operators[-1], rho_ss)
     42 t.append(np.sqrt(kappa) * a_out/drive_amp)

File /opt/anaconda3/envs/trial_env/lib/python3.11/site-packages/qutip/solver/steadystate.py:177, in steadystate(A, c_ops, method, solver, **kwargs)
    175     kwargs.pop(\"power_eps\", 0)
    176     kwargs.pop(\"sparse\", 0)
--> 177     return _steadystate_direct(A, kwargs.pop(\"weight\", 0),
    178                                method=solver, **kwargs)
    180 elif method == \"power\":
    181     # Remove unused kwargs, so only used and pass-through ones are included
    182     kwargs.pop(\"weight\", 0)

File /opt/anaconda3/envs/trial_env/lib/python3.11/site-packages/qutip/solver/steadystate.py:246, in _steadystate_direct(A, weight, **kw)
    243 rho_ss = _data.column_unstack(steadystate, n)
    244 rho_ss = _data.add(rho_ss, rho_ss.adjoint()) * 0.5
--> 246 return Qobj(rho_ss, dims=A.dims[0], isherm=True)

File /opt/anaconda3/envs/trial_env/lib/python3.11/site-packages/qutip/core/qobj.py:307, in Qobj.__init__(self, arg, dims, copy, superrep, isherm, isunitary)
    305 self._isherm = isherm
    306 self._isunitary = isunitary
--> 307 self._initialize_data(arg, dims, copy)
    309 if superrep is not None:
    310     self.superrep = superrep

File /opt/anaconda3/envs/trial_env/lib/python3.11/site-packages/qutip/core/qobj.py:300, in Qobj._initialize_data(self, arg, dims, copy)
    296     self._dims = Dimensions(
    297         dims or [[self._data.shape[0]], [self._data.shape[1]]]
    298     )
    299 if self._dims.shape != self._data.shape:
--> 300     raise ValueError('Provided dimensions do not match the data: ' +
    301                      f\"{self._dims.shape} vs {self._data.shape}\")

ValueError: Provided dimensions do not match the data: (65536, 65536) vs (17, 17)"
}
```


### Expected Behaviour

In Qutip 4.7 (and python 3.9), I see the following (correct output):
<img width="541" alt="image" src="https://github.com/qutip/qutip/assets/61804899/4480c250-b1c6-446e-936d-5ee48f91db8d">


### Your Environment

```shell
QuTiP Version:      5.0.0
Numpy Version:      1.26.4
Scipy Version:      1.12.0
Cython Version:     None
Matplotlib Version: 3.8.4
Python Version:     3.11.8
Number of CPUs:     8
BLAS Info:          Generic
INTEL MKL Ext:      False
Platform Info:      Darwin (x86_64)
```


### Additional Context

_No response_


Discussion:

Resolving patch:
diff --git a/qutip/solver/steadystate.py b/qutip/solver/steadystate.py
--- a/qutip/solver/steadystate.py
+++ b/qutip/solver/steadystate.py
@@ -233,7 +233,6 @@ def _steadystate_direct(A, weight, **kw):
         else:
             warn("Only sparse solver use preconditioners.", RuntimeWarning)
 
-
     method = kw.pop("method", None)
     steadystate = _data.solve(L, b, method, options=kw)
 
@@ -243,7 +242,7 @@ def _steadystate_direct(A, weight, **kw):
     rho_ss = _data.column_unstack(steadystate, n)
     rho_ss = _data.add(rho_ss, rho_ss.adjoint()) * 0.5
 
-    return Qobj(rho_ss, dims=A.dims[0], isherm=True)
+    return Qobj(rho_ss, dims=A._dims[0].oper, isherm=True)
 
 
 def _steadystate_eigen(L, **kw):
@@ -258,9 +257,12 @@ def _steadystate_eigen(L, **kw):
 
 
 def _steadystate_svd(L, **kw):
+    N = L.shape[0]
+    n = int(N**0.5)
     u, s, vh = _data.svd(L.data, True)
-    vec = Qobj(_data.split_columns(vh.adjoint())[-1], dims=[L.dims[0],[1]])
-    rho = vector_to_operator(vec)
+    vec = _data.split_columns(vh.adjoint())[-1]
+    rho = _data.column_unstack(vec, n)
+    rho = Qobj(rho, dims=L._dims[0].oper, isherm=True)
     return rho / rho.tr()
 
 
@@ -305,7 +307,7 @@ def _steadystate_power(A, **kw):
     if use_rcm:
         y = _reverse_rcm(y, perm)
 
-    rho_ss = Qobj(_data.column_unstack(y, N**0.5), dims=A.dims[0])
+    rho_ss = Qobj(_data.column_unstack(y, N**0.5), dims=A._dims[0].oper)
     rho_ss = rho_ss + rho_ss.dag()
     rho_ss = rho_ss / rho_ss.tr()
     rho_ss.isherm = True


Test patch:
diff --git a/qutip/tests/test_enr_state_operator.py b/qutip/tests/test_enr_state_operator.py
--- a/qutip/tests/test_enr_state_operator.py
+++ b/qutip/tests/test_enr_state_operator.py
@@ -152,3 +152,40 @@ def test_mesolve_ENR():
 
     np.testing.assert_allclose(result_JC.expect[0],
                                result_enr.expect[0], atol=1e-2)
+
+
+def test_steadystate_ENR():
+    # Ensure ENR states work with steadystate functions
+    # We compare the output to an exact truncation of the
+    # single-excitation Jaynes-Cummings model
+    eps = 2 * np.pi
+    omega_c = 2 * np.pi
+    g = 0.1 * omega_c
+    gam = 0.01 * omega_c
+    N_cut = 2
+
+    sz = qutip.sigmaz() & qutip.qeye(N_cut)
+    sm = qutip.destroy(2).dag() & qutip.qeye(N_cut)
+    a = qutip.qeye(2) & qutip.destroy(N_cut)
+    H_JC = (0.5 * eps * sz + omega_c * a.dag()*a +
+            g * (a * sm.dag() + a.dag() * sm))
+    c_ops = [np.sqrt(gam) * a]
+
+    result_JC = qutip.steadystate(H_JC, c_ops)
+    exp_sz_JC = qutip.expect(sz, result_JC)
+
+    N_exc = 1
+    dims = [2, N_cut]
+    d = qutip.enr_destroy(dims, N_exc)
+    sz = 2*d[0].dag()*d[0]-1
+    b = d[0]
+    a = d[1]
+    H_enr = (eps * b.dag()*b + omega_c * a.dag() * a +
+             g * (b.dag() * a + a.dag() * b))
+    c_ops = [np.sqrt(gam) * a]
+
+    result_enr = qutip.steadystate(H_enr, c_ops)
+    exp_sz_enr = qutip.expect(sz, result_enr)
+
+    np.testing.assert_allclose(exp_sz_JC,
+                               exp_sz_enr, atol=1e-2)