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 __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)
def gmin(x, y): return g.where(x < y, x, y)
def gmax(x, y): return g.where(x > y, x, y)
def __call__(self, link, staple, mask): """ Generate new U(1) links with P(U) = e^{ Re Staple U } using the heatbath algorithm of Hattori-Nakajima (hep-lat/9210016), which draws a random variable x in (-pi, -pi) from P(x) ~ exp(a cos(x)). """ verbose = g.default.is_verbose( "u1_heat_bath" ) # need verbosity categories [ performance, progress ] assert type(link) == g.lattice and type(staple) == g.lattice # component-wise functions needed below exp = g.component.exp log = g.component.log sqrt = g.component.sqrt cos = g.component.cos tan = g.component.tan atan = g.component.atan cosh = g.component.cosh tanh = g.component.tanh atanh = g.component.atanh inv = g.component.inv # functions needed in Hattori-Nakajima method def gmax(x, y): return g.where(x > y, x, y) def gmin(x, y): return g.where(x < y, x, y) def h(x): return g.eval( 2.0 * inv(alpha) * atanh(g.eval(beta_s * tan(g.eval((2.0 * x - one) * tmp))))) def gg(x): return exp(g.eval(-a * G(h(x)))) def G(x): return g.eval(one - cos(x) - a_inv * log( g.eval(one + (cosh(g.eval(alpha * x)) - one) * inv(g.eval(one + beta))))) # temporaries a = g.component.abs(staple) # absolute value of staple a_inv = g.eval(inv(a)) # needed several times grid = a.grid one = g.identity(g.complex(grid)) zero = g.identity(g.complex(grid)) zero[:] = 0 Unew = g.complex(grid) # proposal for new links accepted = g.complex(grid) # mask for accepted links num_sites = round(g.norm2(g.where(mask, one, zero))) x1 = g.complex(grid) x2 = g.complex(grid) nohit = 0 # to compute acceptance ratio # parameters of Hattori-Nakajima method eps = 0.001 astar = 0.798953686083986 amax = gmax(zero, g.eval(a - astar * one)) delta = g.eval(0.35 * amax + 1.03 * sqrt(amax)) alpha = gmin(sqrt(g.eval(a * (2.0 - eps))), gmax(sqrt(g.eval(eps * a)), delta)) beta = g.eval((gmax( g.eval(alpha * alpha * a_inv), g.eval((cosh(g.eval(np.pi * alpha)) - one) * inv(g.eval(exp(g.eval(2.0 * a)) - one))), ) - one)) beta_s = sqrt(g.eval((one + beta) * inv(g.eval(one - beta)))) tmp = atan(g.eval(inv(beta_s) * tanh(g.eval(0.5 * np.pi * alpha)))) # main loop (large optimization potential but not time-critical anyway) num_accepted = 0 accepted[:] = 0 Unew[:] = 0 # worst-case acceptance ratio of Hattori-Nakajima is 0.88 while num_accepted < num_sites: self.rng.uniform_real(x1, min=0.0, max=1.0) self.rng.uniform_real(x2, min=0.0, max=1.0) Unew = g.where(accepted, Unew, exp(g.eval(1j * h(x1)))) newly_accepted = g.where(x2 < gg(x1), one, zero) accepted = g.where( mask, g.where(newly_accepted, newly_accepted, accepted), zero) num_accepted = round(g.norm2(g.where(accepted, one, zero))) nohit += num_sites - num_accepted if verbose: g.message( f"Acceptance ratio for U(1) heatbath update = {num_sites/(num_sites+nohit)}" ) # Unew was drawn with phase angle centered about zero # -> need to shift this by phase angle of staple # (we update every link, thus accepted = mask) link @= g.where(accepted, Unew * staple * a_inv, link)
g.message(f"Test bilinear combination of vector {j}: {eps2}") assert eps2 < 1e-13 ################################################################################ # Test where ################################################################################ grid = grid_dp sel = g.complex(grid) rng.uniform_int(sel, min=0, max=1) yes = g.vcomplex(grid, 8) no = g.vcomplex(grid, 8) rng.cnormal([yes, no]) w = g.where(sel, yes, no) eps = np.linalg.norm(w[:] - np.where(sel[:] != 0.0, yes[:], no[:])) / np.linalg.norm( w[:] ) g.message( f"Test gpt.where <> numpy.where with a selection of {g.norm2(sel)} points: {eps}" ) assert eps == 0.0 ################################################################################ # Test comparators ################################################################################ a = g.complex(grid) b = g.complex(grid)