//  [python]
def __call__(
        self, n_iterations: Optional[int] = None, eig_threshold: Optional[float] = None
    ) -> None:
        """Diagonalize Kohn-Sham Hamiltonian in electrons.
        Also available as :meth:`__call__` to make `Davidson` callable.
        """
        el = self.electrons
        n_bands = el.fillings.n_bands
        n_bands_max = n_bands + el.fillings.n_bands_extra
        helper = type(self) != Davidson
        inner_loop = not (
            helper or ((n_iterations is None) and (eig_threshold is None))
        )
        n_iterations = n_iterations if n_iterations else self.n_iterations
        eig_threshold = eig_threshold if eig_threshold else self.eig_threshold
        n_eigs_target = el.fillings.n_bands_min if inner_loop else n_bands

        # Initialize subspace:
        if 2 * n_bands_max >= el.basis.n_min:
            raise ValueError(
                f"n_bands + n_bands_extra = {n_bands_max} exceeds"
                f" min(n_basis)/2 = {el.basis.n_min//2} in Davidson"
            )
        HC = el.hamiltonian(el.C)
        el.eig, V = torch.linalg.eigh((el.C ^ HC).wait())  # subspace eigs
        el.deig_max = np.inf  # don't know eig accuracy yet
        el.C = el.C @ V  # switch to eigen-basis
        HC = HC @ V  # switch to eigen-basis
        self._i_iter = 0
        self._report(inner_loop=inner_loop)
        n_eigs_done = 0

        for self._i_iter in range(self._i_iter + 1, n_iterations + 1):
            n_bands_cur = el.C.n_bands()

            # Compute subspace expansion after dropping converged eigenpairs:
            # --- select unconverged eigenpairs
            eig_sel = el.eig[:, :, n_eigs_done:, None, None]
            C_sel = el.C[:, :, n_eigs_done:] if n_eigs_done else el.C
            HC_sel = HC[:, :, n_eigs_done:] if n_eigs_done else HC
            # --- compute subspace expansion
            KEref = C_sel.band_ke()  # reference KE for preconditioning
            Cexp = self.precondition(HC_sel - C_sel.overlap() * eig_sel, KEref)
            norm_exp = Cexp.band_norm()
            self._regularize(Cexp, norm_exp, self._i_iter)
            Cexp *= 1.0 / norm_exp[..., None, None]
            Cexp.constrain()
            n_bands_exp = Cexp.n_bands()
            n_bands_new = n_bands_cur + n_bands_exp

            # Combine current and expansion subspace:
            Cnew = el.C.cat(Cexp, clear=True)  # this clears el.C and Cexp memory
            Cexp = Cnew[:, :, n_bands_cur:]  # re-set to a view of the concatenation

            # Expansion subspace overlaps:
            C_OC = torch.eye(n_bands_cur, device=V.device)[None, None]
            C_OC_new = TileExpansion(C_OC, Cnew.dot_O(Cexp))

            # Expansion subspace Hamiltonian:
            HCexp = el.hamiltonian(Cexp)
            del Cexp
            C_HC = torch.diag_embed(el.eig)
            C_HC_new = TileExpansion(C_HC, Cnew ^ HCexp)

            # Solve expanded subspace generalized eigenvalue problem:
            eig_new, V_new = eighg(C_HC_new, C_OC_new.wait())
            n_bands_next = min(n_bands_new, n_bands_max)  # number to retain
            V_new = V_new[..., :n_bands_next]  # drop extra bands
            Vcur, Vexp = V_new.split((n_bands_cur, n_bands_exp), dim=2)

            # Update C and HC to optimum n_bands_next subspace from Cnew:
            el.C = Cnew @ V_new
            del Cnew
            HC = HC @ Vcur
            HC += HCexp @ Vexp
            del HCexp
            deig = torch.abs(el.eig - eig_new[..., :n_bands_cur])
            el.eig = eig_new[..., :n_bands_next]

            # Test convergence and report:
            el.deig_max, n_eigs_done = self._check_deig(deig, eig_threshold)
            converged = n_eigs_done >= n_eigs_target
            converge_failed = (self._i_iter == n_iterations) and (
                not (helper or converged)
            )
            self._report(
                inner_loop=inner_loop,
                n_eigs_done=n_eigs_done,
                converged=converged,
                converge_failed=converge_failed,
            )
            if converged:
                break
        if helper:
            self._HC = HC