Skip to content

Commit

Permalink
new features
Browse files Browse the repository at this point in the history
  • Loading branch information
lehner committed Sep 5, 2024
1 parent 9e51790 commit c58bb68
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 13 deletions.
22 changes: 21 additions & 1 deletion lib/gpt/algorithms/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import gpt, sys
import gpt, sys, os
from datetime import datetime


class base:
Expand Down Expand Up @@ -69,15 +70,34 @@ class base_iterative(base):
def __init__(self, name=None):
super().__init__(name)
self.verbose_convergence = gpt.default.is_verbose(self.name + "_convergence")
self.verbose_log_convergence = gpt.default.is_verbose(self.name + "_log_convergence")
self.converged = None

def get_log_file(self):
if not self.verbose_log_convergence or gpt.rank() != 0:
return None

self.log_directory = "log/" + datetime.today().strftime("%Y-%m-%d")
if not os.path.exists(self.log_directory):
os.makedirs(self.log_directory, exist_ok=True)

log_filename = f"{self.log_directory}/{self.name}." + datetime.now().strftime("%H-%M-%f")
gpt.message(f"Convergence of {self.name} saved in {log_filename}")
return open(log_filename, "wt")

def log_convergence(self, iteration, value, target=None):
if (isinstance(iteration, int) and iteration == 0) or (
isinstance(iteration, tuple) and all([x == 0 for x in iteration])
):
self.history = []
self.log_file = self.get_log_file()

self.history.append(value)
if self.log_file is not None:
if target is None:
self.log_file.write(f"{iteration} {value}\n")
else:
self.log_file.write(f"{iteration} {value:e} {target:e}\n")

if target is not None:
self.converged = value <= target
Expand Down
1 change: 1 addition & 0 deletions lib/gpt/core/group/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
compose,
projected_convert,
inverse,
invariant_distance,
)
from gpt.core.group.differentiable_functional import differentiable_functional
from gpt.core.group.diffeomorphism import diffeomorphism, local_diffeomorphism
6 changes: 6 additions & 0 deletions lib/gpt/core/group/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ def defect(field):
return field.otype.defect(field)


def invariant_distance(field, field_prime):
field = g(field)
field_prime = g(field_prime)
return field.otype.invariant_distance(field, field_prime)


def cartesian(field):
if isinstance(field, list):
return [cartesian(f) for f in field]
Expand Down
12 changes: 12 additions & 0 deletions lib/gpt/core/object_type/su_n.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ def __init__(self, Nc, Ndim, name):
def cartesian(self):
return self

def invariant_distance(self, a, b):
c = gpt(a - b)
ds2 = 2.0 * gpt.sum(gpt.trace(c * c)).real
return ds2**0.5

def defect(self, A):
err2 = gpt.norm2(gpt.adj(A) - A)
err2 += gpt.norm2(gpt.trace(A))
Expand Down Expand Up @@ -129,6 +134,13 @@ def __init__(self, Nc, Ndim, name):
def compose(self, a, b):
return a * b

def invariant_distance(self, a, b):
d = gpt(a - b)
v = gpt(a + b)
c = self.infinitesimal_to_cartesian(v, d)
ds2 = 2.0 * gpt.sum(gpt.trace(c * c)).real
return ds2**0.5

def defect(self, U):
I = gpt.identity(U)
I_s = gpt.identity(gpt.complex(U.grid))
Expand Down
2 changes: 1 addition & 1 deletion lib/gpt/qcd/gauge/smear/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
#
from gpt.qcd.gauge.smear.stout import stout, differentiable_stout
from gpt.qcd.gauge.smear.local_stout import local_stout
from gpt.qcd.gauge.smear.wilson_flow import wilson_flow
from gpt.qcd.gauge.smear.wilson_flow import wilson_flow, gradient_flow
from gpt.qcd.gauge.smear.differentiable import differentiable_field_transformation
25 changes: 17 additions & 8 deletions lib/gpt/qcd/gauge/smear/differentiable.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,24 @@
#
import gpt as g
from gpt.core.group import diffeomorphism, differentiable_functional
from gpt.ad import reverse as rad


def assert_compatible(a, b, tag=""):
if type(a) is not type(b):
raise Exception(f"Incompatible types: {type(a)} and {type(b)}{tag}")
if isinstance(a, rad.node_base):
assert_compatible(a.value, b.value, " root " + str(type(a)))


class dft_diffeomorphism(diffeomorphism):
def __init__(self, U, ft):
rad = g.ad.reverse
self.ft = ft
self.aU = [rad.node(u.new()) for u in U]
self.aU = [rad.node(u) for u in U]
self.aUft = ft(self.aU)

def __call__(self, fields):
# ft needs to be callable with a node or a lattice
res = self.ft(fields)
return [g(x) for x in res]

