Skip to content

Implement equality of two table_views - #22319

Merged
rapids-bot[bot] merged 12 commits into
NVIDIA:mainfrom
wence-:wence/fea/table-equal
May 12, 2026
Merged

Implement equality of two table_views#22319
rapids-bot[bot] merged 12 commits into
NVIDIA:mainfrom
wence-:wence/fea/table-equal

Conversation

@wence-

@wence- wence- commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Description

At various times, it is useful to check whether two tables are equal. For example, in cudf-polars we use this to check if two tables are "compatibly" partitioned. Previously there have been no such utilities in libcudf proper. The best one can do is to loop over the columns, call cudf::binary_operation with NULL_EQUALS and then cudf::reduce on the result. This launches many more kernels than necessary.

Instead, use the existing row_equality operators to perform a single transform_reduce over the table checking for equality.

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

At various times, it is useful to check whether two tables are equal. For
example, in cudf-polars we use this to check if two tables are
"compatibly" partitioned. Previously there have been no such utilities in
libcudf proper. The best one can do is to loop over the columns, call
cudf::binary_operation with NULL_EQUALS and then cudf::reduce on the
result. This launches many more kernels than necessary.

Instead, use the existing row_equality operators to perform a single
transform_reduce over the table checking for equality.
@copy-pr-bot

copy-pr-bot Bot commented Apr 28, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-actions github-actions Bot added libcudf Affects libcudf (C++/CUDA) code. CMake CMake build issue labels Apr 28, 2026
Comment thread cpp/include/cudf/table/equality.hpp Outdated
wence- added 4 commits April 29, 2026 10:09
The row_operator function is too complex for transform-reduce, resulting in
very long compile times in general, and a bug in cicc 13.1.
Previously if two tables had column types that were not
equality-comparable, cudf::logic_error was thrown, while the documented
exception was std::invalid_argument. Fix this by throwing the correct
exception.
@wence- wence- added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change labels Apr 29, 2026
@wence-
wence- marked this pull request as ready for review April 29, 2026 11:51
@wence-
wence- requested review from a team as code owners April 29, 2026 11:51
@wence-
wence- requested review from davidwendt and devavret April 29, 2026 11:51
Comment thread cpp/tests/types/traits_test.cpp

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

New APIs should be added a streams test as well
https://github.com/rapidsai/cudf/tree/main/cpp/tests/streams
This is just to ensure the stream is passed all the way through the underlying CUDA calls.
No need to test all variations of parameters and no need to verify the results since a stream violation will surface as an exception.

Should we consider a benchmark for this API as well? Though I would not deem it necessary to merge this.

@wence-

wence- commented Apr 29, 2026

Copy link
Copy Markdown
Contributor Author

No need to test all variations of parameters and no need to verify the results since a stream violation will surface as an exception.

Thanks. Done.

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

Should the test utility cudf::test::detail::expect_tables_equal modified to adopt this?

@wence-

wence- commented Apr 29, 2026

Copy link
Copy Markdown
Contributor Author

Should the test utility cudf::test::detail::expect_tables_equal modified to adopt this?

I think no, because that test equality has special casing for floating point (you can compare to some ulp) and it would have to run over the whole tables again anyway to generate the differences when things are not equal?

Comment thread cpp/src/table/table_equal.cu
@wence-
wence- requested a review from ttnghia April 30, 2026 16:36
@GregoryKimball GregoryKimball moved this to Burndown in libcudf May 4, 2026

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

@davidwendt

Copy link
Copy Markdown
Contributor

Let's also replace this utility in our examples with this API as well?

Perhaps this can be done in a follow-on PR. Maybe that is what you are suggesting since you already approved this one.

@mhaseeb123

Copy link
Copy Markdown
Contributor

Maybe that is what you are suggesting since you already approved this one.

Yup, just as a note for follow up. I can open a PR as soon as this one merges

@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown

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: 86460b98-3eb7-4888-a46d-72032869bc97

📥 Commits

Reviewing files that changed from the base of the PR and between d612665 and 615c06a.

📒 Files selected for processing (2)
  • cpp/CMakeLists.txt
  • cpp/tests/CMakeLists.txt
🚧 Files skipped from review as they are similar to previous changes (2)
  • cpp/tests/CMakeLists.txt
  • cpp/CMakeLists.txt

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added a table equality API to compare tables by shape, column types, and element-wise values with configurable null semantics and NaN-as-equal handling; reports errors for non-comparable column types.
  • Tests
    • Added unit and stream-mode tests covering equality, inequality, shape/type mismatches, null handling, NaN behavior, and nested (struct/list) cases.
  • Chores
    • Build updated to include the new table equality implementation in releases.

Walkthrough

This PR adds cudf::tables_equal: a CUDA-accelerated table-view equality API and implementation, strengthens exception handling to use std::invalid_argument for non-comparable types, adds build wiring for the new source and stream test, and expands unit tests covering value/shape/type/null/NaN/nested cases.

Changes

Table Equality Function

Layer / File(s) Summary
Public API Declaration
cpp/include/cudf/table/equality.hpp
Declares cudf::tables_equal(table_view, table_view, null_equality, stream) with documentation for null-handling and NaN comparison semantics.
Exception Infrastructure
cpp/src/row_operator/row_operators.cu
Adds #include <stdexcept>, updates SPDX year, and modifies check_eq_compatibility to explicitly pass std::invalid_argument as the exception type for non-comparable columns.
CUDA Equality Implementation
cpp/src/table/table_equal.cu
Adds templated implementation using a two-table row comparator, CUB DeviceTransform to produce per-row equality, and logical AND reduction; includes dispatcher for nested vs non-nested columns and a public wrapper.
Build Configuration
cpp/CMakeLists.txt, cpp/tests/CMakeLists.txt
Adds src/table/table_equal.cu to cuDF sources and registers STREAM_TABLE_EQUALITY_TEST stream test target.
Test Coverage
cpp/tests/streams/table_equality_test.cpp, cpp/tests/table/table_tests.cpp, cpp/tests/types/traits_test.cpp
Adds stream test for inequality, expands table_tests with equal/unequal, shape/type mismatches, null equality modes, NaN handling, nested structures, and an expected exception case; fixes trait test and updates headers.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% 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
Title check ✅ Passed The title directly and concisely describes the main change: implementing a function to check equality of two table_view objects.
Description check ✅ Passed The description clearly explains the motivation (avoiding multiple kernel launches), the implementation approach (using row_equality operators), and confirms testing and documentation updates.
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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

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

🧹 Nitpick comments (2)
cpp/include/cudf/table/equality.hpp (1)

30-33: ⚡ Quick win

Add [[nodiscard]] attribute.

The function is side-effect-free and returns a meaningful bool value that should not be discarded. As per coding guidelines, side-effect-free functions with non-void return types should have the [[nodiscard]] attribute.

🔧 Suggested fix
-bool tables_equal(table_view const& left,
-                  table_view const& right,
-                  null_equality nulls_equal    = null_equality::EQUAL,
-                  rmm::cuda_stream_view stream = cudf::get_default_stream());
+[[nodiscard]] bool tables_equal(table_view const& left,
+                                 table_view const& right,
+                                 null_equality nulls_equal    = null_equality::EQUAL,
+                                 rmm::cuda_stream_view stream = cudf::get_default_stream());

As per coding guidelines: "Add [[nodiscard]] attribute to side-effect-free functions with non-void return types"

🤖 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 `@cpp/include/cudf/table/equality.hpp` around lines 30 - 33, The tables_equal
declaration is a pure query whose boolean result must not be ignored; add the
[[nodiscard]] attribute to its declaration (i.e., change the signature to
[[nodiscard]] bool tables_equal(...)) and mirror the attribute on any
corresponding definition/overload for consistency (ensure the attribute is
placed immediately before the return type in the declaration/definition of
tables_equal).
cpp/tests/streams/table_equality_test.cpp (1)

17-26: 💤 Low value

Capture the return value to avoid potential warnings.

While stream tests primarily validate stream propagation rather than functional correctness, the return value should still be captured to avoid potential unused-result warnings.

📝 Suggested improvement
 TEST_F(TableEqualTest, NotEqual)
 {
   cudf::test::fixed_width_column_wrapper<int> left(
     {{0, 0, 0, 0, 0}, {false, false, true, true, true}});
   cudf::test::fixed_width_column_wrapper<int> right({1, 1, 1, 1, 1});
-  cudf::tables_equal(cudf::table_view{{left}},
-                     cudf::table_view{{right}},
-                     cudf::null_equality::EQUAL,
-                     cudf::test::get_default_stream());
+  [[maybe_unused]] auto result = cudf::tables_equal(cudf::table_view{{left}},
+                                                     cudf::table_view{{right}},
+                                                     cudf::null_equality::EQUAL,
+                                                     cudf::test::get_default_stream());
 }
🤖 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 `@cpp/tests/streams/table_equality_test.cpp` around lines 17 - 26, The test
TEST_F(TableEqualTest, NotEqual) calls cudf::tables_equal but ignores its return
value, which can trigger unused-result warnings; modify the test to capture the
result (e.g., auto result = cudf::tables_equal(...) or bool equal =
cudf::tables_equal(...)) and, if desired, assert on it
(ASSERT_FALSE/ASSERT_TRUE) or cast to void to silence warnings—update the call
site where cudf::tables_equal(cudf::table_view{{left}},
cudf::table_view{{right}}, cudf::null_equality::EQUAL,
cudf::test::get_default_stream()) is invoked.
🤖 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.

Nitpick comments:
In `@cpp/include/cudf/table/equality.hpp`:
- Around line 30-33: The tables_equal declaration is a pure query whose boolean
result must not be ignored; add the [[nodiscard]] attribute to its declaration
(i.e., change the signature to [[nodiscard]] bool tables_equal(...)) and mirror
the attribute on any corresponding definition/overload for consistency (ensure
the attribute is placed immediately before the return type in the
declaration/definition of tables_equal).

In `@cpp/tests/streams/table_equality_test.cpp`:
- Around line 17-26: The test TEST_F(TableEqualTest, NotEqual) calls
cudf::tables_equal but ignores its return value, which can trigger unused-result
warnings; modify the test to capture the result (e.g., auto result =
cudf::tables_equal(...) or bool equal = cudf::tables_equal(...)) and, if
desired, assert on it (ASSERT_FALSE/ASSERT_TRUE) or cast to void to silence
warnings—update the call site where cudf::tables_equal(cudf::table_view{{left}},
cudf::table_view{{right}}, cudf::null_equality::EQUAL,
cudf::test::get_default_stream()) is invoked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1639e346-5f79-4afd-9049-ae7ac4110d43

📥 Commits

Reviewing files that changed from the base of the PR and between 64a3109 and abce883.

📒 Files selected for processing (8)
  • cpp/CMakeLists.txt
  • cpp/include/cudf/table/equality.hpp
  • cpp/src/row_operator/row_operators.cu
  • cpp/src/table/table_equal.cu
  • cpp/tests/CMakeLists.txt
  • cpp/tests/streams/table_equality_test.cpp
  • cpp/tests/table/table_tests.cpp
  • cpp/tests/types/traits_test.cpp

@wence-
wence- force-pushed the wence/fea/table-equal branch from e20feb7 to 12f428c Compare May 8, 2026 10:15
@mhaseeb123 mhaseeb123 removed their assignment May 8, 2026
@wence-

wence- commented May 12, 2026

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit 25e1b26 into NVIDIA:main May 12, 2026
116 of 117 checks passed
@wence-
wence- deleted the wence/fea/table-equal branch May 12, 2026 11:28
shrshi pushed a commit to shrshi/cudf that referenced this pull request May 12, 2026
At various times, it is useful to check whether two tables are equal. For example, in cudf-polars we use this to check if two tables are "compatibly" partitioned. Previously there have been no such utilities in libcudf proper. The best one can do is to loop over the columns, call cudf::binary_operation with NULL_EQUALS and then cudf::reduce on the result. This launches many more kernels than necessary.

Instead, use the existing row_equality operators to perform a single transform_reduce over the table checking for equality.

Authors:
  - Lawrence Mitchell (https://github.com/wence-)
  - Muhammad Haseeb (https://github.com/mhaseeb123)

Approvers:
  - David Wendt (https://github.com/davidwendt)
  - Muhammad Haseeb (https://github.com/mhaseeb123)

URL: NVIDIA#22319
@vuule vuule moved this from Burndown to Landed in libcudf May 12, 2026
galipremsagar pushed a commit to galipremsagar/cudf that referenced this pull request May 13, 2026
At various times, it is useful to check whether two tables are equal. For example, in cudf-polars we use this to check if two tables are "compatibly" partitioned. Previously there have been no such utilities in libcudf proper. The best one can do is to loop over the columns, call cudf::binary_operation with NULL_EQUALS and then cudf::reduce on the result. This launches many more kernels than necessary.

Instead, use the existing row_equality operators to perform a single transform_reduce over the table checking for equality.

Authors:
  - Lawrence Mitchell (https://github.com/wence-)
  - Muhammad Haseeb (https://github.com/mhaseeb123)

Approvers:
  - David Wendt (https://github.com/davidwendt)
  - Muhammad Haseeb (https://github.com/mhaseeb123)

URL: NVIDIA#22319
rapids-bot Bot pushed a commit that referenced this pull request May 15, 2026
Follow up #22319 

Use `cudf::tables_equal` API in libcudf examples instead of anti join to check if two tables are equal

Authors:
  - Muhammad Haseeb (https://github.com/mhaseeb123)
  - Lawrence Mitchell (https://github.com/wence-)
  - Vukasin Milovanovic (https://github.com/vuule)

Approvers:
  - Shruti Shivakumar (https://github.com/shrshi)
  - David Wendt (https://github.com/davidwendt)

URL: #22428
rapids-bot Bot pushed a commit that referenced this pull request May 21, 2026
xref #22319

Hoping to use this in rapidsmpf for Python testing

(Primarily agent generated)

Authors:
  - Matthew Roeschke (https://github.com/mroeschke)

Approvers:
  - Bradley Dice (https://github.com/bdice)
  - Muhammad Haseeb (https://github.com/mhaseeb123)

URL: #22611
@GregoryKimball GregoryKimball removed this from libcudf Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CMake CMake build issue improvement Improvement / enhancement to an existing function libcudf Affects libcudf (C++/CUDA) code. non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants