Ejemplo n.º 1
0
def test_lanczos(n=30, k=5, tol=5.e-15):
    # generate Hermitian test array
    leg = gen_random_legcharge(ch, n)
    H = npc.Array.from_func_square(rmat.GUE, leg)
    H_flat = H.to_ndarray()
    E_flat, psi_flat = np.linalg.eigh(H_flat)
    E0_flat, psi0_flat = E_flat[0], psi_flat[:, 0]
    qtotal = npc.detect_qtotal(psi0_flat, [leg])

    H_Op = H  # use `matvec` of the array
    psi_init = npc.Array.from_func(np.random.random, [leg], qtotal=qtotal)

    E0, psi0, N = lanczos.lanczos(H_Op, psi_init, {'verbose': 1})
    print("full spectrum:", E_flat)
    print("E0 = {E0:.14f} vs exact {E0_flat:.14f}".format(E0=E0,
                                                          E0_flat=E0_flat))
    print("|E0-E0_flat| / |E0_flat| =", abs((E0 - E0_flat) / E0_flat))
    psi0_H_psi0 = npc.inner(psi0,
                            npc.tensordot(H, psi0, axes=[1, 0]),
                            do_conj=True)
    print("<psi0|H|psi0> / E0 = 1. + ", psi0_H_psi0 / E0 - 1.)
    assert (abs(psi0_H_psi0 / E0 - 1.) < tol)
    print("<psi0_flat|H_flat|psi0_flat> / E0_flat = ", end=' ')
    print(np.inner(psi0_flat.conj(), np.dot(H_flat, psi0_flat)) / E0_flat)
    ov = np.inner(psi0.to_ndarray().conj(), psi0_flat)
    print("|<psi0|psi0_flat>|=", abs(ov))
    assert (abs(1. - abs(ov)) < tol)

    # now repeat, but keep orthogonal to original ground state
    # -> should give second eigenvector psi1 in the same charge sector
    for i in range(1, len(E_flat)):
        E1_flat, psi1_flat = E_flat[i], psi_flat[:, i]
        qtotal = npc.detect_qtotal(psi1_flat, psi0.legs)
        if np.all(qtotal == psi0.qtotal):
            break  # found psi1 in same charge sector
    else:
        print(
            "warning: test didn't find a second eigenvector in the same charge sector!"
        )
        return  # just ignore the rest....
    E1, psi1, N = lanczos.lanczos(H_Op,
                                  psi_init, {'verbose': 1},
                                  orthogonal_to=[psi0])
    print("E1 = {E1:.14f} vs exact {E1_flat:.14f}".format(E1=E1,
                                                          E1_flat=E1_flat))
    print("|E1-E1_flat| / |E1_flat| =", abs((E1 - E1_flat) / E1_flat))
    psi1_H_psi1 = npc.inner(psi1,
                            npc.tensordot(H, psi1, axes=[1, 0]),
                            do_conj=True)
    print("<psi1|H|psi1> / E1 = 1 + ", psi1_H_psi1 / E1 - 1.)
    assert (abs(psi1_H_psi1 / E1 - 1.) < tol)
    print("<psi1_flat|H_flat|psi1_flat> / E1_flat = ", end=' ')
    print(np.inner(psi1_flat.conj(), np.dot(H_flat, psi1_flat)) / E1_flat)
    ov = np.inner(psi1.to_ndarray().conj(), psi1_flat)
    print("|<psi1|psi1_flat>|=", abs(ov))
    assert (abs(1. - abs(ov)) < tol)
    # and finnally check also orthogonality to psi0
    ov = npc.inner(psi0, psi1, do_conj=True)
    print("|<psi0|psi1>| =", abs(ov))
    assert (abs(ov) < tol**0.5)
Ejemplo n.º 2
0
def test_ED():
    # just quickly check that it runs without errors for a small system
    xxz_pars = dict(L=4, Jxx=1., Jz=1., hz=0.0, bc_MPS='finite')
    M = XXZChain(xxz_pars)
    ED = ExactDiag(M)
    ED.build_full_H_from_mpo()
    H, ED.full_H = ED.full_H, None
    ED.build_full_H_from_bonds()
    H2 = ED.full_H
    assert (npc.norm(H - H2, np.inf) < 1.e-14)
    ED.full_diagonalization()
    psi = ED.groundstate()
    print("select charge_sector =", psi.qtotal)
    ED2 = ExactDiag(M, psi.qtotal)
    ED2.build_full_H_from_mpo()
    ED2.full_diagonalization()
    psi2 = ED2.groundstate()
    full_psi2 = psi.zeros_like()
    full_psi2[ED2._mask] = psi2
    ov = npc.inner(psi, full_psi2, do_conj=True)
    print("overlab <psi | psi2> = 1. -", 1. - ov)
    assert (abs(abs(ov) - 1.) < 1.e-15)
    # starting from a random guess in the correct charge sector,
    # check if we can also do lanczos.
    np.random.seed(12345)
    psi3 = npc.Array.from_func(np.random.random,
                               psi2.legs,
                               qtotal=psi2.qtotal,
                               shape_kw='size')
    E0, psi3, N = lanczos(ED2, psi3)
    print("Lanczos E0 =", E0)
    ov = npc.inner(psi3, psi2, do_conj=True)
    print("overlab <psi2 | psi3> = 1. -", 1. - ov)
    assert (abs(abs(ov) - 1.) < 1.e-15)
Ejemplo n.º 3
0
def test_lanczos_gs(n, N_cache, tol=5.e-14):
    # generate Hermitian test array
    leg = gen_random_legcharge(ch, n)
    H = npc.Array.from_func_square(rmat.GUE, leg)
    H_flat = H.to_ndarray()
    E_flat, psi_flat = np.linalg.eigh(H_flat)
    E0_flat, psi0_flat = E_flat[0], psi_flat[:, 0]
    qtotal = npc.detect_qtotal(psi0_flat, [leg])

    H_Op = H  # use `matvec` of the array
    psi_init = npc.Array.from_func(np.random.random, [leg], qtotal=qtotal)

    E0, psi0, N = lanczos.lanczos(H_Op, psi_init, {
        'verbose': 1,
        'N_cache': N_cache
    })
    print("full spectrum:", E_flat)
    print("E0 = {E0:.14f} vs exact {E0_flat:.14f}".format(E0=E0,
                                                          E0_flat=E0_flat))
    print("|E0-E0_flat| / |E0_flat| =", abs((E0 - E0_flat) / E0_flat))
    psi0_H_psi0 = npc.inner(psi0,
                            npc.tensordot(H, psi0, axes=[1, 0]),
                            'range',
                            do_conj=True)
    print("<psi0|H|psi0> / E0 = 1. + ", psi0_H_psi0 / E0 - 1.)
    assert (abs(psi0_H_psi0 / E0 - 1.) < tol)
    print("<psi0_flat|H_flat|psi0_flat> / E0_flat = ", end=' ')
    print(np.inner(psi0_flat.conj(), np.dot(H_flat, psi0_flat)) / E0_flat)
    ov = np.inner(psi0.to_ndarray().conj(), psi0_flat)
    print("|<psi0|psi0_flat>|=", abs(ov))
    assert (abs(1. - abs(ov)) < tol)

    print("version with arpack")
    E0a, psi0a = lanczos.lanczos_arpack(H_Op, psi_init, {'verbose': 1})
    print("E0a = {E0a:.14f} vs exact {E0_flat:.14f}".format(E0a=E0a,
                                                            E0_flat=E0_flat))
    print("|E0a-E0_flat| / |E0_flat| =", abs((E0a - E0_flat) / E0_flat))
    psi0a_H_psi0a = npc.inner(psi0a,
                              npc.tensordot(H, psi0a, axes=[1, 0]),
                              'range',
                              do_conj=True)
    print("<psi0a|H|psi0a> / E0a = 1. + ", psi0a_H_psi0a / E0a - 1.)
    assert (abs(psi0a_H_psi0a / E0a - 1.) < tol)
    ov = np.inner(psi0a.to_ndarray().conj(), psi0_flat)
    print("|<psi0a|psi0_flat>|=", abs(ov))
    assert (abs(1. - abs(ov)) < tol)

    # now repeat, but keep orthogonal to original ground state
    orthogonal_to = [psi0]
    # -> should give second eigenvector psi1 in the same charge sector
    for i in range(1, len(E_flat)):
        E1_flat, psi1_flat = E_flat[i], psi_flat[:, i]
        qtotal = npc.detect_qtotal(psi1_flat, psi0.legs, cutoff=1.e-10)
        if np.any(qtotal != psi0.qtotal):
            continue  # not in same charge sector
        print("--- excited state #", len(orthogonal_to))
        ortho_to = [psi.copy()
                    for psi in orthogonal_to]  # (gets modified inplace)
        lanczos_params = {'verbose': 1, 'reortho': True}
        if E1_flat > -0.01:
            lanczos_params['E_shift'] = -2. * E1_flat - 0.2
        E1, psi1, N = lanczos.lanczos(
            sparse.OrthogonalNpcLinearOperator(H_Op, ortho_to), psi_init,
            lanczos_params)
        print("E1 = {E1:.14f} vs exact {E1_flat:.14f}".format(E1=E1,
                                                              E1_flat=E1_flat))
        print("|E1-E1_flat| / |E1_flat| =", abs((E1 - E1_flat) / E1_flat))
        psi1_H_psi1 = npc.inner(psi1,
                                npc.tensordot(H, psi1, axes=[1, 0]),
                                'range',
                                do_conj=True)
        print("<psi1|H|psi1> / E1 = 1 + ", psi1_H_psi1 / E1 - 1.)
        assert (abs(psi1_H_psi1 / E1 - 1.) < tol)
        print("<psi1_flat|H_flat|psi1_flat> / E1_flat = ", end='')
        print(np.inner(psi1_flat.conj(), np.dot(H_flat, psi1_flat)) / E1_flat)
        ov = np.inner(psi1.to_ndarray().conj(), psi1_flat)
        print("|<psi1|psi1_flat>|=", abs(ov))
        assert (abs(1. - abs(ov)) < tol)
        # and finnally check also orthogonality to previous states
        for psi_prev in orthogonal_to:
            ov = npc.inner(psi_prev, psi1, 'range', do_conj=True)
            assert (abs(ov) < tol)
        orthogonal_to.append(psi1)
    if len(orthogonal_to) == 1:
        print(
            "warning: test didn't find a second eigenvector in the same charge sector!"
        )