Skip to content

fix(cc): handle nloc==0 in DeepSpinPTExpt with phantom-atom padding#5485

Merged
njzjz merged 7 commits into
deepmodeling:masterfrom
wanghan-iapcm:fix-spin-pt2-empty-rank-fpe
Jun 4, 2026
Merged

fix(cc): handle nloc==0 in DeepSpinPTExpt with phantom-atom padding#5485
njzjz merged 7 commits into
deepmodeling:masterfrom
wanghan-iapcm:fix-spin-pt2-empty-rank-fpe

Conversation

@wanghan-iapcm
Copy link
Copy Markdown
Collaborator

@wanghan-iapcm wanghan-iapcm commented Jun 2, 2026

Problem

Multi-rank spin MD can leave a rank with zero real local atoms (nloc_real == 0) when atoms migrate to other subdomains. The with-comm AOTI artifact hits an intermittent SIGFPE (integer divide by zero) at runtime in inductor-generated shape arithmetic that uses nloc as a divisor.

Reproduced on master CI run 26667802665:

Caught signal 8 (Floating point exception: integer divide by zero)
4  forward_lower_with_comm/.../wrapper.so(AOTInductorModel::run_impl+0xf482)

Root cause:

  • The graph was traced with nloc_min=1 (serialization.py:362) and inductor lowered an even stricter nloc >= 2 runtime-check (visible in the generated wrapper.cpp's check_input_3).
  • That runtime-check is gated by env var AOTI_RUNTIME_CHECK_INPUTS (default OFF), so with nloc = 0 the check is silently bypassed and the compiled graph runs through its own divide-by-zero on shape arithmetic.
  • Whether the offending divide is actually emitted depends on inductor's code-gen choices, which vary across compiles — hence the intermittent nature.

Fix

Prepend two phantom atoms with empty neighbour lists when nloc_real == 0 so the AOTI graph runs with nloc == 2 and never reaches the integer-divide-by-zero path. Phantoms have no neighbours so they contribute zero atomic energy / force / virial, preserving the physically-correct "this rank has no real atoms" result.

Key details (all in source/api_cc/src/DeepSpinPTExpt.cc):

  • dcoord / datype / dspin get two zero-valued rows prepended.
  • firstneigh_tensor gets two -1 rows prepended (no neighbours).
  • mapping_tensor gets two identity entries prepended.
  • comm_dict.nlocal is set to 2 (not the LAMMPS-reported 0) so border_op writes received ghost features past the phantom slots.
  • Output arrays (dforce, dforce_mag, datom_energy, datom_virial) get the phantom prefix stripped before being scattered back to LAMMPS via select_map.

Why phantoms rather than Dim(min=0) re-export

Bumping the trace constraint to min=0 would require:

  1. auditing every nloc-dependent divide in deepmd/dpmodel/{descriptor,fitting,model}/ and protecting with xp.maximum(nloc, 1);
  2. torch.export re-emitting compatible guards (currently fails because spin-side shape relationships require nloc >= 1 to be inferable);
  3. inductor cooperating with the relaxed bound (it makes independent specialization choices downstream);
  4. re-exporting every .pt2 archive in source/tests/infer/.

The phantom approach is a strict superset of correctness and self-contained in one C++ file. The two approaches aren't mutually exclusive — the min=0 route can land as a follow-up once the dpmodel audit is done.

Test plan

  • Local CPU rebuild + runUnitTests_cc --gtest_filter='*Spin*': 42 / 42 spin C++ regression tests pass (12 TF-backend tests skipped, as expected in the PT-only venv).
  • CI: the multi-rank LAMMPS test test_pair_deepmd_mpi_dpa3_spin_empty_subdomain should now pass deterministically. Local Python LAMMPS-MPI verification is blocked by a pre-existing OpenMPI/MPICH ABI mismatch in my local venv (the plugin's ompi_mpi_* symbols can't resolve against MPICH's libmpi.so.12), so end-to-end verification falls to CI.

Known limitations

  • The phantom path is structurally inert for nloc_real > 0 (the if (phantom_n > 0) branch never fires), so the common path is unchanged.
  • If a future inductor version bumps the nloc lower-bound to >2, phantom_n will need to track that minimum.
  • This fix is in DeepSpinPTExpt only. The corresponding non-spin path in DeepPotPTExpt has the same code shape; non-spin DPA3 empty-subdomain currently passes in CI but could regress similarly with a future inductor change. Deferred to a follow-up if observed.
  • Supersedes test(lammps): skip spin DPA3 empty-subdomain pt2 case #5478 (which proposed skipping the test); this PR fixes the underlying bug instead.

Summary by CodeRabbit

  • Bug Fixes
    • Prevented crashes and incorrect results when some processes have no local atoms during distributed runs; placeholder (phantom) atoms are ignored in neighbor, force, energy, and per-atom outputs so reported values match real atoms.
  • Tests
    • Updated tests to pass explicit per-atom parameters and exercise empty-subdomain and multi-rank behaviors.
  • Documentation
    • Clarified test docstrings and model config comments about per-atom parameter handling.

Multi-rank spin MD can leave a rank with zero real local atoms when
all atoms migrate to other subdomains.  The with-comm AOTI artifact
hits an intermittent SIGFPE (integer divide by zero) at runtime in
inductor-generated shape arithmetic that uses nloc as a divisor.

The graph was traced with nloc_min=1 and inductor lowered an even
stricter nloc>=2 runtime-check which is silently bypassed because
AOTI_RUNTIME_CHECK_INPUTS is unset by default.  Whether the offending
divide is actually emitted depends on inductor's code-gen choices,
which vary across compiles -- hence the random nature of the failure
(reproduced on CI run 26667802665).

Fix: prepend two phantom atoms with empty neighbour lists ahead of
the real atoms when nloc_real==0.  The AOTI graph then runs with
nloc==2, satisfying the inductor specialisation.  Phantoms have no
neighbours so they contribute zero atomic energy / force / virial,
preserving the physically-correct 'this rank has no real atoms'
result.  comm_dict's nlocal is set to 2 so border_op writes received
ghost features past the phantom slots; outputs are stripped of the
phantom prefix before being scattered back to LAMMPS via select_map.
@dosubot dosubot Bot added the bug label Jun 2, 2026
@github-actions github-actions Bot added C++ and removed bug labels Jun 2, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47f15b41a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread source/api_cc/src/DeepSpinPTExpt.cc
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR modifies DeepSpinPTExpt::compute to handle ranks with zero real local atoms by prepending phantom atoms for model inputs, adjusting mapping and neighbor-list tensors so phantoms are isolated, zeroing reduced energy when needed, and stripping phantom entries from force and atomic output tensors before returning to LAMMPS.

Changes

Phantom-atom padding for zero-local-atoms corner case

Layer / File(s) Summary
Phantom-atom padding initialization
source/api_cc/src/DeepSpinPTExpt.cc
When nloc_real == 0 and nall_real > 0, prepend two phantom atoms with zero values; update nall_real, nloc_real, and nloc; reconstruct spin tensor so phantom spins remain zero and real atoms are populated via bkw_map with an offset.
Tensor mappings and neighbor-list preparation
source/api_cc/src/DeepSpinPTExpt.cc
Rebuild mapping_tensor so phantom slots use identity mappings and real slots are adjusted for the phantom prefix; prepend phantom_n neighbor-list rows filled with -1 to firstneigh_tensor so the model sees padded nloc while phantom atoms have no neighbors.
Post-inference energy zeroing
source/api_cc/src/DeepSpinPTExpt.cc
When phantom padding was applied, explicitly zero the reduced energy array ener after inference to prevent phantom contributions from affecting MPI-reduced totals.
Output post-processing and phantom removal
source/api_cc/src/DeepSpinPTExpt.cc
After inference, strip phantom-prefixed entries from dforce and dforce_mag and decrement nall_real; when atomic outputs are enabled, remove phantom-prefixed entries from datom_energy and datom_virial so per-atom outputs correspond only to real atoms.
Tests, fixtures, and model config updates
source/api_cc/tests/test_with_comm_load_failure_ptexpt.cc, source/lmp/tests/run_mpi_pair_deepmd_spin_dpa3_pt2.py, source/lmp/tests/test_lammps_spin_dpa3_pt2.py, source/tests/infer/gen_spin.py
Tests now pass explicit per-atom aparam/fparam to DeepSpin::compute; LAMMPS fixture pair_style adds aparam 1.0; generated DPA3 YAMLs include numb_aparam: 1 so CI fixtures exercise the aparam + phantom-atom path.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

bug

Suggested reviewers

  • njzjz
  • iProzd
  • anyangml
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main fix: handling the nloc==0 edge case in DeepSpinPTExpt via phantom-atom padding, which aligns directly with the changeset's core objective.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@source/api_cc/src/DeepSpinPTExpt.cc`:
- Around line 487-489: The mapping assignment for real atoms fails to account
for phantom padding: when phantom_n > 0 the indices returned by fwd_map(...) are
in the pre-padding space and must be shifted by phantom_n. Update the loop that
sets mapping[ii] (which uses fwd_map[lmp_list.mapping[bkw_map[ii - phantom_n]]])
to add phantom_n to the fwd_map result so real-atom targets point into the
post-padding index range; keep all other indexing (ii, bkw_map,
lmp_list.mapping) unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e4e67575-7512-48ab-a532-4f17dad67d93

📥 Commits

Reviewing files that changed from the base of the PR and between c67b7f7 and 47f15b4.

📒 Files selected for processing (1)
  • source/api_cc/src/DeepSpinPTExpt.cc

Comment thread source/api_cc/src/DeepSpinPTExpt.cc
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 2, 2026

Codecov Report

❌ Patch coverage is 67.50000% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.37%. Comparing base (c67b7f7) to head (9460092).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
source/api_cc/src/DeepSpinPTExpt.cc 75.00% 2 Missing and 7 partials ⚠️
...api_cc/tests/test_with_comm_load_failure_ptexpt.cc 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5485      +/-   ##
==========================================
+ Coverage   81.36%   81.37%   +0.01%     
==========================================
  Files         868      868              
  Lines       96437    96598     +161     
  Branches     4233     4241       +8     
==========================================
+ Hits        78463    78611     +148     
- Misses      16674    16683       +9     
- Partials     1300     1304       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Codex flagged on PR deepmodeling#5485: phantoms have constant atomic-energy
outputs that flow into 'energy_redu'.  On the spin path the SpinModel
doubles atoms internally, so both real and spin phantom halves
contribute -- and 'output_map["energy"]' only exposes the real half
after the '[:, :nloc]' slice.  Subtracting only that real half (a
first attempt) left the spin half leaking into the MPI-reduced LAMMPS
total: CI run 26796476553 showed mpi-2 = -2.45 vs mpi-1 ref = -1.49.

Simpler exact fix: a rank with no real local atoms contributes zero
to the total energy by definition.  The phantoms are pure scaffolding
to satisfy inductor's nloc>=2 specialisation; their fitting output is
a numerical artifact, not physics.  Zero 'ener' directly when
phantom_n > 0.

Forces / force_mag / virial are unaffected because phantom outputs
are coord-independent (no neighbours) so their derivatives are zero --
no analogous correction is needed there.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
source/api_cc/src/DeepSpinPTExpt.cc (1)

393-401: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pad aparam_ when you synthesize phantom locals.

Lines 398-400 change the local-atom count from 0 to 2, but aparam_ stays in the pre-padding state. On an empty-local rank with daparam > 0, Lines 551-560 still send an empty tensor, so this path can still break for spin models that were exported with atomic parameters.

🧩 Suggested fix
   if (phantom_n > 0) {
     dcoord.insert(dcoord.begin(), static_cast<size_t>(phantom_n) * 3,
                   static_cast<VALUETYPE>(0));
     datype.insert(datype.begin(), static_cast<size_t>(phantom_n), 0);
+    if (daparam > 0) {
+      aparam_.insert(aparam_.begin(),
+                     static_cast<size_t>(phantom_n) * daparam,
+                     static_cast<VALUETYPE>(0));
+    }
     nall_real += phantom_n;
     nloc_real = phantom_n;
     nloc = nall_real - nghost_real;
   }

Also applies to: 550-560

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/api_cc/src/DeepSpinPTExpt.cc` around lines 393 - 401, When
synthesizing phantom locals (phantom_n > 0) you must pad the per-atom parameter
array aparam_ to match the new phantom atoms: insert
static_cast<size_t>(phantom_n) * static_cast<size_t>(daparam) default-valued
entries at the front of aparam_ (similar to how dcoord and datype are padded) so
subsequent send logic (the path around the existing tensor sends) sees the
correct size; perform this insert in the same block that updates dcoord, datype,
nall_real, nloc_real, and nloc.
♻️ Duplicate comments (1)
source/api_cc/src/DeepSpinPTExpt.cc (1)

487-489: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Offset real-atom mapping targets into the post-padding index space.

This is still using fwd_map[...] from the pre-padding layout. After Lines 395-400 prepend two phantom rows, every real/ghost row has moved by phantom_n, so the current mapping can resolve to a phantom slot instead of the intended atom row.

🐛 Minimal fix
       for (int ii = phantom_n; ii < nall_real; ii++) {
-        mapping[ii] = fwd_map[lmp_list.mapping[bkw_map[ii - phantom_n]]];
+        mapping[ii] =
+            fwd_map[lmp_list.mapping[bkw_map[ii - phantom_n]]] + phantom_n;
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@source/api_cc/src/DeepSpinPTExpt.cc` around lines 487 - 489, The mapping loop
uses fwd_map from the pre-padding layout so indices can point into phantom rows;
update the resolved index by offsetting into the post-padding layout by
phantom_n. Concretely, in the loop that sets mapping[ii] (which references
fwd_map, lmp_list.mapping and bkw_map), add phantom_n to the index into fwd_map
(e.g. use fwd_map[ lmp_list.mapping[bkw_map[ii - phantom_n]] + phantom_n ] or
otherwise shift the resolved value by phantom_n) so every real/ghost row maps
into the post-padding index space.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@source/api_cc/src/DeepSpinPTExpt.cc`:
- Around line 393-401: When synthesizing phantom locals (phantom_n > 0) you must
pad the per-atom parameter array aparam_ to match the new phantom atoms: insert
static_cast<size_t>(phantom_n) * static_cast<size_t>(daparam) default-valued
entries at the front of aparam_ (similar to how dcoord and datype are padded) so
subsequent send logic (the path around the existing tensor sends) sees the
correct size; perform this insert in the same block that updates dcoord, datype,
nall_real, nloc_real, and nloc.

---

Duplicate comments:
In `@source/api_cc/src/DeepSpinPTExpt.cc`:
- Around line 487-489: The mapping loop uses fwd_map from the pre-padding layout
so indices can point into phantom rows; update the resolved index by offsetting
into the post-padding layout by phantom_n. Concretely, in the loop that sets
mapping[ii] (which references fwd_map, lmp_list.mapping and bkw_map), add
phantom_n to the index into fwd_map (e.g. use fwd_map[
lmp_list.mapping[bkw_map[ii - phantom_n]] + phantom_n ] or otherwise shift the
resolved value by phantom_n) so every real/ghost row maps into the post-padding
index space.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 1b0da563-36d4-460d-8300-e08ca6d9f052

📥 Commits

Reviewing files that changed from the base of the PR and between 47f15b4 and c43468f.

📒 Files selected for processing (1)
  • source/api_cc/src/DeepSpinPTExpt.cc

@njzjz-bot
Copy link
Copy Markdown
Contributor

Thanks for the update. CI is green now, but I think two small correctness issues still need to be addressed before approval:

  1. The mapping tensor still uses pre-padding indices for real/ghost atoms:
mapping[ii] = fwd_map[lmp_list.mapping[bkw_map[ii - phantom_n]]];

When phantom_n > 0, the real/ghost rows have been shifted by the phantom prefix, so the resolved target should be shifted into the post-padding index space, e.g. add + phantom_n to the resolved fwd_map[...] value.

  1. If daparam > 0, aparam_ also needs phantom padding. dcoord and datype are prepended with phantom local atoms, but aparam_ remains in the pre-padding layout; the later atomic-parameter tensor path can therefore still see an empty/mismatched per-atom parameter array on empty-local ranks.

Could you please add a small follow-up commit for these two cases? After that this should be good to approve.

— OpenClaw 2026.5.28 (model: gpt-5.5)

Comment thread source/api_cc/src/DeepSpinPTExpt.cc
Han Wang added 2 commits June 4, 2026 08:53
The nloc==0 phantom-atom prefix padded dcoord/datype/dspin/nlist/mapping but
not aparam_, so with dim_aparam > 0 the aparam tensor (shape {1, nloc, daparam})
was built against the padded nloc while aparam_ still held the pre-padding
layout -- a shape mismatch (or a silently-skipped aparam when nloc_real==0 left
aparam_ empty).

Prepend phantom_n * daparam zero rows to aparam_ when phantom_n > 0 and
daparam > 0, so the two phantom local atoms carry zero atomic parameters and the
aparam tensor stays aligned with the padded local atoms. aparam_nall is false on
this path, so aparam_ is a per-local-atom buffer.
…in fixture

Give the DPA3 spin fixture (deeppot_dpa3_spin{,_mpi}.pt2) numb_aparam=1 so the
empty-subdomain MPI test exercises the phantom-atom aparam padding added in
DeepSpinPTExpt (rank with nloc_real==0 must prepend zero aparam rows). The spin
LAMMPS runner now supplies a uniform `aparam`, and the C++ with-comm
load-failure test passes a uniform aparam to its DeepSpin compute calls (the
shared fixture now has dim_aparam=1 and there is no default_aparam).

The spin LAMMPS tests are self-consistent (mpi-N vs mpi-1), so no reference
values change. Reuses the existing fixture rather than adding a new model.
Han Wang added 3 commits June 4, 2026 09:59
…ure test

multi_rank_compute_throws simulated multi-rank via inlist.nswap=1, but the
DeepSpinPTExpt dispatch keys on lmp_list.nprocs>1 (nswap is unsound for
atom_style spin). With nprocs unset, multi_rank was false and the
use_with_comm/with-comm-loader-failed throw never fired -- the compute returned
without throwing (also note nghost==0 skips the message-passing fail-fast
block). Set inlist.nprocs=2 so the test exercises the real multi-rank dispatch
throw. Verified locally: both tests in the suite pass against the regenerated
numb_aparam=1 DPA3 spin fixture.
In the nloc==0 phantom-padding path, the rebuilt mapping resolved real/ghost
rows to fwd_map[...] — a pre-padding local index. Since the phantom prefix
shifts every real/ghost row by phantom_n, the resolved target must be shifted
by +phantom_n into the post-padding local index space (no-op when
phantom_n == 0). This branch is reached by the empty-subdomain test (multi-rank
+ with-comm + atom_modify map yes populates lmp_list.mapping).
Clarify that the lmp_list.mapping branch with phantom_n>0 is structurally
unreachable (set_mapping is single-rank only; phantom_n>0 is multi-rank only),
so the +phantom_n shift is a no-op on every reachable path and is kept only to
keep the mapping correct if that invariant ever changes. Corrects the prior
commit's overstated reachability claim.
@wanghan-iapcm wanghan-iapcm requested a review from njzjz-bot June 4, 2026 03:26
Copy link
Copy Markdown
Contributor

@njzjz-bot njzjz-bot left a comment

Choose a reason for hiding this comment

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

Re-reviewed the latest head (94600920). The previous aparam_ concern is addressed by padding phantom_n * daparam zero rows, and the added fixture now exercises the empty-subdomain path with numb_aparam=1. CI is green as well.

The mapping + phantom_n change is defensive on the current LAMMPS path (the branch is still structurally unreachable when phantom_n > 0), but it is harmless and keeps the invariant explicit if that changes later.

Looks good to me.

— OpenClaw 2026.5.28 (model: custom-chat-jinzhezeng-group/gpt-5.5)

@njzjz njzjz added this pull request to the merge queue Jun 4, 2026
Merged via the queue into deepmodeling:master with commit fb6ff93 Jun 4, 2026
70 checks passed
@wanghan-iapcm wanghan-iapcm deleted the fix-spin-pt2-empty-rank-fpe branch June 4, 2026 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants