Skip to content

[libcu++] Support complex type mixing in cuda::isclose#9891

Open
davebayer wants to merge 1 commit into
NVIDIA:mainfrom
davebayer:fix_isclose
Open

[libcu++] Support complex type mixing in cuda::isclose#9891
davebayer wants to merge 1 commit into
NVIDIA:mainfrom
davebayer:fix_isclose

Conversation

@davebayer

Copy link
Copy Markdown
Contributor

#9577 got merged before my feedback was discussed/addressed. This PR simplifies the constraints on complex types and adds support for complex type mixing (for example cuda::isclose(cuda::std::complex<float>{}, cuda::complex<float>{}) in cuda::isclose

@davebayer
davebayer requested review from a team as code owners July 16, 2026 07:28
@davebayer
davebayer requested a review from wmaxey July 16, 2026 07:28
@github-project-automation github-project-automation Bot moved this to Todo in CCCL Jul 16, 2026
@cccl-authenticator-app cccl-authenticator-app Bot moved this from Todo to In Review in CCCL Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 3b25af18-8984-40d7-8fea-3bcfb3e59af8

📥 Commits

Reviewing files that changed from the base of the PR and between 3149dcb and 6749450.

📒 Files selected for processing (2)
  • docs/libcudacxx/extended_api/numeric/isclose.rst
  • libcudacxx/include/cuda/__numeric/isclose.h
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/libcudacxx/extended_api/numeric/isclose.rst
  • libcudacxx/include/cuda/__numeric/isclose.h

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved cuda::isclose support for complex-number comparisons.
    • Standardized complex overloads so tolerance values consistently match the underlying scalar type.
    • Updated relative and absolute tolerance handling for clearer, more predictable comparisons.
  • Documentation

    • Revised the cuda::isclose documentation to reflect the updated complex-number overloads and tolerance behavior.

Walkthrough

Changes

The complex cuda::isclose implementation and public overloads now use an explicit scalar type for complex operands and absolute tolerance. The API documentation matches the revised declarations and constraints.

Changes

Complex isclose overloads

Layer / File(s) Summary
Complex comparison implementation
libcudacxx/include/cuda/__numeric/isclose.h
The internal helper accepts an explicit scalar type, validates floating-point usage, and converts complex components and absolute tolerance for comparison.
Public complex overloads
libcudacxx/include/cuda/__numeric/isclose.h
Complex overloads use one scalar type with a complex template, constrain accepted operands, and forward tolerances to the implementation.
Complex overload documentation
docs/libcudacxx/extended_api/numeric/isclose.rst
Documentation reflects the unified scalar template parameter and removes the former absolute-tolerance type-matching constraint.

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d5d13923-bb53-4ce0-948b-2d73e381da6f

📥 Commits

Reviewing files that changed from the base of the PR and between 37dc633 and 3149dcb.

📒 Files selected for processing (3)
  • docs/libcudacxx/extended_api/numeric/isclose.rst
  • libcudacxx/include/cuda/__numeric/isclose.h
  • libcudacxx/test/libcudacxx/cuda/numeric/isclose/isclose.pass.cpp

Comment on lines +24 to +37
template <class T>
[[nodiscard]] __host__ __device__
bool isclose(const Complex& lhs, const Complex& rhs) noexcept;
bool isclose(const /*complex-type*/<T>& lhs, const /*complex-type*/<T>& rhs) noexcept;

template <class Complex>
template <class T>
[[nodiscard]] __host__ __device__
bool isclose(const Complex& lhs, const Complex& rhs, float relative_tol) noexcept;
bool isclose(const /*complex-type*/<T>& lhs, const /*complex-type*/<T>& rhs, float relative_tol) noexcept;

template <class Complex, class AbsTol>
template <class T>
[[nodiscard]] __host__ __device__
bool isclose(const Complex& lhs,
const Complex& rhs,
bool isclose(const /*complex-type*/<T>& lhs,
const /*complex-type*/<T>& rhs,
float relative_tol,
AbsTol absolute_tol) noexcept;
T absolute_tol) noexcept;

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Document cuda::complex<T> and independently selectable lhs/rhs complex types. The signatures repeat one /*complex-type*/ placeholder and Line 70 lists only cuda::std::complex<T> and std::complex<T>, but the new tested API supports cuda::std::complex<T> mixed with cuda::complex<T>. State that both operands may use different supported complex implementations with the same scalar T. As per path instructions, documentation changes must be technically accurate and API-consistent.

