Пример #1
0
    def test_ground_state_matches(self, dense, MPO_ham, cyclic):
        n = 10

        tol = 3e-2 if cyclic else 1e-4

        h = MPO_ham(n, cyclic=cyclic)
        dmrg = DMRG1(h, bond_dims=[4, 8, 12])
        dmrg.opts['local_eig_ham_dense'] = dense
        dmrg.opts['periodic_segment_size'] = 1.0
        dmrg.opts['periodic_nullspace_fudge_factor'] = 1e-6
        assert dmrg.solve(tol=tol / 10, verbosity=1)
        assert dmrg.state.cyclic == cyclic
        eff_e, mps_gs = dmrg.energy, dmrg.state
        mps_gs_dense = mps_gs.to_dense()

        assert_allclose(mps_gs_dense.H @ mps_gs_dense, 1.0, rtol=tol)

        h_dense = h.to_dense()

        # check against dense form
        actual_e, gs = eigh(h_dense, k=1)
        assert_allclose(actual_e, eff_e, rtol=tol)
        assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol)

        # check against actual MPO_ham
        if MPO_ham is MPO_ham_XY:
            ham_dense = ham_heis(n, cyclic=cyclic,
                                 j=(1.0, 1.0, 0.0), sparse=True)
        elif MPO_ham is MPO_ham_heis:
            ham_dense = ham_heis(n, cyclic=cyclic, sparse=True)

        actual_e, gs = eigh(ham_dense, k=1)
        assert_allclose(actual_e, eff_e, rtol=tol)
        assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol)
Пример #2
0
def two_qubit_eigsectors(strA='XY', strB='YX'):
    '''

    Params: strA, strB [strings]
        Action of stabilizers on face-qubit subspace.

    Return: `eigsectors` [ndarray(shape=(2,2), dtype=object)]
        Each element of eigsector contains the unique vector
        in the face-qubit subspace that diagonalizes strA, strB
        with respective eigenvalues +/-1.

        eigsectors[0,0]: +1, +1
        eigsectors[0,1]: +1, -1
        eigsectors[1,0]: -1, +1
        eigsectors[1,1]: -1, -1

    '''
    sign_dic = {0: 1.0,  1: -1.0}
    X, Y, Z, I = (qu.pauli(mu) for mu in ['x','y','z','i'])
    opmap = {'X': X, 'Y':Y, 'Z':Z, 'I':I}

    face_dims = [2]*2 #dimensions of face-qubit subspace

    # ###
    # strA = 'XY'
    # strB = 'YX'
    # ###

    SA = qu.kron(*[opmap[Q] for Q in strA])
    SB = qu.kron(*[opmap[Q] for Q in strB])
    # SA, SB = X&Y, Y&X

    eigsectors = np.ndarray(shape=face_dims, dtype=object)


    eva, Ua = qu.eigh(SA)
    for indA, signA in sign_dic.items():
        
        #pick evectors in (signA) sector
        Ua_sgn = Ua[:, np.isclose(eva, signA)] #4x2
        
        #Stabilizer B on (signA) eigspace of SA
        Qb = Ua_sgn.H @ SB @ Ua_sgn
        
        evb, Ub = qu.eigh(Qb)

        for indB, signB in sign_dic.items():

            #pick evector in signB sector
            Ub_sgn = Ub[:,np.isclose(evb, signB)] #2x1
            
            face_state =  Ua_sgn @ Ub_sgn #4x1

            assert np.allclose(SA@face_state, signA*face_state)
            assert np.allclose(SB@face_state, signB*face_state)

            eigsectors[indA,indB] = face_state

    return eigsectors
Пример #3
0
    def test_eigh(self):
        H = qu.ham_mbl(6, dh=2.5)
        a_el, a_ev = qu.eigh(H, autoblock=False)
        el, ev = qu.eigh(H, autoblock=True)

        assert qu.norm(ev @ qu.ldmul(el, ev.H) - H, 'fro') < 1e-12
        assert_allclose(a_el, el)
        assert_allclose(ev.H @ ev, np.eye(H.shape[0]), atol=1e-12)
Пример #4
0
 def test_thermal_state_tuple(self):
     full = rand_herm(2**4)
     l, v = eigh(full)
     for beta in (0, 0.5, 1, 10):
         rhoth1 = thermal_state(full, beta)
         rhoth2 = thermal_state((l, v), beta)
         assert_allclose(rhoth1, rhoth2)
Пример #5
0
    def test_project_eig(self, backend):
        Hl = qu.Lazy(qu.ham_heis, 4, sparse=True, shape=(16, 16))
        Pl = qu.Lazy(qu.zspin_projector, 4, shape=(16, 6))

        ge, gs = qu.eigh(Hl, P=Pl, k=1, backend=backend)

        assert ge == pytest.approx(-2)
        assert qu.expec(gs, gs) == pytest.approx(1.0)
Пример #6
0
 def solve_ED(self):
     '''
     Solves full spectrum of simulator Hamiltonian, 
     stores eigensystem. 
     
     Assumes self._HamSim exists.
     '''
     self._eigens, self._eigstates = qu.eigh(self._HamCode)
Пример #7
0
 def test_eigsys(self, mat_herm_dense):
     u, a = mat_herm_dense
     evals, v = qu.eigh(a)
     assert(set(np.rint(evals)) == set((-1, 2, 4, -3)))
     assert_allclose(evals, [-3, -1, 2, 4])
     for i, j in zip([3, 0, 1, 2], range(4)):
         o = u[:, [i]].H @ v[:, [j]]
         assert_allclose(abs(o), 1.)
Пример #8
0
 def test_cross_equality(self, mat_herm_sparse, k, which):
     _, a = mat_herm_sparse
     sigma = 1 if which in {None, "TR"} else None
     lks, vks = zip(*(qu.eigh(a, k=k, which=which, sigma=sigma, backend=b)
                      for b in eigs_backends))
     lks, vks = tuple(lks), tuple(vks)
     for i in range(len(lks) - 1):
         assert_allclose(lks[i], lks[i + 1])
         assert_allclose(abs(vks[i].H @ vks[i + 1]), qu.eye(k), atol=1e-14)
Пример #9
0
    def test_exp_sparse(self):

        a = rand_herm(100, sparse=True, density=0.1)
        k = rand_ket(100)

        out = mfn_multiply_slepc(a, k)

        al, av = eigh(a.A)
        expected = av @ np.diag(np.exp(al)) @ av.conj().T @ k

        assert_allclose(out, expected)
Пример #10
0
    def test_eigs_slepc_eigvecs(self, dtype):
        h = rand_herm(32, sparse=True, density=0.5)
        if dtype == 'real':
            h = h.real
        lks, vks = eigs_slepc(h, k=5)
        lka, vka = eigh(h, k=5, backend='scipy')
        assert vks.shape == vka.shape
        assert h.dtype == vks.dtype

        assert_allclose(lks, lka)
        assert_allclose(abs(vka.H @ vks), np.eye(5), atol=1e-8)
Пример #11
0
 def test_eigs_sparse_wvecs(self, mat_herm_sparse, backend):
     u, a = mat_herm_sparse
     assert qu.issparse(a)
     lk, vk = qu.eigh(a, k=2, backend=backend)
     assert_allclose(lk, (-3, -1))
     for i, j in zip([3, 0], [0, 1]):
         o = u[:, [i]].H @ vk[:, [j]]
         assert_allclose(abs(o), 1.)
     vk = qu.eigvecsh(a, k=2, backend=backend)
     for i, j in zip([3, 0], [0, 1]):
         o = u[:, [i]].H @ vk[:, [j]]
         assert_allclose(abs(o), 1.)
Пример #12
0
    def test_1(self):
        a = rand_herm(100, sparse=True)
        el, ev = eigh(a.A)
        which = abs(el) < 0.2
        el, ev = el[which], ev[:, which]

        offset = norm(a, 'fro')
        a = a + offset * sp.eye(a.shape[0])

        sl, sv = eigs_slepc(a, k=6, l_win=(-0.2 + offset, 0.2 + offset))
        sl -= offset
        assert_allclose(el, sl)
        assert_allclose(np.abs(sv.H @ ev), np.eye(el.size), atol=1e-11)
