From fc68e9a464a7f6726eb663f999bfe7b2a545b5ee Mon Sep 17 00:00:00 2001 From: lkdvos Date: Thu, 10 Sep 2026 13:39:08 -0400 Subject: [PATCH 1/2] fix: canonical ordering for `sectors(::SumSpace)` `_sectors` returned `values(::Set)`, i.e. hash iteration order, which changed in Julia 1.13 and broke the two `sectors(V)` assertions in the SumSpace tests (they had codified 1.12's order). The order also leaks into fusion tree enumeration via `map(sectors, P)`, making the layout within a block depend on the Julia version. Sort the result instead, consistent with `sectors(::GradedSpace)` (sorted by construction) and `blocksectors(::ProductSpace)` (ends with `sort!`), and assert the invariant with `issorted` rather than a hardcoded permutation. Co-Authored-By: Claude Opus 5 (1M context) --- src/vectorspaces/sumspace.jl | 5 +++-- test/vectorspaces/sumspace.jl | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/vectorspaces/sumspace.jl b/src/vectorspaces/sumspace.jl index b4d97a4..8415b62 100644 --- a/src/vectorspaces/sumspace.jl +++ b/src/vectorspaces/sumspace.jl @@ -128,9 +128,10 @@ end function TensorKit._sectors(S::SumSpace, ::Type{I}) where {I} s = Set{I}() for v in S.spaces - s = s ∪ sectors(v) + union!(s, sectors(v)) end - return values(s) + # sorted for a canonical order, consistent with `GradedSpace` and `blocksectors` + return sort!(collect(s)) end TensorKit.dim(S::SumSpace, sector::Sector) = sum(v -> dim(v, sector), S.spaces; init = 0) diff --git a/test/vectorspaces/sumspace.jl b/test/vectorspaces/sumspace.jl index e4faa52..1c877ba 100644 --- a/test/vectorspaces/sumspace.jl +++ b/test/vectorspaces/sumspace.jl @@ -129,6 +129,7 @@ end @test @constinferred(sectortype(V)) == sectortype(V1) @test ((@constinferred sectors(V))...,) == (U1Irrep(0), U1Irrep(1)) + @test issorted(sectors(V)) @test length(sectors(V)) == 2 @test @constinferred(hassector(V, U1Irrep(0))) @test !@constinferred(hassector(V, U1Irrep(2))) @@ -188,7 +189,8 @@ end @test unitspace(V) == unitspace(V1) @test @constinferred(sectortype(V)) == sectortype(V1) - @test ((@constinferred sectors(V))...,) == (C1, C0, D1, D0, M) # ordering matters + @test ((@constinferred sectors(V))...,) == (C0, C1, M, D0, D1) # sorted order + @test issorted(sectors(V)) @test length(sectors(V)) == 5 @test @constinferred(hassector(V, M)) @test !@constinferred(hassector(V, Mop)) From 4585c7bab54278bc7f924e5dbf3fa3bdb8ab59c2 Mon Sep 17 00:00:00 2001 From: lkdvos Date: Thu, 10 Sep 2026 15:08:49 -0400 Subject: [PATCH 2/2] fix: normalize `One`/`Zero` scalars before `LinearAlgebra` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `mul!` accumulates block contributions with `β = One()`, which reaches `LinearAlgebra` untouched. On Julia 1.13 the HERK path calls `isreal(β)`, which `VectorInterface.One` does not implement, so `w' * w` errors. Map `One`/`Zero` to `true`/`false` at that hand-off; the latter is exactly the strong zero `LinearAlgebra` documents, so the semantics are unchanged. The generic `_mul!!` fallbacks keep the `One`/`Zero` types for VectorInterface's promotion. Co-Authored-By: Claude Opus 5 (1M context) --- src/linalg/linalg.jl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/linalg/linalg.jl b/src/linalg/linalg.jl index aedc2bb..0abd9a3 100644 --- a/src/linalg/linalg.jl +++ b/src/linalg/linalg.jl @@ -129,8 +129,14 @@ const _TM_CAN_MUL = Union{ TensorMap, AdjointTensorMap{<:Any, <:Any, <:Any, <:Any, <:TensorMap}, BraidingTensor, } function _mul!!(C::_TM_CAN_MUL, A::_TM_CAN_MUL, B::_TM_CAN_MUL, α::Number, β::Number) - return mul!(C, A, B, α, β) + return mul!(C, A, B, _blasscalar(α), _blasscalar(β)) end + +# `LinearAlgebra` cannot handle `One`/`Zero`, which carry the same meaning as `true`/`false` +# TODO: remove once `VectorInterface` implements the full `Number` interface for these +_blasscalar(α::Number) = α +_blasscalar(::One) = true +_blasscalar(::Zero) = false # TODO: optimize other implementations # ensure that mixes with AbstractBlockTensorMap and AbstractTensorMap behave as expected: