Conversation
|
Errors are Enzyme + Julia 1.13 - related and not related to the changes here. |
|
Hope springs eternal that Enzyme fixed this somehow in the last 5 days |
Codecov Report❌ Patch coverage is
🚀 New features to boost your workflow:
|
|
@Jutho do you still want to have a look here or is this ok? The main annoyance is it being breaking, do you think that is fair/warranted? |
|
Any news on this? |
| Base.Bool(::One) = true | ||
| Base.Bool(::Zero) = false | ||
| Base.Complex(::One) = Complex(true) | ||
| Base.Complex(::Zero) = Complex(false) | ||
| Base.Complex{T}(::One) where {T <: Real} = Complex{T}(one(T)) | ||
| Base.Complex{T}(::Zero) where {T <: Real} = Complex{T}(zero(T)) |
There was a problem hiding this comment.
Aside from Complex, which is abstract, aren't Bool and Complex{T} not covered by the (T:Type{<:Number}) constructors on line 90 - 91?
There was a problem hiding this comment.
These are all here to fix dispatch, in this case because Base defines Complex{T}(x::Real) where {T <: Real}, which would be ambiguous with (T::Type{<:Number})(::One).
(This is true for all methods under this header)
|
I am fine with this, making them |
|
The invalidations workflow actually is checking that this is not creating any new invalidations, and indeed the methods are meant to have everything working as much as possible without ambiguities. |
Julia 1.13's `mul!` calls `isreal` on the `α`/`β` coefficients, which forced
`Base.isreal` methods on `Zero`/`One` in the previous commit. That gap was not
isolated: because the singletons were `<: Number` but not `<: Real`, they
inherited almost none of Base's numeric fallbacks, and `real`, `imag`, `abs`,
`abs2`, `sign`, `signbit`, `isinteger`, `isinf`, `isless`/`<`/`<=` (hence `min`,
`max`, `cmp`, `sort`, `clamp`) and `isapprox` all threw `MethodError`.
Change the supertype instead of chasing these one release at a time. `isreal`,
`real`, `imag`, `abs`, `abs2`, `signbit`, `angle`, `sqrt`, `isnan`, mixed-type
ordering, `isapprox` and `Complex(One(), Zero())` now come from `Real`, so the
two `isreal` methods are dropped again.
This has to be paid for in one batch:
- 26 method ambiguities appear against Base's Real-vs-Complex methods; add a
disambiguation block whose bodies mirror the existing `::Number` methods.
- `hash` regresses to a `MethodError` and `isfinite` stops working; define both.
- `<(x::T, y::T) where {T <: Real}` is a Base no-op error and
`promote(Zero(), Zero())` is a fixed point, so same-type `isless`/`<`/`<=`
and `sign` need explicit methods.
- `min`/`max` are defined to preserve the singletons rather than promote to
`Bool`, keeping `α === One()` fast paths alive.
- Drop the two `convert(::Type{T}, ...) where {T <: Number}` methods. Once
`Zero <: Real` they supersede `convert(::Type{T}, x::Number)` for real
argument types and take invalidations from 6 to 201. Base's own
`convert(::Type{T}, x::Number) = T(x)::T` routes through the constructors
instead, which is equivalent and leaves 0 invalidations.
Also fixes a pre-existing bug: `isequal(Zero(), 0)` was true while the hashes
differed, so `Dict(0 => :a)[Zero()]` threw a `KeyError`.
Tested on 1.10, 1.12 and 1.13, including the 5-arg `mul!` cases that motivated
this. Breaking, since downstream dispatch on `::Real` vs `::Number` changes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This PR changes the
Zero/Oneimplementations, which is triggered because the new Julia 1.13'smul!callsisrealon theα/βcoefficients.This aims to fix that, and meanwhile also adds a bunch of other functions that I (and my robot friend) could come up with in an attempt to avoid this in the future.
I made a judgement call and changed these to subtype
Realinstead ofNumber, which means (I think?) that this is now a breaking change, but I'm open to suggestions here.Below is some comments by Claude:
Paid for in this PR:
::Numberbodies.hashregresses to aMethodErrorandisfinitestops working → both defined.<(x::T, y::T) where {T <: Real}is a Base no-op error andpromote(Zero(), Zero())is a fixed point → same-typeisless/</<=andsignneed explicit methods.min/maxdefined to preserve the singletons instead of promoting toBool, soα === One()fast paths keep firing.convert(::Type{T}, ...) where {T <: Number}methods. OnceZero <: Realthey supersedeconvert(::Type{T}, x::Number)for real argument types, taking invalidations from 6 to 201. Base'sconvert(::Type{T}, x::Number) = T(x)::Troutes through the constructors instead — equivalent, and 0 invalidations.Also fixes a pre-existing bug:
isequal(Zero(), 0)wastruewhile the hashes differed, soDict(0 => :a)[Zero()]threw aKeyError.Verification
enzyme,mooncake,chainrulestest/onezero.jlon 1.10 / 1.12 / 1.13Aqua.test_allon 1.10 / 1.12 / 1.13main, 201 with a naive supertype swap)linsolve/eigsolve, real + complexNew tests cover the 5-arg
mul!cases directly (mul!(C, A, B, One(), Zero())andmul!(C, A, B, One(), One()), real and complex), plusaxpy!/rmul!/lmul!, so whatever 1.13 calls on the coefficients is pinned.Breaking — a supertype change alters downstream dispatch for anything with separate
::Realand::Numbermethods. Version bumped to 0.7.0; worth a heads-up to KrylovKit and TensorKit before tagging.🤖 Generated with Claude Code