From f5809a096fcbf1421820ff2df78cea2a55697dde Mon Sep 17 00:00:00 2001 From: Matthew Fishman Date: Mon, 20 Jul 2026 17:16:00 -0400 Subject: [PATCH] Skip the tag-dictionary walk in `IndexName` equality when tags are identical ## Summary Adds a `===` fast path to `==` and `isequal` on `IndexName` so a comparison skips the tag-dictionary walk when both names carry the same tags object. An index leg reused across tensors carries the same `IndexName`, and therefore the same tags container, so the common equal case drops from walking the tag dictionary to a single pointer check (roughly 6.5 ns to 2.7 ns for a two-tag name). The check sits on the tags field, which is the only costly one to compare: `uuid` and `plev` stay as the cheap primary discriminators, so names with a different id or prime level short-circuit before reaching the tags at all. This is sound because the tags are `SortedDict{Symbol, Symbol}` and `Symbol` equality is reflexive, so identical tag objects always compare equal. --- Project.toml | 2 +- src/index.jl | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Project.toml b/Project.toml index 17f558c..8db9c7a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ITensorBase" uuid = "4795dd04-0d67-49bb-8f44-b89c448a1dc7" -version = "0.12.3" +version = "0.12.4" authors = ["ITensor developers and contributors"] [workspace] diff --git a/src/index.jl b/src/index.jl index af11093..cc59e8c 100644 --- a/src/index.jl +++ b/src/index.jl @@ -85,14 +85,18 @@ Return the prime level of an index or index name: a non-negative integer raised """ plev(n::IndexName) = getfield(n, :plev) +# The tags dictionary is the only costly field to compare, so short-circuit it with `===`: +# a name reused across tensors carries the same tags object and skips the dictionary walk. function Base.:(==)(n1::IndexName, n2::IndexName) return uuid(n1) == uuid(n2) && plev(n1) == plev(n2) && - tags_stored(n1) == tags_stored(n2) + (tags_stored(n1) === tags_stored(n2) || tags_stored(n1) == tags_stored(n2)) end function Base.isequal(n1::IndexName, n2::IndexName) - return isequal(uuid(n1), uuid(n2)) && - isequal(plev(n1), plev(n2)) && - isequal(tags_stored(n1), tags_stored(n2)) + return isequal(uuid(n1), uuid(n2)) && isequal(plev(n1), plev(n2)) && + ( + tags_stored(n1) === tags_stored(n2) || + isequal(tags_stored(n1), tags_stored(n2)) + ) end function Base.isless(n1::IndexName, n2::IndexName) t1 = (uuid(n1), plev(n1), keys(tags_stored(n1)), values(tags_stored(n1)))