Skip to content

Add many other numeric methods #78

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

Merged
merged 14 commits into from
Nov 12, 2023
Merged

Add many other numeric methods #78

merged 14 commits into from
Nov 12, 2023

Conversation

MilesCranmer
Copy link
Member

@MilesCranmer MilesCranmer commented Nov 4, 2023

This adds methods for the following functions. Most of these will throw an error if the quantity has nonzero dimensions. However some of the functions allow nonzero dimensions, and simply return an output with the same dimensions.

  • div
  • sin
  • cos
  • tan
  • sinh
  • cosh
  • tanh
  • asin
  • acos
  • asinh
  • acosh
  • atanh
  • sec
  • csc
  • cot
  • asec
  • acsc
  • acot
  • sech
  • csch
  • coth
  • asech
  • acsch
  • acoth
  • sinc
  • cosc
  • cosd
  • cotd
  • cscd
  • secd
  • sinpi
  • cospi
  • sind
  • tand
  • acosd
  • acotd
  • acscd
  • asecd
  • asind
  • log
  • log2
  • log10
  • log1p
  • exp
  • exp2
  • exp10
  • expm1
  • frexp
  • exponent
  • atan
  • atand
  • adjoint
  • unsigned
  • identity
  • transpose
  • copysign
  • flipsign
  • mod
  • ldexp
  • round
  • floor
  • trunc
  • ceil
  • significand
  • modf
  • signbit (in utils.jl)

It also moves methods over to math.jl for:

  • real
  • imag
  • conj
  • nextfloat
  • prevfloat

TODO:

  • Add unittests for each

Copy link
Contributor

github-actions bot commented Nov 4, 2023

Benchmark Results

main 40521a1... t[main]/t[40521a1...]
Quantity/creation/Quantity(x) 3.1 ± 0.01 ns 2.79 ± 0.01 ns 1.11
Quantity/creation/Quantity(x, length=y) 4.02 ± 0.011 ns 3.11 ± 0.01 ns 1.29
Quantity/with_numbers/*real 3.1 ± 0.01 ns 3.1 ± 0.01 ns 1
Quantity/with_numbers/^int 8.05 ± 1.9 ns 7.75 ± 1.8 ns 1.04
Quantity/with_numbers/^int * real 8.05 ± 1.9 ns 8.65 ± 1.9 ns 0.932
Quantity/with_quantity/+y 5.27 ± 0.01 ns 5.27 ± 0.01 ns 1
Quantity/with_quantity//y 3.42 ± 0.011 ns 3.42 ± 0.01 ns 1
Quantity/with_self/dimension 1.55 ± 0.01 ns 1.56 ± 0.01 ns 0.994
Quantity/with_self/inv 3.11 ± 0.01 ns 3.11 ± 0.01 ns 1
Quantity/with_self/ustrip 1.55 ± 0.01 ns 1.55 ± 0.01 ns 1
QuantityArray/broadcasting/multi_array_of_quantities 0.148 ± 0.012 ms 0.149 ± 0.014 ms 0.994
QuantityArray/broadcasting/multi_normal_array 0.0471 ± 0.00023 ms 0.0498 ± 0.00031 ms 0.946
QuantityArray/broadcasting/multi_quantity_array 0.158 ± 0.00058 ms 0.16 ± 0.0014 ms 0.99
QuantityArray/broadcasting/x^2_array_of_quantities 25.5 ± 2.1 μs 25.4 ± 2.5 μs 1
QuantityArray/broadcasting/x^2_normal_array 4.26 ± 0.82 μs 4.4 ± 0.96 μs 0.968
QuantityArray/broadcasting/x^2_quantity_array 5.98 ± 0.33 μs 5.93 ± 0.33 μs 1.01
QuantityArray/broadcasting/x^4_array_of_quantities 0.0816 ± 0.00052 ms 0.0785 ± 0.00068 ms 1.04
QuantityArray/broadcasting/x^4_normal_array 0.0436 ± 0.00017 ms 0.0467 ± 0.00017 ms 0.934
QuantityArray/broadcasting/x^4_quantity_array 0.0561 ± 0.00017 ms 0.0562 ± 0.0061 ms 0.999
time_to_load 0.161 ± 0.00063 s 0.161 ± 0.00075 s 1

Benchmark Plots

A plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR.
Go to "Actions"->"Benchmark a pull request"->[the most recent run]->"Artifacts" (at the bottom).

@MilesCranmer MilesCranmer changed the title [WIP] add many other numeric methods Add many other numeric methods Nov 5, 2023
@MilesCranmer
Copy link
Member Author

FYI the errors seem to be coming from this issue: JuliaPhysics/Measurements.jl#162 so not related to this PR at all.

Copy link
Collaborator

@gaurav-arya gaurav-arya left a comment

Choose a reason for hiding this comment

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

Looks good to me! Only thing I wondered is whether something like exp(x) should return an instance of the base type or a dimensionless quantity. This goes back to the one debate too (ugh), e.g. f(q) = iszero(q) ? one(q) : exp(q) wouldn't be type stable currently. But I don't see an obvious answer here (nor do I think it has to be resolved in this PR). It is indeed nice to go back to the simpler scalars when we can, which is a big plus of the current behaviour.

@MilesCranmer
Copy link
Member Author

MilesCranmer commented Nov 9, 2023

I think it's okay because one is supposed to return the exact same type, but a lot of these numerical operators are not required nor expected to. For example, your function f(q) would also be type unstable for Int64 input, as it would get converted to a float output for exp. But one's purpose is to return the exact same type representing a 1.

@MilesCranmer
Copy link
Member Author

MilesCranmer commented Nov 9, 2023

I guess the downside is that if someone did stuff like

x = 0.9u"km/s"
y = [x, x / x, exp(x / x * 0.3)]

it would be Vector{Number}. Which is bad and feels like it approaches Unitful type instabilities again...

So maybe you are right and we should just always keep to the original quantity type... to absolutely guarantee type stability.

@MilesCranmer
Copy link
Member Author

I think I am 50/50 on this... So I'd welcome any opinions one way or the other.

@MilesCranmer
Copy link
Member Author

it would be Vector{Number}. Which is bad and feels like it approaches Unitful type instabilities again...

I guess we could also fix this by simply defining a promotion rule for all the primitive numeric types in https://docs.julialang.org/en/v1/manual/integers-and-floating-point-numbers/. (Recalling that the reason I avoided a generic Number promotion rule is that it might conflict with other abstract types that are also <: Number)

@gaurav-arya
Copy link
Collaborator

I do feel like [3.0, 1u"m"] should promote in any case, yes.

@gaurav-arya
Copy link
Collaborator

gaurav-arya commented Nov 9, 2023

My overall opinion is that the scalar-output approach for exp and friends seems very appealing, and I think we should take it unless we/others find an insurmountable obstable, e.g. type instability in a reasonable use case with no other fix.

@MilesCranmer
Copy link
Member Author

Okay we could rebase this on #84 if you are on board with that change

@MilesCranmer
Copy link
Member Author

My overall opinion is that the scalar-output approach for exp and friends seems very appealing, and I think we should take it unless we/others find an insurmountable obstable, e.g. type instability in a reasonable use case with no other fix.

Sounds good!

@MilesCranmer MilesCranmer merged commit 29454c1 into main Nov 12, 2023
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

Successfully merging this pull request may close these issues.

2 participants