Example #1
0
def get_T(pars):
    T = tensordispenser.get_normalized_tensor(pars)
    parts = ()
    if pars["do_coarse_momenta"]:
        # TODO Should this bond dimension be an independent parameter?
        chis = [chi for chi in pars["chis_trg"]]
        T_orig = T
        if pars["print_errors"]:
            print("Building the coarse-grained transfer matrix times "
                  "translation.")
        T_dg = T.conjugate().transpose((0, 3, 2, 1))
        y_env = scon(
            (T, T, T_dg, T_dg),
            ([1, -1, 5, 2], [5, -2, 3, 4], [1, 2, 6, -3], [6, 4, 3, -4]))
        U = y_env.eig((0, 1), (2, 3), hermitian=True, chis=chis)[1]
        y = U.conjugate().transpose((2, 0, 1))
        y_dg = y.conjugate().transpose((1, 2, 0))
        SW, NE = T.split((0, 3), (1, 2), chis=chis)
        SW = SW.transpose((0, 2, 1))
        NE = NE.transpose((1, 2, 0))
        T = scon(
            (NE, y, T, SW, y_dg),
            ([1, 3, -1], [-2, 1, 4], [3, 4, 6, 5], [6, -3, 2], [5, 2, -4]))
        parts = (y, y_dg, NE, SW, T_orig)
        # TODO quantify the error in this coarse-graining and print it.
    return T, parts
Example #2
0
def optimize_isometries(u, v, w, A_list, A_part_list, pars, gauges, chi=None):
    # Compute environments M_v and M_w
    if chi is None:
        chi_v = type(u).flatten_dim(v.shape[1])
        chi_w = type(u).flatten_dim(w.shape[0])
    else:
        chi_v = chi
        chi_w = chi
    if pars["print_errors"] > 2:
        print('Optimizing isometries.')
    for i in range(pars["opt_iters_tens"]):
        upb = upper_block(u, v, w, A_list, A_part_list, pars)
        if pars["use_parts"]:
            # TODO Could figure out a way to do this in O(chi^6). I
            # wasn't able to come up with one and probably this won't be
            # used much, so I left it be.
            warnings.warn("In TNR, use_parts is True but is not utilized in "
                          "optimize_disentanglers. Reverting back to the "
                          "O(chi^7) algorithm.")
        # This is O(chi^7).
        env_top = scon(
            (v, u, A_list[0], A_list[1]),
            ([1, -3, 3], [-2, 1, 4, 2], [-1, 4, 5, -4], [5, 2, 3, -5]))
        env_top_dg = env_top.conjugate().transpose((0, 3, 4, 2, 1))
        M_w = scon(
            (env_top, upb_dg(upb), upb, env_top_dg),
            ([-1, -2, 7, 3, 4], [3, 4, 2, 1], [1, 2, 5, 6], [-3, 5, 6, 7, -4]))
        # Get the optimal isometry by SVDing the environment.
        S, U = M_w.eig((0, 1), (2, 3),
                       chis=chi_w,
                       hermitian=True,
                       print_errors=pars["print_errors"] - 2)
        w = U.conjugate().transpose((2, 1, 0))
        if pars["horz_refl"]:
            v = w_hat(w, gauges)
        else:
            if pars["use_parts"]:
                # TODO see above.
                warnings.warn("In TNR, use_parts is True but is not utilized "
                              "in optimize_disentanglers. Reverting back to "
                              "the O(chi^7) algorithm.")
            # This is O(chi^7).
            env_top = scon(
                (w, u, A_list[0], A_list[1]),
                ([-1, 1, 2], [1, -2, 3, 4], [2, 3, 5, -4], [5, 4, -3, -5]))
            env_top_dg = env_top.conjugate().transpose((3, 4, 2, 1, 0))
            M_v = scon((env_top, upb_dg(upb), upb, env_top_dg),
                       ([5, -1, -2, 3, 4
                         ], [3, 4, 2, 1], [1, 2, 6, 7], [6, 7, -4, -3, 5]))
            S, U = M_v.eig((0, 1), (2, 3),
                           chis=chi_v,
                           hermitian=True,
                           print_errors=pars["print_errors"] - 2)
            v = U.conjugate().transpose((0, 2, 1))
            v = v.flip_dir(1)
    return v, w
Example #3
0
def fix_A_new_gauge_optimize_X(A_new, A, X, Y):
    X_dg = matrix_dagger(X)
    Y_dg = matrix_dagger(Y)
    env = scon((A.conjugate(), Y, A_new, Y_dg, X_dg),
               ([6, -2, 4, 5], [6, 2], [2, -1, 1, 3], [1, 4], [3, 5]))
    env_U, env_S, env_V = env.svd((0, ), (1, ))
    env_U_dg = matrix_dagger(env_U)
    env_V_dg = matrix_dagger(env_V)
    X = scon((env_V_dg, env_U_dg), ([-1, 1], [1, -2]))
    return X
Example #4
0
def A4_frob_norm_sq(A_list, A_part_list, pars):
    # This is O(chi^6). Thus no need to utilize A_part_list even if
    # pars["use_parts"] is True.
    NW_corner = scon((A_list[0], A_list[0].conjugate()),
                     ([1, 2, -1, -2], [1, 2, -3, -4]))
    NE_corner = scon((A_list[1], A_list[1].conjugate()),
                     ([-1, 1, 2, -2], [-3, 1, 2, -4]))
    N_row = scon((NW_corner, NE_corner), ([1, -1, 2, -3], [1, -2, 2, -4]))
    norm_sq = N_row.norm_sq()
    return norm_sq
Example #5
0
def get_T_first(T, pars, alpha=0):
    if pars["KW"]:
        T_first = initialtensors.get_KW_tensor(pars)
    elif pars["do_momenta"]:
        defect_horz = get_defect(alpha, T, 0)
        defect_vert = get_defect(alpha, T, 1).conjugate().transpose()
        T_first = scon((T, defect_horz, defect_vert),
                       ([1, -2, -3, 4], [-1, 1], [4, -4]))
    else:
        defect_horz = get_defect(alpha, T, 0)
        T_first = scon((T, defect_horz), ([1, -2, -3, -4], [-1, 1]))
    return T_first
Example #6
0
def fix_A_new_gauge_update_to_gauge(A_new, BUS, BSV, z, X, Y, G_hh=None):
    X_dg = matrix_dagger(X)
    Y_dg = matrix_dagger(Y)
    A_new = scon((A_new, Y, X, Y_dg, X_dg),
                 ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4]))
    BUS = scon((BUS, Y_dg), ([-1, 2, -3], [2, -2]))
    BSV = scon((Y, BSV), ([-1, 1], [1, -2, -3]))
    z = scon((X, z), ([-1, 1], [1, -2, -3]))
    return_value = (A_new, BUS, BSV, z)
    if G_hh is not None:
        G_hh = scon((Y, G_hh, Y_dg), ([-1, 1], [1, 2], [2, -2]))
        return_value += (G_hh, )
    return return_value
Example #7
0
 def transfer_op(v, charge=0):
     v = np.reshape(v, (flatdim1, flatdim2) + (flatdimT,)*(block_width-2))
     v = caster(v, charge=charge)
     if pars["do_momenta"] and not pars["do_coarse_momenta"]:
         v = np.transpose(v, translation)
         v = scon((U, v),
                  ([-1,-2,-3,1,2,3],
                   [1,2,3] + [-i for i in range(4, block_width+1)]))
     print(".", end='', flush=True)
     scon_list = [v] + scon_list_end
     Av = scon(scon_list, index_list)
     Av = Av.to_ndarray()
     Av = np.reshape(Av, (matrix_flatdim,))
     return Av
Example #8
0
def upper_block(u, v, w, A_list, A_part_list, pars):
    """ upper_block is the upper half of B. Often also called upb in the code.
    """
    if pars["use_parts"]:
        # This is O(chi^8), O(chi^6) if A can be split with just chi.
        upb = scon((u, v, w, A_part_list[0][0], A_part_list[0][1],
                    A_part_list[1][0], A_part_list[1][1]),
                   ([3, 5, 4, 6], [5, -2, 2], [-1, 3, 1], [1, 4, 7],
                    [7, 9, -3], [6, 2, 8], [9, 8, -4]))
    else:
        # This is O(chi^7).
        upb = scon((w, v, u, A_list[0], A_list[1]),
                   ([-1, 6, 2], [4, -2, 1], [6, 4, 5, 3], [2, 5, 7, -3
                                                           ], [7, 3, 1, -4]))
    return upb
Example #9
0
def build_A_new(v, w, z, BUS, BSV):
    # This is O(chi^6).
    A_new = scon(
        (z, v_dg(v), w_dg(w), BSV, BUS, v_prime(v), w_prime(w), z_dg(z)),
        ([-2, 3, 4], [3, 1, 7], [1, 4, 10], [-1, 7, 9], [10, -3, 8], [9, 2, 5],
         [2, 8, 6], [5, 6, -4]))
    return A_new
Example #10
0
def split_B(B, pars):
    if pars["print_errors"] > 0:
        print('-Splitting B.')
    if pars["horz_refl"]:
        S, U = B.eig((0, 3), (1, 2),
                     chis=pars["chis_trg"],
                     hermitian=True,
                     eps=pars["opt_eps_chi"],
                     print_errors=pars["print_errors"])
        # G_hh is a diagonal matrix populated with signs of the
        # eigenvalues of B.
        G_hh = S.sign()
        G_hh = G_hh.diag()
        S_sqrt = S.abs().sqrt()
        U = U.transpose((0, 2, 1))
        V = scon((U.conjugate(), G_hh), ([-2, 1, -3], [-1, 1]))
    else:
        U, S, V = B.svd((0, 3), (1, 2),
                        chis=pars["chis_trg"],
                        eps=pars["opt_eps_chi"],
                        print_errors=pars["print_errors"])
        S_sqrt = S.sqrt()
        U = U.transpose((0, 2, 1))
        G_hh = None
    US = U.multiply_diag(S_sqrt, 1, direction="r")
    SV = V.multiply_diag(S_sqrt, 0, direction="l")
    return_value = (US, SV)
    if pars["return_gauges"]:
        return_value += (G_hh, )
    if pars["print_errors"] > 0:
        print('Truncated bond dimension in split_B: %i' % len(S))
    return return_value
Example #11
0
def get_T(pars):
    # We always get the invariant tensor here, and cast it to the
    # non-invariant if needed. This gets around the silly fact that the
    # basis of the original tensor depends on symmetry_tensors,
    # something that should be fixed.
    T = tensordispenser.get_tensor(pars, iter_count=0,
                                   symmetry_tensors=True)[0]
    if not pars["symmetry_tensors"]:
        T = Tensor.from_ndarray(T.to_ndarray())
    log_fact = 0
    Fs = []
    Ns = []
    cum = T
    for i in range(1, pars["n_normalization"]):
        cum = toolbox.contract2x2(cum)
        log_fact *= 4
        m = cum.abs().max()
        if m != 0:
            cum /= m
            log_fact += np.log(m)
        N = 4**i
        F = np.log(scon(cum, [1, 2, 1, 2]).value()) + log_fact
        Fs.append(F)
        Ns.append(N)
    A, B = np.polyfit(Ns[pars["n_discard"]:], Fs[pars["n_discard"]:], 1)
    T /= np.exp(A)
    return T
Example #12
0
def compute_TNR_error(u,
                      v,
                      w,
                      A_list,
                      A_part_list,
                      pars,
                      upb=None,
                      B_norm=None,
                      orig_norm=None):
    if orig_norm is None:
        orig_norm_sq = A4_frob_norm_sq(A_list, A_part_list, pars)
        orig_norm = np.sqrt(orig_norm_sq)
    else:
        orig_norm_sq = orig_norm**2
    if B_norm is None:
        if upb is None:
            upb = upper_block(u, v, w, A_list, A_part_list, pars)
        B = scon((upb, upb_dg(upb)), ([-1, -2, 1, 2], [1, 2, -3, -4]))
        B_norm_sq = B.norm_sq()
    else:
        B_norm_sq = B_norm**2
    # The norm |TNR block - original block| can be reduced to this form
    diff_norm = np.sqrt(orig_norm_sq - B_norm_sq)
    err = diff_norm / orig_norm
    return err
Example #13
0
def generate_normalized_tensors(pars):
    # Number of tensors to use to fix the normalization
    n = max(8, pars["iter_count"] + 4)
    # Number of tensors from the beginning to discard
    n_discard = max(min(pars["iter_count"]-3, 3), 0)
    tensors_and_log_facts = []
    for i in reversed(list(range(n+1))):
        tensors_and_log_facts.append(get_tensors(pars=pars, iter_count=i))
    tensors_and_log_facts = tuple(reversed(tensors_and_log_facts))
    A_lists = tuple(map(lambda t: t[0], tensors_and_log_facts))
    log_fact_lists = np.array(tuple(map(lambda t: t[1], tensors_and_log_facts)))
    Us = np.array(tuple(map(lambda t: t[2], tensors_and_log_facts)))

    Zs = np.array(tuple(scon(A_list, ([1,2,3,2], [3,4,1,4])).norm() for A_list in A_lists))
    log_Zs = np.log(Zs)
    log_Zs = np.array(tuple(log_Z + log_fact_list[0] + log_fact_list[1]
                            for log_Z, log_fact_list in zip(log_Zs, log_fact_lists)))
    Ns = np.array([4*4**i-2**i for i in range(n+1)])
    A, B = np.polyfit(Ns[pars["n_discard"]:], log_Zs[pars["n_discard"]:], 1)

    if pars["print_errors"]:
        print("Fit when normalizing Ts: %.3e * N + %.3e"%(A,B))

    A_lists = [[A_list[0]/np.exp(N*A/2 - log_fact_list[0]),
                A_list[1]/np.exp(N*A/2 - log_fact_list[1])]
               for A_list, N, log_fact_list in zip(A_lists, Ns, log_fact_lists)]

    id_pars = get_tensor_id_pars(pars)
    for i, (A_list, U) in enumerate(zip(A_lists, Us)):
        write_tensor_file(data=(A_list, U), prefix="KW_tensors_normalized",
                          pars=id_pars, iter_count=i, filename=filename)

    A_list = A_lists[pars["iter_count"]]
    U = Us[pars["iter_count"]]
    return A_list, U
Example #14
0
def ascend_U(U, u, u1, z, z1, z2, pars):
    # This is O(chi^10).
    if pars["print_errors"]:
        print("Ascending U.")
    U1 = U.flip_dir(1)
    U2 = U.flip_dir(2)
    U2 = U2.flip_dir(3)
    U2 = U2.flip_dir(5)
    u_dg = u.conjugate().transpose((2,3,0,1))
    u1_dg = u1.conjugate().transpose((2,3,0,1))
    z_dg = z.conjugate().transpose((1,2,0))
    z1_dg = z1.conjugate().transpose((1,2,0))
    z2_dg = z2.conjugate().transpose((1,2,0))
    asc_U = scon((z1, z2, z,
                  u1, u,
                  U1,
                  U2,
                  u_dg, u1_dg,
                  z_dg, z1_dg, z2_dg),
                 ([-1,15,16], [-2,5,6], [-3,19,18],
                  [16,5,1,2], [6,19,7,14],
                  [1,2,7,11,12,13],
                  [12,13,14,9,3,4],
                  [11,9,17,10], [3,4,8,20],
                  [15,17,-4], [10,8,-5], [20,18,-6]))
    return asc_U
Example #15
0
def get_T_last(T, pars, alpha=0, parts=None):
    if pars["do_coarse_momenta"]:
        if pars["print_errors"] > 1:
            print("Optimizing y_last, alpha =", alpha)
        y, y_dg, NE, SW, T_orig = parts
        defect_horz = get_defect(alpha, T_orig, 0)
        defect_vert = get_defect(alpha, T_orig, 1).conjugate().transpose()
        cost = np.inf
        cost_change = np.inf
        counter = 0
        y_last = y
        y_last_dg = y_dg
        # TODO Should this bond dimension be an independent parameter?
        chis = [chi for chi in pars["chis_trg"]]
        while cost_change > 1e-11 and counter < 10000:
            # The optimization step
            # This is O(chi^6). Could use a pre-environment too.
            env_part1 = scon(
                (NE, defect_horz, T_orig, SW, defect_vert, y_last_dg),
                ([-2, 1, -1], [1, 6], [6, -3, 5, 2], [5, -4, 3
                                                      ], [2, 4], [4, 3, -5]))
            env = scon((env_part1, env_part1.conjugate()),
                       ([1, -1, -2, 2, 3], [1, -3, -4, 2, 3]))
            U = env.eig((0, 1), (2, 3), hermitian=True, chis=chis)[1]
            y_last_dg = U
            y_last = y_last_dg.conjugate().transpose((2, 0, 1))
            old_cost = cost
            cost = scon((env, y_last, y_last_dg),
                        ([1, 2, 3, 4], [5, 1, 2], [3, 4, 5])).value()
            if np.imag(cost) > 1e-13:
                warnings.warn("optimize y_last cost is complex: " + str(cost))
            else:
                cost = np.real(cost)
            cost_change = np.abs((old_cost - cost) / cost)
            counter += 1
        T_last = scon(
            (y_last, NE, defect_horz, T_orig, SW, defect_vert, y_last_dg),
            ([-2, 7, 8], [7, 1, -1], [1, 6], [6, 8, 5, 2], [5, -3, 3], [2, 4],
             [4, 3, -4]))
        if pars["print_errors"] > 1:
            orig_T_last = scon(
                (NE, defect_horz, T_orig, SW, defect_vert),
                ([-2, 1, -1], [1, 6], [6, -3, 5, 2], [5, -4, -6], [2, -5]))
            coarsed_T_last = scon((y_last_dg, T_last, y_last),
                                  ([-2, -3, 1], [-1, 1, -4, 2], [2, -5, -6]))
            err = (orig_T_last - coarsed_T_last).norm() / orig_T_last.norm()
            print("After %i iterations, error in optimize y_last is %.3e." %
                  (counter, err))
    elif pars["do_momenta"]:
        defect_horz = get_defect(alpha, T, 0)
        defect_vert = get_defect(alpha, T, 1).conjugate().transpose()
        T_last = scon((T, defect_horz, defect_vert),
                      ([1, -2, -3, 4], [-1, 1], [4, -4]))
    else:
        defect_horz = get_defect(alpha, T, 0)
        T_last = scon((T, defect_horz), ([1, -2, -3, -4], [-1, 1]))
    return T_last
Example #16
0
def fix_A_new_gauge_optimize_Y(A_new, A, X, Y, return_cost=False):
    X_dg = matrix_dagger(X)
    Y_dg = matrix_dagger(Y)
    env = scon((A.conjugate(), X, A_new, Y_dg, X_dg),
               ([-2, 6, 4, 5], [6, 2], [-1, 2, 1, 3], [1, 4], [3, 5]))
    env_U, env_S, env_V = env.svd((0, ), (1, ))
    env_U_dg = matrix_dagger(env_U)
    env_V_dg = matrix_dagger(env_V)
    Y = scon((env_V_dg, env_U_dg), ([-1, 1], [1, -2]))
    if return_cost:
        cost = scon((env, Y), ([1, 2], [2, 1])).value()
        if np.imag(cost) > 1e-13:
            warnings.warn("fix_A_new_gauge cost is complex: " + str(cost))
        else:
            cost = np.real(cost)
        return Y, cost
    else:
        return Y
Example #17
0
 def transfer_op(v, charge=0):
     v = np.reshape(v,
                    (flatdim1, flatdim2) + (flatdimT, ) * (block_width - 2))
     v = caster(v, charge=charge)
     print(".", end='', flush=True)
     scon_list = [v] + scon_list_end
     Av = scon(scon_list, index_list)
     Av = Av.to_ndarray()
     Av = np.reshape(Av, (matrix_flatdim, ))
     return Av
Example #18
0
def get_KW_unitary(pars):
    eye = np.eye(2, dtype=np.complex_)
    CZ = Csigma_np("z")
    U = scon(
        (CZ, R_np(np.pi / 4, 'z'), R_np(np.pi / 4, 'x'), R_np(np.pi / 4, 'y')),
        ([-1, -2, 5, 6], [-3, 5], [3, 6], [-4, 3]))
    u = symmetry_bases["ising"]
    u_dg = u.T.conjugate()
    U = scon((U, u, u_dg, u_dg, u),
             ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4]))
    U *= -1j
    if pars["symmetry_tensors"]:
        U = TensorZ2.from_ndarray(U,
                                  shape=[[1, 1]] * 4,
                                  qhape=[[0, 1]] * 4,
                                  dirs=[1, 1, -1, -1])
    else:
        U = Tensor.from_ndarray(U, dirs=[1, 1, 1, -1, -1, -1])
    return U
Example #19
0
def generate_initial_tensors(pars):
    T = initialtensors.get_initial_tensor(pars)
    D_sigma = initialtensors.get_KW_tensor(pars)
    U = initialtensors.get_KW_unitary(pars)
    eye = np.eye(2, dtype=np.complex_)
    eye = type(U).from_ndarray(eye, shape=[[1,1]]*2, qhape=[[0,1]]*2,
                               dirs=[1,-1])
    U = scon((U, eye), ([-1,-2,-4,-5], [-3,-6]))
    A_list = [D_sigma, T]
    log_fact_list = [0,0]
    return A_list, log_fact_list, U
Example #20
0
def optimize_G_hv(A_new, G_hh, pars):
    if pars["print_errors"] > 1:
        print("Optimizing G_hv.")
    Ah = A_new.conjugate().transpose((2, 1, 0, 3))
    dim = A_new.shape[1]
    try:
        qim = A_new.qhape[1]
    except TypeError:
        qim = None
    G_hv = type(A_new).eye(dim, qim=qim, dtype=A_new.dtype)
    G_hv = G_hv.flip_dir(0)
    cost = np.inf
    cost_change = np.inf
    counter = 0
    pre_env_A_new = scon((A_new, G_hh, G_hh),
                         ([1, -2, 3, -4], [-1, 1], [3, -3]))
    while cost_change > 1e-11 and counter < 10000:
        # The optimization step
        G_hv_dg = matrix_dagger(G_hv)
        env = scon((pre_env_A_new, G_hv_dg, Ah.conjugate()),
                   ([3, -1, 4, 1], [1, 2], [3, -2, 4, 2]))
        env_U, env_S, env_V = env.svd((0, ), (1, ))
        env_U_dg = matrix_dagger(env_U)
        env_V_dg = matrix_dagger(env_V)
        G_hv = scon((env_V_dg, env_U_dg), ([-1, 1], [1, -2]))

        old_cost = cost
        cost = scon((env, G_hv), ([1, 2], [2, 1])).value()
        if np.imag(cost) > 1e-13:
            warnings.warn("optimize_G_hv cost is complex: " + str(cost))
        else:
            cost = np.real(cost)
        cost_change = np.abs((old_cost - cost) / cost)
        counter += 1
    if pars["print_errors"] > 1:
        GAG_dg = scon((G_hv, pre_env_A_new, G_hv.conjugate().transpose()),
                      ([-2, 2], [-1, 2, -3, 4], [4, -4]))
        err = (GAG_dg - Ah).norm()
        print("After %i iterations, error in optimize_G_hv is %.3e." %
              (counter, err))
    return G_hv
Example #21
0
def contract2x2_Tensor(T_list, vert_flip=False):
    if vert_flip:

        def flip(T):
            T.transpose((0, 3, 2, 1))

        flip(T_list[2])
        flip(T_list[3])
    T4 = scon((T_list[0], T_list[1], T_list[2], T_list[3]),
              ([-2, -3, 1, 3], [1, -4, -6, 4], [-1, 3, 2, -7], [2, 4, -5, -8]))
    T4 = T4.join_indices((0, 1), (2, 3), (4, 5), (6, 7), dirs=[1, 1, -1, -1])
    return T4
Example #22
0
def print_Z_error(A_list, log_fact, A_new, new_log_fact):
    """ Error in the partition function that is the trace of a block of
    4 A tensors.
    """
    A4_Z = A4_trace(A_list)
    A_new_Z_tensor = scon(A_new,
                          [1, 2, 1, 2]) * np.exp(new_log_fact - 4 * log_fact)
    A_new_Z = A_new_Z_tensor.norm()
    err = (A4_Z - A_new_Z) / A_new_Z
    print(
        'Relative difference in Z from exact A4 and from A_new:  %.3e + %gj' %
        (np.real(err), np.imag(err)))
    return err
Example #23
0
def symmetrize_A_list(A_list, pars, gauges):
    """ Symmetrizes A_list according to the value of horz_refl. """
    new_list = A_list.copy()
    if pars["horz_refl"]:
        new_list[1] = new_list[0].conjugate().transpose((2, 1, 0, 3))
        if gauges["G_hh"] is not None:
            new_list[1] = scon((new_list[1], gauges["G_hh"], gauges["G_hh"]),
                               ([1, -2, 3, -4], [-1, 1], [3, -3]))
    else:
        if A_list[1].dirs == A_list[0].dirs:
            new_list[1] = A_list[1].flip_dir(1)
            new_list[1] = new_list[1].flip_dir(3)
    return new_list
Example #24
0
def optimize_disentangler(u,
                          v,
                          w,
                          A_list,
                          A_part_list,
                          pars,
                          return_B_norm=False):
    # Compute environment M
    for i in range(pars["opt_iters_tens"]):
        upb = upper_block(u, v, w, A_list, A_part_list, pars)
        # Note that by construction, B = B^dg.
        B = build_B(u, v, w, A_list, A_part_list, pars, upb=upb)
        if pars["use_parts"]:
            # This is O(chi^8), O(chi^6) if A can be split with just chi.
            M = scon((w, v, A_part_list[0][0], A_part_list[0][1],
                      A_part_list[1][0], A_part_list[1][1], upb_dg(upb), B),
                     ([10, -3, 3], [-4, 8, 4], [3, -1, 9], [9, 5, 6],
                      [-2, 4, 11], [5, 11, 7], [6, 7, 2, 1], [1, 2, 8, 10]))
        else:
            # This is O(chi^7).
            M = scon((w, v, A_list[0], A_list[1], upb_dg(upb), B),
                     ([3, -3, 4], [-4, 9, 6], [4, -1, 7, 5], [7, -2, 6, 8],
                      [5, 8, 2, 1], [1, 2, 9, 3]))
        U, S, V = M.svd((0, 1), (2, 3))
        u = scon((U.conjugate(), V.conjugate()), ([-3, -4, 1], [1, -1, -2]))
        if pars["horz_refl"]:
            # u should be symmetric under a horizontal reflection
            # already, but we symmetrize to kill numerical errors.
            u = (u + u.conjugate().transpose((1, 0, 3, 2))) / 2
    if return_B_norm:
        B_norm_sq = scon((M, u), ([1, 2, 3, 4], [3, 4, 1, 2])).value()
        if np.imag(B_norm_sq) / np.abs(B_norm_sq) > 1e-13:
            warnings.warn("B_norm_sq is complex: " + str(B_norm_sq))
        else:
            B_norm_sq = np.real(B_norm_sq)
        B_norm = np.sqrt(B_norm_sq)
        return u, B_norm
    else:
        return u
Example #25
0
def contract2x2_ndarray(T_list, vert_flip=False):
    if vert_flip:

        def flip(T):
            return np.transpose(T.conjugate(), (0, 3, 2, 1))

        T_list[2] = flip(T_list[2])
        T_list[3] = flip(T_list[3])
    T4 = scon((T_list[0], T_list[1], T_list[2], T_list[3]),
              ([-2, -3, 1, 3], [1, -4, -6, 4], [-1, 3, 2, -7], [2, 4, -5, -8]))
    sh = T4.shape
    S = np.reshape(
        T4, (sh[0] * sh[1], sh[2] * sh[3], sh[4] * sh[5], sh[6] * sh[7]))
    return S
Example #26
0
def initial_uvw(A_list, chi, pars, gauges, pieces):
    """ Returns the initial disentangler and isometries that are the
    starting point of the optimization. The initial u is the identity,
    the initial isometries are SVDed from A just like in TRG, truncated
    to dimension chi.
    """
    do_reuse = False
    if (pars["reuse_initial"] and pieces["w"] is not None
            and pieces["u"] is not None and pieces["v"] is not None):
        w_shp = pieces["w"].shape
        w_chi = type(A_list[0]).flatten_dim(w_shp[0])
        if (w_chi == chi and A_list[0].compatible_indices(pieces["u"], 1, 2)
                and A_list[0].compatible_indices(pieces["w"], 0, 2)):
            do_reuse = True
    if do_reuse:
        u = pieces["u"].copy()
        v = pieces["v"].copy()
        w = pieces["w"].copy()
    else:
        # Some performance could be saved here if the As would not be SVDed
        # again. This would be simple if A_part_list elements didn't have
        # the S_sqrt multiplied into them.  The performance of this part
        # should be very much subleading though.
        # u:
        dim1 = A_list[0].shape[1]
        try:
            qim1 = A_list[0].qhape[1]
        except TypeError:
            qim1 = None
        dim2 = A_list[1].shape[1]
        try:
            qim2 = A_list[1].qhape[1]
        except TypeError:
            qim2 = None
        eye1 = type(A_list[0]).eye(dim1, qim=qim1)
        eye2 = type(A_list[0]).eye(dim2, qim=qim2)
        u = scon((eye1, eye2), ([-1, -3], [-4, -2]))
        # w:
        w_dg = A_list[0].svd((0, 1), (2, 3), chis=chi)[0]
        w = w_dg.transpose((2, 1, 0)).conjugate()
        # v:
        if pars["horz_refl"]:
            v = w_hat(w, gauges)
        else:
            v_dg = A_list[1].svd((0, 3), (1, 2), chis=chi)[2]
            v = v_dg.transpose((1, 0, 2)).conjugate()
    return u, v, w
Example #27
0
 def scon_op(v, charge=0):
     v = np.reshape(v, in_flatdims)
     v = type_.from_ndarray(v,
                            shape=in_dims,
                            qhape=in_qims,
                            charge=charge,
                            dirs=in_dirs)
     if scon_func is None:
         scon_list = tensor_list + [v]
         Av = scon(scon_list, index_list)
     else:
         Av = scon_func(v)
     Av = Av.to_ndarray()
     Av = np.transpose(Av, perm)
     Av = np.reshape(Av, (matrix_flatdim, ))
     if print_progress:
         print(".", end='', flush=True)
     return Av
Example #28
0
def get_initial_tensor(pars, **kwargs):
    if kwargs:
        pars = pars.copy()
        pars.update(kwargs)
    model_name = pars["model"].strip().lower()
    ham = hamiltonians[model_name](pars)
    boltz = np.exp(-pars["beta"] * ham)
    T_0 = np.einsum('ab,bc,cd,da->abcd', boltz, boltz, boltz, boltz)
    if pars["symmetry_tensors"]:
        u = symmetry_bases[model_name]
        u_dg = u.T.conjugate()
        T_0 = scon((T_0, u, u, u_dg, u_dg),
                   ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4]))
        cls, dim, qim = symmetry_classes_dims_qims[model_name]
        T_0 = cls.from_ndarray(T_0,
                               shape=[dim] * 4,
                               qhape=[qim] * 4,
                               dirs=[1, 1, -1, -1])
    else:
        T_0 = Tensor.from_ndarray(T_0)
    return T_0
Example #29
0
def qnums_from_eigenvectors(evects, pars):
    sites = len(evects.shape) - 1
    if pars["model"].strip().lower() == "ising":
        symop = np.array([[1, 0], [0, -1]], dtype=np.float_)
        symop = type(evects).from_ndarray(symop)
    else:
        # TODO generalize symop to models other than Ising.
        NotImplementedError("Symmetry operators for models other than "
                            "Ising have not been implemented.")
    ncon_list = (evects, evects.conjugate()) + (symop, ) * sites
    index_list = ((list(range(1, sites + 1)) + [-1],
                   list(range(sites + 1, 2 * sites + 1)) + [-2]) +
                  tuple([i + sites, i] for i in range(1, sites + 1)))
    qnums = scon(ncon_list, index_list)
    qnums = qnums.diag()
    # Round to the closest possible qnum for the given model.
    pos_qnums = initialtensors.symmetry_classes_dims_qims[pars["model"]][2]
    max_qnum = max(pos_qnums)
    qnums = qnums.astype(np.complex_).log() * (max_qnum + 1) / (2j * np.pi)
    qnums = [min(pos_qnums, key=lambda x: abs(x - q)) for q in qnums]
    return qnums
Example #30
0
def get_D(t, pars):
    ham = (-pars["J"] * np.array([[1, -1], [-1, 1]], dtype=pars["dtype"]) +
           pars["H"] * np.array([[-1, 0], [0, 1]], dtype=pars["dtype"]))
    boltz = np.exp(-pars["beta"] * ham)
    ham_g = -pars["g"] * pars["J"] * np.array([[1, -1], [-1, 1]],
                                              dtype=pars["dtype"])
    boltz_g = np.exp(-pars["beta"] * ham_g)
    ones = np.ones((2, 2), dtype=pars["dtype"])
    D = np.einsum('ab,bc,cd,da->abcd', boltz, boltz_g, boltz_g, boltz)
    u = np.array([[1, 1], [1, -1]]) / np.sqrt(2)
    u_dg = u.T.conjugate()
    D = scon((D, u, u, u_dg, u_dg),
             ([1, 2, 3, 4], [-1, 1], [-2, 2], [3, -3], [4, -4]))
    if pars["symmetry_tensors"]:
        D = TensorZ2.from_ndarray(D,
                                  shape=[[1, 1]] * 4,
                                  qhape=[[0, 1]] * 4,
                                  dirs=[1, 1, -1, -1])
    else:
        D = Tensor.from_ndarray(D)
    return D