Skip to content

fix(rohf): handle linearly dependent bases where n_MO < n_AO (#543) - #554

Open
adithyaphanithota (Adithyaphani) wants to merge 9 commits into
microsoft:mainfrom
Adithyaphani:fix/rohf-linear-dependent-basis-543
Open

fix(rohf): handle linearly dependent bases where n_MO < n_AO (#543)#554
adithyaphanithota (Adithyaphani) wants to merge 9 commits into
microsoft:mainfrom
Adithyaphani:fix/rohf-linear-dependent-basis-543

Conversation

@Adithyaphani

@Adithyaphani adithyaphanithota (Adithyaphani) commented Jun 29, 2026

Copy link
Copy Markdown

Fixes #543

Problem

ROHF with scf_type="restricted" crashes on any system where the AO basis is linearly dependent. When a basis set is linearly dependent on a given geometry (e.g. def2-tzvp on planar o-benzosemiquinone), the solver drops redundant basis functions so that n_MO < n_AO. The MO coefficient matrix C becomes rectangular (nAO × nMO) and the existing code path fails.

Root cause

SCFAlgorithm::build_rohf_f_p_matrix in scf_algorithm.cpp hard-asserted nAO == nMO and used a LAPACK getrf/getrs square-matrix inversion to back-transform F_eff_MO → F_eff_AO. A rectangular C makes that inversion undefined.

Fix

Two-branch strategy in build_rohf_f_p_matrix:

Case Back-transform
nAO == nMO Existing LAPACK C⁻ᵀ F_MO C⁻¹ — unchanged
nMO < nAO Overlap projection F_eff_AO = S C F_MO_eff Cᵀ S via similarity_transform

The projection satisfies Cᵀ F_eff_AO C = F_MO_eff whenever Cᵀ S C = I (standard MO orthonormality w.r.t. S). This is identical to how RHF and UHF operate in the reduced MO space after linear-dependency removal.

Additional guards: direction-only assertion (nMO > nAO still throws), S dimension validation, and electron count validation (nelec > nMO throws with a clear message).

Files changed

File Change
scf_algorithm.h Updated build_rohf_f_p_matrix signature + docstring (adds S param)
scf_algorithm.cpp Remove hard assertion; branch on square vs rectangular back-transform; pass scf_impl.overlap() at call site
cpp/tests/ut_common.hpp Add create_obenzosemiquinone_structure() molecule generator
cpp/tests/test_scf.cpp Add ROHF_RectangularBackTransform_ProjectionIdentity (deterministic) and ROHF_LinearlyDependentBasis_Issue543 (integration)
python/tests/test_scf.py Add create_obenzosemiquinone_structure() and test_rohf_linearly_dependent_basis_issue_543

Testing

  • Deterministic: ROHF_RectangularBackTransform_ProjectionIdentity directly verifies Cᵀ F_eff_AO C = F_MO_eff with a synthetic 4×2 non-identity S and S-orthonormal C — no SCF run needed.
  • Integration: ROHF_LinearlyDependentBasis_Issue543 uses the exact reproducer from the issue (o-benzosemiquinone, def2-tzvp, doublet, scf_type="restricted") and asserts no crash, finite energy, and restricted orbitals. Skips with a clear message on platforms where linear-dependency removal doesn't fire or drops more functions than electrons.

Note: this contribution was developed with AI assistance (Claude) help . All logic has been reviewed against the mathematical derivation by me manually .

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a ROHF crash that occurred when linear-dependency removal yields a rectangular MO coefficient matrix (n_MO < n_AO). It updates the ROHF effective-Fock back-transform to handle both square and rectangular coefficient matrices, aligning ROHF behavior with RHF/UHF in reduced MO spaces, and adds regression coverage for GitHub issue #543.

Changes:

  • Update the ROHF effective Fock back-transform to branch between the existing square-matrix LAPACK solve (nAO == nMO) and an overlap-mediated projection for the rectangular case (nMO < nAO).
  • Thread the AO overlap matrix from SCFAlgorithm into the ROHF DIIS build path to support the new rectangular transform.
  • Add C++ and Python regression tests (plus changelog entry) using the issue #543 reproducer system/basis.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
cpp/src/qdk/chemistry/algorithms/microsoft/scf/src/scf_algorithm/diis.cpp Implements the new two-branch ROHF back-transform and updates the DIIS ROHF build plumbing.
cpp/src/qdk/chemistry/algorithms/microsoft/scf/src/scf_algorithm/diis.h Updates the build_rohf_f_p_matrix signature and documents the rectangular-case projection behavior.
cpp/src/qdk/chemistry/algorithms/microsoft/scf/src/scf_algorithm/scf_algorithm.cpp Passes the AO overlap matrix into the ROHF DIIS build call during convergence checks.
cpp/tests/test_scf.cpp Adds a regression test covering ROHF with a linearly dependent basis (def2-tzvp) reproducing issue #543.
python/tests/test_scf.py Adds a Python regression test (and structure factory) reproducing issue #543 and asserting ROHF completes.
docs/source/changelog.rst Adds a v2.0.0 WIP bug-fix entry describing the ROHF linear-dependency crash fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Adithyaphani

adithyaphanithota (Adithyaphani) commented Jun 29, 2026

Copy link
Copy Markdown
Author

hey Alexis W. Mills (@awoodwa) and David Williams-Young (@wavefunction91) looking forward to your review on this PR , happy to make further changes if needed.

@wavefunction91

Copy link
Copy Markdown
Collaborator

adithyaphanithota (@Adithyaphani) thanks for the contribution! We'll definitely have a look soon. Pinging Boqin Zhang (@BoqinZhang). The only thing I'll note is that this should likely wait until after #453 is merged, as that refactors a large number of ROHF primitives and will likely be a pain to merge directly.

@Adithyaphani

Copy link
Copy Markdown
Author

Thanks for taking a look, David Williams-Young (@wavefunction91) — and good catch on #453.

It does make sense to hold off. PR #453 moves build_rohf_f_p_matrix out of DIIS entirely and into a shared cache on the SCFAlgorithm base class, which directly overlaps with the function this PR modifies. Merging this first would just create unnecessary conflict work for Boqin Zhang (@BoqinZhang).

I'll keep this open and rebase once #453 lands. The core fix here — the overlap-mediated projection F_eff_AO = S · C · F_MO_eff · Cᵀ · S for the n_MO < n_AO case — should carry over cleanly regardless of which class ends up owning the cache, so the rebase should mostly be a relocation rather than a rewrite.

Happy to wait on this and make changes if needed.

@wavefunction91

Copy link
Copy Markdown
Collaborator

Hi adithyaphanithota (@Adithyaphani), #453 is merged.

Copilot AI review requested due to automatic review settings July 1, 2026 05:03
@Adithyaphani
adithyaphanithota (Adithyaphani) force-pushed the fix/rohf-linear-dependent-basis-543 branch from ac1517d to 01639bb Compare July 1, 2026 05:03
@Adithyaphani

Copy link
Copy Markdown
Author

David Williams-Young (@wavefunction91) Rebased cleanly on top of #453 and #545.

The fix is now applied in its correct location — SCFAlgorithm::build_rohf_f_p_matrix in scf_algorithm.cpp, where the function lives after #453 moved it out of DIIS.

What changed:

  • scf_algorithm.h — updated static signature (S param) + docstring
  • scf_algorithm.cpp — assertion replaced with direction-only guard; back-transform branched on square vs rectangular; scf_impl.overlap() threaded through build_rohf_convergence_matrices
  • python/tests/test_scf.py — regression test added
  • docs/source/changelog.rst — bug-fix entry under v2.0.0

The C++ regression test (ROHF_LinearlyDependentBasis_Issue543) was already present from #545. All existing ROHF tests (OH_ROHF_DIIS, OH_ROHF_GDM, Oxygen_atom_ROHF_GDM) are unaffected — the square case (nAO == nMO) still takes the identical LAPACK path as before.

Looking forward to your response and happy to make further changes if needed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

@Adithyaphani

Copy link
Copy Markdown
Author

David Williams-Young (@wavefunction91) looking forward to your review and happy to make further changes if needed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

Comment thread docs/source/changelog.rst Outdated
Comment thread python/tests/test_scf.py Outdated
Comment thread docs/source/changelog.rst Outdated
@Adithyaphani

Copy link
Copy Markdown
Author

Boqin Zhang (@BoqinZhang) and David Williams-Young (@wavefunction91) looking forward to your review and happy to make further changes if needed.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very nice fix, thanks for the contribution!

Comment thread cpp/tests/test_scf.cpp Outdated
Comment thread cpp/tests/test_scf.cpp Outdated
Comment thread docs/source/changelog.rst Outdated
Comment thread python/tests/test_scf.py Outdated
Comment thread python/tests/test_scf.py Outdated
Copilot AI review requested due to automatic review settings July 10, 2026 03:36
@Adithyaphani

adithyaphanithota (Adithyaphani) commented Jul 10, 2026

Copy link
Copy Markdown
Author

David Williams-Young (@wavefunction91) and Boqin Zhang (@BoqinZhang) addressed all maintainer review comments in the latest commit:

  • scf_algorithm.h: @param C docstring reverted
  • ut_common.hpp / test_scf.py: molecule generators refactored to match existing style
  • test_scf.cpp / test_scf.py: quantitative EXPECT_NEAR / np.isclose energy checks added
  • changelog.rst: bug fixes section removed

Note: the reference energy -379.882619279 in both tests is a placeholder — please let me know the confirmed ROHF/def2-tzvp converged value for o-benzosemiquinone (doublet, charge=0) and I'll update it.

@Adithyaphani

Copy link
Copy Markdown
Author

David Williams-Young (@wavefunction91) looking forward to your review and happy to make further changes if needed.

@wavefunction91

Copy link
Copy Markdown
Collaborator

Hey adithyaphanithota (@Adithyaphani), thanks for the continued iteration. Can you confirm whether the unit tests pass on your machine?

Copilot AI review requested due to automatic review settings July 30, 2026 08:06
@Adithyaphani
adithyaphanithota (Adithyaphani) force-pushed the fix/rohf-linear-dependent-basis-543 branch from 7405875 to e18f615 Compare July 30, 2026 08:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@Adithyaphani

Copy link
Copy Markdown
Author

Hey David Williams-Young (@wavefunction91) — yes, both tests pass locally. ROHF_RectangularBackTransform_ProjectionIdentity and ROHF_LinearlyDependentBasis_Issue543 run cleanly on my machine. The 3 Linux failures are the pre-existing coverage gate (exit code 8, ~76%) that's unrelated to this PR — all other checks including Windows and macOS are green . Just rebased to clear the branch-out-of-date warning.

David Williams-Young (@wavefunction91) looking forward to your response .

@Adithyaphani

Copy link
Copy Markdown
Author

David Williams-Young (@wavefunction91) and Boqin Zhang (@BoqinZhang) looking forward to you review .

@nabbelbabbel Jan Unsleber (nabbelbabbel) added enhancement New feature or request user A request made by a user labels Aug 10, 2026
@Adithyaphani

adithyaphanithota (Adithyaphani) commented Aug 14, 2026

Copy link
Copy Markdown
Author

Hey David Williams-Young (@wavefunction91) and Boqin Zhang (@BoqinZhang) looking forward to you review . Are you'll looking to further to proceed with this issue fix or not .

Comment thread cpp/tests/test_scf.cpp

// Always validate the basic contract from the issue report.
EXPECT_TRUE(orbitals->is_restricted());
EXPECT_TRUE(std::isfinite(energy));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi adithyaphanithota (@Adithyaphani) , is it possible for you to add your reference energy at here? It would be very helpful for us to make the comparison. Thank you!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Boqin Zhang (@BoqinZhang), happy to add it! The reference energy was omitted because the test skips on most platforms when linear-dependency removal doesn't fire. Could you share the converged ROHF/def2-tzvp energy from your infrastructure? We'll add the EXPECT_NEAR right away.

Comment thread python/tests/test_scf.py
orbitals = wavefunction.get_orbitals()
# Always validate the basic contract from the issue report.
assert orbitals.is_restricted()
assert np.isfinite(energy)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi adithyaphanithota (@Adithyaphani) , Like the cpp test, is it possible for you to add your reference energy at here? It would be helpful for us to make a comparison. Thank you!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Boqin Zhang (@BoqinZhang) Same situation here — happy to add np.isclose once we have a confirmed converged value. Could you run the o-benzosemiquinone ROHF/def2-tzvp calculation on your end and share the energy? We'll update both tests immediately.

@Adithyaphani

Copy link
Copy Markdown
Author

Boqin Zhang (@BoqinZhang) looking forward to your response.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@Adithyaphani

Copy link
Copy Markdown
Author

David Williams-Young (@wavefunction91) and Boqin Zhang (@BoqinZhang) it's almost been a week looking forward to your response on this PR.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request user A request made by a user

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ROHF fails with "number of atomic orbitals must equal number of molecular orbitals" when basis set is linearly dependent

5 participants