LinearAlgebra.jl icon indicating copy to clipboard operation
LinearAlgebra.jl copied to clipboard

evalpoly for matrix polynomials

Open stevengj opened this issue 11 months ago • 9 comments

Closes #1161.

Includes a generic out-of-place fallback implementation as well as an in-place evalpoly! method; the latter is called by default only for X::StridedMatrix{<:Number} for now, to be conservative. (e.g. it's much trickier to allocate the in-place buffers correctly for matrices of matrices, which we don't support very well, and I'm not sure this would work well for sparse matrices.) More optimized cases can always be added later.

stevengj avatar Jan 03 '25 22:01 stevengj

In addition to X::StridedMatrix{<:Number}, doesn't the in-place version need to widen based on the coefficients' types? Some failure cases:

julia> evalpoly([1 2; 3 4], (5, 6))  # error without this PR
2×2 Matrix{Int64}:
 11  12
 18  29

julia> evalpoly([1 2; 3 4], (5, 6.7))
ERROR: InexactError: Int64(6.7)
Stacktrace:
...
 [11] evalpoly!(Y::Matrix{Int64}, X::Matrix{Int64}, p::Tuple{Int64, Float64})
    @ Main ./REPL[4]:19

julia> evalpoly([1.0 2.0; 3.0 4.0], (2, 3+im, 4))
ERROR: InexactError: Float64(7.0 + 1.0im)

mcabbott avatar Jan 03 '25 22:01 mcabbott

Argh, this is a PITA to get right for heterogeneous tuples of coefficients, especially for a tuple of dimensionful coefficients. (e.g. suppose that X is in meters, and the coefficients p are in (s, s/m, s/m^2) — this is dimensionfully correct with an evalpoly result in seconds, but you can't simply promote the elements of p).

What is a good way to compute the correct element type of the result matrix?

For p a tuple of numbers, I'm tempted to do typeof(evalpoly(zero(eltype(X)), p)), but that will fail if eltype(X) is abstract.

One option would be to just punt on evalpoly! for now. Another option would be to only support homogeneous tuples.

stevengj avatar Jan 03 '25 22:01 stevengj

Ah now I see some logic for p[begin] which my examples happened to avoid.

Only accepting p::NTuple (and concretely typed vectors) seems fine really. And perhaps even StridedMatrix{<:AbstractFloat} with real coefficients (to avoid my integer example), sim. complex with real-or-complex?

Easy to add methods to send your own fancy types to evalpoly! if you want something not covered by this.

mcabbott avatar Jan 03 '25 23:01 mcabbott

I tightened up the type signatures for dispatch to evalpoly! and it fixes your examples, along with abstractly typed arrays. (Also added tests.)

stevengj avatar Jan 04 '25 00:01 stevengj

This is a little harder to fool, but:

julia> evalpoly([1 2; 3 4], Number[5.5, 6])
ERROR: InexactError: Int64(11.5)

julia> evalpoly([1.0 2.0; 3.0 4.0], Number[2, 3, 4+im])
ERROR: InexactError: Float64(4.0 + 1.0im)

mcabbott avatar Jan 04 '25 01:01 mcabbott

Codecov Report

Attention: Patch coverage is 87.75510% with 6 lines in your changes missing coverage. Please review.

Project coverage is 92.02%. Comparing base (61e444d) to head (68b3f0f).

Files with missing lines Patch % Lines
src/evalpoly.jl 87.75% 6 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1163      +/-   ##
==========================================
- Coverage   92.03%   92.02%   -0.02%     
==========================================
  Files          34       35       +1     
  Lines       15501    15550      +49     
==========================================
+ Hits        14267    14310      +43     
- Misses       1234     1240       +6     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

codecov[bot] avatar Jan 04 '25 10:01 codecov[bot]

I think it makes sense to dispatch to _evalpoly in the case of vectors with non-concrete eltype. We could do a reducion with promotion but I don't think it's worth trying particularly hard to optimize that case.

LilithHafner avatar Jan 04 '25 13:01 LilithHafner

Is this good to merge (assuming tests pass)?

ViralBShah avatar Mar 01 '25 15:03 ViralBShah

@mcabbott's comment is still not addressed. That said, those cases already error.

LilithHafner avatar Mar 02 '25 12:03 LilithHafner

Would it be better to merge this if it is at least addressing some of the issues?

ViralBShah avatar Apr 11 '25 12:04 ViralBShah

CI failure is in matmul so probably unrelated. If so, I think it's likely reasonable to merge this even with @mcabbott's unresolved comment. Do you agree, @mcabbott?

LilithHafner avatar Apr 15 '25 12:04 LilithHafner

I have no strong feelings... my examples above invented to break this do seem unlikely to show up in the wild.

mcabbott avatar Apr 15 '25 13:04 mcabbott

@stevengj We should have merged this earlier, but it would be great if you can update the PR and get it in.

ViralBShah avatar May 31 '25 16:05 ViralBShah