• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

RimuQMC / Rimu.jl / 15290741585

28 May 2025 03:23AM UTC coverage: 94.569% (-0.2%) from 94.762%
15290741585

push

github

web-flow
Operator Column (#317)

Adds an `operator_column` used for spawning instead of `offdiagonals`.
This allows for sampling a Hamiltonian without needing to index the
off-diagonal elements, or know how many there are.

---------

Co-authored-by: mtsch <matijacufar@gmail.com>
Co-authored-by: Joachim Brand <joachim.brand@gmail.com>

129 of 152 new or added lines in 14 files covered. (84.87%)

3 existing lines in 1 file now uncovered.

7000 of 7402 relevant lines covered (94.57%)

11671554.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.13
/src/InterfaceTests.jl
1
"""
2
The module `Rimu.InterfaceTests` provides functions to test compliance with the
3
[`AbstractObservable`](@ref), [`AbstractOperator`](@ref), and [`AbstractHamiltonian`](@ref)
4
interfaces. Load the module with `using Rimu.InterfaceTests`.
5

6
The module exports the following functions:
7
- [`test_observable_interface`](@ref Rimu.InterfaceTests.test_observable_interface)
8
- [`test_operator_interface`](@ref Rimu.InterfaceTests.test_operator_interface)
9
- [`test_hamiltonian_interface`](@ref Rimu.InterfaceTests.test_hamiltonian_interface)
10
- [`test_hamiltonian_structure`](@ref Rimu.InterfaceTests.test_hamiltonian_structure)
11
"""
12
module InterfaceTests
13

14
using Test: Test, @test, @testset, @test_throws
15
using Rimu: Rimu, DVec, Interfaces, LOStructure, IsHermitian, IsDiagonal, AdjointKnown,
16
    Hamiltonians, num_offdiagonals, allows_address_type, offdiagonals, random_offdiagonal,
17
    diagonal_element, dimension, dot_from_right, IsDeterministic, starting_address, PDVec,
18
    sparse, scale!, scalartype, operator_column, AbstractOperatorColumn
19
using Rimu.Hamiltonians: AbstractHamiltonian, AbstractOperator, AbstractObservable,
20
    AbstractOffdiagonals
21
using LinearAlgebra: dot, mul!, isdiag, ishermitian
22

23
export test_observable_interface, test_operator_interface, test_hamiltonian_interface,
24
    test_hamiltonian_structure
25

26
"""
27
    test_observable_interface(obs, addr)
28

29
This function tests compliance with the [`AbstractObservable`](@ref) interface for an
30
observable `obs` at address `addr` (typically
31
[`<: AbstractFockAddress`](@ref Rimu.BitStringAddresses.AbstractFockAddress)) by checking
32
that all required methods are defined.
33

34
The following properties are tested:
35
- `dot(v, obs, v)` returns a value of the same type as the `eltype` of the observable
36
- `LOStructure` is set consistently
37

38
### Example
39
```julia-doctest
40
julia> using Rimu.InterfaceTests
41

42
julia> test_observable_interface(ReducedDensityMatrix(2), FermiFS(1,0,1,1));
43
Test Summary:                              | Pass  Total  Time
44
Observable interface: ReducedDensityMatrix |    4      4  0.0s
45
```
46

47
See also [`AbstractObservable`](@ref), [`test_operator_interface`](@ref),
48
[`test_hamiltonian_interface`](@ref).
49
"""
50
function test_observable_interface(obs, addr)
54✔
51
    @testset "`AbstractObservable` interface test: $(nameof(typeof(obs)))" begin
54✔
52
        @testset "three way dot" begin # this works with vector valued operators
54✔
53
            v = DVec(addr => scalartype(obs)(2))
162✔
54
            @test dot(v, obs, v) isa eltype(obs)
54✔
55
            @test dot(v, obs, v) ≈ Interfaces.dot_from_right(v, obs, v)
54✔
56
        end
57
        @testset "LOStructure" begin
×
58
            @test LOStructure(obs) isa LOStructure
108✔
59
            if LOStructure(obs) isa IsHermitian
54✔
60
                @test obs' === obs
28✔
61
            elseif LOStructure(obs) isa IsDiagonal
26✔
62
                @test num_offdiagonals(obs, addr) == 0
9✔
63
                if scalartype(obs) <: Real
9✔
64
                    @test obs' === obs
8✔
65
                end
66
            elseif LOStructure(obs) isa AdjointKnown
17✔
67
                @test begin
6✔
68
                    obs'
6✔
69
                    true
×
70
                end # make sure no error is thrown
71
            else
72
                @test_throws ArgumentError obs'
33✔
73
            end
74
        end
75
    end
76
end
77

78
"""
79
    test_operator_interface(op, addr; test_iterable_offdiagonals=true, test_random_offdiagonal=true)
80

81
This function tests compliance with the [`AbstractOperator`](@ref) interface for an operator
82
`op` at address `addr` (typically
83
[`<: AbstractFockAddress`](@ref Rimu.BitStringAddresses.AbstractFockAddress)) by
84
checking that all required methods are defined.
85

86
The following properties are tested:
87
- `operator_column(op, addr)` returns a `column` object that is subtype to [`AbstractOperatorColumn`](@ref)
88

89
If `test_random_offdiagonal` is `true`, tests are performed that require `random_offdiagonal(column)`
90
to be defined. If `test_iterable_offdiagonals` is `true`, tests are performed that require
91
`offdiagonals(column)` to be iterable.
92

93
- `diagonal_element(column)` returns a value of the same type as the `eltype` of the operator
94
- `offdiagonals` iterates `address => value` pairs of consistent type (only if `test_iterable_offdiagonals==true`)
95
- `num_offdiagonals` returns the correct number of offdiagonals
96
- `random_offdiagonal` returns a tuple with the correct types (only if `test_random_offdiagonal==true`)
97
- `mul!` and `dot` work as expected
98
- `dimension` returns a consistent value
99
- the [`AbstractObservable`](@ref) interface is tested
100

101
### Example
102
```julia-doctest
103
julia> using Rimu.InterfaceTests
104

105
julia> test_operator_interface(SuperfluidCorrelator(3), BoseFS(1, 2, 3, 1));
106
Test Summary:                              | Pass  Total  Time
107
Observable interface: SuperfluidCorrelator |    4      4  0.0s
108
Test Summary:       | Pass  Total  Time
109
allows_address_type |    1      1  0.0s
110
Test Summary:                            | Pass  Total  Time
111
Operator interface: SuperfluidCorrelator |    9      9  0.0s
112
```
113

114
See also [`AbstractOperator`](@ref), [`test_observable_interface`](@ref),
115
[`test_hamiltonian_interface`](@ref).
116
"""
117
function test_operator_interface(op, addr; test_iterable_offdiagonals=true, test_random_offdiagonal=true)
104✔
118
    test_observable_interface(op, addr)
52✔
119
    @testset "`AbstractOperator` interface test: $(nameof(typeof(op)))" begin
×
120

121
        @testset "allows_address_type" begin
52✔
122
            @test allows_address_type(op, addr)
160✔
123
        end
124
        column = operator_column(op, addr)
76✔
125
        @test column isa AbstractOperatorColumn
52✔
UNCOV
126
        @testset "Operator interface: $(nameof(typeof(op)))" begin
×
127
            @testset "starting_address(column)" begin
52✔
128
                @test starting_address(column) == addr
104✔
129
            end
UNCOV
130
            @testset "diagonal_element" begin
×
131
                @test diagonal_element(column) isa eltype(op)
104✔
132
                @test eltype(diagonal_element(column)) == scalartype(op)
52✔
133
                if hasmethod(diagonal_element, (typeof(op), typeof(addr)))
104✔
134
                    @test diagonal_element(column) == diagonal_element(op, addr)
52✔
135
                end
136
            end
137
            if test_iterable_offdiagonals
52✔
NEW
138
                @testset "offdiagonals" begin
×
139
                    offdiags = offdiagonals(column)
104✔
140
                    if hasmethod(num_offdiagonals, (typeof(op), typeof(addr)))
104✔
141
                        @test num_offdiagonals(column) == num_offdiagonals(op, addr)
52✔
142
                    end
143
                    if num_offdiagonals(column) > 0
105✔
144
                        @test iterate(offdiags)[1] isa Union{Tuple{typeof(addr),eltype(op)},Pair{typeof(addr),eltype(op)}}
41✔
145
                    end
146
                    @test eltype(offdiags) <: Union{Tuple{typeof(addr),eltype(op)},Pair{typeof(addr),eltype(op)}}
52✔
147
                end
148
            end
149
            if test_random_offdiagonal
52✔
NEW
150
                @testset "random_offdiagonal" begin
×
151
                    if num_offdiagonals(column) > 0
155✔
152
                        @test random_offdiagonal(column) isa Tuple{typeof(addr),<:Real,eltype(op)}
40✔
153
                    end
154
                end
155
            end
156
            @testset "mul!" begin # this works with vector valued operators
×
157
                v = DVec(addr => scalartype(op)(2))
156✔
158
                w = empty(v, eltype(op); style=IsDeterministic{scalartype(op)}())
52✔
159
                mul!(w, op, v) # operator vector product
52✔
160
                @test dot(v, op, v) ≈ Interfaces.dot_from_right(v, op, v) ≈ dot(v, w)
52✔
161
            end
162
            @testset "dimension" begin
×
163
                @test dimension(addr) ≥ dimension(op, addr)
104✔
164
            end
165
        end
166
    end
167
end
168

169
"""
170
    test_hamiltonian_interface(h, addr=starting_address(h); test_iterable_offdiagonals=true, test_random_offdiagonal=true)
171

172
The main purpose of this test function is to check that all required methods of the
173
[`AbstractHamiltonian`](@ref) interface are defined and work as expected.
174

175
Set `test_iterable_offdiagonals=false` to skip tests that require [`offdiagonals(column)`](@ref)
176
to be iterable. Set `test_random_offdiagonal=false` to skip tests that require
177
[`random_offdiagonal(column)`](@ref) to be defined.
178

179
This function also tests the following properties of the Hamiltonian:
180
- `dimension(h) ≥ dimension(h, addr)`
181
- `scalartype(h) === eltype(h)`
182
- Hamiltonian action on a vector <: `AbstractDVec`
183
- `starting_address` returns an [`allows_address_type`](@ref) address
184
- `LOStructure` is one of `IsDiagonal`, `IsHermitian`, `AdjointKnown`
185
- the [`AbstractOperator`](@ref) interface is tested
186
- the [`AbstractObservable`](@ref) interface is tested
187

188
### Example
189
```julia-doctest
190
julia> using Rimu.InterfaceTests
191

192
julia> test_hamiltonian_interface(HubbardRealSpace(BoseFS(2,0,3,1)));
193
Test Summary:                          | Pass  Total  Time
194
Observable interface: HubbardRealSpace |    4      4  0.0s
195
Test Summary:       | Pass  Total  Time
196
allows_address_type |    1      1  0.0s
197
Test Summary:                        | Pass  Total  Time
198
Operator interface: HubbardRealSpace |    9      9  0.0s
199
Test Summary:       | Pass  Total  Time
200
allows_address_type |    1      1  0.0s
201
Test Summary:                                 | Pass  Total  Time
202
Hamiltonians-only tests with HubbardRealSpace |    6      6  0.0s
203
```
204

205
See also [`test_operator_interface`](@ref), [`test_observable_interface`](@ref).
206
"""
207
function test_hamiltonian_interface(h, addr=starting_address(h); test_iterable_offdiagonals=true, test_random_offdiagonal=true)
120✔
208
    test_operator_interface(h, addr; test_iterable_offdiagonals, test_random_offdiagonal)
40✔
UNCOV
209
    @testset "`AbstractHamiltonian` interface test: $(nameof(typeof(h)))" begin
×
210

211
        @testset "allows_address_type on starting_address" begin
40✔
212
            @test allows_address_type(h, starting_address(h))
124✔
213
        end
214
        @testset "Hamiltonians-only tests with $(nameof(typeof(h)))" begin
×
215
            # starting_address is specific to Hamiltonians
216
            @test allows_address_type(h, starting_address(h))
124✔
217

218
            @test dimension(h) ≥ dimension(h, addr)
40✔
219

220
            # Hamiltonians can only have scalar eltype
221
            @test scalartype(h) === eltype(h)
40✔
222

223
            # Hamiltonian action on a vector
224
            v = DVec(addr => scalartype(h)(2))
80✔
225
            v1 = similar(v)
80✔
226
            mul!(v1, h, v)
40✔
227
            v2 = h * v
40✔
228
            v3 = similar(v)
80✔
229
            h(v3, v)
40✔
230
            v4 = h(v)
40✔
231
            @test v1 == v2 == v3 == v4
40✔
232
            column = operator_column(h, addr)
57✔
233
            v5 = DVec(addr => diagonal_element(column))
80✔
234
            for (addr, val) in offdiagonals(column)
74✔
235
                v5[addr] += val
1,003✔
236
            end
1,003✔
237
            scale!(v5, scalartype(h)(2))
40✔
238
            v5[addr] = v5[addr] # remove possible 0.0 from the diagonal
75✔
239
            @test v5 == v1
40✔
240

241
            if test_iterable_offdiagonals && test_random_offdiagonal
40✔
242
                # applying an operator on a PDVec uses spawn!, which requires
243
                # random_offdiagonal(column) to be defined, and offdiagonals(column) to be
244
                # iterable.
245
                pv = PDVec(addr => scalartype(h)(2))
39✔
246
                pv1 = h(pv)
39✔
247
                @test dot(pv1, h, pv) ≈ Interfaces.dot_from_right(pv1, h, pv) ≈ dot(v1, v1)
39✔
248
            end
249
        end
250
    end
251
end
252

253
"""
254
    test_hamiltonian_structure(h::AbstractHamiltonian; sizelim=20)
255

256
Test the `LOStructure` of a small Hamiltonian `h` by instantiating it as a sparse matrix and
257
checking whether the structure of the matrix is constistent with the result of
258
`LOStructure(h)` and the `eltype` is consistent with `eltype(h)`.
259

260
This function is intended to be used in automated test for small Hamiltonians where
261
instantiating the matrix is quick. A warning will print if the dimension of the Hamiltonian
262
is larger than `20`.
263

264
### Example
265
```julia-doctest
266
julia> using Rimu.InterfaceTests
267

268
julia> test_hamiltonian_structure(HubbardRealSpace(BoseFS(2,0,1)));
269
Test Summary: | Pass  Total  Time
270
structure     |    4      4  0.0s
271
```
272
"""
273
function test_hamiltonian_structure(h::AbstractHamiltonian; sizelim=20)
24✔
274
    @testset "Hamiltonian structure: $(nameof(typeof(h)))" begin
12✔
275
        d = dimension(h)
24✔
276
        d > 20 && @warn "This function is intended for small Hamiltonians. The dimension is $d."
12✔
277
        m = sparse(h; sizelim)
12✔
278
        @test eltype(m) === eltype(h)
12✔
279
        if LOStructure(h) == IsDiagonal()
12✔
280
            @test isdiag(m)
2✔
281
        elseif LOStructure(h) == IsHermitian()
11✔
282
            @test h' == h
6✔
283
            @test h' === h
6✔
284
            @test ishermitian(m)
12✔
285
        elseif LOStructure(h) == AdjointKnown()
5✔
286
            @test m' == sparse(h')
5✔
287
        end
288
        if !ishermitian(m)
12✔
289
            @test LOStructure(h) != IsHermitian()
5✔
290
            if LOStructure(h) == IsDiagonal()
5✔
291
                @test !isreal(m)
×
292
                @test !(eltype(h) <: Real)
×
293
            end
294
        end
295
    end
296
end
297
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc