def __call__(self, link, staple, mask): verbose = g.default.is_verbose( "metropolis" ) # need verbosity categories [ performance, progress ] project_method = self.params["project_method"] step_size = self.params["step_size"] number_accept = 0 possible_accept = 0 t = g.timer("metropolis") t("action") action = g.component.real(g.eval(-g.trace(link * g.adj(staple)) * mask)) t("lattice") V = g.lattice(link) V_eye = g.identity(link) t("random") self.rng.element(V, scale=step_size, normal=True) t("update") V = g.where(mask, V, V_eye) link_prime = g.eval(V * link) action_prime = g.component.real( g.eval(-g.trace(link_prime * g.adj(staple)) * mask)) dp = g.component.exp(g.eval(action - action_prime)) rn = g.lattice(dp) t("random") self.rng.uniform_real(rn) t("random") accept = dp > rn accept *= mask number_accept += g.norm2(accept) possible_accept += g.norm2(mask) link @= g.where(accept, link_prime, link) t() g.project(link, project_method) # g.message(t) if verbose: g.message( f"Metropolis acceptance rate: {number_accept / possible_accept}" )
def left_increment(dst, src_left, scale): dst = g.util.to_list(dst) src_left = g.util.to_list(src_left) group = dst[0].otype algebra = group.cartesian() assert src_left[0].otype.__name__ == algebra.__name__ for src_left_mu, dst_mu in zip(src_left, dst): if group.__name__ != algebra.__name__: dst_mu @= group.compose( g.project(g.convert(g(scale * src_left_mu), group), "defect"), dst_mu) else: dst_mu @= group.compose(g(scale * src_left_mu), dst_mu)
def __call__(self, link, staple, mask): verbose = g.default.is_verbose( "su2_heat_bath" ) # need verbosity categories [ performance, progress ] project_method = self.params["project_method"] # params niter = self.params["niter"] # temporaries grid = link.grid u2 = g.lattice(grid, g.ot_matrix_su_n_fundamental_group(2)) u2_eye = g.identity(u2) one = g.identity(g.complex(grid)) zero = g.complex(grid) zero[:] = 0 eps = g.complex(grid) eps[:] = grid.precision.eps * 10.0 xr = [g.complex(grid) for i in range(4)] a = [g.complex(grid) for i in range(4)] two_pi = g.complex(grid) two_pi[:] = 2.0 * np.pi accepted = g.complex(grid) d = g.complex(grid) V_eye = g.identity(link) # pauli pauli1, pauli2, pauli3 = tuple([g.lattice(u2) for i in range(3)]) ident = g.identity(u2) pauli1[:] = 1j * np.array([[0, 1], [1, 0]], dtype=grid.precision.complex_dtype) pauli2[:] = 1j * np.array([[0, 1j], [-1j, 0]], dtype=grid.precision.complex_dtype) pauli3[:] = 1j * np.array([[1, 0], [0, -1]], dtype=grid.precision.complex_dtype) # counter num_sites = round(g.norm2(g.where(mask, one, zero))) # shortcuts inv = g.component.pow(-1.0) # go through subgroups for subgroup in link.otype.su2_subgroups(): V = g.eval(link * g.adj(staple)) # extract u2 subgroup following Kennedy/Pendleton link.otype.block_extract(u2, V, subgroup) u2 @= u2 - g.adj(u2) + g.identity(u2) * g.trace(g.adj(u2)) udet = g.matrix.det(u2) adet = g.component.abs(udet) nzmask = adet > eps u2 @= g.where(nzmask, u2, u2_eye) udet = g.where(nzmask, udet, one) xi = g.eval(0.5 * g.component.sqrt(udet)) u2 @= 0.5 * u2 * inv(xi) # make sure that su2 subgroup projection worked assert g.group.defect(u2) < u2.grid.precision.eps * 10.0 xi @= 2.0 * xi alpha = g.component.real(xi) # main loop it = 0 num_accepted = 0 accepted[:] = 0 d[:] = 0 while (num_accepted < num_sites) and (it < niter): self.rng.uniform_real(xr, min=0.0, max=1.0) xr[1] @= -g.component.log(xr[1]) * inv(alpha) xr[2] @= -g.component.log(xr[2]) * inv(alpha) xr[3] @= g.component.cos(g.eval(xr[3] * two_pi)) xr[3] @= xr[3] * xr[3] xrsq = g.eval(xr[2] + xr[1] * xr[3]) d = g.where(accepted, d, xrsq) thresh = g.eval(one - d * 0.5) xrsq @= xr[0] * xr[0] newly_accepted = g.where(xrsq < thresh, one, zero) accepted = g.where(mask, g.where(newly_accepted, newly_accepted, accepted), zero) num_accepted = round(g.norm2(g.where(accepted, one, zero))) it += 1 if verbose: g.message(f"SU(2)-heatbath update needed {it} / {niter} iterations") # update link a[0] @= g.where(mask, one - d, zero) a123mag = g.component.sqrt(g.component.abs(one - a[0] * a[0])) phi, cos_theta = g.complex(grid), g.complex(grid) self.rng.uniform_real([phi, cos_theta]) phi @= phi * two_pi cos_theta @= (cos_theta * 2.0) - one sin_theta = g.component.sqrt(g.component.abs(one - cos_theta * cos_theta)) a[1] @= a123mag * sin_theta * g.component.cos(phi) a[2] @= a123mag * sin_theta * g.component.sin(phi) a[3] @= a123mag * cos_theta ua = g.eval(a[0] * ident + a[1] * pauli1 + a[2] * pauli2 + a[3] * pauli3) b = g.where(mask, g.adj(u2) * ua, ident) link.otype.block_insert(V, b, subgroup) link @= g.where(accepted, V * link, link) # check check = g.where(accepted, ua * g.adj(ua) - ident, 0.0 * ident) delta = (g.norm2(check) / g.norm2(ident)) ** 0.5 assert delta < grid.precision.eps * 10.0 check = g.where(accepted, b * g.adj(b) - ident, 0.0 * ident) delta = (g.norm2(check) / g.norm2(ident)) ** 0.5 assert delta < grid.precision.eps * 10.0 check = g.where(accepted, V * g.adj(V) - V_eye, 0.0 * V_eye) delta = (g.norm2(check) / g.norm2(V_eye)) ** 0.5 assert delta < grid.precision.eps * 10.0 # project g.project(link, project_method)
################################################################################ # Test projection schemes on promoting SP to DP group membership ################################################################################ V0 = g.convert(rng.element(g.mcolor(grid_sp)), g.double) for method in ["defect_left", "defect_right"]: V = g.copy(V0) I = g.identity(V) I_s = g.identity(g.complex(grid_dp)) for i in range(3): eps_uni = (g.norm2(g.adj(V) * V - I) / g.norm2(I))**0.5 eps_det = (g.norm2(g.matrix.det(V) - I_s) / g.norm2(I_s))**0.5 g.message( f"Before {method} iteration {i}, unitarity defect: {eps_uni}, determinant defect: {eps_det}" ) g.project(V, method) assert eps_uni < 1e-14 and eps_det < 1e-14 ################################################################################ # Test SU(2) fundamental and conversion to adjoint ################################################################################ rng = g.random("test") for eps_ref, grid in [(1e-6, grid_sp), (1e-12, grid_dp)]: g.message( f"Test SU(2) fundamental and adjoint conversion on grid {grid.precision.__name__}" ) U = [g.matrix_su2_fundamental(grid) for i in range(2)] rng.element(
def projected_convert(x, otype): return g.project(g.convert(x, otype), "defect")
group_defect = g.group.defect(Vt_split[t]) g.message(f"Distance to group manifold: {group_defect}") if group_defect > 1e-12: g.message( f"Time slice {t} on split grid {Vt_split[t].grid.srank} has group_defect = {group_defect}" ) sys.exit(1) g.message("Unsplit") g.unsplit(Vt, Vt_split, cache) g.message("Project to group (should only remove rounding errors)") Vt = [g.project(vt, "defect") for vt in Vt] g.message("Test") # test results for t in range(Nt): f = g.qcd.gauge.fix.landau([Usep[mu][t] for mu in range(3)]) dfv = f.gradient(Vt[t], Vt[t]) theta = g.norm2(dfv).real / Vt[t].grid.gsites / dfv.otype.Nc g.message(f"theta[{t}] = {theta}") g.message(f"V[{t}][0,0,0] = ", Vt[t][0, 0, 0]) if theta > p_theta_eps or np.isnan(theta): g.message(f"Time slice{t} did not converge: {theta} >= {p_theta_eps}") sys.exit(1) # merge time slices
def update_field(P, U, ep): for Pmu, Umu in zip(P, U): Umu @= g.project(g.matrix.exp(g(ep * Pmu)), "defect") * Umu