You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
BaseArray::abs(&self) isn't implemented for integers (isize, i64, etc) #1462
So I think the general approach up to now has been that this can be accomplished via arr.mapv(num_traits::abs) or arr.mapv(i64::abs) if you want have / want more specificity. I would maybe like to see a sort of parallel implementation of num-like traits for arrays, but this gets back to the problem of how many methods are in ndarray.
If I'm not mistaken, I believe that's the exact way it's being done for the floats using the unary_ops macro.
#[cfg(feature = "std")]macro_rules! unary_ops {($($(#[$meta:meta])*fn $id:ident)+) => {
$($(#[$meta])*
#[must_use = "method returns a new array and does not mutate the original value"]pubfn $id(&self) -> Array<A,D> {self.mapv(A::$id)})+
};}
Maybe some of the methods such as absand signum could be moved to a different section/macro that would treat both cases?
What's bugging me is the issue of partial functionality. Why should this method only work with floats when it affects negative numbers as a whole?
If it the functionality is not added to integers, we should maybe update the documentation to make it clearer since, although the abs method is in the Element-wise methods for float arrays section, it is far enough into it that the section name does not appear on screen when navigating through the side menu. This makes it unclear that it only applies to floats when quickly browsing the docs.
Honestly I agree, and would welcome a PR that documents that. If you're up for it, what I'd love to see is a PR that modifies the implementation of element-wise mathematics to mimic num, so that if a type is num_traits::Signed it will have abs and signum.
I have some code laying around that starts that more comprehensive PR, but feel that I've got a few items I've got to check off first.
@Sh3mm you've inspired me to go back and take a look at that code. I think it's realistic for me to implement the more comprehensive PR. However, I'd like for the methods with additional arguments to accept both scalars and arrays, and I've got four ways to do it. Which of these do you think you'd prefer?
Implement them as separate methods, abs_sub, abs_sub_mut, abs_sub_scalar, and abs_sub_scalar_mut
Pros: Absolutely no ambiguity in method resolution. Cons: Verbose, and when methods have additional arguments (e.g., mul_add) you can't mix scalars and arrays.
Use two traits, e.g., SignedScalar and SignedArr, that have overlapping method names abs_sub and abs_sub_mut
Pros: When only using one of the traits, no ambiguity. Cons: When using both kinds in the same scope, requires specifying the method via fully-qualified syntax, and you still can't mix scalars and arrays. Also, you'd have to import the appropriate trait.
Use only two methods, but allow the additional arguments to be passed as wrapped enums, e.g., arr.abs_sub(Arg::Arr(1.0))
Pros: No method ambiguity, no proliferation of method names, and you can mix arrays and scalars. Cons: arguments are now verbose.
Use a const-generic-based approach that lets me implement just two methods, abs and abs_mut, without needing the enums.
Pros: No proliferation of method names and you can succinctly mix arrays and scalars. Cons: Complex implementation means that compiler hints are less helpful when something does go wrong. Seems to work for almost all methods, but for some reason mimicking num::Pow requires me to essentially fall back to one of the above options.
I am currently leaning strongly towards (4), but I am curious to get your take.
Hum, here are my toughs about each way of doing thing:
Implement them as separate methods, abs_sub, abs_sub_mut, abs_sub_scalar, and abs_sub_scalar_mut
I enjoy the simplicity, however, It might make it confusing for the users since they might not understand the difference between the two version just by reading the name. I think it's a nice way to do things, but I would also make sure to link the scalar version in the doc of the array one and vice versa.
Use two traits, e.g., SignedScalar and SignedArr, that have overlapping method names abs_sub and abs_sub_mut
I'm a bit uncomfortable with this implementation. Importing the trait when needed is one thing, but it's not rare to do operation with both scalars and array in the same code. I would not like to be in the situation where I have an existing code base using the SignedScalar and having to comeback and modifying all previous uses of the abs_sub method to their fully-qualified syntax if I suddenly need the SignedArr version.
Use only two methods, but allow the additional arguments to be passed as wrapped enums, e.g., arr.abs_sub(Arg::Arr(1.0))
Frankly, this one feels a bit like a hack, but it feels to me like the best compromise of library management & ease of use.
Use a const-generic-based approach that lets me implement just two methods, abs and abs_mut, without needing the enums.
First, I haven't really used const-generic, so I'm unsure of implementation details. However, based on your pros/cons, here's how I feel:
From a maintainer point of view, I dislike exceptions, so the num::Pow would royally tick me off. The complexity might be a problem, but since I do not understand how you'd do it, I refrain judgment.
As a user, I feel like the hint issue is easily manageable with a good doc.
Overall, I would tend towards (3) or (4). However, depending on philosophy, (1) might be good. The only one I feel negatively about would be the (2).
Activity
akern40 commentedon Dec 5, 2024
So I think the general approach up to now has been that this can be accomplished via
arr.mapv(num_traits::abs)orarr.mapv(i64::abs)if you want have / want more specificity. I would maybe like to see a sort of parallel implementation ofnum-like traits for arrays, but this gets back to the problem of how many methods are inndarray.Sh3mm commentedon Dec 5, 2024
If I'm not mistaken, I believe that's the exact way it's being done for the floats using the
unary_opsmacro.Maybe some of the methods such as
absandsignumcould be moved to a different section/macro that would treat both cases?What's bugging me is the issue of partial functionality. Why should this method only work with floats when it affects negative numbers as a whole?
If it the functionality is not added to integers, we should maybe update the documentation to make it clearer since, although the
absmethod is in the Element-wise methods for float arrays section, it is far enough into it that the section name does not appear on screen when navigating through the side menu. This makes it unclear that it only applies to floats when quickly browsing the docs.akern40 commentedon Dec 7, 2024
Honestly I agree, and would welcome a PR that documents that. If you're up for it, what I'd love to see is a PR that modifies the implementation of element-wise mathematics to mimic
num, so that if a type isnum_traits::Signedit will haveabsandsignum.I have some code laying around that starts that more comprehensive PR, but feel that I've got a few items I've got to check off first.
akern40 commentedon Dec 16, 2024
@Sh3mm you've inspired me to go back and take a look at that code. I think it's realistic for me to implement the more comprehensive PR. However, I'd like for the methods with additional arguments to accept both scalars and arrays, and I've got four ways to do it. Which of these do you think you'd prefer?
abs_sub,abs_sub_mut,abs_sub_scalar, andabs_sub_scalar_mutPros: Absolutely no ambiguity in method resolution. Cons: Verbose, and when methods have additional arguments (e.g.,
mul_add) you can't mix scalars and arrays.SignedScalarandSignedArr, that have overlapping method namesabs_subandabs_sub_mutPros: When only using one of the traits, no ambiguity. Cons: When using both kinds in the same scope, requires specifying the method via fully-qualified syntax, and you still can't mix scalars and arrays. Also, you'd have to import the appropriate trait.
arr.abs_sub(Arg::Arr(1.0))Pros: No method ambiguity, no proliferation of method names, and you can mix arrays and scalars. Cons: arguments are now verbose.
absandabs_mut, without needing the enums.Pros: No proliferation of method names and you can succinctly mix arrays and scalars. Cons: Complex implementation means that compiler hints are less helpful when something does go wrong. Seems to work for almost all methods, but for some reason mimicking
num::Powrequires me to essentially fall back to one of the above options.I am currently leaning strongly towards (4), but I am curious to get your take.
Sh3mm commentedon Dec 16, 2024
Hum, here are my toughs about each way of doing thing:
I enjoy the simplicity, however, It might make it confusing for the users since they might not understand the difference between the two version just by reading the name. I think it's a nice way to do things, but I would also make sure to link the
scalarversion in the doc of thearrayone and vice versa.I'm a bit uncomfortable with this implementation. Importing the trait when needed is one thing, but it's not rare to do operation with both scalars and array in the same code. I would not like to be in the situation where I have an existing code base using the
SignedScalarand having to comeback and modifying all previous uses of theabs_submethod to their fully-qualified syntax if I suddenly need theSignedArrversion.Frankly, this one feels a bit like a hack, but it feels to me like the best compromise of library management & ease of use.
First, I haven't really used const-generic, so I'm unsure of implementation details. However, based on your pros/cons, here's how I feel:
From a maintainer point of view, I dislike exceptions, so the
num::Powwould royally tick me off. The complexity might be a problem, but since I do not understand how you'd do it, I refrain judgment.As a user, I feel like the hint issue is easily manageable with a good doc.
Overall, I would tend towards (3) or (4). However, depending on philosophy, (1) might be good. The only one I feel negatively about would be the (2).