Example #1
0
 def is_element(self, U):
     I = gpt.identity(U)
     I_s = gpt.identity(gpt.complex(U.grid))
     err2 = gpt.norm2(U * gpt.adj(U) - I) / gpt.norm2(I)
     err2 += gpt.norm2(gpt.matrix.det(U) - I_s) / gpt.norm2(I_s)
     # consider additional determinant check
     return err2**0.5 < U.grid.precision.eps * 10.0
Example #2
0
    def __call__(self, mat, src, t):
        dst, tmp = g.lattice(src), g.copy(src)

        tmp /= g.norm2(tmp) ** 0.5

        ev_prev = None
        for it in range(self.maxit):
            t("matrix")
            mat(dst, tmp)
            t("inner_product")
            ev = g.inner_product(tmp, dst)
            t("other")
            if self.real:
                ev = ev.real
            self.log_convergence(it, ev)
            t("normalize")
            tmp @= dst / g.norm2(dst) ** 0.5
            t("other")
            if ev_prev is not None:
                if abs(ev - ev_prev) < self.tol * abs(ev):
                    self.log(f"converged in iteration {it}")
                    return (ev, tmp, True)
            ev_prev = ev

        return (ev, tmp, False)
Example #3
0
def check_unitarity(U, eps_ref):
    eye = g.lattice(U)
    eye[:] = np.eye(U.otype.shape[0], dtype=U.grid.precision.complex_dtype)
    eps = (g.norm2(U * g.adj(U) - eye) / g.norm2(eye))**0.5
    g.message(f"Test unitarity: {eps}")
    assert eps < eps_ref
    U.otype.is_element(U)
Example #4
0
def log(i, convergence_threshold=0.5):
    # i = n*(1 + x), log(i) = log(n) + log(1+x)
    # x = i/n - 1, |x|^2 = <i/n - 1, i/n - 1> = |i|^2/n^2 + |1|^2 - (<i,1> + <1,i>)/n
    # d/dn |x|^2 = -2 |i|^2/n^3 + (<i,1> + <1,i>)/n^2 = 0 -> 2|i|^2 == n (<i,1> + <1,i>)
    if i.grid.precision != gpt.double:
        x = gpt.convert(i, gpt.double)
    else:
        x = gpt.copy(i)
    I = numpy.identity(x.otype.shape[0], x.grid.precision.complex_dtype)
    lI = gpt.lattice(x)
    lI[:] = I
    n = gpt.norm2(x) / gpt.inner_product(x, lI).real
    x /= n
    x -= lI
    n2 = gpt.norm2(x)**0.5 / x.grid.gsites
    order = 8 * int(16 / (-numpy.log10(n2)))
    assert n2 < convergence_threshold
    o = gpt.copy(x)
    xn = gpt.copy(x)
    for j in range(2, order + 1):
        xn @= xn * x
        o -= xn * ((-1.0)**j / j)
    o += lI * numpy.log(n)
    if i.grid.precision != gpt.double:
        r = gpt.lattice(i)
        gpt.convert(r, o)
        o = r
    return o
Example #5
0
 def inv(dst, src):
     for i in range(len(dst)):
         eps = g.norm2(mat * dst[i] - src[i]) ** 0.5
         nrm = g.norm2(src[i]) ** 0.5
         g.message(
             f"{self.tag}| mat * dst[{i}] - src[{i}] | / | src | = {eps/nrm}, | src[{i}] | = {nrm}"
         )
Example #6
0
 def __call__(self, mat, src, psi):
     assert (src != psi)
     self.history = []
     verbose = g.default.is_verbose("cg")
     t0 = g.time()
     p, mmp, r = g.copy(src), g.copy(src), g.copy(src)
     guess = g.norm2(psi)
     mat(psi, mmp)  # in, out
     d = g.innerProduct(psi, mmp).real
     b = g.norm2(mmp)
     r @= src - mmp
     p @= r
     a = g.norm2(p)
     cp = a
     ssq = g.norm2(src)
     rsq = self.eps**2. * ssq
     for k in range(1, self.maxiter + 1):
         c = cp
         mat(p, mmp)
         dc = g.innerProduct(p, mmp)
         d = dc.real
         a = c / d
         cp = g.axpy_norm2(r, -a, mmp, r)
         b = cp / c
         psi += a * p
         p @= b * p + r
         self.history.append(cp)
         if verbose:
             g.message("res^2[ %d ] = %g" % (k, cp))
         if cp <= rsq:
             if verbose:
                 t1 = g.time()
                 g.message("Converged in %g s" % (t1 - t0))
             break
Example #7
0
def test(slv, name):
    t0 = g.time()
    dst = g.eval(slv * src)
    t1 = g.time()
    eps2 = g.norm2(dst_cg - dst) / g.norm2(dst_cg)
    g.message("%s finished: eps^2(CG) = %g" % (name, eps2))
    timings[name] = t1 - t0
    resid[name] = eps2**0.5
    assert eps2 < 5e-7
Example #8
0
    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}"
            )
Example #9
0
        def inv(psi, src):
            self.history = []
            verbose = g.default.is_verbose("mr")

            t = g.timer("mr")
            t("setup")

            r, mmr = g.copy(src), g.copy(src)

            mat(mmr, psi)
            r @= src - mmr

            r2 = g.norm2(r)
            ssq = g.norm2(src)
            # if ssq == 0.0:
            # assert r2 != 0.0  # need either source or psi to not be zero
            # ssq = r2
            rsq = self.eps ** 2.0 * ssq

            for k in range(self.maxiter):
                t("mat")
                mat(mmr, r)

                t("inner")
                ip, mmr2 = g.inner_product_norm2(mmr, r)
                if mmr2 == 0.0:
                    continue

                t("linearcomb")
                alpha = ip.real / mmr2 * self.relax
                psi += alpha * r

                t("axpy_norm")
                r2 = g.axpy_norm2(r, -alpha, mmr, r)

                t("other")
                self.history.append(r2)

                if verbose:
                    g.message("mr: res^2[ %d ] = %g, target = %g" % (k, r2, rsq))

                if r2 <= rsq:
                    if verbose:
                        t()
                        g.message(
                            "mr: converged in %d iterations, took %g s"
                            % (k + 1, t.dt["total"])
                        )
                        g.message(t)
                    break
Example #10
0
        def opt(x, dx, t):
            x = g.util.to_list(x)
            dx = g.util.to_list(dx)
            for i in range(self.maxiter):
                d = f.gradient(x, dx)

                c = self.line_search(d, x, dx, d, f.gradient, -self.step)

                for nu, x_mu in enumerate(dx):
                    x_mu @= g.group.compose(-self.step * c * d[nu], x_mu)

                rs = (sum(g.norm2(d)) /
                      sum([s.grid.gsites * s.otype.nfloats for s in d]))**0.5

                self.log_convergence(i, rs, self.eps)

                if i % self.nf == 0:
                    self.log(
                        f"iteration {i}: f(x) = {f(x):.15e}, |df|/sqrt(dof) = {rs:e}, step = {c*self.step}"
                    )

                if rs <= self.eps:
                    self.log(
                        f"converged in {i+1} iterations: f(x) = {f(x):.15e}, |df|/sqrt(dof) = {rs:e}"
                    )
                    return True

            self.log(
                f"NOT converged in {i+1} iterations;  |df|/sqrt(dof) = {rs:e} / {self.eps:e}"
            )
            return False
Example #11
0
def verify_projected_even_odd(M, Meo, dst_p, src_p, src):
    src_proj_p = g.lattice(src)
    src_proj_p[:] = 0
    g.set_checkerboard(src_proj_p, src_p)

    dst_proj_p = g.eval(M * src_proj_p)
    g.pick_checkerboard(dst_p.checkerboard(), dst_p, dst_proj_p)

    reference = g.copy(dst_p)

    dst_p @= Meo * src_p

    eps = (g.norm2(dst_p - reference) / g.norm2(reference)) ** 0.5
    eps_ref = src.grid.precision.eps * finger_print_tolerance
    g.message(f"Test projected full matrix result versus eo matrix: {eps}")
    assert eps < eps_ref
Example #12
0
def test_matrix_application(rp):
    rp_src = g(rp(mat) * src)
    rp_src /= rp.norm

    for p in rp.poles:
        g.message(p)
        rp_src @= mat * rp_src - p * rp_src

    dst = g.copy(src)
    for z in rp.zeros:
        g.message(z)
        dst @= mat * dst - z * dst

    eps2 = g.norm2(dst - rp_src) / g.norm2(dst)
    g.message(f"Test of matrix application: {eps2}")
    assert eps2 < 1e-9
Example #13
0
    def implicit_restart(self, H, evals, p):
        n = len(self.H)
        k = n - p
        Q = np.identity(n, np.complex128)
        eye = np.identity(n, np.complex128)

        t0 = g.time()
        for i in range(p):
            Qi, Ri = np.linalg.qr(H - evals[i] * eye)
            H = Ri @ Qi + evals[i] * eye
            Q = Q @ Qi
        t1 = g.time()

        if self.verbose:
            g.message(f"Arnoldi: QR in {t1-t0} s")

        r = g.eval(self.basis[k] * H[k, k - 1] +
                   self.basis[-1] * self.H[-1][-1] * Q[n - 1, k - 1])
        rn = g.norm2(r)**0.5

        t0 = g.time()
        g.rotate(self.basis, np.ascontiguousarray(Q.T), 0, k, 0, n)
        t1 = g.time()

        if self.verbose:
            g.message(f"Arnoldi: rotate in {t1-t0} s")

        self.basis = self.basis[0:k]
        self.basis.append(g.eval(r / rn))
        self.H = [[H[j, i] for j in range(i + 2)] for i in range(k)]
        self.H[-1][-1] = rn
Example #14
0
    def arnoldi(self, mat, V, rlen, mmp, sfgmres, prec, idx, t):
        H = []
        for i in range(rlen):
            if prec is not None:

                t("prec")
                Z = [sfgmres[j].Z[i] for j in idx] + [mmp]
                for z in Z:
                    z[:] = 0
                rhos = prec(Z, [V[i]])
                for j, rho in zip(idx, rhos[0:-1]):
                    sfgmres[j].gamma[i] = rho / rhos[-1]

            t("arnoldi")
            ips = np.zeros(i + 2, np.complex128)
            zv = mmp if prec is not None else V[i]
            mat(V[i + 1], zv)
            g.orthogonalize(
                V[i + 1],
                V[0:i + 1],
                ips[0:-1],
                nblock=10,
            )
            ips[-1] = g.norm2(V[i + 1])**0.5
            V[i + 1] /= ips[-1]
            H.append(ips)
        return H
Example #15
0
    def __call__(self, mat, src, psi):
        verbose = g.default.is_verbose("mr")
        t0 = time()

        r, mmr = g.copy(src), g.copy(src)

        mat(psi, mmr)
        r @= src - mmr

        ssq = g.norm2(src)
        rsq = self.eps**2. * ssq

        for k in range(self.maxiter):
            mat(r, mmr)
            ip, mmr2 = g.innerProductNorm2(mmr, r)

            if mmr2 == 0.:
                continue

            alpha = ip.real / mmr2 * self.relax

            psi += alpha * r
            r2 = g.axpy_norm2(r, -alpha, mmr, r)

            if verbose:
                g.message("res^2[ %d ] = %g" % (k, r2))

            if r2 <= rsq:
                if verbose:
                    t1 = time()
                    g.message("Converged in %g s" % (t1 - t0))
                break
Example #16
0
    def perform(self, root):
        global basis_size, T, current_config
        if current_config is not None and current_config.conf_file != self.conf_file:
            current_config = None
        if current_config is None:
            current_config = config(self.conf_file)

        c = None
        vcj = [
            g.vcolor(current_config.l_exact.U_grid) for jr in range(basis_size)
        ]
        for vcjj in vcj:
            vcjj[:] = 0

        for tprime in range(T):
            basis_evec, basis_evals = g.load(self.basis_fmt %
                                             (self.conf, tprime))

            plan = g.copy_plan(vcj[0],
                               basis_evec[0],
                               embed_in_communicator=vcj[0].grid)
            c = g.coordinates(basis_evec[0])
            plan.destination += vcj[0].view[np.hstack(
                (c, np.ones((len(c), 1), dtype=np.int32) * tprime))]
            plan.source += basis_evec[0].view[c]
            plan = plan()

            for l in range(basis_size):
                plan(vcj[l], basis_evec[l])

        for l in range(basis_size):
            g.message("Check norm:", l, g.norm2(vcj[l]))

        g.save(f"{root}/{self.name}/basis", vcj)
Example #17
0
def exp(i):
    if i.grid.precision != gpt.double:
        x = gpt.convert(i, gpt.double)
    else:
        x = gpt.copy(i)
    n = gpt.norm2(x)**0.5 / x.grid.gsites
    order = 19
    maxn = 0.05
    ns = 0
    if n > maxn:
        ns = int(numpy.log2(n / maxn))
        x /= 2**ns
    o = gpt.lattice(x)
    o[:] = 0
    nfac = 1.0
    xn = gpt.copy(x)
    o[:] = numpy.identity(o.otype.shape[0], o.grid.precision.complex_dtype)
    o += xn
    for j in range(2, order + 1):
        nfac /= j
        xn @= xn * x
        o += xn * nfac
    for j in range(ns):
        o @= o * o
    if i.grid.precision != gpt.double:
        r = gpt.lattice(i)
        gpt.convert(r, o)
        o = r
    return o
Example #18
0
File: evals.py Project: ssolbUR/gpt
def evals(matrix, evec, check_eps2 = None):
    assert(len(evec) > 0)
    tmp=g.lattice(evec[0])
    ev=[]
    for i,v in enumerate(evec):
        matrix(v,tmp)
        # M |v> = l |v> -> <v|M|v> / <v|v>
        l=g.innerProduct(v,tmp).real / g.norm2(v)
        ev.append(l)
        if not check_eps2 is None:
            eps2=g.norm2(tmp - l*v)
            g.message("eval[ %d ] = %g, eps^2 = %g" % (i,l,eps2))
            if eps2 > check_eps2:
                assert(0)

    return ev
Example #19
0
        def inv(psi, src, t):
            t("setup")

            # inner source
            n = len(src)
            _s = [g.lattice(x) for x in src]

            # norm of source
            norm2_of_source = g.norm2(src)
            for j in range(n):
                if norm2_of_source[j] == 0.0:
                    norm2_of_source[j] = g.norm2(outer_mat * psi[j])
                    if norm2_of_source[j] == 0.0:
                        norm2_of_source[j] = 1.0

            for i in range(self.maxiter):

                t("outer matrix")
                for j in range(n):
                    _s[j] @= src[j] - outer_mat * psi[j]  # remaining src

                t("norm2")
                norm2_of_defect = g.norm2(_s)

                # true resid
                t("norm2")
                eps = max([(norm2_of_defect[j] / norm2_of_source[j])**0.5
                           for j in range(n)])

                self.log_convergence(i, eps, self.eps)

                if eps < self.eps:
                    self.log(f"converged in {i+1} iterations")
                    break

                # normalize _s to avoid floating-point underflow in inner_inv_mat
                t("linear algebra")
                for j in range(n):
                    _s[j] /= norm2_of_source[j]**0.5

                # correction step
                t("inner inverter")
                _d = inner_inv_mat(_s)

                t("linear algebra")
                for j in range(n):
                    psi[j] += _d[j] * norm2_of_source[j]**0.5
Example #20
0
    def draw(self, fields, rng):
        M, U, phi = self._updated(fields)

        eta = g.lattice(phi)
        rng.cnormal(eta, sigma=2.0**-0.5)  # 1/sqrt(2)

        phi @= self.operator.M(M) * eta
        return g.norm2(eta)
Example #21
0
def multi_shift_test(ms, name):
    dst_ms = g(ms(mat) * src)
    for i, s in enumerate(shifts):
        g.message(
            f"General multi-shift vs multi_shift_{name} for shift {i} = {s}")
        for jsrc in range(2):
            eps2 = g.norm2(dst_all[2 * i + jsrc] -
                           dst_ms[2 * i + jsrc]) / g.norm2(
                               dst_ms[2 * i + jsrc])
            g.message(
                f"Test general solution versus ms{name} solution: {eps2}")
            assert eps2 < 1e-14
            eps2 = g.norm2(mat * dst_ms[2 * i + jsrc] +
                           s * dst_ms[2 * i + jsrc] - src[jsrc]) / g.norm2(
                               src[jsrc])
            g.message(f"Test ms{name} inverter solution: {eps2}")
            assert eps2 < 1e-14
