Skip to content

BUG: Preserve object common-dtype promotion in Quad ufuncs - #118

Open
SwayamInSync wants to merge 2 commits into
numpy:mainfrom
SwayamInSync:fix-object-promotion-114
Open

BUG: Preserve object common-dtype promotion in Quad ufuncs#118
SwayamInSync wants to merge 2 commits into
numpy:mainfrom
SwayamInSync:fix-object-promotion-114

Conversation

@SwayamInSync

@SwayamInSync SwayamInSync commented Jul 29, 2026

Copy link
Copy Markdown
Member

Closes #114

The promoters now preserve NumPy's ObjectDType precedence. When a Quad ufunc receives an object-array input, it selects NumPy's existing object loop rather than forcing the object operand to Quad.

This applies in both operand orders and covers:

  • Arithmetic ufuncs such as add and multiply
  • Comparisons with Boolean output
  • Logical operations with the object output used by NumPy's object loops
  • matmul
  • Broadcasting and masked out= operations
  • Both SLEEF and long-double backends

Operations without an applicable object loop continue to raise normally. Unsupported Quad/complex and Quad/string promotion is unchanged, and importing quaddtype does not affect built-in-only NumPy dispatch.

The change also makes matmul promoter registration failures propagate instead of being silently cleared.

@SwayamInSync
SwayamInSync requested a review from ngoldbaum July 29, 2026 13:05
@SwayamInSync

Copy link
Copy Markdown
Member Author

This is small addition but important to ensure we do not override NumPy's default

@ngoldbaum ngoldbaum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry for taking so long! Just one comment about the promoters below and a request for a comment. Also maybe take a look if the promoters are overly-broad right now elsewhere in the implementation (try to avoid promoters that match for all dtypes).



static bool
comparison_object_output_is_bool(PyUFuncObject *ufunc)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

maybe a one-line comment that this is needed to match numpy's semantics, which use bools for the comparison loops but object dtype for the logical_ functions.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done

Comment thread src/csrc/umath/comparison_ops.cpp Outdated
@@ -373,7 +386,7 @@ create_quad_comparison_ufunc(PyObject *numpy, const char *ufunc_name)

// Register promoter for (Any, QuadPrecDType, Bool) - needed for reverse mixed-type comparisons
DTypes = PyTuple_Pack(3, &PyArrayDescr_Type, &QuadPrecDType, &PyArray_BoolDType);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should this one and the one on line 373 use PyArray_ObjectDType as the result and "other" operand dtype? For changing the result dtype, this works just fine (for example):

>>> import numpy as np
>>> a = np.array(4, dtype='O')
>>> b = np.array(4.5)
>>> result = np.array(7, dtype='O')
>>> np.equal(a, b, out=result)
array(False, dtype=object)
>>> result
array(False, dtype=object)

The way you have it written here with exactly Bool as the output doesn't match that.

Also use PyArray_ObjectDtype instead of PyArrayDescr_Type, the latter fires for all dtypes so even if that doesn't lead to a bug and cause weirdness in unrelated dtypes, it's also a performance hit for all ufunc dispatch for all other dtypes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addressed and the 2nd point is also validated #118 (comment)

Comment thread tests/test_quaddtype.py
Comment on lines +6570 to +6573
with pytest.raises(AttributeError):
np.logical_xor(left.astype(object), right.astype(object))
with pytest.raises(AttributeError):
np.logical_xor(left, right)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

AttributeError?? Is this test encoding a bug in numpy or something?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is from NumPy. np.logical_xor does register an object loop (OO->O), but NumPy's object loop calls a method named after the ufunc on each element, so it looks for int.logical_xor and raises AttributeError.
An object that defines logical_xor works fine. np.logical_xor(obj_arr, obj_arr) raises the same AttributeError without any quad involved.

Comment thread tests/test_quaddtype.py

@pytest.mark.parametrize("backend", ["sleef", "longdouble"], indirect=True)
@pytest.mark.parametrize("reverse", [False, True])
def test_divmod_without_object_loop_still_raises(self, operands, reverse):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why not add a divmod object loop?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Because NumPy has no object loop for it, np.divmod.types contains no O entries at all, unlike floor_divide and remainder which both have OO->O.

@SwayamInSync

Copy link
Copy Markdown
Member Author

I addressed the reviews

No contamination of unrelated dtypes. Every one of quaddtype's promoter patterns pins concrete QuadPrecDType in at least one input slot. numpy's matcher in dispatching.cpp:resolve_implementation_info bails on the first concrete mismatch.
QuadPrecDType is declared NPY_DT_PARAMETRIC | NPY_DT_NUMERIC
NPY_DT_ABSTRACT is not set, so a call without Quad in that slot can never match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: Quad ufunc promoters override valid object common-dtype promotion

2 participants