Skip to content

Reject building a user monoid from a built-in BinaryOp - #617

Open
eriknw wants to merge 1 commit into
35-ssconfig-attr-guardfrom
36-monoid-builtin-binaryop-guard
Open

Reject building a user monoid from a built-in BinaryOp#617
eriknw wants to merge 1 commit into
35-ssconfig-attr-guardfrom
36-monoid-builtin-binaryop-guard

Conversation

@eriknw

@eriknw eriknw commented Aug 5, 2026

Copy link
Copy Markdown
Member

Registering a monoid from a built-in binaryop used to crash partway
through construction:

Monoid.register_new("mymax", binary.max, 0)
    AttributeError: 'TypedBuiltinBinaryOp' object has no attribute
    '_monoid' and no __dict__ for setting new attributes

and by the time it raised, it had already repointed binary.max's monoid
association at the half-built monoid, so binary.max.monoid stayed
corrupted for the rest of the session. (This is the latent bug that the
fmax/fmin identity test surfaced on mapnumpy=True CI runs.)

Even patched over, the result would lie. SuiteSparse ignores the
identity passed to GrB_Monoid_new whenever the built-in op already has a
built-in monoid, measured with GxB_Monoid_identity:

Monoid.register_new("mymax", binary.max, 0)[INT64] -> -9223372036854775808
the same monoid built on a UDF max                 -> 0

The override applies to exactly the ops that have built-in monoids (max,
min, plus, times, any) and not the rest (minus, first, second, pow,
bor, lxor), so a permissive fix would produce a monoid whose Python-side
identity silently disagrees with what GraphBLAS computes with. If a
monoid over a built-in op's function made sense, the built-in monoid
would already exist.

Monoid._build now rejects built-in binaryops up front with a TypeError
that points at BinaryOp.register_new / register_anonymous as the way to
build a monoid over the same function with a chosen identity. Built-ins
are detected as ops with neither a Python function nor a numba function,
which also covers assembled ops like binary.numpy.float_power. The
rejection happens before any object is created, so nothing is mutated on
the failing path.

@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from dbce7b2 to 488622d Compare August 5, 2026 03:18
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from 488622d to 8f138a4 Compare August 5, 2026 17:44
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from 8f138a4 to 2c9fdaa Compare August 5, 2026 18:03
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from 2c9fdaa to 88922bd Compare August 5, 2026 18:05
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from 88922bd to 99668c2 Compare August 6, 2026 07:59
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from 99668c2 to 1b70585 Compare August 6, 2026 15:39
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from 1b70585 to 076218f Compare August 6, 2026 15:41
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch 2 times, most recently from 1ddb541 to dd0e7ef Compare August 6, 2026 20:41
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from dd0e7ef to 35065c5 Compare August 7, 2026 02:49
@eriknw
eriknw force-pushed the 36-monoid-builtin-binaryop-guard branch from 35065c5 to 727fe12 Compare August 7, 2026 05:09
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.

1 participant