Letting DIIS choose its own depth: R-CDIIS and AD-CDIIS¶
Pulay’s DIIS keeps a fixed-size rolling window of the last m iterates
(diis_subspace_size, default 8) and extrapolates from all of them.
That fixed m is a compromise: too small and the extrapolation has too
little history to work with; too large and stale, near-linearly-dependent
iterates make the least-squares problem ill-conditioned and can stall or
oscillate the tail of the SCF. This tutorial introduces two accelerators
that remove the guesswork by letting the history depth adapt on the fly.
Both are production routes (label vocabulary in
Methods: theory and status),
and the Theory section gives the restart and window criteria.
They follow Chupin, Dupuy, Legendre and Sere, Convergence analysis of
adaptive DIIS algorithms with application to electronic ground state
calculations, ESAIM: M2AN 55, 2785 (2021),
doi:10.1051/m2an/2021069.
Both variants are drop-in replacements for SCFAccelerator.DIIS: the
extrapolation step is byte-for-byte Pulay’s commutator DIIS, and only the
set of retained iterates differs. They are the adaptive-depth companions
to the EDIIS+DIIS stiff-convergence recipe, which
instead switches the mixing rule near convergence.
Theory¶
What plain DIIS does. Pulay’s commutator DIIS (Pulay, Péter (1980). *Convergence acceleration of iterative sequences. The case of SCF iteration.* Chemical Physics Letters, **73**(2), 393–398. doi:[10.1016/0009-2614(80)80396-4](https://doi.org/10.1016/0009-2614(80)80396-4), Pulay, Péter (1982). *Improved SCF convergence acceleration.* Journal of Computational Chemistry, **3**(4), 556–560. doi:[10.1002/jcc.540030413](https://doi.org/10.1002/jcc.540030413)) stores the Fock matrices \(\mathbf F_j\) and error vectors \(\mathbf e_j = \mathbf F_j\mathbf D_j\mathbf S - \mathbf S\mathbf D_j\mathbf F_j\) of the last \(m\) iterates and extrapolates \(\mathbf F = \sum_j c_j\mathbf F_j\) with the coefficients that minimise the error of the combination under the normalisation constraint,
a small bordered linear system built from the overlaps
\(\langle\mathbf e_i,\mathbf e_j\rangle\) (written out on the
EDIIS+DIIS page). The window length \(m\)
(diis_subspace_size, default 8) is fixed. A short window discards history
that would still help; a long window keeps early iterates whose errors are
far larger than the current one and whose differences are nearly linearly
dependent, so the overlap matrix becomes ill-conditioned and the fitted
Fock matrix noisy. The adaptive variants of
Chupin, Maxime, Dupuy, Mi-Song, et al. (2021). *Convergence analysis of adaptive DIIS algorithms with application to electronic ground state calculations.* ESAIM: Mathematical Modelling and Numerical Analysis, **55**(6), 2785–2825. doi:[10.1051/m2an/2021069](https://doi.org/10.1051/m2an/2021069) keep the same minimisation and
change only which iterates are in the window at each step.
R-CDIIS (restarted). The window grows every iteration. Write \(\Delta\mathbf e_k = \mathbf e_{k+1} - \mathbf e_k\) for the newest error difference and \(\Pi_k\) for the orthogonal projector onto the span of the stored differences. The history is restarted (everything dropped but the last iterate, then regrown) when the new difference is nearly contained in that span,
which is exactly the situation in which the least-squares problem is about
to become ill-conditioned. diis_restart_tau sets \(\tau\); the default
\(10^{-4}\) is the paper’s recommendation.
AD-CDIIS (adaptive depth). Instead of restarting, keep only the iterates whose error is comparable to the current one,
so the window shrinks smoothly as the residual falls and early, large-error
iterates leave it. There is no restart discontinuity, and in the paper’s
numerics this variant tends to give the fastest convergence.
diis_adaptive_delta sets \(\delta\); the default is again \(10^{-4}\).
diis_subspace_size stays a hard cap on the stored iterates for both
variants (a memory safety bound); in practice the adaptive rule trims first
and the mean depth is usually below the fixed default.
Where this helps and where it does not. The adaptive rules address the fixed-history compromise, not the far-from-convergence failure of the commutator objective: they change how the tail of a well-behaved SCF is extrapolated, and they leave the answer unchanged (the accelerator is a solver detail, not a change to the energy functional). On a small, easy molecule they can even take a few more iterations than plain DIIS, as the example below shows. For oscillation far from the minimum, the EDIIS+DIIS hybrid changes the objective instead; the two ideas are independent.
Selecting the accelerator¶
Both variants are ordinary scf_accelerator values, selectable by enum
or by keyword string, exactly like DIIS or EDIIS_DIIS:
import vibeqc as vq
opts = vq.RHFOptions()
# Restarted CDIIS with the paper's default restart parameter.
opts.scf_accelerator = vq.SCFAccelerator.R_CDIIS
opts.diis_restart_tau = 1e-4 # tau in (0, 1); smaller => deeper history
# Or adaptive-depth CDIIS.
opts.scf_accelerator = vq.SCFAccelerator.AD_CDIIS
opts.diis_adaptive_delta = 1e-4 # delta > 0; smaller => deeper history
The keyword-string form (handy for YAML or CLI-driven runs) accepts
"r_cdiis" and "ad_cdiis" plus a few ergonomic spellings:
opts.scf_accelerator = vq.SCFAccelerator.from_string("ad_cdiis")
A molecular example¶
The adaptive variants converge to the same fixed point as plain DIIS; they change the path, not the answer. Water in a minimal basis makes that concrete:
import vibeqc as vq
mol = vq.Molecule([
vq.Atom(8, [0.0, 0.000, 0.221]),
vq.Atom(1, [0.0, 1.427, -0.890]),
vq.Atom(1, [0.0, -1.427, -0.890]),
]) # coordinates in bohr
basis = vq.BasisSet(mol, "sto-3g")
def energy(accel):
opts = vq.RHFOptions()
opts.scf_accelerator = accel
opts.conv_tol_energy = 1e-10
opts.conv_tol_grad = 1e-8
return vq.run_rhf(mol, basis, opts).energy
e_diis = energy(vq.SCFAccelerator.DIIS)
e_rcdiis = energy(vq.SCFAccelerator.R_CDIIS)
e_adcdiis = energy(vq.SCFAccelerator.AD_CDIIS)
assert abs(e_rcdiis - e_diis) < 1e-9
assert abs(e_adcdiis - e_diis) < 1e-9
On a vibe-qc 0.17.10 development build all accelerators converge to
-74.9629979688 Ha. The iteration counts on this easy problem are 7 for
plain DIIS, 7 for the default EDIIS+DIIS, 9 for R-CDIIS and 8 for AD-CDIIS,
so the adaptive variants do not pay off on a system that converges in seven
iterations; their purpose is the stiff tail of harder SCFs.
The same holds for UHF, RKS and UKS: the accelerator is a solver detail, not a change to the energy functional.
A periodic example¶
Because the depth policy lives on the single canonical DIIS kernel, the adaptive variants are available on the periodic drivers too, at a single k-point and across a k-mesh. Here is an H2 chain sampled at a Monkhorst-Pack mesh:
import numpy as np
import vibeqc as vq
sysp = vq.PeriodicSystem(
1, np.diag([6.0, 30.0, 30.0]),
[vq.Atom(1, [0.0, 15.0, 15.0]), vq.Atom(1, [1.4, 15.0, 15.0])],
)
basis = vq.BasisSet(sysp.unit_cell_molecule(), "sto-3g")
kmesh = vq.monkhorst_pack(sysp, [2, 1, 1])
opts = vq.PeriodicRHFOptions()
opts.scf_accelerator = vq.SCFAccelerator.AD_CDIIS
opts.diis_adaptive_delta = 1e-4
res = vq.run_rhf_periodic_multi_k_ewald3d(
sysp, basis, kmesh, opts, omega=0.5, spacing_bohr=0.4,
)
print("converged:", res.converged, "E =", res.energy)
On a vibe-qc 0.17.10 development build this chain (two k-points) converged
in 3 iterations to E = -2.22162183 Ha with plain DIIS, with
AD_CDIIS and with R_CDIIS alike, so on a system this small the
accelerator changes nothing. This is the multi-k Ewald route; a
one-dimensional cell with a k mesh fails closed on the GDF route at present,
so keep GDF examples three-dimensional or Gamma-only.
For the multi-k drivers the depth policy operates on the k-weighted DIIS history, so the restart and residual-ratio tests use the same weighted inner product the Fock extrapolation already minimises.
Choosing the parameters¶
The paper recommends \(\tau = \delta = 10^{-4}\) as a good default, and those are the vibe-qc defaults. The knobs behave monotonically:
Parameter |
Effect of a smaller value |
Effect of a larger value |
|---|---|---|
|
restarts less often, larger mean depth |
restarts more often, shallower history |
|
retains more iterates, larger mean depth |
trims more aggressively, shallower history |
In the paper’s experiments the convergence rate improves as the
parameters shrink, but the mean depth (and therefore the per-iteration
cost) grows roughly linearly, so \(10^{-4}\) is the reported sweet spot.
If a run is memory-bound, diis_subspace_size still caps the worst-case
history length.
When to reach for these¶
Use the adaptive variants when a fixed diis_subspace_size is a poor fit
for the problem: when a large window becomes ill-conditioned and stalls,
or when a small window has too little history to accelerate well. They
self-tune the depth to the problem and, in the paper’s tests, converge at
least as fast as, and often faster than, a hand-picked fixed depth. For
the orthogonal failure mode, oscillation or plateauing far from the
minimum on stiff open-shell or small-gap systems, prefer the
EDIIS+DIIS hybrid, which changes the mixing rule
rather than the depth. The two ideas are independent and target different
problems.
See also¶
SCF convergence, the full accelerator reference and per-backend support table.
Stiff molecular SCF: EDIIS+DIIS, the rule-switching companion for oscillating stiff cases.