def test_lattice(): chinfo = npc.ChargeInfo([1, 3]) leg = gen_random_legcharge(chinfo, 8) leg2 = gen_random_legcharge(chinfo, 2) op1 = npc.Array.from_func(np.random.random, [leg, leg.conj()], shape_kw='size') op2 = npc.Array.from_func(np.random.random, [leg2, leg2.conj()], shape_kw='size') site1 = lattice.Site(leg, [('up', 0), ('down', -1)], op1=op1) site2 = lattice.Site(leg2, [('down', 0), ('up', -1)], op2=op2) for order in ['default', 'Fstyle', 'snake', 'snakeFstyle']: print("order =", order) Ls = [5, 2] basis = [[1., 1.], [0., 1.]] pos = [[0.1, 0.], [0.2, 0.]] lat = lattice.Lattice(Ls, [site1, site2], order=order, basis=basis, positions=pos, bc='periodic', bc_MPS='infinite') assert lat.dim == len(Ls) assert lat.N_sites == np.prod(Ls) * 2 for i in range(lat.N_sites): assert lat.lat2mps_idx(lat.mps2lat_idx(i)) == i idx = [4, 1, 0] assert np.all(lat.mps2lat_idx(lat.lat2mps_idx(idx)) == idx) # index conversion should also work for arbitrary index arrays and indices outside bc_MPS # for bc_MPS=infinite i = np.arange(-3, lat.N_sites * 2 - 3).reshape((-1, 2)) assert np.all(lat.lat2mps_idx(lat.mps2lat_idx(i)) == i) # test position npt.assert_equal([4.1, 5.], lat.position(idx)) # test lat.mps2lat_values A = np.random.random([lat.N_sites, 2, lat.N_sites]) print(A.shape) Ares = lat.mps2lat_values(A, axes=[-1, 0]) Ares_ma = lat.mps2lat_values_masked(A, [-1, 0], [None] * 2, [None] * 2) for i in range(lat.N_sites): idx_i = lat.mps2lat_idx(i) for j in range(lat.N_sites): idx_j = lat.mps2lat_idx(j) for k in range(2): idx = tuple(idx_i) + (k, ) + tuple(idx_j) assert Ares[idx] == A[i, k, j] assert Ares_ma[idx] == A[i, k, j] # and again for fixed `u` within the unit cell for u in range(len(lat.unit_cell)): mps_u = lat.mps_idx_fix_u(u) A_u = A[np.ix_(mps_u, np.arange(2), mps_u)] A_u_res = lat.mps2lat_values(A_u, axes=[-1, 0], u=u) A_u_res_masked = lat.mps2lat_values_masked(A_u, axes=[-1, 0], mps_inds=[mps_u] * 2, include_u=[False] * 2) A_u_expected = Ares[:, :, u, :, :, :, u] npt.assert_equal(A_u_res, A_u_expected) npt.assert_equal(A_u_res_masked, A_u_expected)
def test_npc_Array_reshape(): a = random_Array((20, 15, 10), chinfo, sort=False) aflat = a.to_ndarray() for comb_legs, transpose in [([[1]], [0, 1, 2]), ([[1], [2]], [0, 1, 2]), ([[0], [1], [2]], [0, 1, 2]), ([[2, 0]], [1, 2, 0]), ([[2, 0, 1]], [2, 0, 1])]: print('combine legs', comb_legs) with warnings.catch_warnings(): warnings.simplefilter("ignore", FutureWarning) acomb = a.combine_legs(comb_legs) # just sorts second leg print("=> labels: ", acomb.get_leg_labels()) acomb.test_sanity() asplit = acomb.split_legs() asplit.test_sanity() npt.assert_equal(asplit.to_ndarray(), aflat.transpose(transpose)) print("test squeeze") b = random_Array((10, 1, 5, 1), chinfo3, sort=True) bflat = b.to_ndarray() bs = b.squeeze() bs.test_sanity() npt.assert_equal(bs.to_ndarray(), np.squeeze(bflat)) bs.test_sanity() if b.stored_blocks > 0: # find a index with non-zero entry idx = tuple([l.slices[qi] for l, qi in zip(b.legs, b._qdata[0])]) else: idx = tuple([0] * b.rank) assert b[idx[0], :, idx[2], :].squeeze() == bflat[idx] print("test add_trivial_leg") be = bs.copy(deep=True).add_trivial_leg(1, 'tr1', +1).add_trivial_leg(3, 'tr2', -1) be.test_sanity() npt.assert_equal(be.to_ndarray(), bflat) print("test concatenate") # create array `c` to concatenate with b along axis 2 legs = b.legs[:] legs[1] = gen_random_legcharge(b.chinfo, 5) c1 = npc.Array.from_func(np.random.random, legs, qtotal=b.qtotal, shape_kw='size') c1flat = c1.to_ndarray() legs[1] = gen_random_legcharge(b.chinfo, 3) c2 = npc.Array.from_func(np.random.random, legs, qtotal=b.qtotal, shape_kw='size') c2flat = c2.to_ndarray() bc1c2 = npc.concatenate([b, c1, c2], axis=1) bc1c2.test_sanity() npt.assert_equal(bc1c2.to_ndarray(), np.concatenate([bflat, c1flat, c2flat], axis=1)) print("trivial charges") a = npc.Array.from_func(np.random.random, [lcTr, lcTr.conj()], shape_kw='size') aflat = a.to_ndarray() acomb = a.combine_legs([0, 1]) acomb.test_sanity() asplit = acomb.split_legs([0]) asplit.test_sanity() npt.assert_equal(asplit.to_ndarray(), aflat)
def test_npc_grid_concat(): # this is also a heavy test of Array.__getitem__ ci = chinfo3 legs = [gen_random_legcharge(ci, l) for l in [5, 4, 3]] A = npc.Array.from_func(np.random.random, legs, qtotal=[0], shape_kw='size') print("orig legs") for l in legs: print(l) print('---') Aflat = A.to_ndarray() grid = [A[..., :2, :], A[:, 2:3, ...], A[:, 3:]] A_full = npc.grid_concat(grid, [1]) npt.assert_equal(Aflat, A_full.to_ndarray()) grid = [[A[:, :1, 2:3], A[:, :1, 0:2]], [A[:, 2:, 2:3], A[:, 2:, 0:2]]] # yapf: disable A_part = npc.grid_concat(grid, [1, 2]).to_ndarray() A_part_exact = Aflat[:, [0, 2, 3], :][:, :, [2, 0, 1]] npt.assert_equal(A_part, A_part_exact) grid[1][0] = None A_part = npc.grid_concat(grid, [1, 2]).to_ndarray() A_part_exact[:, 1:, 0] = 0. npt.assert_equal(A_part, A_part_exact)
def test_npc_grid_outer(): ci = chinfo3 p_leg = gen_random_legcharge(ci, 4) legs_op = [p_leg, p_leg.conj()] op_0 = 1.j * npc.Array.from_func(np.random.random, legs_op, qtotal=[0], shape_kw='size') op_pl = npc.Array.from_func(np.random.random, legs_op, qtotal=[1], shape_kw='size') op_min = npc.Array.from_func(np.random.random, legs_op, qtotal=[-1], shape_kw='size') op_id = npc.eye_like(op_0) grid = [[op_id, op_pl, op_min, op_0, None], [None, None, None, None, op_min], [None, None, None, None, op_pl], [None, None, None, None, op_0], [None, None, None, None, op_id]] # yapf: disable leg_WL = npc.LegCharge.from_qflat(ci, ci.make_valid([[0], [1], [-1], [0], [0]])) leg_WR = npc.LegCharge.from_qflat(ci, ci.make_valid([[0], [1], [-1], [0], [0]]), -1) leg_WR_calc = npc.detect_grid_outer_legcharge(grid, [leg_WL, None], qconj=-1)[1] leg_WR.test_equal(leg_WR_calc) W = npc.grid_outer(grid, [leg_WL, leg_WR]) W.test_sanity() Wflat = np.zeros([5, 5, 4, 4], dtype=W.dtype) for idx, op in [[(0, 0), op_id], [(0, 1), op_pl], [(0, 2), op_min], [(0, 3), op_0], [(1, 4), op_min], [(2, 4), op_pl], [(3, 4), op_0], [(4, 4), op_id]]: Wflat[idx] = op.to_ndarray() npt.assert_equal(W.to_ndarray(), Wflat)
def test_LegPipe(): shape = (20, 10, 8) legs = [gen_random_legcharge(ch_1, s) for s in shape] for sort, bunch in it.product([True, False], repeat=2): pipe = charges.LegPipe(legs, sort=sort, bunch=bunch) pipe.test_sanity() pipe_conj = pipe.conj() pipe.test_contractible(pipe.conj()) pipe_equal = pipe.flip_charges_qconj() pipe_equal.test_equal(pipe) assert (pipe.ind_len == np.prod(shape)) print(pipe.q_map) # test pipe._map_incoming_qind qind_inc = pipe.q_map[:, 3:].copy() # all possible qindices np.random.shuffle( qind_inc) # different order to make the test non-trivial qmap_ind = pipe._map_incoming_qind(qind_inc) for i in range(len(qind_inc)): npt.assert_equal(pipe.q_map[qmap_ind[i], 3:], qind_inc[i]) size = np.prod([ l.slices[j + 1] - l.slices[j] for l, j in zip(legs, qind_inc[i]) ]) assert size == pipe.q_map[qmap_ind[i], 1] - pipe.q_map[qmap_ind[i], 0]
def test_site(): chinfo = npc.ChargeInfo([1, 3]) leg = gen_random_legcharge(chinfo, 8) op1 = npc.Array.from_func(np.random.random, [leg, leg.conj()], shape_kw='size') op2 = npc.Array.from_func(np.random.random, [leg, leg.conj()], shape_kw='size') labels = ['up'] + [None] * (leg.ind_len - 2) + ['down'] s = site.Site(leg, labels, silly_op=op1) assert s.state_index('up') == 0 assert s.state_index('down') == leg.ind_len - 1 assert s.opnames == set(['silly_op', 'Id', 'JW']) assert s.silly_op is op1 s.add_op('op2', op2) assert s.op2 is op2 assert s.get_op('op2') is op2 assert s.get_op('silly_op') is op1 npt.assert_equal( s.get_op('silly_op op2').to_ndarray(), npc.tensordot(op1, op2, [1, 0]).to_ndarray()) leg2 = npc.LegCharge.from_drop_charge(leg, 1) leg2 = npc.LegCharge.from_change_charge(leg2, 0, 2, 'changed') s2 = copy.deepcopy(s) s2.change_charge(leg2) perm_qind, leg2s = leg2.sort() perm_flat = leg2.perm_flat_from_perm_qind(perm_qind) s2s = copy.deepcopy(s2) s2s.change_charge(leg2s, perm_flat) for site_check in [s2, s2s]: print("site_check.leg = ", site_check.leg) for opn in site_check.opnames: op1 = s.get_op(opn).to_ndarray() op2 = site_check.get_op(opn).to_ndarray() perm = site_check.perm npt.assert_equal(op1[np.ix_(perm, perm)], op2)
def test_FlatHermitianOperator(n=30, k=5, tol=5.e-15): 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_sparse = sparse.FlatHermitianOperator.from_NpcArray(H, charge_sector=qtotal) psi_init = npc.Array.from_func(np.random.random, [leg], qtotal=qtotal) psi_init /= npc.norm(psi_init) psi_init_flat = H_sparse.npc_to_flat(psi_init) # check diagonalization E, psi = scipy.sparse.linalg.eigsh(H_sparse, k, v0=psi_init_flat, which='SA') E0, psi0 = E[0], psi[:, 0] 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)) assert (abs((E0 - E0_flat) / E0_flat) < tol) psi0_H_psi0 = np.inner(psi0.conj(), H_sparse.matvec(psi0)).item() print("<psi0|H|psi0> / E0 = 1. + ", psi0_H_psi0 / E0 - 1.) assert (abs(psi0_H_psi0 / E0 - 1.) < tol)
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)
def test_eig(): size = 10 max_nulp = 10 * size**3 ci = chinfo3 l = gen_random_legcharge(ci, size) A = npc.Array.from_func(np.random.random, [l, l.conj()], qtotal=None, shape_kw='size') print("hermitian A") A += A.conj().itranspose() Aflat = A.to_ndarray() W, V = npc.eigh(A, sort='m>') V.test_sanity() V_W = V.scale_axis(W, axis=-1) recalc = npc.tensordot(V_W, V.conj(), axes=[1, 1]) npt.assert_array_almost_equal_nulp(Aflat, recalc.to_ndarray(), max_nulp) Wflat, Vflat = np.linalg.eigh(Aflat) npt.assert_array_almost_equal_nulp(np.sort(W), Wflat, max_nulp) W2 = npc.eigvalsh(A, sort='m>') npt.assert_array_almost_equal_nulp(W, W2, max_nulp) print("check complex B") B = 1.j * npc.Array.from_func(np.random.random, [l, l.conj()], shape_kw='size') B += B.conj().itranspose() B = A + B Bflat = B.to_ndarray() W, V = npc.eigh(B, sort='m>') V.test_sanity() recalc = npc.tensordot(V.scale_axis(W, axis=-1), V.conj(), axes=[1, 1]) npt.assert_array_almost_equal_nulp(Bflat, recalc.to_ndarray(), max_nulp) Wflat, Vflat = np.linalg.eigh(Bflat) npt.assert_array_almost_equal_nulp(np.sort(W), Wflat, max_nulp) print("calculate without 'hermitian' knownledge") W, V = npc.eig(B, sort='m>') assert (np.max(np.abs(W.imag)) < EPS * max_nulp) npt.assert_array_almost_equal_nulp(np.sort(W.real), Wflat, max_nulp) print("sparse speigs") qi = 1 ch_sect = B.legs[0].get_charge(qi) k = min(3, B.legs[0].slices[qi + 1] - B.legs[0].slices[qi]) Wsp, Vsp = npc.speigs(B, ch_sect, k=k, which='LM') for W_i, V_i in zip(Wsp, Vsp): V_i.test_sanity() diff = npc.tensordot(B, V_i, axes=1) - V_i * W_i assert (npc.norm(diff, np.inf) < EPS * max_nulp) print("for trivial charges") A = npc.Array.from_func(np.random.random, [lcTr, lcTr.conj()], shape_kw='size') A = A + A.conj().itranspose() Aflat = A.to_ndarray() W, V = npc.eigh(A) recalc = npc.tensordot(V.scale_axis(W, axis=-1), V.conj(), axes=[1, 1]) npt.assert_array_almost_equal_nulp(Aflat, recalc.to_ndarray(), 10 * A.shape[0]**3)
def test_expm(size=10): ci = chinfo3 l = gen_random_legcharge(ci, size) A = npc.Array.from_func(np.random.random, [l, l.conj()], qtotal=None, shape_kw='size') A_flat = A.to_ndarray() exp_A = npc.expm(A) exp_A.test_sanity() from scipy.linalg import expm npt.assert_array_almost_equal_nulp(expm(A_flat), exp_A.to_ndarray(), size * size)
def test_lattice(): chinfo = npc.ChargeInfo([1, 3]) leg = gen_random_legcharge(chinfo, 8) leg2 = gen_random_legcharge(chinfo, 2) op1 = npc.Array.from_func(np.random.random, [leg, leg.conj()], shape_kw='size') op2 = npc.Array.from_func(np.random.random, [leg2, leg2.conj()], shape_kw='size') site1 = lattice.Site(leg, [('up', 0), ('down', -1)], op1=op1) site2 = lattice.Site(leg2, [('down', 0), ('up', -1)], op2=op2) for order in ['default', 'Fstyle', 'snake', 'snakeFstyle']: print("order =", order) Ls = [5, 2] basis = [[1., 1.], [0., 1.]] pos = [[0.1, 0.], [0.2, 0.]] lat = lattice.Lattice(Ls, [site1, site2], order=order, basis=basis, positions=pos) nst.eq_(lat.dim, len(Ls)) nst.eq_(lat.N_sites, np.prod(Ls) * 2) for i in range(lat.N_sites): nst.eq_(lat.lat2mps_idx(lat.mps2lat_idx(i)), i) idx = (4, 1, 0) nst.eq_(lat.mps2lat_idx(lat.lat2mps_idx(idx)), idx) npt.assert_equal([4.1, 5.], lat.position(idx)) # test lat.mps2lat_values A = np.random.random([lat.N_sites, 2, lat.N_sites]) print(A.shape) Ares = lat.mps2lat_values(A, axes=[-1, 0]) for i in range(lat.N_sites): idx_i = lat.mps2lat_idx(i) for j in range(lat.N_sites): idx_j = lat.mps2lat_idx(j) for k in range(2): idx = idx_i + (k, ) + idx_j nst.eq_(Ares[idx], A[i, k, j]) # and again for fixed `u` within the unit cell for u in range(len(lat.unit_cell)): A_u = A[np.ix_(lat.mps_idx_fix_u(u), np.arange(2), lat.mps_idx_fix_u(u))] A_u_res = lat.mps2lat_values(A_u, axes=[-1, 0], u=u) npt.assert_equal(A_u_res, Ares[:, :, u, :, :, :, u])
def test_trace(): chinfo = chinfo3 legs = [gen_random_legcharge(chinfo, s) for s in (7, 8, 9)] legs.append(legs[1].conj()) A = npc.Array.from_func(np.random.random, legs, qtotal=[1], shape_kw='size') Aflat = A.to_ndarray() Atr = npc.trace(A, leg1=1, leg2=-1) Atr.test_sanity() Aflattr = np.trace(Aflat, axis1=1, axis2=-1) npt.assert_array_almost_equal_nulp(Atr.to_ndarray(), Aflattr, A.shape[1])
def test_gramschmidt(n=30, k=5, tol=1.e-15): leg = gen_random_legcharge(ch, n) vecs_old = [ npc.Array.from_func(np.random.random, [leg], shape_kw='size') for i in range(k) ] vecs_new, _ = lanczos.gram_schmidt(vecs_old, rcond=0., verbose=1) assert all([v == w for v, w in zip(vecs_new, vecs_old)]) vecs_new, _ = lanczos.gram_schmidt(vecs_old, rcond=tol, verbose=1) vecs = [v.to_ndarray() for v in vecs_new] ovs = np.zeros((k, k)) for i, v in enumerate(vecs): for j, w in enumerate(vecs): ovs[i, j] = np.inner(v.conj(), w) print(ovs) assert (np.linalg.norm(ovs - np.eye(k)) < 2 * n * k * k * tol)
def test_arnoldi(n, which): tol = 5.e-14 if n <= 20 else 1.e-10 # generate Hermitian test array leg = gen_random_legcharge(ch, n) # if looking for small/large real part, ensure hermitian H func = rmat.GUE if which[-1] == 'R' else rmat.standard_normal_complex H = npc.Array.from_func_square(func, leg) H_flat = H.to_ndarray() E_flat, psi_flat = np.linalg.eig(H_flat) if which == 'LM': i = np.argmax(np.abs(E_flat)) elif which == 'LR': i = np.argmax(np.real(E_flat)) elif which == 'SR': i = np.argmin(np.real(E_flat)) E0_flat, psi0_flat = E_flat[i], psi_flat[:, i] 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) eng = lanczos.Arnoldi(H_Op, psi_init, { 'which': which, 'num_ev': 1, 'N_max': 20 }) (E0, ), (psi0, ), N = eng.run() 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)) assert abs((E0 - E0_flat) / E0_flat) < tol 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)
def test_lanczos_evolve(n, N_cache, tol=5.e-15): # generate Hermitian test array leg = gen_random_legcharge(ch, n) H = npc.Array.from_func_square(rmat.GUE, leg) - npc.diag(1., leg) H_flat = H.to_ndarray() H_Op = H # use `matvec` of the array qtotal = leg.to_qflat()[0] psi_init = npc.Array.from_func(np.random.random, [leg], qtotal=qtotal) psi_init /= npc.norm(psi_init) psi_init_flat = psi_init.to_ndarray() lanc = lanczos.LanczosEvolution(H_Op, psi_init, { 'verbose': 1, 'N_cache': N_cache }) for delta in [-0.1j, 0.1j, 1.j]: #, 0.1, 1.]: psi_final_flat = expm(H_flat * delta).dot(psi_init_flat) psi_final, N = lanc.run(delta) ov = np.inner(psi_final.to_ndarray().conj(), psi_final_flat) ov /= np.linalg.norm(psi_final_flat) print("<psi1|psi1_flat>/norm=", ov) assert (abs(1. - abs(ov)) < tol)
def test_lanczos_evolve(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) - npc.diag(1., leg) H_flat = H.to_ndarray() H_Op = H # use `matvec` of the array qtotal = leg.to_qflat()[0] psi_init = npc.Array.from_func(np.random.random, [leg], qtotal=qtotal) #psi_init /= npc.norm(psi_init) # not necessary psi_init_flat = psi_init.to_ndarray() lanc = lanczos.LanczosEvolution(H_Op, psi_init, {'N_cache': N_cache}) for delta in [-0.1j, 0.1j, 1.j, 0.1, 1.]: psi_final_flat = expm(H_flat * delta).dot(psi_init_flat) norm = np.linalg.norm(psi_final_flat) psi_final, N = lanc.run(delta, normalize=False) diff = np.linalg.norm(psi_final.to_ndarray() - psi_final_flat) print("norm(|psi_final> - |psi_final_flat>)/norm = ", diff / norm) # should be 1. assert diff / norm < tol psi_final2, N = lanc.run(delta, normalize=True) assert npc.norm(psi_final / norm - psi_final2) < tol
def test_FlatHermitianOperator(n=30, k=5, tol=1.e-14): leg = gen_random_legcharge(ch, n // 2) leg2 = gen_random_legcharge(ch, 2) pipe = npc.LegPipe([leg, leg2], qconj=+1) H = npc.Array.from_func_square(rmat.GUE, pipe) H.iset_leg_labels(["(a.b)", "(a*.b*)"]) 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, [pipe]) H_sparse = sparse.FlatHermitianOperator.from_NpcArray(H, charge_sector=qtotal) psi_init = npc.Array.from_func(np.random.random, [pipe], qtotal=qtotal) psi_init /= npc.norm(psi_init) psi_init.iset_leg_labels(["(a.b)"]) psi_init_flat = H_sparse.npc_to_flat(psi_init) # check diagonalization E, psi = scipy.sparse.linalg.eigsh(H_sparse, k, v0=psi_init_flat, which='SA') E0, psi0 = E[0], psi[:, 0] 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)) assert (abs((E0 - E0_flat) / E0_flat) < tol) psi0_H_psi0 = np.inner(psi0.conj(), H_sparse.matvec(psi0)).item() print("<psi0|H|psi0> / E0 = 1. + ", psi0_H_psi0 / E0 - 1.) assert (abs(psi0_H_psi0 / E0 - 1.) < tol) # split H to check `FlatHermitianOperator.from_guess_with_pipe`. print("=========") print("split legs and define separate matvec") assert psi_init.legs[0] is pipe psi_init_split = psi_init.split_legs([0]) H_split = H.split_legs() def H_split_matvec(vec): vec = npc.tensordot(H_split, vec, [["a*", "b*"], ["a", "b"]]) # TODO as additional challenge, transpose the resulting vector return vec H_sparse_split, psi_init_split_flat = sparse.FlatLinearOperator.from_guess_with_pipe( H_split_matvec, psi_init_split, dtype=H_split.dtype) # diagonalize E, psi = scipy.sparse.linalg.eigsh(H_sparse_split, k, v0=psi_init_split_flat, which='SA') E0, psi0 = E[0], psi[:, 0] 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)) assert (abs((E0 - E0_flat) / E0_flat) < tol) psi0_H_psi0 = np.inner(psi0.conj(), H_sparse.matvec(psi0)).item() print("<psi0|H|psi0> / E0 = 1. + ", psi0_H_psi0 / E0 - 1.) assert (abs(psi0_H_psi0 / E0 - 1.) < tol)
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!" )