Skip to content

gh-1021: Add decorator for np conversions#1137

Open
prady0t wants to merge 9 commits into
glass-dev:mainfrom
prady0t:add-decorator-for-np-conversions
Open

gh-1021: Add decorator for np conversions#1137
prady0t wants to merge 9 commits into
glass-dev:mainfrom
prady0t:add-decorator-for-np-conversions

Conversation

@prady0t

@prady0t prady0t commented Jun 16, 2026

Copy link
Copy Markdown

Description

Addresses #1021

Checks

  • Is your code passing linting?
  • Is your code passing tests?
  • Have you added additional tests (if required)?
  • Have you modified/extended the documentation (if required)?
  • Have you added a one-liner changelog entry above (if required)?

prady0t and others added 3 commits June 16, 2026 17:27
Signed-off-by: Pradyot Ranjan <99216956+pradyotRanjan@users.noreply.github.com>
Signed-off-by: Pradyot Ranjan <99216956+pradyotRanjan@users.noreply.github.com>
@prady0t prady0t changed the title Add decorator for np conversions ENH: Add decorator for np conversions Jun 16, 2026
@prady0t prady0t changed the title ENH: Add decorator for np conversions gh-1021: Add decorator for np conversions Jun 16, 2026
Comment thread glass/_array_api_utils.py Outdated
dxp = default_xp(xp.__name__)
return tuple(xp.asarray(arr) for arr in dxp.tril_indices(n, k=k, m=m))

def numpy_fallback(func):

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@lucascolley This could be more generalised for the standard. Currently, I feel the limitation is the inability to specify parameters such as dtype for xp.asarray.

@ntessore @paddyroddy Would love some feedback.

@lucascolley lucascolley Jun 23, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

cc @betatim, I wonder whether there is any overlap between this and scikit-learn/scikit-learn#34324 which would be nice to upstream into xpx.numpy.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is pretty much out of my purview, and @paddyroddy is on leave currently, so it might be a bit before he can answer.

In my opinion, which as I said doesn't carry much weight here, I don't think this is something where GLASS should have to innovate. We're in the cosmological simulations business, not the array business 🙂

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

There isn't a lot of context in the PR description, what I figure from a quick browse: this PR adds a decorator that converts all "arrays" that are passed to a function to numpy arrays, then calls the wrapped function and converts any "arrays" in the output back to the original namespace.

I'm not sure how much the work in scikit-learn/scikit-learn#34324 is useful for others. It feels somewhat scikit-learn specific. The tricky (imho) part is deciding when to convert to numpy, which I guess is a library specific thing? At least in scikit-learn the decision to convert to numpy is not a simple "this function is hard to support". It depends on the global config, the specific constructor arguments of the class and what the type of the input array is. Once you know you want to convert to numpy it feels like you are "home free".

For this library it looks like most of the code of the decorator deals with finding arrays in the input arguments and such infrastructure. One thing I'm wondering is what to do if the inputs use different array namespaces or if one of the inputs is a torch array and another a list. But maybe these are things aren't an issue here? In scikit-learn we allow a mix of things :-/

Conclusion, I wonder if we can make a generic fallback decorator for xpx that doesn't get mega complex and at the same time supports most of the different behaviours users would want. If the answer is "yes we can" then I think it would be a useful tool (even if I don't think we'd use it in scikit-learn).

@paddyroddy paddyroddy 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.

This seems like a really nice approach and is the kind of thing I was thinking of. Long-term I definitely wouldn't want the code in this repo as it is complex, and our current approach would be easier for contributors to understand. Do we think we've captured all edge cases here? I assume the decorator is smart enough to detect which variables need to be converted and which don't?

Comment thread glass/grf/_solver.py Outdated
Comment on lines 85 to 86
# This function is difficult to port to the Array API so for now we work
# in NumPy and ultimately convert back at the end of it.

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.

We would need to remove this comment too

Comment thread glass/_array_api_utils.py Outdated
dxp = default_xp(xp.__name__)
return tuple(xp.asarray(arr) for arr in dxp.tril_indices(n, k=k, m=m))

def numpy_fallback(func):

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.

Some typing and a docstring would be good here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for the review. I've added some in the latest commit.

prady0t added 2 commits July 6, 2026 15:31
Signed-off-by: Pradyot Ranjan <99216956+pradyotRanjan@users.noreply.github.com>

@prady0t prady0t left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Currently, the state of the decorator is:

  • Goes through all the function parameters (args and kwargs) and collects those which have __array_namespace__ attribute.
  • If xp is in kwargs, it uses its value. If value is none, then use default_xp(). xp value overwrites parameter's __array_namespace__ attribute value.
  • If no xp parameter and no parameter has __array_namespace__ attribute, returns the function as is.
  • Parameters are converted to numpy
  • Depending on what the original function returns, the wrapper recursively converts (so that it can support tuple, list and dict) back to the xp.

There are two places where we cannot use this decorator: pixwin and the query_strip function, as we are specifying dtype during conversion. Something that this decorator cannot do yet.

Comment thread glass/healpix.py
@paddyroddy paddyroddy linked an issue Jul 8, 2026 that may be closed by this pull request
@paddyroddy paddyroddy added enhancement New feature or request maintenance Maintenance: refactoring, typos, etc. array-api Work is related to the Array API labels Jul 8, 2026
paddyroddy and others added 2 commits July 8, 2026 17:40
Signed-off-by: Pradyot Ranjan <99216956+pradyotRanjan@users.noreply.github.com>
Comment thread glass/_array_api_utils.py
Comment on lines +590 to +598
def collect_arrays(obj):
if hasattr(obj, "__array_namespace__"):
list_of_xp.append(obj)
elif isinstance(obj, dict):
for v in obj.values():
collect_arrays(v)
elif isinstance(obj, Sequence) and not isinstance(obj, (str, bytes)):
for item in obj:
collect_arrays(item)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I've made the decorator even smarter! Now, it's able to extract xp if the given arguments are a collection (or Sequence) of xp. Similarly, NumPy conversions are also being done recursively. This is helpful in the places commented below.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@paddyroddy gentle ping for a review.

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 I've been on leave

Comment thread glass/healpix.py
Comment on lines +64 to +70
return healpy.alm2map(
alms,
nside,
inplace=inplace,
lmax=lmax,
pixwin=pixwin,
pol=pol,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Instance 1

Comment thread glass/healpix.py
Comment on lines +266 to +271
return healpy.map2alm(
maps,
datapath=_get_healpy_datapath(),
lmax=lmax,
pol=pol,
use_pixel_weights=use_pixel_weights,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

2

Comment thread glass/healpix.py
theta, phi = healpix.randang(
nside,
np.asarray(ipix),
ipix,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

3

Comment thread glass/healpix.py
return xp.asarray(
healpy.Rotator(coord=self.coord).rotate_map_pixel(np.asarray(m)),
)
return healpy.Rotator(coord=self.coord).rotate_map_pixel(m)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

4

@prady0t
prady0t marked this pull request as ready for review July 8, 2026 21:12
Comment thread array-api-tests Outdated
Signed-off-by: Pradyot Ranjan <99216956+pradyotRanjan@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

array-api Work is related to the Array API enhancement New feature or request maintenance Maintenance: refactoring, typos, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decorator for input output conversion array-api porting

5 participants