diff --git a/NEWS.md b/NEWS.md index 618bb6ab9..aae72ba01 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,8 +8,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added + - Make `compute_facet_owners(...)` more flexible, allowing the user to provide a function to select the owner from neighboring cells. Since PR[#1291](https://github.com/gridap/Gridap.jl/pull/1291). +### Fixed + +- Fixed type instability for tensor operations between `MultiValue` and scalars. Since PR[#1293](https://github.com/gridap/Gridap.jl/pull/1293). + ## [0.20.5] - 2026-04-28 ### Fixed diff --git a/src/TensorValues/MultiValueTypes.jl b/src/TensorValues/MultiValueTypes.jl index 47999353e..15c5cfc76 100644 --- a/src/TensorValues/MultiValueTypes.jl +++ b/src/TensorValues/MultiValueTypes.jl @@ -71,6 +71,8 @@ has 6 and a `SymTracelessTensorValue{3}` has 5. But they all have 9 (non indepen num_indep_components(::Type{T}) where T<:Number = num_components(T) num_indep_components(::T) where T<:Number = num_indep_components(T) +get_indep_components(a::MultiValue) = Tuple(a) + """ !!! warning Deprecated in favor on [`num_components`](@ref). diff --git a/src/TensorValues/Operations.jl b/src/TensorValues/Operations.jl index 65ad3f53f..768857fce 100644 --- a/src/TensorValues/Operations.jl +++ b/src/TensorValues/Operations.jl @@ -86,14 +86,12 @@ for op in (:+,:-) @eval begin function ($op)(a::T) where T<:MultiValue - Li = num_indep_components(T) - r = map($op, Tuple(a)[1:Li]) + r = map($op, get_indep_components(a)) T(r) end function ($op)(a::V, b::V) where V<:MultiValue - Li = num_indep_components(V) - r = map(($op), Tuple(a)[1:Li], Tuple(b)[1:Li]) + r = map(($op), get_indep_components(a), get_indep_components(b)) V(r) end end @@ -134,16 +132,14 @@ end for op in (:+,:-,:*) @eval begin function ($op)(a::MultiValue, b::_Scalar) - Li = num_indep_components(a) - r = _bc($op, Tuple(a)[1:Li], b) + r = _bc($op, get_indep_components(a), b) T = _eltype($op, r, a, b) M = change_eltype(a, T) M(r) end function ($op)(a::_Scalar, b::MultiValue) - Li = num_indep_components(b) - r = _bc($op, a, Tuple(b)[1:Li]) + r = _bc($op, a, get_indep_components(b)) T = _eltype($op, r, a, b) M = change_eltype(b, T) M(r) @@ -159,8 +155,7 @@ _err = "This operation is undefined for traceless tensors" (-)(::_Scalar, ::_AbstractTracelessTensor) = error(_err) function (/)(a::MultiValue, b::_Scalar) - Li = num_indep_components(a) - r = _bc(/, Tuple(a)[1:Li], b) + r = _bc(/, get_indep_components(a), b) T = _eltype(/, r, a, b) P = change_eltype(a, T) P(r) diff --git a/src/TensorValues/SymTracelessTensorValueTypes.jl b/src/TensorValues/SymTracelessTensorValueTypes.jl index 8ddb80ffd..eba6c9787 100644 --- a/src/TensorValues/SymTracelessTensorValueTypes.jl +++ b/src/TensorValues/SymTracelessTensorValueTypes.jl @@ -141,3 +141,5 @@ change_eltype(::Type{SymTracelessTensorValue{D,T1,L}},::Type{T2}) where {D,T1,T2 num_indep_components(::Type{<:SymTracelessTensorValue{0}}) = 0 num_indep_components(::Type{<:SymTracelessTensorValue{D}}) where {D} = D*(D+1)÷2-1 +get_indep_components(a::SymTracelessTensorValue) = Base.front(Tuple(a)) + diff --git a/test/TensorValuesTests/OperationsTests.jl b/test/TensorValuesTests/OperationsTests.jl index b0b4f4e16..d7c38d9e5 100644 --- a/test/TensorValuesTests/OperationsTests.jl +++ b/test/TensorValuesTests/OperationsTests.jl @@ -1585,4 +1585,51 @@ ref4 = [sum(T3b[i,j,k]*B[i,k] for i in 1:3, k in 1:3) for j in 1:2] @test_throws ArgumentError tensor_contraction(VectorValue(1,2), VectorValue(1,2), (3,), (1,)) @test_throws ArgumentError tensor_contraction(TensorValue{2,2}(1:4...), VectorValue(1,2), (1,1), (1,1)) + +# promote_op + +function test_op_promote(T, op, args...) + @test Base.promote_op(op, map(typeof, args)...) == T +end + +v = VectorValue(1, 2, 3) +t = TensorValue(1, 2, 3, 4, 5, 6, 7, 8, 9) +st = SymTensorValue(1, 2, 3, 5, 6, 9) +qt = SymTracelessTensorValue(1, 2, 3, 5, 6) +sk = SkewSymTensorValue(1, 2, 3) +fo = one(SymFourthOrderTensorValue{2, Int}) + +test_op_promote(typeof(v * 2), *, v, 2) +test_op_promote(typeof(v * 2.0), *, v, 2.0) +test_op_promote(typeof(2 * v), *, 2, v) +test_op_promote(typeof(2.0 * v), *, 2.0, v) +test_op_promote(typeof(t * 2), *, t, 2) +test_op_promote(typeof(t * 2.0), *, t, 2.0) +test_op_promote(typeof(st * 2), *, st, 2) +test_op_promote(typeof(st * 2.0), *, st, 2.0) +test_op_promote(typeof(qt * 2), *, qt, 2) +test_op_promote(typeof(qt * 2.0), *, qt, 2.0) +test_op_promote(typeof(sk * 2), *, sk, 2) +test_op_promote(typeof(sk * 2.0), *, sk, 2.0) +test_op_promote(typeof(fo * 2), *, fo, 2) +test_op_promote(typeof(fo * 2.0), *, fo, 2.0) + +test_op_promote(typeof(v / 2.0), /, v, 2.0) +test_op_promote(typeof(t / 2.0), /, t, 2.0) +test_op_promote(typeof(st / 2.0), /, st, 2.0) +test_op_promote(typeof(qt / 2.0), /, qt, 2.0) +test_op_promote(typeof(sk / 2.0), /, sk, 2.0) +test_op_promote(typeof(fo / 2.0), /, fo, 2.0) + +test_op_promote(typeof(v ⊗ 2), ⊗, v, 2) +test_op_promote(typeof(v ⊗ 2.0), ⊗, v, 2.0) +test_op_promote(typeof(st ⊗ 2.0), ⊗, st, 2.0) +test_op_promote(typeof(qt ⊗ 2.0), ⊗, qt, 2.0) +test_op_promote(typeof(sk ⊗ 2.0), ⊗, sk, 2.0) + +test_op_promote(typeof(v ⊗ v), ⊗, v, v) +test_op_promote(typeof(v ⊗ st), ⊗, v, st) +test_op_promote(typeof(st ⊗ st), ⊗, st, st) +test_op_promote(typeof(qt ⊗ qt), ⊗, qt, qt) + end # module OperationsTests