From 11bb2508bb0f23437ff9d3833b01312e90722242 Mon Sep 17 00:00:00 2001 From: CarloLucibello Date: Tue, 20 Oct 2026 07:37:05 +0200 Subject: [PATCH 1/4] Preserve BFloat16 in ProjectTo Add a BFloat16s extension defining ProjectTo(::BFloat16) = ProjectTo{BFloat16}(), like Float16/Float32/Float64, instead of falling back to ProjectTo{Real}. Closes #718. Co-Authored-By: Claude Opus 5.5 --- Project.toml | 5 ++++- ext/ChainRulesCoreBFloat16sExt.jl | 8 ++++++++ test/Project.toml | 2 ++ test/projection.jl | 8 ++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 ext/ChainRulesCoreBFloat16sExt.jl diff --git a/Project.toml b/Project.toml index 290ccca4c..378d78f0f 100644 --- a/Project.toml +++ b/Project.toml @@ -1,19 +1,22 @@ name = "ChainRulesCore" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.26.3" +version = "1.26.4" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [compat] +BFloat16s = "0.5, 0.6" LinearAlgebra = "1" SparseArrays = "1" julia = "1.10" [extensions] +ChainRulesCoreBFloat16sExt = "BFloat16s" ChainRulesCoreSparseArraysExt = "SparseArrays" [weakdeps] +BFloat16s = "ab4f0b2a-ad5b-11e8-123f-65d77653426b" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [workspace] diff --git a/ext/ChainRulesCoreBFloat16sExt.jl b/ext/ChainRulesCoreBFloat16sExt.jl new file mode 100644 index 000000000..fbe5da78b --- /dev/null +++ b/ext/ChainRulesCoreBFloat16sExt.jl @@ -0,0 +1,8 @@ +module ChainRulesCoreBFloat16sExt + +using ChainRulesCore +using BFloat16s: BFloat16 + +ChainRulesCore.ProjectTo(::BFloat16) = ProjectTo{BFloat16}() + +end diff --git a/test/Project.toml b/test/Project.toml index 77a84d6b8..03dfcda18 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,4 +1,5 @@ [deps] +BFloat16s = "ab4f0b2a-ad5b-11e8-123f-65d77653426b" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000" @@ -9,6 +10,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] +BFloat16s = "0.5, 0.6" BenchmarkTools = "1.5" ChainRulesCore = "1" FiniteDifferences = "0.12.32" diff --git a/test/projection.jl b/test/projection.jl index 2445b79bd..ad3215471 100644 --- a/test/projection.jl +++ b/test/projection.jl @@ -1,6 +1,7 @@ using ChainRulesCore, Test using LinearAlgebra, SparseArrays using OffsetArrays, StaticArrays, BenchmarkTools +using BFloat16s # Like ForwardDiff.jl's Dual struct Dual{T<:Real} <: Real @@ -59,6 +60,13 @@ struct NoSuperType end @test ProjectTo(Dual(1.0, 2.0))(Tangent{Dual}(; value=1.0)) isa Tangent end + @testset "BFloat16" begin + @test ProjectTo(BFloat16(1))(2.5f0) === BFloat16(2.5) + @test ProjectTo(BFloat16(1))(2.5) === BFloat16(2.5) + @test ProjectTo(BFloat16(1))(2) === BFloat16(2) + @test ProjectTo(BFloat16[1, 2])([1.5f0, 2.5f0]) isa Vector{BFloat16} + end + @testset "Base: arrays of numbers" begin pvec3 = ProjectTo([1, 2, 3]) @test pvec3(1.0:3.0) === 1.0:3.0 From bfc2dea810655a5ebacffa022906ef94019d62d7 Mon Sep 17 00:00:00 2001 From: CarloLucibello Date: Tue, 20 Oct 2026 10:17:17 +0200 Subject: [PATCH 2/4] Rename extension to BFloat16sExt and require BFloat16s 0.6 Co-Authored-By: Claude Opus 5.5 --- Project.toml | 4 ++-- ext/{ChainRulesCoreBFloat16sExt.jl => BFloat16sExt.jl} | 2 +- test/Project.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename ext/{ChainRulesCoreBFloat16sExt.jl => BFloat16sExt.jl} (77%) diff --git a/Project.toml b/Project.toml index 378d78f0f..67e024e6f 100644 --- a/Project.toml +++ b/Project.toml @@ -6,13 +6,13 @@ version = "1.26.4" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [compat] -BFloat16s = "0.5, 0.6" +BFloat16s = "0.6" LinearAlgebra = "1" SparseArrays = "1" julia = "1.10" [extensions] -ChainRulesCoreBFloat16sExt = "BFloat16s" +BFloat16sExt = "BFloat16s" ChainRulesCoreSparseArraysExt = "SparseArrays" [weakdeps] diff --git a/ext/ChainRulesCoreBFloat16sExt.jl b/ext/BFloat16sExt.jl similarity index 77% rename from ext/ChainRulesCoreBFloat16sExt.jl rename to ext/BFloat16sExt.jl index fbe5da78b..5eb1a3f06 100644 --- a/ext/ChainRulesCoreBFloat16sExt.jl +++ b/ext/BFloat16sExt.jl @@ -1,4 +1,4 @@ -module ChainRulesCoreBFloat16sExt +module BFloat16sExt using ChainRulesCore using BFloat16s: BFloat16 diff --git a/test/Project.toml b/test/Project.toml index 03dfcda18..38bfe06b0 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -10,7 +10,7 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -BFloat16s = "0.5, 0.6" +BFloat16s = "0.6" BenchmarkTools = "1.5" ChainRulesCore = "1" FiniteDifferences = "0.12.32" From 2d0592318cd080d431cdb0706683e26806bb877c Mon Sep 17 00:00:00 2001 From: CarloLucibello Date: Tue, 20 Oct 2026 11:38:15 +0200 Subject: [PATCH 3/4] Define ProjectTo for Core.BFloat16 instead of a BFloat16s extension BFloat16s.jl's own BFloat16, used where LLVM lacks bf16 support, is left to an extension in BFloat16s.jl. Co-Authored-By: Claude Opus 5.5 --- Project.toml | 3 --- ext/BFloat16sExt.jl | 8 -------- src/projection.jl | 3 +++ test/projection.jl | 13 ++++++++----- 4 files changed, 11 insertions(+), 16 deletions(-) delete mode 100644 ext/BFloat16sExt.jl diff --git a/Project.toml b/Project.toml index 67e024e6f..36edfbd21 100644 --- a/Project.toml +++ b/Project.toml @@ -6,17 +6,14 @@ version = "1.26.4" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [compat] -BFloat16s = "0.6" LinearAlgebra = "1" SparseArrays = "1" julia = "1.10" [extensions] -BFloat16sExt = "BFloat16s" ChainRulesCoreSparseArraysExt = "SparseArrays" [weakdeps] -BFloat16s = "ab4f0b2a-ad5b-11e8-123f-65d77653426b" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [workspace] diff --git a/ext/BFloat16sExt.jl b/ext/BFloat16sExt.jl deleted file mode 100644 index 5eb1a3f06..000000000 --- a/ext/BFloat16sExt.jl +++ /dev/null @@ -1,8 +0,0 @@ -module BFloat16sExt - -using ChainRulesCore -using BFloat16s: BFloat16 - -ChainRulesCore.ProjectTo(::BFloat16) = ProjectTo{BFloat16}() - -end diff --git a/src/projection.jl b/src/projection.jl index 13d472879..90e11ddb4 100644 --- a/src/projection.jl +++ b/src/projection.jl @@ -168,6 +168,9 @@ ProjectTo(x::Complex{<:Integer}) = ProjectTo(float(x)) for T in (Float16, Float32, Float64, ComplexF16, ComplexF32, ComplexF64) @eval ProjectTo(::$T) = ProjectTo{$T}() end +@static if isdefined(Core, :BFloat16) + ProjectTo(::Core.BFloat16) = ProjectTo{Core.BFloat16}() +end # In these cases we can just `convert` as we know we are dealing with plain and simple types (::ProjectTo{T})(dx::AbstractFloat) where {T<:AbstractFloat} = convert(T, dx) diff --git a/test/projection.jl b/test/projection.jl index ad3215471..aac109882 100644 --- a/test/projection.jl +++ b/test/projection.jl @@ -60,11 +60,14 @@ struct NoSuperType end @test ProjectTo(Dual(1.0, 2.0))(Tangent{Dual}(; value=1.0)) isa Tangent end - @testset "BFloat16" begin - @test ProjectTo(BFloat16(1))(2.5f0) === BFloat16(2.5) - @test ProjectTo(BFloat16(1))(2.5) === BFloat16(2.5) - @test ProjectTo(BFloat16(1))(2) === BFloat16(2) - @test ProjectTo(BFloat16[1, 2])([1.5f0, 2.5f0]) isa Vector{BFloat16} + # BFloat16s.jl's own BFloat16, used where LLVM lacks bf16 support, is not covered + if isdefined(Core, :BFloat16) && BFloat16 === Core.BFloat16 + @testset "BFloat16" begin + @test ProjectTo(BFloat16(1))(2.5f0) === BFloat16(2.5) + @test ProjectTo(BFloat16(1))(2.5) === BFloat16(2.5) + @test ProjectTo(BFloat16(1))(2) === BFloat16(2) + @test ProjectTo(BFloat16[1, 2])([1.5f0, 2.5f0]) isa Vector{BFloat16} + end end @testset "Base: arrays of numbers" begin From 673907463e431d98f90508eff752f67e723854d0 Mon Sep 17 00:00:00 2001 From: CarloLucibello Date: Tue, 20 Oct 2026 14:12:42 +0200 Subject: [PATCH 4/4] Test Core.BFloat16 projection without BFloat16s Co-Authored-By: Claude Opus 5.5 --- test/Project.toml | 2 -- test/projection.jl | 11 ++++------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index 38bfe06b0..77a84d6b8 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,5 +1,4 @@ [deps] -BFloat16s = "ab4f0b2a-ad5b-11e8-123f-65d77653426b" BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" FiniteDifferences = "26cc04aa-876d-5657-8c51-4c34ba976000" @@ -10,7 +9,6 @@ StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -BFloat16s = "0.6" BenchmarkTools = "1.5" ChainRulesCore = "1" FiniteDifferences = "0.12.32" diff --git a/test/projection.jl b/test/projection.jl index aac109882..912131242 100644 --- a/test/projection.jl +++ b/test/projection.jl @@ -1,7 +1,6 @@ using ChainRulesCore, Test using LinearAlgebra, SparseArrays using OffsetArrays, StaticArrays, BenchmarkTools -using BFloat16s # Like ForwardDiff.jl's Dual struct Dual{T<:Real} <: Real @@ -60,13 +59,11 @@ struct NoSuperType end @test ProjectTo(Dual(1.0, 2.0))(Tangent{Dual}(; value=1.0)) isa Tangent end - # BFloat16s.jl's own BFloat16, used where LLVM lacks bf16 support, is not covered - if isdefined(Core, :BFloat16) && BFloat16 === Core.BFloat16 + if isdefined(Core, :BFloat16) @testset "BFloat16" begin - @test ProjectTo(BFloat16(1))(2.5f0) === BFloat16(2.5) - @test ProjectTo(BFloat16(1))(2.5) === BFloat16(2.5) - @test ProjectTo(BFloat16(1))(2) === BFloat16(2) - @test ProjectTo(BFloat16[1, 2])([1.5f0, 2.5f0]) isa Vector{BFloat16} + # Base defines no conversions to Core.BFloat16, so build one from its bits + x = reinterpret(Core.BFloat16, 0x3f80) + @test ProjectTo(x) === ProjectTo{Core.BFloat16}() end end