def METHOD_NAME(psi, src, t):
    # timing
    t("setup")
    # parameters
    rlen = self.restartlen
    # tensors
    dtype = g.double.complex_dtype
    H = np.zeros((rlen + 1, rlen), dtype)
    c = np.zeros((rlen + 1), dtype)
    s = np.zeros((rlen + 1), dtype)
    y = np.zeros((rlen + 1), dtype)
    gamma = np.zeros((rlen + 1), dtype)
    # fields
    mmpsi, r = (
        g.copy(src),
        g.copy(src),
    )
    V = [g.lattice(src) for i in range(rlen + 1)]
    Z = (
        [g.lattice(src) for i in range(rlen + 1)] if prec is not None else None
    )  # save vectors if unpreconditioned
    ZV = Z if prec is not None else V
    # initial residual
    t("restart")
    r2 = self.restart(mat, psi, mmpsi, src, r, V, Z, gamma, t)
    t("setup")
    # source
    ssq = g.norm2(src)
    if ssq == 0.0:
        assert r2 != 0.0  # need either source or psi to not be zero
        ssq = r2
    # target residual
    rsq = self.eps**2.0 * ssq
    for k in range(self.maxiter):
        # iteration within current krylov space
        i = k % rlen
        # iteration criteria
        need_restart = i + 1 == rlen
        t("prec")
        if prec is not None:
            ZV[i][:] = 0
            prec(ZV[i], V[i])
        t("mat")
        mat(V[i + 1], ZV[i])
        t("ortho")
        g.orthogonalize(V[i + 1], V[0 : i + 1], H[:, i], nblock=10)
        t("linalg norm2")
        H[i + 1, i] = g.norm2(V[i + 1]) ** 0.5
        if H[i + 1, i] == 0.0:
            self.debug(f"breakdown, H[{i+1:d}, {i:d}] = 0")
            break
        t("linalg div")
        V[i + 1] /= H[i + 1, i]
        t("qr")
        self.qr_update(s, c, H, gamma, i)
        t("other")
        r2 = np.absolute(gamma[i + 1]) ** 2
        self.log_convergence((k, i), r2, rsq)
        if r2 <= rsq or need_restart:
            t("update_psi")
            self.update_psi(psi, gamma, H, y, ZV, i)
        if r2 <= rsq:
            msg = f"converged in {k+1} iterations;  computed squared residual {r2:e} / {rsq:e}"
            if self.checkres:
                res = self.calc_res(mat, psi, mmpsi, src, r, t)
                msg += f";  true squared residual {res:e} / {rsq:e}"
            self.log(msg)
            return
        if need_restart:
            t("restart")
            r2 = self.restart(mat, psi, mmpsi, src, r, V, Z, gamma, t)
            self.debug("performed restart")
    msg = f"NOT converged in {k+1} iterations;  computed squared residual {r2:e} / {rsq:e}"
    if self.checkres:
        res = self.calc_res(mat, psi, mmpsi, src, r, t)
        msg += f";  true squared residual {res:e} / {rsq:e}"
    self.log(msg)