Skip to content

Conversation

@guan404ming
Copy link
Member

@guan404ming guan404ming commented Jan 2, 2026

Why

Users need guidance on how to perform structural equality comparison for containers.

How

  • Add notes to Array and Map docstrings pointing to structural_equal and structural_hash APIs

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @guan404ming, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a limitation where Array and Map objects relied solely on object identity for equality checks or were unhashable, preventing structural comparisons. By integrating C++ backend functions for structural equality and hashing, and exposing these via FFI to Python, the change enables deep comparison and consistent hashing for these container types, significantly enhancing their utility in Python code.

Highlights

  • Structural Equality and Hashing for Array and Map: This pull request introduces support for structural equality and hashing for Array and Map objects, moving beyond object identity for comparisons.
  • C++ Backend Implementation: The C++ FFI layer now exposes StructuralEqual and StructuralHash functions, which are utilized for deep comparison and hashing of container types. The ArrayContains method was also updated to use StructuralEqual.
  • Python Integration: The Python Array and Map classes have been updated to implement the __eq__, __ne__, and __hash__ dunder methods, delegating their logic to the newly exposed C++ FFI functions.
  • Comprehensive Testing: New test cases have been added to verify the correct behavior of structural equality and hashing for both Array and Map objects, including scenarios with nested containers.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

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 adds structural equality and hashing support for Array and Map containers. The changes involve exposing C++ StructuralEqual and StructuralHash functionalities through the FFI to Python, and implementing __eq__, __ne__, and __hash__ methods on the Python Array and Map classes. The implementation is sound and the accompanying tests verify the basic functionality. My review includes suggestions to simplify the Python code by removing redundant __ne__ implementations and to significantly expand the test suite to cover more edge cases and interactions with native Python types, ensuring the new features are robust.

Comment on lines 207 to 209
def __ne__(self, other: object) -> bool:
"""Return True if the array is not equal to another array."""
return not _ffi_api.ArrayEqual(self, other)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The __ne__ method can be removed. Python's default implementation for __ne__ delegates to __eq__ and inverts the result, which is exactly what's being done here. Removing this explicit implementation will make the code more concise without changing its behavior.

Comment on lines 395 to 397
def __ne__(self, other: object) -> bool:
"""Return True if the map is not equal to another map."""
return not _ffi_api.MapEqual(self, other)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

Similar to the Array class, the __ne__ method for Map can be removed. Python will automatically provide the correct __ne__ behavior based on the __eq__ implementation, making this explicit definition redundant.

Comment on lines 234 to 292
[
(tvm_ffi.Array([1, 2, 3]), tvm_ffi.Array([1, 2, 3]), True),
(tvm_ffi.Array([1, 2, 3]), tvm_ffi.Array([1, 2, 4]), False),
(tvm_ffi.Array([tvm_ffi.Array([1])]), tvm_ffi.Array([tvm_ffi.Array([1])]), True),
(tvm_ffi.Array([tvm_ffi.Array([1])]), tvm_ffi.Array([tvm_ffi.Array([2])]), False),
(tvm_ffi.Map({"a": 1, "b": 2}), tvm_ffi.Map({"a": 1, "b": 2}), True),
(tvm_ffi.Map({"a": 1, "b": 2}), tvm_ffi.Map({"a": 1, "b": 3}), False),
],
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The current tests for container equality are a good start, but they could be more comprehensive. I suggest adding more test cases to cover comparisons with native Python containers (list, dict), order independence for maps, handling of empty containers, nested containers, and comparisons between different container types. This will ensure the new equality and hashing logic is robust.

    [
        # Array equality
        (tvm_ffi.Array([1, 2, 3]), tvm_ffi.Array([1, 2, 3]), True),
        (tvm_ffi.Array([1, 2, 3]), tvm_ffi.Array([1, 2, 4]), False),
        (tvm_ffi.Array([1, 2, 3]), [1, 2, 3], True),
        (tvm_ffi.Array([1, 2, 3]), [1, 2, 4], False),
        (tvm_ffi.Array([]), tvm_ffi.Array([]), True),
        (tvm_ffi.Array([]), [], True),
        (tvm_ffi.Array([1]), [], False),
        # Nested Array equality
        (tvm_ffi.Array([tvm_ffi.Array([1])]), tvm_ffi.Array([tvm_ffi.Array([1])]), True),
        (tvm_ffi.Array([tvm_ffi.Array([1])]), tvm_ffi.Array([tvm_ffi.Array([2])]), False),
        (tvm_ffi.Array([[1]]), [[1]], True),
        # Map equality
        (tvm_ffi.Map({"a": 1, "b": 2}), tvm_ffi.Map({"a": 1, "b": 2}), True),
        (tvm_ffi.Map({"a": 1, "b": 2}), tvm_ffi.Map({"b": 2, "a": 1}), True),
        (tvm_ffi.Map({"a": 1, "b": 2}), tvm_ffi.Map({"a": 1, "b": 3}), False),
        (tvm_ffi.Map({"a": 1, "b": 2}), {"a": 1, "b": 2}, True),
        (tvm_ffi.Map({"a": 1, "b": 2}), {"b": 2, "a": 1}, True),
        (tvm_ffi.Map({"a": 1}), tvm_ffi.Map({"c": 1}), False),
        (tvm_ffi.Map({"a": 1}), tvm_ffi.Map({"a": 1, "b": 2}), False),
        (tvm_ffi.Map({}), tvm_ffi.Map({}), True),
        (tvm_ffi.Map({}), {}, True),
        (tvm_ffi.Map({1: 2}), {}, False),
        # Nested Map equality
        (tvm_ffi.Map({"a": {"b": 1}}), tvm_ffi.Map({"a": {"b": 1}}), True),
        (tvm_ffi.Map({"a": {"b": 1}}), tvm_ffi.Map({"a": {"b": 2}}), False),
        # Cross-type equality
        (tvm_ffi.Array([1]), tvm_ffi.Map({1: 1}), False),
        (tvm_ffi.Array([]), tvm_ffi.Map({}), False),
    ],

@guan404ming guan404ming marked this pull request as ready for review January 2, 2026 10:53
@junrushao
Copy link
Member

I'm not totally sure about using structural equality/hash for array/map comparison - It's a recursively defined equality based on IR structure, which is rather compute intensive. Does Python define it's tuple/dict equality recursively?

@guan404ming
Copy link
Member Author

I'm not totally sure about using structural equality/hash for array/map comparison - It's a recursively defined equality based on IR structure, which is rather compute intensive. Does Python define it's tuple/dict equality recursively?

Thanks for the question! Based on my review of CPython's implementation, Python does use recursive equality for tuple/dict. For example, tuple_richcompare (tupleobject.c:689) calls PyObject_RichCompareBool recursively on each element. Dict equality follows the same pattern. So I think StructuralEqual matches Python's semantics here.

Reference

@tqchen
Copy link
Member

tqchen commented Jan 8, 2026

Thanks for the contribution. For this particular case, i feel we should defer a bit, since structural equalty is already supported through explicitly. While classes like list do not necessarily support nested comparison directly via operators. For immutable objects there is some merits for having the feature. This is mainly a consideration of minimalism and also consistency with wrt to instances like c++.

As a middle ground, perhaps let us first document structural_equal and structural_hash APIs and refer users to them. Personally i think keeping it simple here might better

@guan404ming guan404ming changed the title feat: add equality and hash support for Array and Map docs: document structural_equal and structural_hash for Array and Map Jan 9, 2026
@guan404ming
Copy link
Member Author

Thanks for the review and suggestion! I agree that keeping it simple and explicit is the better approach. I've updated the PR to just add documentation pointing users to structural_equal and structural_hash APIs.

@tqchen tqchen merged commit 6643e2c into apache:main Jan 9, 2026
8 checks passed
@guan404ming guan404ming deleted the add-array-equality branch January 9, 2026 14:04
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.

3 participants