fix(linalg): compute GPU Kron product in the promoted output dtype#995
fix(linalg): compute GPU Kron product in the promoted output dtype#995pcchen wants to merge 1 commit into
Conversation
cuKron_kernel wrote `Lin[x] * Rin[y]` straight into the output. The raw cucomplex operator* overloads follow the left operand's precision, so cuFloatComplex * double yields cuFloatComplex. After #858 made mixed complex/real pairs promote by precision (ComplexFloat + Double -> ComplexDouble), the output dtype is cuDoubleComplex, and assigning the cuFloatComplex product to it fails to compile: cuKron_internal.cuh:49: error: no operator "=" matches these operands operand types are: cuDoubleComplex = cuFloatComplex This broke the GPU build (instantiations (cuFloatComplex, cytnx_double) and its mirror). CI never caught it because it does not build the CUDA path; the CPU Kron handles the conversion and compiled fine. Fix: multiply in the output type via a cuKron_mul<TO> helper that promotes both operands to TO before cuCmul/cuCmulf (static_cast for real TO), mirroring the existing cuDiv_dispatch pattern. Verified on sm_70 (V100): Kron(ComplexFloat, Double) now yields ComplexDouble and matches the CPU result. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request introduces helper functions (cuKron_to_cd, cuKron_to_cf, and cuKron_mul) in cuKron_internal.cuh to correctly handle type promotion and multiplication of mixed complex/real types on CUDA devices, updating cuKron_kernel to use cuKron_mul. Feedback is provided to use the standard CUDA utility function cuComplexDoubleToFloat instead of manually reconstructing the float complex number in cuKron_to_cf for better consistency.
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.
| __device__ inline cuComplex cuKron_to_cf(const cuDoubleComplex &v) { | ||
| return make_cuFloatComplex(static_cast<cytnx_float>(cuCreal(v)), | ||
| static_cast<cytnx_float>(cuCimag(v))); | ||
| } |
There was a problem hiding this comment.
For consistency with cuComplexFloatToDouble used in cuKron_to_cd, you can use the standard CUDA utility function cuComplexDoubleToFloat from <cuComplex.h> instead of manually reconstructing the float complex number.
__device__ inline cuComplex cuKron_to_cf(const cuDoubleComplex &v) {
return cuComplexDoubleToFloat(v);
}
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #995 +/- ##
=======================================
Coverage 30.88% 30.88%
=======================================
Files 229 229
Lines 34758 34758
Branches 14409 14409
=======================================
Hits 10734 10734
Misses 16720 16720
Partials 7304 7304
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
|
Priority note: Independently verified: built the full Note that CI has no CUDA runner, so none of this is exercised by CI — worth keeping in mind for the whole GPU cluster. Posted by Claude Code on behalf of @pcchen |
|
From discussion in #999, the actual root cause here is the Cytnx declarations in __host__ __device__
cuFloatComplex operator*(const cuFloatComplex &ln, const cytnx_double &rn) {
return cuCmulf(make_cuFloatComplex(rn, 0), ln);
}
__host__ __device__
cuFloatComplex operator*(const cytnx_double &rn, const cuFloatComplex &ln) {
return cuCmulf(make_cuFloatComplex(rn, 0), ln);
}It is better to fix these, rather than patch Even better would be to replace the old |
|
Superseded — closing. master already computes the Kron product in the promoted output dtype via |
What
Fix a GPU build break in
cuKron_kernel: compute the Kron product in the promoted output dtype instead of relying on the rawoperator*result type.Why
cuKron_kerneldidout[i] = Lin[x] * Rin[y]. The cucomplexoperator*overloads follow the left operand's precision, socuFloatComplex * double -> cuFloatComplex. After #858 made mixed complex/real pairs promote by precision (ComplexFloat + Double -> ComplexDouble), the output type iscuDoubleComplex, and assigning thecuFloatComplexproduct to it fails to compile:This broke the CUDA build for the
(cuFloatComplex, cytnx_double)instantiation (and its mirror). CI didn't catch it because it does not build the GPU path; the CPUKron_generalhandles the conversion and compiled fine.How
Introduce a
cuKron_mul<TO>helper that promotes both operands toTObefore multiplying (cuCmul/cuCmulffor complexTO,static_cast<TO>otherwise), mirroring the existingcuDiv_dispatch.cupattern. This makes the result assignable for every promoted(TO, TL, TR)triple.Testing
Built the full
cytnxtarget with CUDA + cuTENSOR + cuQuantum (CUDA 12.9, sm_70 / V100) — compiles and links. RanKron(ComplexFloat, Double)on the GPU: output dtype isComplexDoubleand the values match the CPU reference and hand-computed expected results.Note: this class of regression would be caught by a minimal GPU compile job in CI (no GPU hardware needed to compile the templates). Worth considering as a follow-up.
Fixes #994
🤖 Generated with Claude Code
Posted by Claude Code on behalf of @pcchen