Also applies to: 70-70

Source: Path instructions

Comment on lines +289 to +292
_CCCL_TEMPLATE(class _Tp, template <class> class _LhsComplex, template <class> class _RhsComplex)
_CCCL_REQUIRES(::cuda::std::__cccl_is_integer_v<_Tp> || ::cuda::is_floating_point_v<_Tp>)
[[nodiscard]] _CCCL_HOST_DEVICE_API bool isclose(
const _LhsComplex<_Tp>& __lhs, const _RhsComplex<_Tp>& __rhs, const float __rel_tol, const _Tp __abs_tol) noexcept

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Restrict all complex overloads to floating-point _Tp. Lines 290, 304, and 317 admit integral _Tp, but Line 96 hard-errors after overload selection. Use ::cuda::is_floating_point_v<_Tp> consistently so unsupported complex scalar types are excluded by constraints rather than failing in the function body; add constraint coverage for this case. As per path instructions, libcudacxx changes require correctness and API stability.

Also applies to: 303-320

Source: Path instructions

@davebayer
davebayer requested review from fbusato and removed request for wmaxey July 16, 2026 08:58
@github-actions

This comment has been minimized.

Comment on lines +92 to +94
template <class _Tp, template <class> class _LhsComplex, template <class> class _RhsComplex>
[[nodiscard]] _CCCL_HOST_DEVICE_API bool __isclose_complex_impl(
const _ComplexType& __lhs, const _ComplexType& __rhs, const float __rel_tol, const _AbsTol __abs_tol) noexcept
const _LhsComplex<_Tp>& __lhs, const _RhsComplex<_Tp>& __rhs, const float __rel_tol, const _Tp __abs_tol) noexcept

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If complex type mixing is not desired, we can do:

Suggested change
template <class _Tp, template <class> class _LhsComplex, template <class> class _RhsComplex>
[[nodiscard]] _CCCL_HOST_DEVICE_API bool __isclose_complex_impl(
const _ComplexType& __lhs, const _ComplexType& __rhs, const float __rel_tol, const _AbsTol __abs_tol) noexcept
const _LhsComplex<_Tp>& __lhs, const _RhsComplex<_Tp>& __rhs, const float __rel_tol, const _Tp __abs_tol) noexcept
template <class _Tp, template <class> class _Complex>
[[nodiscard]] _CCCL_HOST_DEVICE_API bool __isclose_complex_impl(
const _Complex<_Tp>& __lhs, const _Complex<_Tp>& __rhs, const float __rel_tol, const _Tp __abs_tol) noexcept

template <class T>
[[nodiscard]] __host__ __device__
bool isclose(const Complex& lhs, const Complex& rhs) noexcept;
bool isclose(const /*complex-type*/<T>& lhs, const /*complex-type*/<T>& rhs) noexcept;

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.

Is this functionally any different from the previous form? From your change it seems like what we actually support is

template <class LhsComplex, class RhsComplex>
isclose(const LhsComplex&, const RhsComplex&);

}

template <typename _ComplexType, typename _AbsTol>
template <class _Tp, template <class> class _LhsComplex, template <class> class _RhsComplex>

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.

If we are going to be truly generic to the complex type implementation here, then we should not enforce only a single template parameter and should just take a fully generic ComplexType. We can extract the _Tp inside the function using typename ComplexType::value_type. If we are concerned this is too broad, then we can make a is_complex_type concept that we static_assert() inside the function:

template <class T>
concept is_complex_type = requires(const T& cplx) {
  { cplx.imag() } -> ...
  { cplx.real() } -> ...
  // etc
};

@fbusato fbusato 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.

I'm not really in favor of this change. It would be weird if a user mixes two different types of complex types (cuda::complex vs. cuda::std::complex) in the same call.
The additional complexity does not motivate this change

@github-actions

Copy link
Copy Markdown
Contributor

🥳 CI Workflow Results

🟩 Finished in 1h 36m: Pass: 100%/120 | Total: 1d 07h | Max: 57m 48s | Hits: 98%/366831

See results here.

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

Labels

None yet

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

3 participants