Пример #13
0
    def test_matches_exact(self, dense, MPO_ham, cyclic):
        n = 6
        h = MPO_ham(n, cyclic=cyclic)

        tol = 3e-2 if cyclic else 1e-4

        dmrg = DMRG2(h, bond_dims=[4, 8, 12])
        assert dmrg._k[0].dtype == float
        dmrg.opts['local_eig_ham_dense'] = dense
        dmrg.opts['periodic_segment_size'] = 1.0
        dmrg.opts['periodic_nullspace_fudge_factor'] = 1e-6

        assert dmrg.solve(tol=tol / 10, verbosity=1)

        # XXX: need to dispatch SLEPc eigh on real input
        # assert dmrg._k[0].dtype == float

        eff_e, mps_gs = dmrg.energy, dmrg.state
        mps_gs_dense = mps_gs.to_dense()

        assert_allclose(expec(mps_gs_dense, mps_gs_dense), 1.0, rtol=tol)

        h_dense = h.to_dense()

        # check against dense form
        actual_e, gs = eigh(h_dense, k=1)
        assert_allclose(actual_e, eff_e, rtol=tol)
        assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol)

        # check against actual MPO_ham
        if MPO_ham is MPO_ham_XY:
            ham_dense = ham_heis(n, cyclic=cyclic, j=(1.0, 1.0, 0.0))
        elif MPO_ham is MPO_ham_heis:
            ham_dense = ham_heis(n, cyclic=cyclic)

        actual_e, gs = eigh(ham_dense, k=1)
        assert_allclose(actual_e, eff_e, rtol=tol)
        assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0, rtol=tol)
Пример #14
0
    def test_expm_multiply(self, num_workers, bigsparsemat, big_vec):
        a = bigsparsemat
        k = big_vec

        if ((num_workers is not None) and ALREADY_RUNNING_AS_MPI
                and num_workers > 1 and num_workers != NUM_MPI_WORKERS):
            with pytest.raises(ValueError):
                mfn_multiply_slepc_spawn(a, k, num_workers=num_workers)

        else:
            out = mfn_multiply_slepc_spawn(a, k, num_workers=num_workers)
            al, av = eigh(a.A)
            expected = av @ np.diag(np.exp(al)) @ av.conj().T @ k
            assert_allclose(out, expected)
Пример #15
0
    def test_sqrt_sparse(self):
        import scipy.sparse as sp

        a = rand_pos(32, sparse=True, density=0.1)
        a = a + 0.001 * sp.eye(32)
        k = rand_ket(32)

        out = mfn_multiply_slepc(a, k, fntype='sqrt', isherm=True)

        al, av = eigh(a.A)
        al[al < 0] = 0.0  # very small neg values spoil sqrt
        expected = av @ np.diag(np.sqrt(al)) @ av.conj().T @ k

        assert_allclose(out, expected, rtol=1e-6)
Пример #16
0
    def test_ising_and_MPS_product_state(self):
        h = MPO_ham_ising(6, bx=2.0, j=0.1)
        dmrg = DMRG1(h, bond_dims=8)
        assert dmrg.solve(verbosity=1)
        eff_e, mps_gs = dmrg.energy, dmrg.state
        mps_gs_dense = mps_gs.to_dense()
        assert_allclose(mps_gs_dense.H @ mps_gs_dense, 1.0)

        # check against dense
        h_dense = h.to_dense()
        actual_e, gs = eigh(h_dense, k=1)
        assert_allclose(actual_e, eff_e)
        assert_allclose(abs(expec(mps_gs_dense, gs)), 1.0)

        exp_gs = MPS_product_state([plus()] * 6)
        assert_allclose(abs(exp_gs.H @ mps_gs), 1.0, rtol=1e-3)
Пример #17
0
 def test_evo_ham_dense_ket_solve(self, ham_rcr_psi, sparse, presolve):
     ham, trc, p0, tm, pm = ham_rcr_psi
     ham = qu(ham, sparse=sparse)
     if presolve:
         l, v = eigh(ham)
         sim = Evolution(p0, (l, v))
         assert sim._solved
     else:
         sim = Evolution(p0, ham, method='solve')
     sim.update_to(tm)
     assert_allclose(sim.pt, pm)
     assert expec(sim.pt, p0) < 1.0
     sim.update_to(trc)
     assert_allclose(sim.pt, p0)
     assert isinstance(sim.pt, np.matrix)
     assert sim.t == trc
Пример #18
0
 def test_evo_ham_dense_ket_solve(self, ham_rcr_psi, sparse, presolve):
     ham, trc, p0, tm, pm = ham_rcr_psi
     ham = qu.qu(ham, sparse=sparse)
     if presolve:
         l, v = qu.eigh(ham)
         sim = qu.Evolution(p0, (l, v))
         assert isinstance(sim._ham, tuple) and len(sim._ham) == 2
     else:
         sim = qu.Evolution(p0, ham, method='solve')
     sim.update_to(tm)
     assert_allclose(sim.pt, pm)
     assert qu.expec(sim.pt, p0) < 1.0
     sim.update_to(trc)
     assert_allclose(sim.pt, p0)
     assert isinstance(sim.pt, qu.qarray)
     assert sim.t == trc
Пример #19
0
    def projected_ham_3(self):
        '''
        Should be equivalent to self.ham_code()
        '''
        #X because stabilizer acts with X on 7th qubit
        _, Ux = qu.eigh(qu.pauli('x'))

        U = qu.ikron(Ux.copy(), dims=self._sim_dims, inds=[6])

        Stilde = (U.H @ self.stabilizer() @ U).real.round()
        #Stilde should be diagonal!

        U_plus = U[:, np.where(np.diag(Stilde) == 1.0)[0]]

        HamProj = U_plus.H @ self.ham_sim() @ U_plus

        return HamProj  #in +1 stabilizer eigenbasis
Пример #20
0
    def make_stabilizer(self):
        '''
        DEPREC -- DON'T USE 
        
        TODO: 
        * add a projector onto codespace (see method 2)
        * generalize indices, rotation, reshape, etc
        * always need to round? check always real
        '''

        X, Z = (qu.pauli(mu) for mu in ['x', 'z'])

        ## TODO: make general
        # ops = [Z,Z,Z,Z,X]
        # inds = [1,2,4,5,6]
        # stabilizer = qu.ikron(ops=ops, dims=self._sim_dims, inds=inds)

        _, Ux = qu.eigh(qu.pauli('x'))

        stab_data = self.loop_stabilizer_data(0, 1)
        oplist = [qu.pauli(Q) for Q in stab_data['opstring']]

        stabilizer = qu.ikron(ops=oplist,
                              dims=self._sim_dims,
                              inds=stab_data['inds'])
        #TODO: change to general rather than inds=6, Ux
        U = qu.ikron(Ux.copy(), dims=self._sim_dims, inds=[6])

        #TODO: can this be done without rounding()/real part?
        Stilde = (U.H @ stabilizer @ U).real.round()

        assert is_diagonal(Stilde)

        U_plus = U[:, np.where(np.diag(Stilde) == 1.0)[0]]

        HamCode = U_plus.H @ self.ham_sim() @ U_plus

        self._stabilizer = stabilizer
        self._Uplus = U_plus  #+1 eigenstates written in full qubit basis
        self._HamCode = HamCode  # in +1 stabilizer eigenbasis
Пример #21
0
    def test_explicit_sweeps(self):
        n = 8
        chi = 16
        ham = MPO_ham_mbl(n, dh=4, seed=42)
        p0 = MPS_rand_state(n, 2).expand_bond_dimension(chi)

        b0 = p0.H
        align_TN_1D(p0, ham, b0, inplace=True)
        en0 = (p0 & ham & b0) ^ ...
        dmrgx = DMRGX(ham, p0, chi)
        dmrgx.sweep_right()
        en1 = dmrgx.sweep_left(canonize=False)
        assert en0 != en1

        dmrgx.sweep_right(canonize=False)
        en = dmrgx.sweep_right(canonize=True)

        # check normalized
        assert_allclose(dmrgx._k.H @ dmrgx._k, 1.0)

        k = dmrgx._k.to_dense()
        h = ham.to_dense()
        el, ev = eigh(h)

        # check variance very low
        assert np.abs((k.H @ h @ h @ k) - (k.H @ h @ k)**2) < 1e-12

        # check exactly one eigenvalue matched well
        assert np.sum(np.abs(el - en) < 1e-12) == 1

        # check exactly one eigenvector is matched with high fidelity
        ovlps = (ev.H @ k).A**2
        big_ovlps = ovlps[ovlps > 1e-12]
        assert_allclose(big_ovlps, [1])

        # check fully
        assert is_eigenvector(k, h, atol=1e-12, rtol=1e-12)
Пример #22
0
LOSCH_ETH = np.array(-np.log(evo_ETH.results['losch'])) / N

### MBL --> ETH ###
W_i = params.W_i

J_MBL = (0.0, 0.0, 0.0)

H_MBL = P.T @ qu.ham_mbl(N,
                         W_i,
                         J_MBL,
                         cyclic=False,
                         dh_dist='qp',
                         beta=0.721,
                         seed=seed,
                         sparse=True).real @ P
Psi_MBL = qu.eigh(H_MBL, k=1, which='SA')[1]

J_evo2 = (J, J, J)

H_evo2 = P.T @ qu.ham_mbl(N,
                          W,
                          J_evo2,
                          cyclic=False,
                          dh_dist='qp',
                          beta=0.721,
                          seed=seed,
                          sparse=True).real @ P

compute = {
    'time': lambda t, p: t,
    'losch': lambda t, p: qu.fidelity(Psi_MBL, p)
Пример #23
0
 def solveED(self):
     '''Diagonalize codespace Ham, 
     store eigensystem.
     '''
     self._eigens, self._eigstates = qu.eigh(self._HamCode)
Пример #24
0
def one_qubit_U_matrices(qlattice, empt_face_coo):
    '''
    TODO: check parity more intelligently

    U matrix for lifting states from 'Fock' space
    to 'Stab' subspace of Simulator space.

    empt_face_coo: tuple (x,y) 
        location of empty face corresponding to the loop
        stabilizer operator.
    '''
    assert qlattice._faces[empt_face_coo] is None

    X, Y, Z = (qu.pauli(mu) for mu in ['x','y','z'])
    opmap = {'X':X, 'Y':Y, 'Z':Z}
    
    #number of fermionic/qubit DOF
    Nfermi = qlattice._Nfermi 
    Nqubit = qlattice._Nsites
    
    #dimensions of simulator space [2,2,...]
    sim_space_dims = qlattice._sim_dims
    code_space_dims = qlattice._encoded_dims
    
    #sites and action-string of stabilizer operator
    stab_data = qlattice.loop_stabilizer_data(*empt_face_coo)

    arrays = [opmap[Q] for Q in stab_data['opstring']]

    #(this is only for one-face-qubit stabilizers)
    assert len(arrays) == 4+1

    inds = stab_data['inds']

    # stabilizer = qu.ikron(  ops=arrays, 
    #                         dims=sim_space_dims,
    #                         inds=inds)

    #action on just the face qubit, either X or Y
    face_op = arrays[4]
    elx, evx = qu.eigh(face_op)
    #diagonalized the face qubit        
    eigenfaces = {-1 : evx[:,0],
                  +1 : evx[:,1]}

    #II..ZZZZ..III parity-check the vertices of face-loop
    corner_parity_op = qu.ikron(ops=arrays[:4],
                                dims=code_space_dims,
                                inds=inds[:4])

    #get all the stabilizer eigenvectors
    Uplus = np.zeros((2**Nqubit, 2**Nfermi))
    Uplus_dagger = np.zeros((2**Nfermi, 2**Nqubit))

    for i in range(2**Nfermi):

        vertex_state_i = qu.basis_vec(i=i, dim=2**Nfermi)
        
        sign = qu.expec(corner_parity_op,
                        vertex_state_i)

        face_state_i = eigenfaces[int(sign)].reshape(-1,1)
        
        full_state_i = vertex_state_i & face_state_i

        Uplus[:,i] = full_state_i.flatten()
        Uplus_dagger[i,:] = full_state_i.H.flatten()

    # if not tensorize:
    return qu.qu(Uplus), qu.qu(Uplus_dagger)
Пример #25
0
def three_qubit_U_matrix(qlattice, qstabs=None):
    '''
    TODO: 
    *define SX_vert (vertices acted on by Z-stabilizer)
    '''
    sectors = {1.0: 0,  -1.0: 1}
    X, Y, Z, I = (qu.pauli(mu) for mu in ['x','y','z','i'])
    opmap = {'X': X, 'Y':Y, 'Z':Z, 'I':I}

    face_dims = [2]*3 #dimensions of face-qubit subspace


    if qstabs==None:

        qstab_A = loopStabOperator( vert_inds=[1,2,5,4],
                                    face_op_str='XYI',
                                    face_inds=[12,13,14])  

        qstab_B = loopStabOperator( vert_inds=[3,4,7,6],
                                    face_op_str='YXY',
                                    face_inds=[12,13,14])  
        
        qstab_C = loopStabOperator( vert_inds=[7,8,11,10],
                                    face_op_str='IYX',
                                    face_inds=[12,13,14])                                                                 
    

    SA = qu.kron(*[opmap[Q] for Q in qstab_A.face_op_str])
    SB = qu.kron(*[opmap[Q] for Q in qstab_B.face_op_str])
    SC = qu.kron(*[opmap[Q] for Q in qstab_C.face_op_str])
    # SA, SB, SC = X&Y&I, Y&X&Y, I&Y&X 

    eigfaces = np.ndarray(shape=face_dims, dtype=object)


    for signA, indA in sectors.items():

        eva, Ua = qu.eigh(SA)
        Ua_sector = Ua[:,eva==signA] #8x4

        Qb = Ua_sector.H @ SB @ Ua_sector
        # Qc = Ua_sector.H @ SC @ Ua_sector
        
        evb, Ub = qu.eigh(Qb)

        for signB, indB in sectors.items():

            Ub_sector = Ub[:, np.isclose(evb,signB)] #4x2

            #SC on b-eigenspace
            Qc = Ub_sector.H @ Ua_sector.H @ SC @ Ua_sector @ Ub_sector #2x2
            
            evc, Uc = qu.eigh(Qc)

            for signC, indC in sectors.items():
                
                #should be in a 1-dimensional subspace now
                vec = Uc[:,np.isclose(evc,signC)]

                #vector in 8-dim face qubit space
                face_vec = Ua_sector @ Ub_sector @ vec

                assert np.allclose(SA@face_vec, signA*face_vec)
                assert np.allclose(SB@face_vec, signB*face_vec)
                assert np.allclose(SC@face_vec, signC*face_vec)
                
                eigfaces[indA,indB,indC] = face_vec


    Nfermi, Nqubit = qlattice._Nfermi, qlattice._Nsites
    code_dims = [2]*Nfermi #vertices 
    qub_dims = [2]*Nqubit #vertices&faces


    #######
    qindices_A = qstab_A.vert_inds
    qindices_B = qstab_B.vert_inds
    qindices_C = qstab_C.vert_inds
    #######

    #parts of stabilizers acting only on vertex qubits
    SA_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_A,
                    dims=code_dims)

    SB_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_B,
                        dims=code_dims)
    
    SC_vert = qu.ikron(ops=[Z,Z,Z,Z], inds=qindices_C,
                        dims=code_dims)
                    
    Uplus = np.ndarray(shape=(2**Nqubit, 2**Nfermi))

    print('here')
    for k in range(2**Nfermi):
        print(k%10)
        #state of vertex qubits, all local z-eigenstates
        vertex_state = qu.basis_vec(i=k, dim=2**Nfermi)

        secA = sectors[qu.expec(SA_vert, vertex_state)]
        secB = sectors[qu.expec(SB_vert, vertex_state)]
        secC = sectors[qu.expec(SC_vert, vertex_state)]

        face_state = eigfaces[secA, secB, secC] 

        full_state = vertex_state & face_state

        #"stable" eigenstate written in qubit basis
        Uplus[:,k] = full_state.flatten()

        #full_state should be +1 eigenstate of all stabilizers
        assert np.allclose((SA_vert&SA) @ full_state, full_state)
        assert np.allclose((SB_vert&SB) @ full_state, full_state)
        assert np.allclose((SC_vert&SC) @ full_state, full_state)

    return qu.qu(Uplus)
Пример #26
0
 def test_against_arpack(self):
     A = qu.rand_herm(32, dtype=float)
     lk, vk = qu.eigh(A, k=6, backend='lobpcg')
     slk, svk = qu.eigh(A, k=6, backend='scipy')
     assert_allclose(lk, slk)
     assert_allclose(np.eye(6), abs(vk.H @ svk), atol=1e-9, rtol=1e-9)