def METHOD_NAME(self, max_iterations=None, tol=1e-7, debug_callback=None):
    check_interval = 20
    if max_iterations is None:
        max_iterations = max(3 * check_interval + 1, 10 * self.operator.shape[0])
    real_resid_interval = min(self.operator.shape[0], 50)
    iterations = 0
    delta_0 = None
    while iterations < max_iterations:
        compute_real_residual = iterations % real_resid_interval == 0
        self.one_iteration(compute_real_residual=compute_real_residual)
        if debug_callback is not None:
            if compute_real_residual:
                what = "it+residual"
            else:
                what = "it"
            debug_callback(
                what, iterations, self.x, self.residual, self.d, self.delta
            )
        # do often enough to allow AsyncInnerProduct
        # to progress through (polled) event chain
        rdq = self.real_delta_queue
        if iterations % check_interval == 0:
            if delta_0 is None:
                delta_0 = rdq[0].get_host_result()
                if delta_0 is not None:
                    rdq.pop(0)
            if delta_0 is not None:
                i = 0
                while i < len(rdq):
                    delta = rdq[i].get_host_result()
                    if delta is not None:
                        if abs(delta) < tol * tol * abs(delta_0):
                            if debug_callback is not None:
                                debug_callback(
                                    "end",
                                    iterations,
                                    self.x,
                                    self.residual,
                                    self.d,
                                    self.delta,
                                )
                            return self.x
                        rdq.pop(i)
                    else:
                        i += 1
        iterations += 1
    raise ConvergenceError("cg failed to converge")