Example #22
0
File: cg.py Project: krox/gpt
 def inv(psi, src):
     assert src != psi
     self.history = []
     verbose = g.default.is_verbose("cg")
     t = g.timer("cg")
     t("setup")
     p, mmp, r = g.copy(src), g.copy(src), g.copy(src)
     mat(mmp, psi)  # in, out
     d = g.inner_product(psi, mmp).real
     b = g.norm2(mmp)
     r @= src - mmp
     p @= r
     a = g.norm2(p)
     cp = a
     ssq = g.norm2(src)
     if ssq == 0.0:
         assert a != 0.0  # need either source or psi to not be zero
         ssq = a
     rsq = self.eps ** 2.0 * ssq
     for k in range(1, self.maxiter + 1):
         c = cp
         t("mat")
         mat(mmp, p)
         t("inner")
         dc = g.inner_product(p, mmp)
         d = dc.real
         a = c / d
         t("axpy_norm")
         cp = g.axpy_norm2(r, -a, mmp, r)
         t("linearcomb")
         b = cp / c
         psi += a * p
         p @= b * p + r
         t("other")
         self.history.append(cp)
         if verbose:
             g.message("cg: res^2[ %d ] = %g, target = %g" % (k, cp, rsq))
         if cp <= rsq:
             if verbose:
                 t()
                 g.message(
                     "cg: converged in %d iterations, took %g s"
                     % (k, t.dt["total"])
                 )
                 g.message(t)
             break
Example #23
0
def fields_agree_openqcd(ref, res):
    """
    Implements the correctness check as it is used in openqcd, sarchive.c:614
    """
    if type(ref) == g.lattice and type(res) == g.lattice:
        assert ref.grid.precision == g.double and res.grid.precision == g.double

    norm2_ref = g.norm2(ref) if type(ref) == g.lattice else ref
    norm2_res = g.norm2(res) if type(res) == g.lattice else res

    diff = abs(norm2_res - norm2_ref)
    tol = 64.0 * (norm2_ref + norm2_res) * sys.float_info.epsilon

    g.message(
        f"openqcd residual check: reference = {norm2_ref:25.20e}, result = {norm2_res:25.20e}, difference = {diff:25.20e}, tol = {tol:25.20e} -> check {'passed' if diff <= tol else 'failed'}"
    )
    return diff <= tol
Example #24
0
        def inv(psi, src, t):

            if len(self.solution_space) == 0:
                return

            t("orthonormalize")
            v = g.orthonormalize(g.copy(self.solution_space))

            # Idea is to minimize
            #
            #  res = | M a_i v_i - src |^2
            #      = v_i^dag a_i^dag M^dag M a_j v_j + src^dag src - src^dag M a_i v_i - v_i^dag a_i^dag M^dag src
            #
            # by selecting an optimal a_i, i.e., to compute
            #
            #  d res/d a_i^dag = v_i^dag M^dag M a_j v_j - v_i^dag M^dag src = 0
            #
            # Therefore
            #
            #  G_ij a_j = b_i
            #
            # with b_i = v_i^dag M^dag src,  G_ij = v_i^dag M^dag M v_j
            #

            t("mat v")
            mat_v = [mat(x) for x in v]

            t("projected source")
            b = g.inner_product(mat_v, src)[:, 0]

            t("projected matrix")
            G_ij = np.matrix([
                g.inner_product(mat_v, mat_v[j])[:, 0] for j in range(len(v))
            ]).T

            t("solve")
            a = np.linalg.solve(G_ij, b)

            t("linear combination")
            g.linear_combination(psi, v, a)

            eps2 = g.norm2(mat(psi) - src) / g.norm2(src)
            self.log(
                f"minimal residual with {len(v)}-dimensional solution space has eps^2 = {eps2}"
            )
Example #25
0
def fields_agree(ref, res, tol):
    """
    Implements the standard correctness check between two fields with their relative deviation
    """
    norm2_ref = g.norm2(ref) if type(ref) == g.lattice else ref
    norm2_res = g.norm2(res) if type(res) == g.lattice else res

    if type(ref) == g.lattice and type(res) == g.lattice:
        diff = g.norm2(res - ref)
    else:
        diff = abs(norm2_ref - norm2_res)

    rel_dev = diff / norm2_ref

    g.message(
        f"default residual check: reference = {norm2_ref:25.20e}, result = {norm2_res:25.20e},    rel_dev = {rel_dev:25.20e}, tol = {tol:25.20e} -> check {'passed' if rel_dev <= tol else 'failed'}"
    )
    return rel_dev <= tol
Example #26
0
def divergence(f, current):
    resN = g.lattice(f)
    resN[:] = 0

    for mu in range(4):
        c_mu = current(f, f, mu)
        resN += c_mu - g.cshift(c_mu, mu, -1)

    return g.norm2(resN)
Example #27
0
File: mr.py Project: wettig/gpt
        def inv(psi, src, t):

            t("setup")

            r, mmr = g.copy(src), g.copy(src)

            mat(mmr, psi)
            r @= src - mmr

            r2 = g.norm2(r)
            ssq = g.norm2(src)
            # if ssq == 0.0:
            # assert r2 != 0.0  # need either source or psi to not be zero
            # ssq = r2
            rsq = self.eps ** 2.0 * ssq

            for k in range(self.maxiter):
                t("mat")
                mat(mmr, r)

                t("inner")
                ip, mmr2 = g.inner_product_norm2(mmr, r)
                if mmr2 == 0.0:
                    continue

                t("linearcomb")
                alpha = ip.real / mmr2 * self.relax
                psi += alpha * r

                t("axpy_norm")
                r2 = g.axpy_norm2(r, -alpha, mmr, r)

                t("other")

                self.log_convergence(k, r2, rsq)

                if r2 <= rsq:
                    self.log(f"converged in {k+1} iterations")
                    return

            self.log(
                f"NOT converged in {k+1} iterations;  squared residual {r2:e} / {rsq:e}"
            )
Example #28
0
def divergence(f, current):
    resN = g.lattice(f)
    resN[:] = 0

    b = g(g.gamma[5] * g.adj(f) * g.gamma[5])
    for mu in range(4):
        c_mu = current(f, b, mu)
        resN += c_mu - g.cshift(c_mu, mu, -1)

    return g.norm2(resN)
Example #29
0
def verify_matrix_element(mat, dst, src, tag):
    src_prime = g.eval(mat * src)
    dst.checkerboard(src_prime.checkerboard())
    X = g.inner_product(dst, src_prime)
    eps_ref = src.grid.precision.eps * 50.0
    if mat.adj_mat is not None:
        X_from_adj = g.inner_product(src, g.adj(mat) * dst).conjugate()
        eps = abs(X - X_from_adj) / abs(X)
        g.message(f"Test adj({tag}): {eps}")
        assert eps < eps_ref
        if mat.inv_mat is not None:
            eps = (g.norm2(src - mat * g.inv(mat) * src) / g.norm2(src))**0.5
            g.message(f"Test inv({tag}): {eps}")
            assert eps < eps_ref
            Y = g.inner_product(dst, g.inv(g.adj(mat)) * src)
            Y_from_adj = g.inner_product(src, g.inv(mat) * dst).conjugate()
            eps = abs(Y - Y_from_adj) / abs(Y)
            g.message(f"Test adj(inv({tag})): {eps}")
            assert eps < eps_ref
    return X
Example #30
0
def check_representation(U, eps_ref):
    algebra = g.convert(U, U.otype.cartesian())

    # then test coordinates function
    algebra2 = g.lattice(algebra)
    algebra2[:] = 0
    algebra2.otype.coordinates(algebra2, algebra.otype.coordinates(algebra))
    eps = (g.norm2(algebra2 - algebra) / g.norm2(algebra))**0.5
    g.message(f"Test coordinates: {eps}")
    assert eps < eps_ref

    # now project to algebra and make sure it is a linear combination of
    # the provided generators
    n0 = g.norm2(algebra)
    algebra2.otype.coordinates(
        algebra2, g.component.real(algebra.otype.coordinates(algebra)))
    algebra -= algebra2
    eps = (g.norm2(algebra) / n0)**0.5
    g.message(f"Test representation: {eps}")
    assert eps < eps_ref