Skip to content

refactor(linalg): typed GPU dispatch for Outer + retire Kron GPU promotion trait (#1003)#1101

Closed
yingjerkao wants to merge 2 commits into
test/gpu-kron-outer-coveragefrom
refactor/1003-outer-kron-gpu-typed-dispatch
Closed

refactor(linalg): typed GPU dispatch for Outer + retire Kron GPU promotion trait (#1003)#1101
yingjerkao wants to merge 2 commits into
test/gpu-kron-outer-coveragefrom
refactor/1003-outer-kron-gpu-typed-dispatch

Conversation

@yingjerkao

Copy link
Copy Markdown
Collaborator

Problem

The last of #1003: Outer and Kron were the two remaining GPU ops still on legacy dispatch.

Fix

Two commits:

  1. Outer → typed dispatch. Replace cuOuter_ii with a single std::variant-based cuOuter_dispatch (the elementwise cu*_dispatch design). Outer.cpp already promotes both operands to the output dtype, so out/Lin/Rin share out->dtype(); the dispatch visits that one type via as_storage_variant and routes exactly as the old diagonal table entries did — floating/complex → cuBLAS GER (A = 1·x·yᵀ), integer/bool → the custom cuOuter_kernel. Deletes the 144 wrappers + the table + its population. Net ≈ −1600 lines.

  2. Kron → retire the trait. Cast both operands to the promoted output dtype up front (a no-op ref when it already matches) and dispatch on the single output type via out.gpu_ptr(). This is numerically identical to the kernel's per-element TO(Lin)*TO(Rin) cast, cuts kernel instantiations from 11×11 → 11, and lets the trait hierarchy be deleted from Type.hpp (no remaining users — only historical comments mention it).

Both changes are GPU-only and behaviour-preserving — they change how a kernel is selected, not the math. The CPU Outer_ii/type_promote_from_pointer_t paths are untouched (out of #1003's CUDA scope).

⚠️ Per the repo guardrails, flagging this as a numerical/dtype-adjacent change for human review — though it is a pure dispatch refactor that reuses the existing kernels unchanged.

Testing

On an RTX 4070 Ti SUPER (CUDA 13.0, sm_89):

  • GPU Kron/Outer suite: 9/9 pass — including the mixed ComplexFloat × Double → ComplexDouble promotion discriminator (output dtype and value) and GPU-vs-CPU cross-checks over every dtype (from test(linalg): GPU correctness coverage for Kron and Outer (#1003, confirms #999) #1100).
  • CPU Outer/Kron/promotion tests pass; both GPU and CPU debug builds are clean (0 errors).
  • Broad GPU sweep: the migrated paths and the elementwise/structural suites are green. Pre-existing, unrelated failures exist in the un-CI'd GPU suite (cuSOLVER SVD/QR, a rank-0 BlockUniTensor::Trace bug, a large-shape Mul OOM) — those tests run byte-identical code on this branch and its base, so the migration does not affect them.

Notes

yingjerkao and others added 2 commits July 20, 2026 14:25
…#1003)

Replace the legacy generated 12x12 cuOuter_ii dtype-pair function table (144
wrappers + a 2D lookup) with a single std::variant-based cuOuter_dispatch,
following the elementwise cu*_dispatch design (#1003; #650/#938 direction).

Outer.cpp already promotes both operands to the output dtype before dispatch,
so out/Lin/Rin share out->dtype(); cuOuter_dispatch visits that single type via
as_storage_variant and routes exactly as the old diagonal table entries did:
floating/complex -> cuBLAS GER (A = 1 * x * y^T), integer/bool -> the custom
cuOuter_kernel. Behaviour and numerics are unchanged; this only changes how the
kernel is selected.

Removed: the 144 cuOuter_internal_* wrappers (cuOuter_internal.cu/.hpp), the
cuOuter_ii member (linalg_internal_interface.hpp) and its ~144-line population
(linalg_internal_interface.cpp). Net -1600 lines. The CPU Outer_ii table is
untouched (out of #1003's CUDA scope).

Testing: GPU Kron/Outer suite 9/9 on an RTX 4070 Ti SUPER (CUDA 13.0), incl.
the mixed ComplexFloat x Double -> ComplexDouble promotion discriminator and
GPU-vs-CPU cross-checks over all dtypes; CPU Outer tests still pass; both GPU
and CPU debug builds clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…put dispatch (#1003)

Kron.cpp was the last user of the bespoke GPU promotion trait hierarchy
(type_promote_gpu_t / type_promote_from_gpu_pointer / _t) in Type.hpp. Its GPU
branch double-visited the input pointers and derived the output type from that
trait.

Cast both operands to the promoted output dtype up front (a no-op ref when the
dtype already matches) and dispatch on the single output type via out.gpu_ptr().
This is numerically identical to the kernel's per-element TO(Lin)*TO(Rin) cast,
drops the kernel instantiations from 11x11 to 11, and lets the trait hierarchy
be deleted from Type.hpp. Follows the same uniform-output-type shape now used by
Outer.

Testing: GPU Kron suite 5/5 (incl. mixed ComplexFloat x Double -> ComplexDouble
promotion + GPU-vs-CPU cross-check over all dtypes) on an RTX 4070 Ti SUPER;
CPU Kron tests still pass; GPU and CPU debug builds clean. No remaining users of
the removed traits (verified by grep; only historical comments mention them).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request refactors the GPU implementation of the Outer and Kron operations by replacing the legacy 12x12 function table with a typed std::visit dispatch on the output dtype. This change significantly reduces boilerplate code and retires the bespoke type_promote_from_gpu_pointer_t trait. The review feedback recommends improving the signature of the newly introduced cuOuter_dispatch function to adhere to the repository style guide. Specifically, it suggests passing input storage pointers by const reference, passing scalar size parameters by value, and replacing the legacy cytnx_uint64 typedef with standard C++ types.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +20 to +23
void cuOuter_dispatch(boost::intrusive_ptr<Storage_base> &out,
boost::intrusive_ptr<Storage_base> &Lin,
boost::intrusive_ptr<Storage_base> &Rin, const cytnx_uint64 &j1,
const cytnx_uint64 &j2);

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.

medium

For the newly introduced cuOuter_dispatch function, we should improve const-correctness and adhere to the repository style guide by:

  1. Passing the read-only input storage pointers Lin and Rin as const boost::intrusive_ptr<Storage_base>& instead of non-const references.
  2. Passing the small scalar size parameters j1 and j2 by value instead of const& (per Repository Style Guide, line 30).
  3. Avoiding the legacy cytnx_uint64 typedef for size parameters in new code, preferring standard C++ types like uint64_t (per Repository Style Guide, line 34).
Suggested change
void cuOuter_dispatch(boost::intrusive_ptr<Storage_base> &out,
boost::intrusive_ptr<Storage_base> &Lin,
boost::intrusive_ptr<Storage_base> &Rin, const cytnx_uint64 &j1,
const cytnx_uint64 &j2);
void cuOuter_dispatch(boost::intrusive_ptr<Storage_base> &out,
const boost::intrusive_ptr<Storage_base> &Lin,
const boost::intrusive_ptr<Storage_base> &Rin,
uint64_t j1, uint64_t j2);
References
  1. Pass small/scalar types by value, not by const&. (link)
  2. For new or touched code, avoid propagating legacy cytnx_XXXX typedefs as ordinary loop counters, sizes, flags, or local arithmetic types. Prefer standard C++ types... (link)

Comment on lines +54 to +57
void cuOuter_dispatch(boost::intrusive_ptr<Storage_base> &out,
boost::intrusive_ptr<Storage_base> &Lin,
boost::intrusive_ptr<Storage_base> &Rin, const cytnx_uint64 &j1,
const cytnx_uint64 &j2) {

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.

medium

Update the definition of cuOuter_dispatch to match the improved signature with const-correct input storage pointers, by-value scalar parameters, and standard C++ types instead of legacy typedefs.

    void cuOuter_dispatch(boost::intrusive_ptr<Storage_base> &out,
                          const boost::intrusive_ptr<Storage_base> &Lin,
                          const boost::intrusive_ptr<Storage_base> &Rin,
                          uint64_t j1, uint64_t j2) {
References
  1. Pass small/scalar types by value, not by const&. (link)
  2. For new or touched code, avoid propagating legacy cytnx_XXXX typedefs as ordinary loop counters, sizes, flags, or local arithmetic types. Prefer standard C++ types... (link)

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

Copy link
Copy Markdown

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: 5a0325e058

ℹ️ 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 include/Type.hpp
@@ -499,29 +499,6 @@ namespace cytnx {
template <typename TL, typename TR>
using type_promote_from_pointer_t = typename type_promote_from_pointer<TL, TR>::type;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Update the CUDA type-promotion tests

Removing Type_class::type_promote_gpu_t here leaves the #ifdef UNI_GPU static assertions in tests/Type_test.cpp still referencing that alias, so any CUDA test build with RUN_TESTS=ON fails to compile before the GPU tests can run. Please update or remove those assertions as part of retiring the GPU promotion trait.

Useful? React with 👍 / 👎.

@yingjerkao
yingjerkao requested review from IvanaGyro and ianmccul July 20, 2026 08:02

@ianmccul ianmccul left a comment

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.

Tensor Outer(const Tensor &lhs, const Tensor &rhs) {
  cytnx_error_msg(lhs.is_void(), "[ERROR] lhs must be initialized.%s", "\n");
  cytnx_error_msg(rhs.is_void(), "[ERROR] rhs must be initialized.%s", "\n");
  cytnx_error_msg(lhs.device() != rhs.device(),
                  "[ERROR] the two tensors must be on the same device.%s", "\n");
  cytnx_error_msg(lhs.rank() != 1, "[ERROR] tensor #1 should have rank-1.%s", "\n");
  cytnx_error_msg(rhs.rank() != 1, "[ERROR] tensor #2 should have rank-1.%s", "\n");

  return Kron(lhs, rhs).reshape(std::vector<cytnx_uint64>{lhs.shape()[0], rhs.shape()[0]});
}

@yingjerkao

Copy link
Copy Markdown
Collaborator Author

Addressing @ianmccul's review comment (replace the Outer dispatch with Kron(lhs,rhs).reshape(...)): implemented in #1105, which reimplements Outer via Kron and deletes the Outer_ii/cuOuter_ii tables — so there is no cuOuter left to add typed dispatch for. Note #1105 leaves type_promote_gpu_t in place (it still backs type_promote_from_gpu_pointer_t, which cuKron uses), so the Type_test.cpp break @chatgpt-codex-connector flagged does not apply there. The typed-GPU-dispatch-for-Outer goal of this PR is superseded by #1105.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

@yingjerkao

Copy link
Copy Markdown
Collaborator Author

The second goal of this PR — retiring type_promote_gpu_t — is now done in #1106: Kron's GPU path (its last functional user) is migrated to the shared host type_promote_t + to_cuda_t-at-the-boundary pattern (#1013), the trait is removed from Type.hpp, and the Type_test.cpp asserts @chatgpt-codex-connector flagged are replaced with device-independent type_promote_t equivalents. Verified against a CUDA 13 build (gpu_test_main + test_main under USE_CUDA=ON) with a new GPU Kron_test.cpp. (The Outer→Kron half is superseded by #1105.)

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create an environment for this repo.

@ianmccul
ianmccul dismissed their stale review July 21, 2026 09:48

Resolved

@yingjerkao

Copy link
Copy Markdown
Collaborator Author

Closing as superseded by #1105 and #1106.

This PR's refactor — route Outer through Kron, delete cuOuter_internal.{cu,hpp}, and retire the type_promote_gpu_t promotion trait — is exactly what landed on master via #1105 (Outer = Kron(a,b).reshape(...), removing the GPU Outer kernels) and #1106 (retire type_promote_gpu_t, typed Kron GPU dispatch).

On current master: cuOuter_internal.cu is gone, type_promote_gpu_t is gone from Type.hpp, and Outer.cpp already routes through Kron. So there's nothing left for this PR to change — merging it would try to delete files that no longer exist.

The GPU test coverage from the sibling PR #1100 is being salvaged into master's existing tests/gpu/linalg_test/Kron_test.cpp / Outer_test.cpp separately. Thanks!

@yingjerkao yingjerkao closed this Jul 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants