@@ -17,7 +17,6 @@ verifies the given `op` relative to `state`. The `state` must pass
1717An "operator" is any object that [`evaluate`](@ref) returns when evaluating a
1818time-dependent dynamic generator. The specific requirements for `op` are:
1919
20- * `eltype(op)` must be defined and return a numeric type
2120* `size(op)` must be defined and return a tuple of integers
2221* `size(op, dim)` must be defined for each dimension and be consistent with
2322 `size(op)`
@@ -26,9 +25,11 @@ time-dependent dynamic generator. The specific requirements for `op` are:
2625* `op * state` must be defined
2726* The [`QuantumPropagators.Interfaces.supports_inplace`](@ref) method must be
2827 defined for `op`. If it returns `true`, it must be possible to evaluate a
29- generator in-place into the existing `op`. See [`check_generator`](@ref).
28+ generator in-place into the existing `op`. See
29+ [`QuantumPropagators.Interfaces.check_generator`](@ref).
3030
31- If [`QuantumPropagators.Interfaces.supports_inplace(state)`](@ref):
31+ If [`QuantumPropagators.Interfaces.supports_inplace(state)`](@ref
32+ QuantumPropagators.Interfaces.supports_inplace):
3233
3334* The 3-argument `LinearAlgebra.mul!` must apply `op` to the given `state`
3435* The 5-argument `LinearAlgebra.mul!` must apply `op` to the given `state`
@@ -40,6 +41,25 @@ If `for_expval` (typically required for optimal control):
4041* `LinearAlgebra.dot(state, op, state)` must return return a number
4142* `dot(state, op, state)` must match `dot(state, op * state)`, if applicable
4243
44+ If [`QuantumPropagators.Interfaces.supports_matrix_interface(op)`](@ref
45+ QuantumPropagators.Interfaces.supports_matrix_interface) is `true`, the
46+ operator must implement the
47+ [Abstract Array interface](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array)
48+ for two-dimensional arrays:
49+
50+ * `eltype(op)` must be defined and return a numeric type
51+ * `getindex(op, i, j)` must be defined and return elements matching `eltype`
52+ * `length(op)` must equal `prod(size(op))`
53+ * `iterate(op)` must be defined
54+ * `similar(op)` must be defined and return a mutable array with the same shape
55+ and element type
56+ * `similar(op, ::Type{S})` must return a mutable array with the same shape and
57+ element type `S`
58+ * `similar(op, dims::Dims)` must return a mutable array with the same element
59+ type and the given dimensions
60+ * `similar(op, ::Type{S}, dims::Dims)` must return a mutable array with the
61+ given element type and dimensions
62+
4363The function returns `true` for a valid operator and `false` for an invalid
4464operator. Unless `quiet=true`, it will log an error to indicate which of the
4565conditions failed.
@@ -74,20 +94,6 @@ function check_operator(
7494 success = false
7595 end
7696
77- try
78- T = eltype (op)
79- if ! (T isa Type && T <: Number )
80- quiet || @error " $(px) `eltype(op)` must return a numeric type, not $T "
81- success = false
82- end
83- catch exc
84- quiet || @error (
85- " $(px) `eltype(op)` must be defined." ,
86- exception = (exc, catch_abbreviated_backtrace ())
87- )
88- success = false
89- end
90-
9197 try
9298 s = size (op)
9399 if ! (s isa Tuple)
@@ -171,7 +177,6 @@ function check_operator(
171177 success = false
172178 end
173179
174-
175180 if supports_inplace (state)
176181
177182 try
@@ -254,6 +259,179 @@ function check_operator(
254259
255260 end
256261
262+ if supports_matrix_interface (op)
263+
264+ try
265+ T = eltype (op)
266+ if ! (T isa Type && T <: Number )
267+ quiet || @error " $(px) `eltype(op)` must return a numeric type, not $T "
268+ success = false
269+ end
270+ catch exc
271+ quiet || @error (
272+ " $(px) `eltype(op)` must be defined." ,
273+ exception = (exc, catch_abbreviated_backtrace ())
274+ )
275+ success = false
276+ end
277+
278+ try
279+ s = size (op)
280+ if length (s) == 2 && all (d -> d > 0 , s)
281+ val = op[1 , 1 ]
282+ T = eltype (op)
283+ if T isa Type && T <: Number && ! (val isa T)
284+ quiet ||
285+ @error " $(px) `op[1, 1]` must return a value of type `eltype(op)=$T `, not $(typeof (val)) "
286+ success = false
287+ end
288+ end
289+ catch exc
290+ quiet || @error (
291+ " $(px) `getindex(op, i, j)` must be defined." ,
292+ exception = (exc, catch_abbreviated_backtrace ())
293+ )
294+ success = false
295+ end
296+
297+ try
298+ l = length (op)
299+ s = size (op)
300+ if l != prod (s)
301+ quiet ||
302+ @error " $(px) `length(op)` must equal `prod(size(op))`: $l ≠ $(prod (s)) "
303+ success = false
304+ end
305+ catch exc
306+ quiet || @error (
307+ " $(px) `length(op)` must be defined." ,
308+ exception = (exc, catch_abbreviated_backtrace ())
309+ )
310+ success = false
311+ end
312+
313+ try
314+ itr = iterate (op)
315+ s = size (op)
316+ if isnothing (itr) && prod (s) > 0
317+ quiet ||
318+ @error " $(px) `iterate(op)` must not return `nothing` for a non-empty operator"
319+ success = false
320+ end
321+ catch exc
322+ quiet || @error (
323+ " $(px) `iterate(op)` must be defined." ,
324+ exception = (exc, catch_abbreviated_backtrace ())
325+ )
326+ success = false
327+ end
328+
329+ try
330+ op2 = similar (op)
331+ if ! supports_inplace (op2)
332+ quiet ||
333+ @error " $(px) `similar(op)` must return a mutable array (`supports_inplace` must be `true`), got $(typeof (op2)) "
334+ success = false
335+ end
336+ if size (op2) != size (op)
337+ quiet ||
338+ @error " $(px) `similar(op)` must return an array with the same shape: size $(size (op2)) ≠ $(size (op)) "
339+ success = false
340+ end
341+ if eltype (op2) != eltype (op)
342+ quiet ||
343+ @error " $(px) `similar(op)` must return an array with the same element type: $(eltype (op2)) ≠ $(eltype (op)) "
344+ success = false
345+ end
346+ catch exc
347+ quiet || @error (
348+ " $(px) `similar(op)` must be defined." ,
349+ exception = (exc, catch_abbreviated_backtrace ())
350+ )
351+ success = false
352+ end
353+
354+ try
355+ S = (eltype (op) == ComplexF64) ? ComplexF32 : ComplexF64
356+ op2 = similar (op, S)
357+ if ! supports_inplace (op2)
358+ quiet ||
359+ @error " $(px) `similar(op, $S )` must return a mutable array (`supports_inplace` must be `true`), got $(typeof (op2)) "
360+ success = false
361+ end
362+ if size (op2) != size (op)
363+ quiet ||
364+ @error " $(px) `similar(op, $S )` must return an array with the same shape: size $(size (op2)) ≠ $(size (op)) "
365+ success = false
366+ end
367+ if eltype (op2) != S
368+ quiet ||
369+ @error " $(px) `similar(op, $S )` must return an array with element type $S , got $(eltype (op2)) "
370+ success = false
371+ end
372+ catch exc
373+ quiet || @error (
374+ " $(px) `similar(op, ::Type{S})` must be defined." ,
375+ exception = (exc, catch_abbreviated_backtrace ())
376+ )
377+ success = false
378+ end
379+
380+ try
381+ dims = size (op)
382+ op2 = similar (op, dims)
383+ if ! supports_inplace (op2)
384+ quiet ||
385+ @error " $(px) `similar(op, dims)` must return a mutable array (`supports_inplace` must be `true`), got $(typeof (op2)) "
386+ success = false
387+ end
388+ if size (op2) != dims
389+ quiet ||
390+ @error " $(px) `similar(op, dims)` must return an array with size $dims , got $(size (op2)) "
391+ success = false
392+ end
393+ if eltype (op2) != eltype (op)
394+ quiet ||
395+ @error " $(px) `similar(op, dims)` must return an array with the same element type: $(eltype (op2)) ≠ $(eltype (op)) "
396+ success = false
397+ end
398+ catch exc
399+ quiet || @error (
400+ " $(px) `similar(op, dims::Dims)` must be defined." ,
401+ exception = (exc, catch_abbreviated_backtrace ())
402+ )
403+ success = false
404+ end
405+
406+ try
407+ S = (eltype (op) == ComplexF64) ? ComplexF32 : ComplexF64
408+ dims = size (op)
409+ op2 = similar (op, S, dims)
410+ if ! supports_inplace (op2)
411+ quiet ||
412+ @error " $(px) `similar(op, $S , dims)` must return a mutable array (`supports_inplace` must be `true`), got $(typeof (op2)) "
413+ success = false
414+ end
415+ if size (op2) != dims
416+ quiet ||
417+ @error " $(px) `similar(op, $S , dims)` must return an array with size $dims , got $(size (op2)) "
418+ success = false
419+ end
420+ if eltype (op2) != S
421+ quiet ||
422+ @error " $(px) `similar(op, $S , dims)` must return an array with element type $S , got $(eltype (op2)) "
423+ success = false
424+ end
425+ catch exc
426+ quiet || @error (
427+ " $(px) `similar(op, ::Type{S}, dims::Dims)` must be defined." ,
428+ exception = (exc, catch_abbreviated_backtrace ())
429+ )
430+ success = false
431+ end
432+
433+ end
434+
257435 return success
258436
259437end
0 commit comments