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

Deprecate gausschebyshev and add gausschebyshevt, ..., gausschebyshevw #123

Merged

Conversation

hyrodium
Copy link
Collaborator

@hyrodium hyrodium commented Sep 14, 2023

We currently have gausschebyshev(n::Integer, kind::Integer), but we don't need arithmetic operations for kind parameter, i.e. some operations such as gausschebyshev(4, 2+1) is not desired.

Enum or Val can be used to solve this problem, however, just splitting and renaming the function would be enough here.

julia> gausschebyshev(5,2)  # deprecated method
([-0.8660254037844387, -0.4999999999999998, 6.123233995736766e-17, 0.5000000000000001, 0.8660254037844387], [0.13089969389957468, 0.3926990816987242, 0.5235987755982988, 0.39269908169872403, 0.13089969389957468])

julia> gausschebyshev2(5)  # new function
([-0.8660254037844387, -0.4999999999999998, 6.123233995736766e-17, 0.5000000000000001, 0.8660254037844387], [0.13089969389957468, 0.3926990816987242, 0.5235987755982988, 0.39269908169872403, 0.13089969389957468])

@hyrodium hyrodium changed the title Deprecate gausschebyshev and add gausschebyshev1 to gausschebyshev4 Deprecate gausschebyshev and add gausschebyshev1, ..., gausschebyshev4 Sep 14, 2023
@codecov
Copy link

codecov bot commented Sep 14, 2023

Codecov Report

Patch coverage: 100.00% and project coverage change: -0.04% ⚠️

Comparison is base (a593294) 96.65% compared to head (93f03ab) 96.62%.
Report is 4 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #123      +/-   ##
==========================================
- Coverage   96.65%   96.62%   -0.04%     
==========================================
  Files           9        9              
  Lines        1227     1244      +17     
==========================================
+ Hits         1186     1202      +16     
- Misses         41       42       +1     
Files Changed Coverage Δ
src/FastGaussQuadrature.jl 100.00% <ø> (ø)
src/gausschebyshev.jl 96.87% <100.00%> (-3.13%) ⬇️

... and 2 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@dlfivefifty
Copy link
Member

I think better names would be gausschebyshevt (or just gausschebyshev), gausschebyshevu, gausschebyshevv and gausschebyshevw.

Cf chebyshevutransform:

https://github.com/JuliaApproximation/FastTransforms.jl/blob/fde025f2fe3643e8673a098fed02bc0d804dc7ed/src/chebyshevtransform.jl#L495

@hyrodium
Copy link
Collaborator Author

I think better names would be gausschebyshevt (or just gausschebyshev), gausschebyshevu, gausschebyshevv and gausschebyshevw.

Thank you for the suggestion! This is not a strong preference, but I thought something like gausschebyshev1 has good visibility.

@hyrodium
Copy link
Collaborator Author

How about gausschebyshev_u etc. or gausschebyshevU?

@hyrodium
Copy link
Collaborator Author

@hyrodium
Copy link
Collaborator Author

Based on the poll, I have updated the name with gausschebyshevT, gausschebyshevU, gausschebyshevV, and gausschebyshevW.

image

@dlfivefifty Do you agree with this naming?

@hyrodium hyrodium changed the title Deprecate gausschebyshev and add gausschebyshev1, ..., gausschebyshev4 Deprecate gausschebyshev and add gausschebyshevT, ..., gausschebyshevW Sep 16, 2023
@dlfivefifty
Copy link
Member

Note in ClassicalOrthogonalPolynomials.jl I use chebyshevt/chebyshevu/etc. as its consistent with SpecialFunctions.jl naming scheme eg besselj or hankelh.

Is there any precedence for using capital letters in this way? If not I think we should follow SpecialFunctions.jl. So either gausschebyshevt or gauss_chebyshevt

@hyrodium
Copy link
Collaborator Author

hyrodium commented Sep 17, 2023

Is there any precedence for using capital letters in this way?

gausschebyshevT has better visibility than gausschebyshevt, and is consistent with $T_n$.

The difference between besselj and gausschebyshevt is their length, and the latter is a little hard to read.
I'm okay with gausschebyshevt, but other people (like in slack) would prefer other naming conventions.

gauss_chebyshevt is not consistent with gausslegendre etc.

In ideal, it would be nice to have names like SpecialFunctions.besselJ, ClassicalOrthogonalPolynomials.chebyshevT, etc., I guess. 😂

@hyrodium
Copy link
Collaborator Author

Or, should we rename all of gausshermite etc. to gauss_hermite etc.?

@MikaelSlevinsky
Copy link
Member

Is there any good reason to deprecate the 2-arg method? Bessel functions in SpecialFunctions have besselj and besselj0 for example.

@hyrodium
Copy link
Collaborator Author

Is there any good reason to deprecate the 2-arg method?

My first comment (#123 (comment)) is the reason. And the 2-arg method is not friendly with the static analyzer JET.jl.

Before this PR

julia> using JET, FastGaussQuadrature

julia> f(n) = gausschebyshev(n, 3)
f (generic function with 1 method)

julia> g(n) = gausschebyshev(n, 5)  # typo
g (generic function with 1 method)

julia> @report_opt f(8)
No errors detected


julia> @report_opt g(8)  # No error!
No errors detected

After this PR

julia> using JET, FastGaussQuadrature

julia> f(n) = gausschebyshevV(n)
f (generic function with 1 method)

julia> g(n) = gausschebyshevZ(n)  # typo
g (generic function with 1 method)

julia> @report_opt f(8)
No errors detected


julia> @report_opt g(8)  # Yay!
═════ 1 possible error found ═════
┌ g(n::Int64) @ Main ./REPL[3]:1
│ runtime dispatch detected: %1::Any(n::Int64)::Any
└────────────────────

The 1-arg method would be compiled lighter than 2-arg version, but this is really a slight advantage.

Bessel functions in SpecialFunctions have besselj and besselj0 for example.

Both arguments of besselj have "mathematical" meaning, but gausschebyshev does not. (1st kind etc. for gausschebyshev are just expedient indexing)

julia> besselj(3.4, 4.2)  # Any numbers are accepted (mathematically)
0.4003115265583054

julia> besselj(0, 4.2)
-0.37655705436756765

julia> besselj0(4.2)  # Some special case has its function (maybe, special optimization inside?)
-0.37655705436756765

@MikaelSlevinsky
Copy link
Member

To me, that sounds like you may have a case to add definitions, but why must we throw away the 2-arg version? Kind has a mathematical meaning; it's just that it must be one of the integers 1, 2, 3, or 4, not any other real or complex number.

@hyrodium
Copy link
Collaborator Author

hyrodium commented Sep 17, 2023

why must we throw away the 2-arg version?

For better package design:

  • avoid confusion
  • friendly for static analyzers

We can release v0.5.2 with the deprecation message, and remove them (including besselroots #124) in the next breaking release v0.6.0.

Are there any reasons to keep the 2-arg version?

Kind has a mathematical meaning; it's just that it must be one of the integers 1, 2, 3, or 4, not any other real or complex number.

That's why I quoted like "mathematical". We can call them type-A to type-D, or something like that. There is not much meaning as an integer (i.e. no addition, no order, etc.), but it's just a label.

@dlfivefifty
Copy link
Member

gausschebyshevT has better visibility than gausschebyshevt, and is consistent with $T_n$.

besselJ has better visibility than besselj and is consistent with $J_n$....

I haven't seen an actual argument for the inconsistency besides you like it better. Personally, I also like it better....but as I said I went with chebyshevt before for consistency, and I don't think it's a good idea to introduce inconsistency at this point.

@hyrodium
Copy link
Collaborator Author

I don't think it's a good idea to introduce inconsistency at this point.

Okay, let's change the names to gausschebyshevt for now!
We can revisit this discussion when we introduce other Gaussian quadrature methods with name which is not just "gauss$(a_name_of_a_person)".

@hyrodium hyrodium changed the title Deprecate gausschebyshev and add gausschebyshevT, ..., gausschebyshevW Deprecate gausschebyshev and add gausschebyshevt, ..., gausschebyshevw Sep 18, 2023
@hyrodium
Copy link
Collaborator Author

@dlfivefifty @MikaelSlevinsky
Do you have any additional comments on this PR? Can I merge this?

@dlfivefifty
Copy link
Member

Can you bump the minor version number?

@dlfivefifty
Copy link
Member

This is a breaking change it should be the minor version, not the patch version

@hyrodium
Copy link
Collaborator Author

This is a breaking change it should be the minor version, not the patch version

No, the 2-arg version is still alive (and is deprecated), so we should bump the patch version.
I will remove the deprecated methods (including besselroots #124) in the next breaking release.

Related comment: #123 (comment)

@dlfivefifty
Copy link
Member

Deprecations are breaking changes: it forces a user to change their code

@dlfivefifty
Copy link
Member

Also exporting new functions is breaking

@hyrodium
Copy link
Collaborator Author

Deprecations are breaking changes: it forces a user to change their code

So, do you think we need two breaking releases to remove gausschebyshev?

  • v0.6.0 - deprecate gausschebyshev
  • v0.7.0 - remove deprecated gausschebyshev

I believe it's not breaking and we need just one breaking release. This is because package users don't have to change their code, and they just receive warnings.

Many other repositories add @deprecate macros etc. without breaking releases.
See https://github.com/search?q=%40deprecate++path%3A*.jl+language%3AJulia&type=Code&ref=advsearch&l=Julia&l= for search results, and some other PR (FluxML/Flux.jl#2328)

Also exporting new functions is breaking

I also believe this is not breaking. They may cause some name conflicts but are not considered as breaking usually. For example, Julia 1.9 exports pkgversion, but Julia v1.8 does not.

@dlfivefifty
Copy link
Member

Umm you just leave the deprecation in. It can be deleted whenever another breaking change comes, there's no rush to remove the code.

But a warning can turn high-performance code into unusably slow code. And it's incredibly annoying if you are a user of another package that depends on this to suddenly have to see warnings all the time

Note the rules are a bit different once something is 1.x. The convention is to deprecate at 1.(x+1) and delete at 1.(x+2). This is because its easier to pin versions at the 1.x level.

@hyrodium
Copy link
Collaborator Author

hyrodium commented Sep 21, 2023

But a warning can turn high-performance code into unusably slow code. And it's incredibly annoying if you are a user of another package that depends on this to suddenly have to see warnings all the time

This behavior can be handled by CLI argument --depwarn=yes or --depwarn=no (default).

julia --depwarn=yes

julia> using BenchmarkTools, FastGaussQuadrature

julia> @benchmark besselroots(0.2,5)
┌ Warning: `besselroots(ν::Real, n::Integer)` is deprecated, use `approx_besselroots(ν, n)` instead.
│   caller = var"##core#293"() at execution.jl:489
└ @ Main ~/.julia/packages/BenchmarkTools/0owsb/src/execution.jl:489
BenchmarkTools.Trial: 579 samples with 1 evaluation.
 Range (min  max):  8.226 ms   12.814 ms  ┊ GC (min  max): 0.00%  0.00%
 Time  (median):     8.504 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   8.629 ms ± 448.184 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

    ▅█▅▃▁▁▁▂ ▁                                                 
  ▃███████████▆▅▄▅▇▅▅▄▄▅▄▄▄▃▃▄▃▄▃▂▃▃▃▁▂▁▃▁▂▂▂▂▃▂▂▂▂▃▁▃▁▂▁▁▁▁▂ ▃
  8.23 ms         Histogram: frequency by time        10.1 ms <

 Memory estimate: 12.83 KiB, allocs estimate: 93.

julia> @benchmark approx_besselroots(0.2,5)
BenchmarkTools.Trial: 10000 samples with 767 evaluations.
 Range (min  max):  164.785 ns   1.729 μs  ┊ GC (min  max): 0.00%  82.24%
 Time  (median):     170.714 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   181.138 ns ± 71.886 ns  ┊ GC (mean ± σ):  2.12% ±  4.83%

  ▁▆▆█▇▃▂▂▁ ▁              ▂▂▁             ▁                   ▁
  █████████████▇▇▇▆▆▆▆▆▅▆▆▇████▇▇▇▆▅▇▆▇█▇▇████▇▇▅▆▅▆▅▅▅▆▅▆▅▅▅▄ █
  165 ns        Histogram: log(frequency) by time       262 ns <

 Memory estimate: 208 bytes, allocs estimate: 2.

julia --depwarn=no

julia> using BenchmarkTools, FastGaussQuadrature

julia> @benchmark besselroots(0.2,5)
BenchmarkTools.Trial: 10000 samples with 685 evaluations.
 Range (min  max):  181.263 ns   2.680 μs  ┊ GC (min  max): 0.00%  82.70%
 Time  (median):     185.461 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   202.780 ns ± 82.863 ns  ┊ GC (mean ± σ):  2.05% ±  4.65%

  ▃██▄▃▃▁▁▁                ▁▅▅▂▁   ▁    ▁                      ▂
  ███████████▇▇▆▆▇▆▆▆▆▆▅▆▆▆███████████▇████▇▆▆▆▅▅▅▄▄▅▆▆▆▆▄▄▄▃▅ █
  181 ns        Histogram: log(frequency) by time       288 ns <

 Memory estimate: 208 bytes, allocs estimate: 2.

julia> @benchmark approx_besselroots(0.2,5)
BenchmarkTools.Trial: 10000 samples with 763 evaluations.
 Range (min  max):  164.336 ns   1.219 μs  ┊ GC (min  max): 0.00%  82.81%
 Time  (median):     167.722 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   180.819 ns ± 58.174 ns  ┊ GC (mean ± σ):  1.57% ±  4.64%

  ▆█▂▂▁           ▂     ▁   ▁                                  ▁
  ███████▇▆▆▆▅▆▆▆███▆▆▅▆██▇▇██▇▇▇▆▆▆▆▆▆▆▆▆▅▆▆▇▆▆▆▆▅▅▄▅▅▅▅▅▅▄▄▄ █
  164 ns        Histogram: log(frequency) by time       313 ns <

 Memory estimate: 208 bytes, allocs estimate: 2.

I understand 8.629 ms is a really bad performance, but 202.780 ns would be acceptable.

Note the rules are a bit different once something is 1.x. The convention is to deprecate at 1.(x+1) and delete at 1.(x+2). This is because its easier to pin versions at the 1.x level.

In Julia community, we treat x.y.zx+1.y.z and 0.y.z0.y+1.z as breaking changes. See
BREAKING tags in https://github.com/JuliaRegistries/General/pulls.
If we need more detailed releases, I suggest releasing v1.0.0.

@dlfivefifty
Copy link
Member

I'm sorry but changing the name of one of the main functions in a package is definitely breaking. I'm not going to tag this as a patch.

@hyrodium
Copy link
Collaborator Author

hyrodium commented Sep 21, 2023

I'm sorry but changing the name of one of the main functions in a package is definitely breaking. I'm not going to tag this as a patch.

Hmm, can I ask two questions for clarity?

  • Should we really need to bump the minor version?
    • We can still use gausschebyshev after this PR, so this PR does not break anything.
    • Many other packages do not add deprecation as a breaking change.
  • Do we need two breaking releases to remove gausschebyshev?

@dlfivefifty
Copy link
Member

Lets just not merge this then until there's another breaking change.

@hyrodium
Copy link
Collaborator Author

Okay...
Can I revert the version bump commits and merge this PR?

@hyrodium
Copy link
Collaborator Author

hyrodium commented Sep 21, 2023

@ranocha Hi, we are planning to split gauschebyshev function into four functions such as gausschebyshevu in this PR. We can still use gauschebyshev function after this PR because it will be just deprecated in this PR.

My question is, should we make a breaking release for this deprecation?
I would like to have your opinion because you are maintaining a package that depends on FastGaussQuadrature.jl. (#113 (comment))

Thank you in advance!

@ranocha
Copy link

ranocha commented Sep 22, 2023

I'm not using gauschebyshev so it's fine with me. I would not consider introducing a deprecation a breaking change (in recent versions of Julia where this is handled via a command line flag) - at least based on what I've seen from other packages.

@dlfivefifty dlfivefifty merged commit de3eb8f into JuliaApproximation:master Oct 2, 2023
11 of 12 checks passed
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.

4 participants