Skip to content

[libcu++] Add support for __nv_fp8_ue5m3 - #12570

Merged
davebayer merged 4 commits into
NVIDIA:mainfrom
davebayer:support_new_fp_type
Nov 11, 2026
Merged

davebayer merged 4 commits into
NVIDIA:mainfrom
davebayer:support_new_fp_type

Conversation

@davebayer

Copy link
Copy Markdown
Contributor

CTK 13.4 introduced __nv_fp8_ue5m3, this PR adds support for this type in libcu++ as we do for similar types.

@davebayer
davebayer requested review from a team as code owners November 10, 2026 07:54
@github-project-automation github-project-automation Bot moved this to Todo in CCCL Nov 10, 2026
@cccl-authenticator-app cccl-authenticator-app Bot moved this from Todo to In Review in CCCL Nov 10, 2026
@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Summary

Summary by CodeRabbit

  • New Features
    • Added conditional support for NVIDIA FP8 UE5M3 scalar and two- and four-element vector types, including conversions, classification, numeric limits, and vector and tuple traits. Support requires NVFP8 and CUDA Toolkit 13.4 or later.
  • Documentation
    • Documented that UE5M3 is unsupported by DLPack and clarified tuple protocol limitations for its vector types.
  • Bug Fixes
    • DLPack conversions now fail at compile time for unsupported UE5M3 values.
    • Unary minus is unavailable for unsigned CCCL floating-point formats.

This change adds feature-gated NVFP8 UE5M3 scalar and vector support to libcudacxx. It extends floating-point formats, conversions, classification, numeric limits, type traits, and tuple interfaces. It also adds DLPack rejection behavior and expands tests and documentation.

Changes: NVFP8 UE5M3 support

Layer / File(s) Summary
Feature detection and format representation
libcudacxx/include/cuda/std/__cccl/extended_data_types.h, libcudacxx/include/cuda/std/__floating_point/*, libcudacxx/include/cuda/std/__type_traits/*
Adds toolkit-version-gated UE5M3 declarations and a feature macro. Floating-point format properties, storage access, constants, and type traits recognize the format.
Floating-point conversions
libcudacxx/include/cuda/std/__floating_point/cast.h, libcudacxx/include/cuda/std/__floating_point/cccl_fp.h, libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/*
Adds UE5M3 conversion paths and tests for casts, conversion ranks, constructors, and operators. A deleted unary-minus overload is added for unsigned __cccl_fp formats.
Numeric limits
libcudacxx/include/cuda/std/__limits/numeric_limits_ext.h, libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/*
Adds UE5M3 numeric_limits values and tests for the specialization and its members.
Classification and decomposition
libcudacxx/include/cuda/std/__cmath/*, libcudacxx/test/libcudacxx/std/numerics/c.math/*, libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/decompose/*
Adds UE5M3 classification overloads and test coverage for classification, sign operations, exponent decomposition, and exponent setting.
Vector interfaces and DLPack behavior
libcudacxx/include/cuda/__type_traits/*, libcudacxx/include/cuda/std/__tuple_dir/vector_types.h, libcudacxx/include/cuda/__mdspan/mdspan_to_dlpack.h, libcudacxx/test/libcudacxx/cuda/type_traits/*, libcudacxx/test/libcudacxx/cuda/utilities/tuple/*, docs/libcudacxx/extended_api/*
Adds vector and tuple metadata for UE5M3 x2 and x4 types. DLPack conversion explicitly rejects UE5M3. Documentation describes the DLPack limitation, supported vector types, and tuple protocol restrictions.
Format operations and validation
libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/*, libcudacxx/test/libcudacxx/cuda/warp/warp_shuffle.pass.cpp, libcudacxx/test/libcudacxx/libcxx/macros/extended_data_types.pass.cpp
Adds tests for UE5M3 format properties, storage, constants, masks, overflow handling, traits, and warp shuffle.

Suggested reviewers: miscco, fbusato

Change: Feature

Merge Risk: Low · up to 3159f

Some long-double conversions can round incorrectly, and the vector documentation is misleading. These bounded issues merit owner awareness before merging.

Architecture risk: Low · up to 3159f

The change affects 2 systems.

Changed systems: libcudacxx, docs

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — libcudacxx (service) was modified; 111 changed files map to changed impact.
  • observed — docs (service) was modified; 3 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in docs/libcudacxx/extended_api/mdspan/mdspan_to_dlpack.rst: The Constraints section adds __nv_fp8_ue5m3 and its vector types to the documented unsupported types, citing the absence of a corresponding DLPack data type code.
  • observed — Modified behavior in docs/libcudacxx/extended_api/type_traits/vector_types.rst: The supported extended floating-point vector types list adds __nv_fp8x2_ue5m3 and __nv_fp8x4_ue5m3.
  • observed — Modified behavior in libcudacxx/include/cuda/__mdspan/mdspan_to_dlpack.h: When _CCCL_HAS_NVFP8_UE5M3() is enabled, __data_type_to_dlpack now matches __nv_fp8_ue5m3 and fails compilation with a dedicated assertion; previously this type had no explicit branch.
  • observed — Modified behavior in libcudacxx/include/cuda/__type_traits/scalar_type.h: Adds scalar_type specializations for the UE5M3 FP8 two- and four-element vector types under _CCCL_HAS_NVFP8_UE5M3(), each mapping to the scalar ::__nv_fp8_ue5m3.
- [ ] Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

  • Source mode: Auto
  • Repository: NVIDIA/cccl
  • Branch: main
  • File: .coderabbit.yaml
  • Commit: 5060e9b
  • Layers: Repository YAML
  • Review profile: CHILL
  • Plan: Enterprise
  • Run ID: c4047744-51dc-4cc1-ba67-0f3ed2aa524a
Commits

Reviewing files that changed from the base of the PR and between de7fb4c and 3159f78.

Files selected for processing: 1

  • libcudacxx/include/cuda/std/__floating_point/constants.h

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.

@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

Nitpick comments: 3

libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/arithmetic/neg.pass.cpp: 1

52-52: Trivial · Maintainability & Code Quality · Quick win

suggestion: Check the value returned by UE5M3 negation. test_fp_neg checks only the return type and noexcept, so this new instantiation cannot detect an incorrect result. Add runtime and static_assert checks for representative UE5M3 values, including a nonzero value. The format is unsigned, and the implementation negates storage by applying the sign mask. (raw.githubusercontent.com) As per coding guidelines, “It is fundamental to verify: ... Runtime and constant-evaluation behavior.”

Source: Coding guidelines

libcudacxx/include/cuda/std/__floating_point/cast.h: 1

643-682: Trivial · Functional Correctness · Quick win

suggestion: Test large UE5M3 source conversions.

The cast test only checks 1.0. It does not cover UE5M3 values above the __half range. Add a large UE5M3 input and assert the target formats’ overflow results.

libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cast.pass.cpp: 1

54-54: Trivial · Maintainability & Code Quality · Quick win

suggestion: Add UE5M3 boundary casts.

The new source and destination cases both check only 1.f. They cannot detect incorrect handling of zero or values above the __half range. Add UE5M3 boundary cases with independently specified expected results. (raw.githubusercontent.com)

As per coding guidelines, libcudacxx tests must verify “Edge cases” and “Input and output types.”

Sources: Coding guidelines, Path instructions

Review info

Run configuration

  • Source mode: Auto
  • Repository: NVIDIA/cccl
  • Branch: main
  • File: .coderabbit.yaml
  • Commit: 39d17f7
  • Layers: Repository YAML
  • Review profile: CHILL
  • Plan: Enterprise
  • Run ID: 23b1782f-68ab-406d-8482-1ad001fb5742
Commits

Reviewing files that changed from the base of the PR and between 39d17f7 and ef55075.

Files selected for processing: 113

  • docs/libcudacxx/extended_api/mdspan/mdspan_to_dlpack.rst
  • docs/libcudacxx/extended_api/type_traits/vector_types.rst
  • docs/libcudacxx/extended_api/vector_tuple_protocol.rst
  • libcudacxx/include/cuda/__mdspan/mdspan_to_dlpack.h
  • libcudacxx/include/cuda/__type_traits/scalar_type.h
  • libcudacxx/include/cuda/__type_traits/vector_size.h
  • libcudacxx/include/cuda/__type_traits/vector_type.h
  • libcudacxx/include/cuda/std/__cccl/extended_data_types.h
  • libcudacxx/include/cuda/std/__cmath/fpclassify.h
  • libcudacxx/include/cuda/std/__cmath/isfinite.h
  • libcudacxx/include/cuda/std/__cmath/isinf.h
  • libcudacxx/include/cuda/std/__cmath/isnan.h
  • libcudacxx/include/cuda/std/__cmath/isnormal.h
  • libcudacxx/include/cuda/std/__floating_point/cast.h
  • libcudacxx/include/cuda/std/__floating_point/constants.h
  • libcudacxx/include/cuda/std/__floating_point/format.h
  • libcudacxx/include/cuda/std/__floating_point/properties.h
  • libcudacxx/include/cuda/std/__floating_point/storage.h
  • libcudacxx/include/cuda/std/__floating_point/traits.h
  • libcudacxx/include/cuda/std/__limits/numeric_limits_ext.h
  • libcudacxx/include/cuda/std/__tuple_dir/vector_types.h
  • libcudacxx/include/cuda/std/__type_traits/is_extended_floating_point.h
  • libcudacxx/include/cuda/std/__type_traits/num_bits.h
  • libcudacxx/test/libcudacxx/cuda/type_traits/is_arithmetic.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/type_traits/is_bitwise_comparable.basic_types.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/type_traits/is_extended_fp_vector_type_v.compile.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/type_traits/is_trivially_copyable.basic_types.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/type_traits/is_vector_type.compile.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/type_traits/scalar_type.compile.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/type_traits/vector_size.compile.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/type_traits/vector_type.compile.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/utilities/tuple/vector_types_tuple_element.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/utilities/tuple/vector_types_tuple_size.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/warp/warp_shuffle.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/macros/extended_data_types.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/arithmetic/neg.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cast.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cccl_fp/arithmetic_operators/unary.minus.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cccl_fp/arithmetic_operators/unary.plus.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cccl_fp/constructors/default.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cccl_fp/constructors/floating_point.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cccl_fp/constructors/integral.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cccl_fp/conversion_operators/floating_point.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/cccl_fp/conversion_operators/integral.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/denorm_min.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/inf.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/lowest.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/max.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/min.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/nan.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/nans.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/one.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/constants/zero.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/conversion_rank_order.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/decompose/get_exp.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/decompose/set_exp.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/format.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/mask/exp_mant_mask.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/mask/exp_mask.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/mask/explicit_bit_mask.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/mask/mant_mask.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/mask/sign_mask.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/native_type.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/overflow_handler/no_sat.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/overflow_handler/sat_finite.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/properties.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/storage.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/traits/classification.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/numerics/floating.point/traits/is_subset.pass.cpp
  • libcudacxx/test/libcudacxx/libcxx/utilities/meta/meta.unary/meta.unary.cat/is_floating_point.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/is_specialized.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/common.h
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/const_data_members.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/denorm_min.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/digits.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/digits10.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/epsilon.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/has_denorm.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/has_denorm_loss.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/has_infinity.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/has_quiet_NaN.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/has_signaling_NaN.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/infinity.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/is_bounded.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/is_exact.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/is_iec559.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/is_integer.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/is_modulo.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/is_signed.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/lowest.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/max.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/max_digits10.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/max_exponent.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/max_exponent10.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/min.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/min_exponent.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/min_exponent10.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/quiet_NaN.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/radix.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/round_error.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/round_style.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/signaling_NaN.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/tinyness_before.pass.cpp
  • libcudacxx/test/libcudacxx/std/language.support/support.limits/limits/numeric.limits.members/traps.pass.cpp
  • libcudacxx/test/libcudacxx/std/numerics/c.math/fp_abs.pass.cpp
  • libcudacxx/test/libcudacxx/std/numerics/c.math/fp_manip/copysign.pass.cpp
  • libcudacxx/test/libcudacxx/std/numerics/c.math/fp_traits/fpclassify.pass.cpp
  • libcudacxx/test/libcudacxx/std/numerics/c.math/fp_traits/isfinite.pass.cpp
  • libcudacxx/test/libcudacxx/std/numerics/c.math/fp_traits/isinf.pass.cpp
  • libcudacxx/test/libcudacxx/std/numerics/c.math/fp_traits/isnan.pass.cpp
  • libcudacxx/test/libcudacxx/std/numerics/c.math/fp_traits/isnormal.pass.cpp
  • libcudacxx/test/libcudacxx/std/numerics/c.math/fp_traits/signbit.pass.cpp
  • libcudacxx/test/libcudacxx/std/utilities/meta/meta.unary/meta.unary.cat/num_bits.pass.cpp

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.

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

Looks reasonable

@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: 3

Review info

Run configuration

  • Source mode: Auto
  • Repository: NVIDIA/cccl
  • Branch: main
  • File: .coderabbit.yaml
  • Commit: 5060e9b
  • Layers: Repository YAML
  • Review profile: CHILL
  • Plan: Enterprise
  • Run ID: 0de7a1ec-9df8-45c4-9b7e-e6a5f18ed341
Commits

Reviewing files that changed from the base of the PR and between ef55075 and 5909a19.

Files selected for processing: 3

  • docs/libcudacxx/extended_api/vector_tuple_protocol.rst
  • libcudacxx/include/cuda/std/__floating_point/cast.h
  • libcudacxx/include/cuda/std/__floating_point/cccl_fp.h

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 11 remain after this review.

# if _CCCL_HAS_NVFP8_UE5M3()
else if constexpr (is_same_v<_To, __nv_fp8_ue5m3>)
{
return ::cuda::std::__fp_cast<__nv_fp8_ue5m3>(::cuda::std::__fp_cast<float>(__v));

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.

Minor · Functional Correctness · Quick win

important: Avoid double rounding the long double input. For 1.0625L + 0x1p-30L, the intermediate float is 1.0625, so nearest-even conversion produces 1.0 instead of 1.125. The double-source path produces 1.125 for the same value. Preserve the discarded bits when converting to UE5M3, and test values on both sides of a midpoint. (docs.nvidia.com)

As per path instructions: “Focus on correctness” for libcudacxx/**/*.

Source: Path instructions

@davebayer

Copy link
Copy Markdown
Contributor Author

pre-commit.ci autofix

@github-actions

This comment has been minimized.

@github-actions

Copy link
Copy Markdown
Contributor

🥳 CI Workflow Results

🟩 Finished in 12h 18m: Pass: 100%/230 | Total: 8d 07h | Max: 4h 46m | Hits: 36%/3197511

See results here.

@davebayer
davebayer merged commit 48eb952 into NVIDIA:main Nov 11, 2026
495 of 498 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to Done in CCCL Nov 11, 2026
@davebayer
davebayer deleted the support_new_fp_type branch November 11, 2026 05:39
miscco added a commit to miscco/cccl that referenced this pull request Nov 12, 2026
…DIA#12612

NVIDIA#12612 made `cuda::std::fmin` and `cuda::std::fmax` work for all extended
floating-point types by comparing with `cuda::std::isless` and
`cuda::std::isgreater`, and tests them in `fp_min_max.pass.cpp`. Drop our
storage order key and its tests. Values that compare equal, like -0 and +0,
now return the first argument instead of ordering -0 before +0.

Also test `cuda::min`, `cuda::max` and `cuda::clamp` with `__nv_fp8_ue5m3`,
which is supported since NVIDIA#12570.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants