Skip to content

Comments

API: Adjust linalg.pinv and linalg.cholesky to Array API#25388

Merged
ngoldbaum merged 1 commit intonumpy:mainfrom
mtsokol:pinv-cholesky-array-api
Dec 21, 2023
Merged

API: Adjust linalg.pinv and linalg.cholesky to Array API#25388
ngoldbaum merged 1 commit intonumpy:mainfrom
mtsokol:pinv-cholesky-array-api

Conversation

@mtsokol
Copy link
Member

@mtsokol mtsokol commented Dec 13, 2023

Hi @rgommers @ngoldbaum,

This PR is (one of) the last Array API compatibility changes:

  1. rtol parameter added to np.linalg.pinv as an alternative to rcond for bc (both can't be provided at the same time) (rtol will still diverge from Array API wrt. default value but at least it can be passed as a keyword argument)
  2. upper parameter added to np.linalg.cholesky
  3. Adjusted array-api-skips.txt to remove redundant skips

@mtsokol mtsokol self-assigned this Dec 13, 2023
@mtsokol mtsokol force-pushed the pinv-cholesky-array-api branch from a0e0fdf to c56cc1b Compare December 13, 2023 17:34
@mtsokol mtsokol force-pushed the pinv-cholesky-array-api branch 2 times, most recently from c0c5104 to cfcf694 Compare December 15, 2023 13:27
(symmetric if real-valued) and positive-definite. No checking is performed
to verify whether `a` is Hermitian or not. In addition, only the lower or
upper-triangular and diagonal elements of `a` are used. Only `L` or `U`
is actually returned.
Copy link
Member

Choose a reason for hiding this comment

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

I think all of these should be double backtick quotes, since they're not cross-references to numpy types.

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, I formatted them.

--------------------------------------------------------------

``upper`` keyword parameter was added to `numpy.linalg.cholesky` and
``rtol`` keyword parameter to `numpy.linalg.pinv` for Array API compatibility.
Copy link
Member

Choose a reason for hiding this comment

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

Weren't both added for array API compat?

I'd also mention that rtol doesn't have the array API default.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's correct, both of these were added to array-api-compat.

rtol doesn't have the default value because default for pinv is always taken from rcond (for backward compatibility) - I added a note about it.

Copy link
Member

@ngoldbaum ngoldbaum Dec 19, 2023

Choose a reason for hiding this comment

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

I'm trying to say it reads like only rtol was added for compat now. Maybe something like:

The ``upper`` and ``rtol`` keyword parameters were added to
`numpy.linalg.colesky` and `numpy.lingalg.ping`, respectively, to
improve array API compatibility.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, now I got it - I updated it.

a, wrap = _makearray(a)
if rtol is not None:
if rcond != 1e-15:
raise ValueError("`rtol` and `rcond` can't be both set.")
Copy link
Member

Choose a reason for hiding this comment

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

What if someone sets rcond=1e-15 and rtol != None. In that case rtol would be ignored. Of course that's a pretty unusual thing to happen.

Still, it might be better to change the default value of rcond to None, and if both are unset, assume the user meant rcond=1e-15 to preserve backward compatibility. Also document that behavior.

Copy link
Member

Choose a reason for hiding this comment

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

Or error if both are set to non-default values and leave the default alone.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure! Changed to rcond=None.

@mtsokol mtsokol force-pushed the pinv-cholesky-array-api branch from cfcf694 to a220d6a Compare December 19, 2023 17:07
Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

One little buglet and a comment.

Bit more generally, might it make sense to move towards the array API and deprecate rcond? (maybe just a FutureDeprecationWarning or so).

Also, might it be an idea to use rtol=np._NoValue as the default for now, to allow passing in rtol=None to opt in to the array API default?

Not sure about either, to be honest.

over='ignore', divide='ignore', under='ignore'):
r = gufunc(a, signature=signature)
if upper:
r = r.T.conj()
Copy link
Contributor

Choose a reason for hiding this comment

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

This is only correct for 2-d arrays, while I think the input can be a stack of matrices. Replace with

r = matrix_transpose(r).conj()

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, right - fixed!

rtol : (...) array_like of float, optional
Same as `rcond`, but it's an Array API compatible parameter name.
Only `rcond` or `rtol` can be set at a time. If none of them are
provided then ``1e-15`` default is used.
Copy link
Contributor

Choose a reason for hiding this comment

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

Needs a .. versionadded:: 2.0.0

Copy link
Member Author

Choose a reason for hiding this comment

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

Done!

Copy link
Contributor

Choose a reason for hiding this comment

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

Should note here that if None is passed in, the API standard default is used.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done!

@mtsokol mtsokol force-pushed the pinv-cholesky-array-api branch 3 times, most recently from 294e51b to 3f5cf73 Compare December 20, 2023 11:59
@mtsokol
Copy link
Member Author

mtsokol commented Dec 20, 2023

Bit more generally, might it make sense to move towards the array API and deprecate rcond? (maybe just a FutureDeprecationWarning or so).

Also, might it be an idea to use rtol=np._NoValue as the default for now, to allow passing in rtol=None to opt in to the array API default?

Not sure about either, to be honest.

@mhvk In my opinion it's a good idea - I added a PendingDeprecationWarning when rcond is set explicitly and made it possible to use rtol default value with rtol=None.

over='ignore', divide='ignore', under='ignore'):
r = gufunc(a, signature=signature)
if upper:
r = matrix_transpose(r).conj()
Copy link
Contributor

Choose a reason for hiding this comment

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

Now wondering about this, since this makes a copy of a potentially large matrix: an alternative would be to actually define cholesky_up (like done for eigenvalues, etc.), i.e., creating a new gufunc by adding to

static void
cholesky_lo(char **args, npy_intp const *dimensions, npy_intp const *steps,
void *NPY_UNUSED(func))
{
cholesky<typ>('L', args, dimensions, steps);
}

GUFUNC_FUNC_ARRAY_REAL_COMPLEX__(cholesky_lo);

{
"cholesky_lo",
"(m,m)->(m,m)",
"cholesky decomposition of hermitian positive-definite matrices. \n"\
"Broadcast to all outer dimensions. \n"\
" \"(m,m)->(m,m)\" \n",
4, 1, 1,
FUNC_ARRAY_NAME(cholesky_lo),
equal_2_types
},

Copy link
Member Author

Choose a reason for hiding this comment

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

If it's Ok, let me create later a separate issue/PR that introduces a new ufunc.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, it is fine to have the support now and improve it later!

Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

Beyond the larger separate comment about maybe creating the appropriate gufunc to avoid copies, a few nits in-line.

rtol : (...) array_like of float, optional
Same as `rcond`, but it's an Array API compatible parameter name.
Only `rcond` or `rtol` can be set at a time. If none of them are
provided then ``1e-15`` default is used.
Copy link
Contributor

Choose a reason for hiding this comment

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

Should note here that if None is passed in, the API standard default is used.

improve array API compatibility.

For `numpy.linalg.pinv` if neither ``rcond`` nor ``rtol`` is specified,
the ``rcond``'s default is used.
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe worth stating that eventually we hope to deprecate rcond?

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure! Added.

def test_pinv_rtol_arg():
a = np.array([[1, 2, 3], [4, 1, 1], [2, 3, 1]])

with suppress_warnings() as sup:
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the warning is intensional, I'd do

with pytest.warns(PendingDeprecationWarning, match="In the future `rcond`"):

Copy link
Member Author

Choose a reason for hiding this comment

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

As the warning got removed it's not needed.

@charris charris changed the title API: Adjust linalg.pinv and linalg.cholesky to Array API API: Adjust linalg.pinv and linalg.cholesky to Array API Dec 20, 2023
@mtsokol mtsokol force-pushed the pinv-cholesky-array-api branch from 3f5cf73 to 32e8eac Compare December 20, 2023 17:51
Copy link
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

All looks good to me!

@mtsokol mtsokol force-pushed the pinv-cholesky-array-api branch 3 times, most recently from 700a78f to dfe7fd6 Compare December 21, 2023 11:42
@mtsokol mtsokol added this to the 2.0.0 release milestone Dec 21, 2023
@ngoldbaum
Copy link
Member

Thanks @mtsokol!

@ngoldbaum ngoldbaum merged commit 5038cef into numpy:main Dec 21, 2023
@mtsokol mtsokol deleted the pinv-cholesky-array-api branch December 21, 2023 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants