Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python Scalars Support #32

Open
nmichlo opened this issue Apr 12, 2021 · 4 comments
Open

Python Scalars Support #32

nmichlo opened this issue Apr 12, 2021 · 4 comments

Comments

@nmichlo
Copy link

nmichlo commented Apr 12, 2021

Feature Request

Would is be possible to support python scalars?

eg.

num_float = ep.astensor(1.0)
num_int = ep.astensor(42)

Why?

This would be helpful for implementing generic functions, for example:

def get_kernel_size(sigma=1.0, trunc=4.0):
    sigma, trunc = ep.astensors(sigma, trunc)
    radius = (sigma * trunc + 0.5).astype(int)
    return (2 * radius + 1).raw

This could be called with default values as well as tensors.

t_sigma = torch.abs(torch.randn(10))
n_trunc = np.abs(np.random.randn(10))

get_kernel_size(sigma=1.0, trunc=4.0)
get_kernel_size(sigma=t_sigma, trunc=4.0)
get_kernel_size(sigma=1.0, trunc=n_trunc)
@jonasrauber
Copy link
Owner

Nice example. I see why this can be useful. It might be possible to add a simple wrapper class for python scalars that automatically gets unwrapped when it interacts with any tensor.

@nmichlo
Copy link
Author

nmichlo commented Apr 13, 2021

That sounds ideal.

I am not sure about the internals of the library, but I imagine this could have implications for the various helper methods and functions? I am not sure how these would or could be handled, or if it would result in any special cases?

@jonasrauber
Copy link
Owner

Yes, I think there are quite a few cases to consider and some corner cases might be challenging, but it should be doable.

For now, this workaround should be fine (if you assume that always at least one of the arguments is a tensor):

def get_kernel_size(sigma=1.0, trunc=4.0):
    if isinstance(sigma, int) or isinstance(sigma, float):
        trunc = ep.astensor(trunc)
        sigma = ep.zeros(trunc, ()) + sigma
    elif isinstance(trunc, int) or isinstance(trunc, float):
        sigma = ep.astensor(sigma)
        trunc = ep.zeros(sigma, ()) + trunc
    else:
        sigma, trunc = ep.astensors(sigma, trunc)
    radius = (sigma * trunc + 0.5).astype(int)
    return (2 * radius + 1).raw

(I didn't test this)

You can introduce helper functions to simplify it further.

In fact, we could actually integrate all of the above into ep.astensors. It works as long as one of the arguments as actually a tensor (i.e., not all of them can be ints and floats).

@peekxc
Copy link

peekxc commented Aug 8, 2024

More generally, you might want to consider doing instance checks against the appropriate number type

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

No branches or pull requests

3 participants