Expand All @@ -37,6 +45,7 @@ def jacobian(self, fields, fields_prime, dfields):
assert len(dfields) == N
aU_prime = [g(2j * dfields[mu] * fields_prime[mu]) for mu in range(N)]
for mu in range(N):
assert_compatible(self.aU[mu].value, fields[mu])
self.aU[mu].value = fields[mu]
gradient = [None] * N
for mu in range(N):
Expand Down Expand Up @@ -69,19 +78,19 @@ def adjoint_jacobian(self, fields, dfields):


class dft_action_log_det_jacobian(differentiable_functional):
def __init__(self, U, ft, dfm, inverter_force, inverter_action):
def __init__(self, U, ft, dfm, dfm_node, inverter_force, inverter_action):
self.dfm = dfm
self.dfm_node = dfm_node
self.inverter_force = inverter_force
self.inverter_action = inverter_action
self.N = len(U)
mom = [g.group.cartesian(u) for u in U]
rad = g.ad.reverse

_U = [rad.node(g.copy(u)) for u in U]
_left = [rad.node(g.copy(u), with_gradient=False) for u in mom]
_right = [rad.node(g.copy(u), with_gradient=False) for u in mom]
_Up = dfm(_U)
J_right = dfm.jacobian(_U, _Up, _right)
_Up = dfm_node(_U)
J_right = dfm_node.jacobian(_U, _Up, _right)

act = None
for mu in range(self.N):
Expand Down Expand Up @@ -167,6 +176,7 @@ def __init__(self, U, ft, inverter_force, inverter_action, optimizer):
self.ft = ft
self.U = U
self.dfm = dft_diffeomorphism(self.U, self.ft)
self.dfm_node = dft_diffeomorphism([rad.node(u) for u in self.U], self.ft)
self.inverter_force = inverter_force
self.inverter_action = inverter_action
self.optimizer = optimizer
Expand All @@ -175,7 +185,6 @@ def diffeomorphism(self):
return self.dfm

def inverse(self, Uft):
rad = g.ad.reverse
aU = [rad.node(g.copy(u)) for u in Uft]
aUft_target = [rad.node(u, with_gradient=False) for u in Uft]
aUft = self.ft(aU)
Expand All @@ -186,5 +195,5 @@ def inverse(self, Uft):

def action_log_det_jacobian(self):
return dft_action_log_det_jacobian(
self.U, self.ft, self.dfm, self.inverter_force, self.inverter_action
self.U, self.ft, self.dfm, self.dfm_node, self.inverter_force, self.inverter_action
)
2 changes: 1 addition & 1 deletion lib/gpt/qcd/gauge/smear/stout.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def __call__(self, aU):

U_prime = []
for mu in range(nd):
U_mu_prime = (
U_mu_prime = g(
g.matrix.exp(g.qcd.gauge.project.traceless_anti_hermitian(C[mu] * g.adj(aU[mu])))
* aU[mu]
)
Expand Down
8 changes: 6 additions & 2 deletions lib/gpt/qcd/gauge/smear/wilson_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@
import gpt as g


def wilson_flow(U, epsilon):
action = g.qcd.gauge.action.wilson(2.0 * U[0].otype.shape[0])
def gradient_flow(U, epsilon, action):
return g.algorithms.integrator.runge_kutta_4(
U, lambda Up: [g(-u) for u in action.gradient(Up, Up)], epsilon
)


def wilson_flow(U, epsilon):
action = g.qcd.gauge.action.wilson(2.0 * U[0].otype.shape[0])
return gradient_flow(U, epsilon, action)
22 changes: 22 additions & 0 deletions tests/qcd/gauge.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,28 @@
# reference plaquette
P = g.qcd.gauge.plaquette(U)

# invariant distance (test axioms)
ds = g.group.invariant_distance(U[0], U[1])
dsp = g.group.invariant_distance(g.group.compose(V, U[0]), g.group.compose(V, U[1]))
assert abs(ds / dsp - 1) < 1e-12

ds = g.group.invariant_distance(U[0], U[1])
dsp = g.group.invariant_distance(g.group.compose(U[0], V), g.group.compose(U[1], V))
assert abs(ds / dsp - 1) < 1e-12

ds = g.group.invariant_distance(U[0], U[0])
assert ds < 1e-12

ds = g.group.invariant_distance(U[0], U[1])
dsp = g.group.invariant_distance(U[1], U[0])
assert abs(ds / dsp - 1) < 1e-12

mom = [g.group.cartesian(u) for u in U]
rng.element(mom)
ds = g.group.invariant_distance(mom[0], mom[1])
dsp = g.group.invariant_distance(g.group.compose(mom[2], mom[0]), g.group.compose(mom[2], mom[1]))
assert abs(ds / dsp - 1) < 1e-12

# import cgpt, sys

# smr = []
Expand Down

0 comments on commit c58bb68

Please sign in to comment.