|
1 | 1 | using Test |
2 | 2 | using LinearAlgebra |
3 | 3 | using QuantumControlTestUtils.RandomObjects: random_matrix, random_state_vector |
4 | | -using QuantumPropagators.Interfaces: check_operator |
| 4 | +using QuantumPropagators.Interfaces: check_operator, supports_matrix_interface |
| 5 | +import QuantumPropagators.Interfaces: supports_inplace |
| 6 | +import QuantumPropagators.Controls: get_controls, evaluate |
5 | 7 | using StaticArrays: SMatrix, SVector |
6 | 8 |
|
7 | 9 | using QuantumPropagators: Generator, Operator, ScaledOperator |
8 | 10 |
|
| 11 | +# A minimal operator type that does not subtype AbstractMatrix, to test that |
| 12 | +# supports_matrix_interface propagates correctly through Operator/ScaledOperator. |
| 13 | +struct MatrixFreeOp |
| 14 | + mat::Matrix{ComplexF64} |
| 15 | +end |
| 16 | + |
| 17 | +Base.size(op::MatrixFreeOp) = size(op.mat) |
| 18 | +Base.size(op::MatrixFreeOp, dim::Integer) = size(op.mat, dim) |
| 19 | +Base.:*(α::Number, op::MatrixFreeOp) = MatrixFreeOp(α * op.mat) |
| 20 | +Base.:*(op::MatrixFreeOp, Ψ::AbstractVector) = op.mat * Ψ |
| 21 | +LinearAlgebra.mul!(ϕ, op::MatrixFreeOp, Ψ, α::Number, β::Number) = mul!(ϕ, op.mat, Ψ, α, β) |
| 22 | +LinearAlgebra.dot(ϕ, op::MatrixFreeOp, Ψ) = dot(ϕ, op.mat, Ψ) |
| 23 | +supports_inplace(::Type{MatrixFreeOp}) = true |
| 24 | +get_controls(::MatrixFreeOp) = () |
| 25 | +evaluate(op::MatrixFreeOp, args...; kwargs...) = op |
| 26 | + |
9 | 27 |
|
10 | 28 | @testset "Operator mul!" begin |
11 | 29 |
|
|
71 | 89 | H₂ = random_matrix(5; hermitian = true) |
72 | 90 | Op = Operator([H₀, H₁, H₂], [2.1, 1.1]) |
73 | 91 | Ψ = random_state_vector(5) |
| 92 | + @test supports_matrix_interface(typeof(Op)) |
74 | 93 | @test check_operator(Op; state = Ψ) |
75 | 94 | end |
76 | 95 |
|
|
277 | 296 | Op = Operator([H₀, H₁, H₂], [2.1, 1.1]) * 0.5 |
278 | 297 | @test Op isa ScaledOperator |
279 | 298 | Ψ = random_state_vector(5) |
| 299 | + @test supports_matrix_interface(typeof(Op)) |
280 | 300 | @test check_operator(Op; state = Ψ) |
281 | 301 | end |
| 302 | + |
| 303 | + |
| 304 | +@testset "supports_matrix_interface" begin |
| 305 | + |
| 306 | + H₀ = random_matrix(5; hermitian = true) |
| 307 | + H₁ = random_matrix(5; hermitian = true) |
| 308 | + H₂ = random_matrix(5; hermitian = true) |
| 309 | + Ψ = random_state_vector(5) |
| 310 | + |
| 311 | + # Operator wrapping standard Matrix → true |
| 312 | + Op = Operator([H₀, H₁, H₂], [2.1, 1.1]) |
| 313 | + @test supports_matrix_interface(typeof(Op)) |
| 314 | + |
| 315 | + # ScaledOperator wrapping Operator{Matrix} → true |
| 316 | + SOp = Op * 0.5 |
| 317 | + @test SOp isa ScaledOperator |
| 318 | + @test supports_matrix_interface(typeof(SOp)) |
| 319 | + |
| 320 | + # Operator wrapping MatrixFreeOp (not AbstractMatrix) → false, but valid operator |
| 321 | + h₀ = MatrixFreeOp(H₀) |
| 322 | + h₁ = MatrixFreeOp(H₁) |
| 323 | + h₂ = MatrixFreeOp(H₂) |
| 324 | + FreeOp = Operator([h₀, h₁, h₂], [2.1, 1.1]) |
| 325 | + @test !supports_matrix_interface(typeof(FreeOp)) |
| 326 | + @test check_operator(FreeOp; state = Ψ) |
| 327 | + |
| 328 | + # ScaledOperator wrapping Operator{MatrixFreeOp} → false, but valid operator |
| 329 | + SFreeOp = FreeOp * 0.5 |
| 330 | + @test SFreeOp isa ScaledOperator |
| 331 | + @test !supports_matrix_interface(typeof(SFreeOp)) |
| 332 | + @test check_operator(SFreeOp; state = Ψ) |
| 333 | + |
| 334 | +end |
0 commit comments