def fill_su2_components_into_suN(dst, su2_comps, su2_indices, cache=None): if isinstance(dst, gpt.lattice): n_colors = dst.otype.Nc separated = gpt.separate_color(dst) elif isinstance(dst, dict): n_keys = len(dst) n_colors = int(np.sqrt(n_keys)) assert (int(n_colors) - 1, int(n_colors) - 1) in dst separated = dst if cache is None: zero = gpt.complex(separated[0, 0].grid) zero[:] = 0.0 one = gpt.complex(separated[0, 0].grid) one[:] = 1.0 else: zero, one = cache i1, i2 = su2_indices separated[i1, i1] @= su2_comps[0] + 1j * su2_comps[3] separated[i1, i2] @= su2_comps[2] + 1j * su2_comps[1] separated[i2, i1] @= -su2_comps[2] + 1j * su2_comps[1] separated[i2, i2] @= su2_comps[0] - 1j * su2_comps[3] for ii in range(n_colors): for jj in range(n_colors): if ii not in [i1, i2] or jj not in [i1, i2]: separated[ii, jj] @= one if ii == jj else zero if isinstance(dst, gpt.lattice): gpt.merge_color(dst, separated)
def fundamental_to_adjoint(U_a, U_f): grid = U_f.grid T = U_f.otype.cartesian().generators(grid.precision.complex_dtype) V = {} for a in range(len(T)): for b in range(len(T)): V[a, b] = gpt.eval(2.0 * gpt.trace(T[a] * U_f * T[b] * gpt.adj(U_f))) gpt.merge_color(U_a, V)
def color_transpose(l): xc = gpt.separate_color(l) Nc = l[:].shape[-1] y = {} for i in range(Nc): for j in range(Nc): y[i, j] = xc[j, i] dst = gpt.mspincolor(l.grid) gpt.merge_color(dst, y) return dst
def fundamental_to_adjoint(U_a, U_f): """ Convert fundamental to adjoint representation. For now only SU(2) is supported. Input: fundamental gauge field Output: adjoint gauge field """ grid = U_f.grid T = U_f.otype.generators(grid.precision.complex_dtype) V = {} for a in range(len(T)): for b in range(len(T)): V[a, b] = g.eval(2.0 * g.trace(T[a] * U_f * T[b] * g.adj(U_f))) g.merge_color(U_a, V)
def diquark(Q1, Q2): eps = g.epsilon(Q1.otype.shape[2]) R = g.lattice(Q1) # D_{a2,a1} = epsilon_{a1,b1,c1}*epsilon_{a2,b2,c2}*spin_transpose(Q1_{b1,b2})*Q2_{c1,c2} Q1 = g.separate_color(Q1) Q2 = g.separate_color(Q2) D = {x: g.lattice(Q1[x]) for x in Q1} for d in D: D[d][:] = 0 for i1, sign1 in eps: for i2, sign2 in eps: D[i2[0], i1[0]] += (sign1 * sign2 * Q1[i1[1], i2[1]] * g.transpose(Q2[i1[2], i2[2]])) g.merge_color(R, D) return R
def project_to_suN_step(dest, unprojected): t_total = -gpt.time() t_product, t_separate, t_merge, t_su2extract, t_su2fill, t_calcnorm, t_applynorm = [ 0.0 for _ in range(7) ] vol = dest.grid.fsites n_colors = dest.otype.Nc tmp = gpt.mcolor(dest.grid) zero = gpt.complex(dest.grid) zero[:] = 0.0 one = gpt.complex(dest.grid) one[:] = 1.0 square = gpt.component.pow(2) norm = gpt.complex(dest.grid) for su2_index in range(n_colors * (n_colors - 1) // 2): index, i1, i2 = 0, None, None for ii in range(1, n_colors): for jj in range(n_colors - ii): if index == su2_index and i1 is None: i1 = jj i2 = ii + jj index += 1 t_product -= gpt.time() tmp @= dest * unprojected t_product += gpt.time() t_separate -= gpt.time() tmp_sep = gpt.separate_color(tmp) t_separate += gpt.time() t_su2extract -= gpt.time() su2_components = extract_su2_components(tmp_sep, [i1, i2]) t_su2extract += gpt.time() t_calcnorm -= gpt.time() norm @= gpt.component.inv( gpt.component.sqrt( gpt.eval(su2_components[0] * su2_components[0] + su2_components[1] * su2_components[1] + su2_components[2] * su2_components[2] + su2_components[3] * su2_components[3]))) t_calcnorm += gpt.time() t_applynorm -= gpt.time() su2_components[0] @= su2_components[0] * norm su2_components[1] @= -su2_components[1] * norm su2_components[2] @= -su2_components[2] * norm su2_components[3] @= -su2_components[3] * norm t_applynorm += gpt.time() t_su2fill -= gpt.time() fill_su2_components_into_suN(tmp_sep, su2_components, [i1, i2], cache=[zero, one]) t_su2fill += gpt.time() t_merge -= gpt.time() gpt.merge_color(tmp, tmp_sep) t_merge += gpt.time() t_product -= gpt.time() dest @= tmp * dest t_product += gpt.time() t_total += gpt.time() if gpt.default.is_verbose("project_to_suN_step"): t_profiled = t_product + t_separate + t_merge + t_su2extract + t_su2fill + t_calcnorm + t_applynorm t_unprofiled = t_total - t_profiled gpt.message("project_to_suN_step: total", t_total, "s") gpt.message("project_to_suN_step: t_product", t_product, "s", round(100 * t_product / t_total, 1), "%") gpt.message("project_to_suN_step: t_separate", t_separate, "s", round(100 * t_separate / t_total, 1), "%") gpt.message("project_to_suN_step: t_merge", t_merge, "s", round(100 * t_merge / t_total, 1), "%") gpt.message("project_to_suN_step: t_su2extract", t_su2extract, "s", round(100 * t_su2extract / t_total, 1), "%") gpt.message("project_to_suN_step: t_su2fill", t_su2fill, "s", round(100 * t_su2fill / t_total, 1), "%") gpt.message("project_to_suN_step: t_calcnorm", t_calcnorm, "s", round(100 * t_calcnorm / t_total, 1), "%") gpt.message("project_to_suN_step: t_applynorm", t_applynorm, "s", round(100 * t_applynorm / t_total, 1), "%") gpt.message("project_to_suN_step: unprofiled", t_unprofiled, "s", round(100 * t_unprofiled / t_total, 1), "%")
assert eps < 1e-13 for c1 in range(3): for c2 in range(3): eps = np.linalg.norm( msc[0, 0, 0, 0].array[:, :, c1, c2] - xc[c1, c2][0, 0, 0, 0].array ) assert eps < 1e-13 msc2 = g.lattice(msc) g.merge_spin(msc2, xs) assert g.norm2(msc2 - msc) < 1e-13 g.merge_color(msc2, xc) assert g.norm2(msc2 - msc) < 1e-13 assert ( g.norm2(g.separate_color(xs[1, 2])[2, 0] - g.separate_spin(xc[2, 0])[1, 2]) < 1e-13 ) ################################################################################ # Setup lattices ################################################################################ l_rb = [field(grid_rb) for i in range(Nlat)] l = [field(grid) for i in range(Nlat)] for i in range(Nlat): l_rb[i].checkerboard(g.odd) rng.cnormal(l_rb)
t0 = g.time() for n in range(N): plan(lhs, rhs) t1 = g.time() g.message("%-50s %g GB/s %g s" % ("copy_plan:", GB / (t1 - t0), (t1 - t0) / N)) # spin/color separate/merge msc = g.mspincolor(grid) rng.cnormal(msc) # 2 * N for read/write GB = 2 * N * msc.otype.nfloats * grid.precision.nbytes * grid.fsites / 1e9 xc = g.separate_color(msc) g.merge_color(msc, xc) t0 = g.time() for n in range(N): xc = g.separate_color(msc) t1 = g.time() for n in range(N): g.merge_color(msc, xc) t2 = g.time() g.message("%-50s %g GB/s %g s" % ("separate_color:", GB / (t1 - t0), (t1 - t0) / N)) g.message("%-50s %g GB/s %g s" % ("merge_color:", GB / (t2 - t1), (t2 - t1) / N)) xs = g.separate_spin(msc) g.merge_spin(msc, xs) t0 = g.time()
def quark_contract_xx(mspincolor1, mspincolor2, components): """ This routine is written for Nc = 3 y^{k2, k1} = \\sum_{i1, i2, j1, j2} \\epsilon^{i1, j1, k1} \\epsilon^{i2, j2, k2} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(0, 1, 2), +(1, 2, 0), +(2, 0, 1), -(1, 0, 2), -(0, 2, 1), -(2, 1, 0) i.e. - y^{0, 0} = \\epsilon^{i1, j1, 0} \\epsilon^{i2, j2, 0} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(1, 2, 0), -(2, 1, 0); +(1, 2, 0), -(2, 1, 0) - y^{0, 1} = \\epsilon^{i1, j1, 1} \\epsilon^{i2, j2, 0} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(2, 0, 1), -(0, 2, 1); +(1, 2, 0), -(2, 1, 0) - y^{0, 2} = \\epsilon^{i1, j1, 2} \\epsilon^{i2, j2, 0} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(0, 1, 2), -(1, 0, 2) +(1, 2, 0), -(2, 1, 0) - y^{1, 0} = \\epsilon^{i1, j1, 0} \\epsilon^{i2, j2, 1} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(1, 2, 0), -(2, 1, 0) +(2, 0, 1), -(0, 2, 1) - y^{1, 1} = \\epsilon^{i1, j1, 1} \\epsilon^{i2, j2, 1} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(2, 0, 1), -(0, 2, 1) +(2, 0, 1), -(0, 2, 1) - y^{1, 2} = \\epsilon^{i1, j1, 2} \\epsilon^{i2, j2, 1} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(0, 1, 2), -(1, 0, 2) +(2, 0, 1), -(0, 2, 1) - y^{2, 0} = \\epsilon^{i1, j1, 0} \\epsilon^{i2, j2, 2} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(1, 2, 0), -(2, 1, 0) +(0, 1, 2), -(1, 0, 2) - y^{2, 1} = \\epsilon^{i1, j1, 1} \\epsilon^{i2, j2, 2} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(2, 0, 1), -(0, 2, 1) +(0, 1, 2), -(1, 0, 2) - y^{2, 2} = \\epsilon^{i1, j1, 2} \\epsilon^{i2, j2, 2} xc1^{i1, i2} xc2^{j1, j2} Permutations: +(0, 1, 2), -(1, 0, 2) +(0, 1, 2), -(1, 0, 2) """ t_separatespin, t_separatecolor, t_create, t_bilinear, t_merge = 0.0, 0.0, 0.0, 0.0, 0.0 t_start = gpt.time() comps1, comps2 = dict(), dict() for mspincolor, comps in [[mspincolor1, comps1], [mspincolor2, comps2]]: if isinstance(mspincolor, gpt.lattice): t_separatespin -= gpt.time() spin_separated = gpt.separate_spin(mspincolor) t_separatespin += gpt.time() for spinkey in spin_separated: t_separatecolor -= gpt.time() comps[spinkey] = gpt.separate_color(spin_separated[spinkey]) t_separatecolor += gpt.time() elif isinstance(mspincolor, dict): for spinkey in mspincolor: n_keys = len(mspincolor[spinkey]) n_colors = np.sqrt(n_keys) assert n_colors == int(n_colors) assert (int(n_colors) - 1, int(n_colors) - 1) in mspincolor[spinkey] comps[spinkey] = mspincolor[spinkey] grid = comps1[0, 0][0, 0].grid t_create -= gpt.time() dst = gpt.mspincolor(grid) spinsep_dst = {(ii // 4, ii % 4): gpt.mcolor(grid) for ii in range(16)} bilinear_result = [gpt.complex(grid) for _ in range(9)] t_create += gpt.time() leftbase = np.array( [[4, 5, 7, 8], [7, 8, 1, 2], [1, 2, 4, 5], [5, 3, 8, 6], [8, 6, 2, 0], [2, 0, 5, 3], [3, 4, 6, 7], [6, 7, 0, 1], [0, 1, 3, 4]], dtype=np.int32) rightbase = np.array( [[8, 7, 5, 4], [2, 1, 8, 7], [5, 4, 2, 1], [6, 8, 3, 5], [0, 2, 6, 8], [3, 5, 0, 2], [7, 6, 4, 3], [1, 0, 7, 6], [4, 3, 1, 0]], dtype=np.int32) for spin_key in components.keys(): lefts, rights = [], [] bilin_coeffs, bilin_leftbasis, bilin_rightbasis = [], [], [] for nn, comps in enumerate(components[spin_key]): c0_0, c0_1, c1_0, c1_1 = comps for ii in range(9): lefts.append(comps1[c0_0, c0_1][ii // 3, ii % 3]) rights.append(comps2[c1_0, c1_1][ii // 3, ii % 3]) bilin_coeffs = np.append(bilin_coeffs, [1.0, -1.0, -1.0, +1.0]) bilin_leftbasis.append(leftbase + nn * 9) bilin_rightbasis.append(rightbase + nn * 9) bilin_coeffs = np.array([bilin_coeffs for _ in range(9)], dtype=np.int32) bilin_leftbasis = np.concatenate(bilin_leftbasis, axis=1) bilin_rightbasis = np.concatenate(bilin_rightbasis, axis=1) t_bilinear -= gpt.time() gpt.bilinear_combination(bilinear_result, lefts, rights, bilin_coeffs, bilin_leftbasis, bilin_rightbasis) t_bilinear += gpt.time() cmat_dict = dict() for ii in range(9): cmat_dict[ii // 3, ii % 3] = bilinear_result[ii] t_merge -= gpt.time() gpt.merge_color(spinsep_dst[spin_key], cmat_dict) t_merge += gpt.time() t_merge -= gpt.time() gpt.merge_spin(dst, spinsep_dst) t_merge += gpt.time() t_total = gpt.time() - t_start t_profiled = t_separatespin + t_separatecolor + t_create + t_bilinear + t_merge if gpt.default.is_verbose("quark_contract_xx"): gpt.message("quark_contract_xx: total", t_total, "s") gpt.message("quark_contract_xx: t_separatespin", t_separatespin, "s", round(100 * t_separatespin / t_total, 1), "%") gpt.message("quark_contract_xx: t_separatecolor", t_separatecolor, "s", round(100 * t_separatecolor / t_total, 1), "%") gpt.message("quark_contract_xx: t_create", t_create, "s", round(100 * t_create / t_total, 1), "%") gpt.message("quark_contract_xx: t_bilinear", t_bilinear, "s", round(100 * t_bilinear / t_total, 1), "%") gpt.message("quark_contract_xx: t_merge", t_merge, "s", round(100 * t_merge / t_total, 1), "%") gpt.message("quark_contract_xx: unprofiled", t_total - t_profiled, "s", round(100 * (t_total - t_profiled) / t_total, 1), "%") return dst
def reunitize(gauge): # 'project' site-local matrix to SU(N). # * roughly equivalent to Grids 'ProjectOnGroup' # * uses the "modified Gram-Schmidt process" # * intended to remove numerical rounding errors during HMC # * can be unstable for very large N or input far away from SU(N) (not an issue for intended usecase) if type(gauge) == list: for u in gauge: reunitize(u) return t_total, t_sep, t_merge, t_c, t_norm, t_det = 0, 0, 0, 0, 0, 0 t_total -= gpt.time() assert type(gauge) == gpt.lattice shape = gauge.otype.shape assert len(shape) == 2 and shape[0] == shape[1] n_color = shape[0] t_sep -= gpt.time() tmp = gpt.separate_color(gauge) t_sep += gpt.time() c = gpt.complex(tmp[0, 0].grid) norm = gpt.complex(tmp[0, 0].grid) # step 1: (modified) Gram-Schmidt process to get a unitary matrix for i in range(n_color): for j in range(i): t_c -= gpt.time() c @= gpt.conj(tmp[j, 0]) * tmp[i, 0] for k in range(1, n_color): c += gpt.conj(tmp[j, k]) * tmp[i, k] for k in range(n_color): tmp[i, k] -= c * tmp[j, k] t_c += gpt.time() t_norm -= gpt.time() norm @= gpt.component.pow(2) * gpt.component.abs(tmp[i, 0]) for k in range(1, n_color): norm += gpt.component.pow(2) * gpt.component.abs(tmp[i, k]) norm @= gpt.component.inv(gpt.component.sqrt(norm)) for k in range(n_color): tmp[i, k] *= norm t_norm += gpt.time() t_merge -= gpt.time() gpt.merge_color(gauge, tmp) t_merge += gpt.time() # step 2: fix the determinant (NOTE: Grids 'ProjectOnGroup' skips this step) t_det -= gpt.time() gauge *= gpt.component.pow(-1. / n_color) * gpt.matrix.det(gauge) t_det += gpt.time() t_total += gpt.time() if gpt.default.is_verbose("reunitize"): t_unprofiled = t_total - t_sep - t_merge - t_norm - t_c - t_det gpt.message("reunitize: total", t_total, "s") gpt.message("reunitize: t_separate", t_sep, "s", round(100 * t_sep / t_total, 1), "%") gpt.message("reunitize: t_merge", t_merge, "s", round(100 * t_merge / t_total, 1), "%") gpt.message("reunitize: t_c", t_c, "s", round(100 * t_c / t_total, 1), "%") gpt.message("reunitize: t_norm", t_norm, "s", round(100 * t_norm / t_total, 1), "%") gpt.message("reunitize: t_det", t_det, "s", round(100 * t_det / t_total, 1), "%") gpt.message("reunitize: unprofiled", t_unprofiled, "s", round(100 * t_unprofiled / t_total, 1), "%")