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

RimuQMC / Rimu.jl / 14700598494

28 Apr 2025 04:59AM UTC coverage: 94.692% (-0.09%) from 94.777%
14700598494

push

github

web-flow
Complex Hamiltonians and Walkers (#313)

Adds the ability to do FCIQMC with complex-valued Hamiltonians, and
complex walkers.

---------

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

40 of 43 new or added lines in 9 files covered. (93.02%)

6 existing lines in 5 files now uncovered.

6940 of 7329 relevant lines covered (94.69%)

11470700.48 hits per line

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

87.37
/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
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)
53✔
51
    @testset "`AbstractObservable` interface test: $(nameof(typeof(obs)))" begin
53✔
52
        @testset "three way dot" begin # this works with vector valued operators
53✔
53
            v = DVec(addr => scalartype(obs)(2))
159✔
54
            @test dot(v, obs, v) isa eltype(obs)
53✔
55
            @test dot(v, obs, v) ≈ Interfaces.dot_from_right(v, obs, v)
53✔
56
        end
57
        @testset "LOStructure" begin
×
58
            @test LOStructure(obs) isa LOStructure
106✔
59
            if LOStructure(obs) isa IsHermitian
53✔
60
                @test obs' === obs
27✔
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_spawning=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
If `test_spawning` is `true`, tests are performed that require `offdiagonals` to return an
87
`Hamiltonians.AbstractOffDiagonals`, which is a prerequisite for using the `spawn!`
88
function. Otherwise, the spawning tests are skipped.
89

90
The following properties are tested:
91
- `diagonal_element` returns a value of the same type as the `eltype` of the operator
92
- `offdiagonals` behaves like an `AbstractVector`
93
- `num_offdiagonals` returns the correct number of offdiagonals
94
- `random_offdiagonal` returns a tuple with the correct types
95
- `mul!` and `dot` work as expected
96
- `dimension` returns a consistent value
97
- the [`AbstractObservable`](@ref) interface is tested
98

99
### Example
100
```julia-doctest
101
julia> using Rimu.InterfaceTests
102

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

112
See also [`AbstractOperator`](@ref), [`test_observable_interface`](@ref),
113
[`test_hamiltonian_interface`](@ref).
114
"""
115
function test_operator_interface(op, addr; test_spawning=true)
102✔
116
    test_observable_interface(op, addr)
51✔
117
    @testset "`AbstractOperator` interface test: $(nameof(typeof(op)))" begin
×
118

119
        @testset "allows_address_type" begin
51✔
120
            @test allows_address_type(op, addr)
157✔
121
        end
122
        @testset "Operator interface: $(nameof(typeof(op)))" begin
×
123
            @testset "diagonal_element" begin
51✔
124
                @test diagonal_element(op, addr) isa eltype(op)
102✔
125
                @test eltype(diagonal_element(op, addr)) == scalartype(op)
51✔
126
            end
127
            @testset "offdiagonals" begin
×
128
                # `get_offdiagonal` is not mandatory and thus not tested
129
                ods = offdiagonals(op, addr)
144✔
130
                vec_ods = collect(ods)
68✔
131
                eltype(vec_ods) == Tuple{typeof(addr),eltype(op)} == eltype(ods)
51✔
132
                @test length(vec_ods) ≤ num_offdiagonals(op, addr)
51✔
133
            end
134
            if test_spawning
51✔
135
                @testset "spawning" begin
×
136
                    ods = offdiagonals(op, addr)
142✔
137
                    @test ods isa AbstractOffdiagonals{typeof(addr),eltype(op)}
50✔
138
                    @test ods isa AbstractVector
50✔
139
                    @test size(ods) == (num_offdiagonals(op, addr),)
50✔
140
                    if length(ods) > 0
50✔
141
                        @test random_offdiagonal(op, addr) isa Tuple{typeof(addr),<:Real,eltype(op)}
39✔
142
                    end
143
                end
144
            end
145
            @testset "mul!" begin # this works with vector valued operators
×
146
                v = DVec(addr => scalartype(op)(2))
153✔
147
                w = empty(v, eltype(op); style=IsDeterministic{scalartype(op)}())
51✔
148
                mul!(w, op, v) # operator vector product
51✔
149
                @test dot(v, op, v) ≈ Interfaces.dot_from_right(v, op, v) ≈ dot(v, w)
51✔
150
            end
151
            @testset "dimension" begin
×
152
                @test dimension(addr) ≥ dimension(op, addr)
102✔
153
            end
154
        end
155
    end
156
end
157

158
"""
159
    test_hamiltonian_interface(h, addr=starting_address(h); test_spawning=true)
160

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

164
Set `test_spawning=false` to skip tests that require [`offdiagonals`](@ref) to return an
165
`AbstractVector`.
166

167
This function also tests the following properties of the Hamiltonian:
168
- `dimension(h) ≥ dimension(h, addr)`
169
- `scalartype(h) === eltype(h)`
170
- Hamiltonian action on a vector <: `AbstractDVec`
171
- `starting_address` returns an [`allows_address_type`](@ref) address
172
- `LOStructure` is one of `IsDiagonal`, `IsHermitian`, `AdjointKnown`
173
- the [`AbstractOperator`](@ref) interface is tested
174
- the [`AbstractObservable`](@ref) interface is tested
175

176
### Example
177
```julia-doctest
178
julia> using Rimu.InterfaceTests
179

180
julia> test_hamiltonian_interface(HubbardRealSpace(BoseFS(2,0,3,1)));
181
Test Summary:                          | Pass  Total  Time
182
Observable interface: HubbardRealSpace |    4      4  0.0s
183
Test Summary:       | Pass  Total  Time
184
allows_address_type |    1      1  0.0s
185
Test Summary:                        | Pass  Total  Time
186
Operator interface: HubbardRealSpace |    9      9  0.0s
187
Test Summary:       | Pass  Total  Time
188
allows_address_type |    1      1  0.0s
189
Test Summary:                                 | Pass  Total  Time
190
Hamiltonians-only tests with HubbardRealSpace |    6      6  0.0s
191
```
192

193
See also [`test_operator_interface`](@ref), [`test_observable_interface`](@ref).
194
"""
195
function test_hamiltonian_interface(h, addr=starting_address(h); test_spawning=true)
117✔
196
    test_operator_interface(h, addr; test_spawning)
39✔
197
    @testset "`AbstractHamiltonian` interface test: $(nameof(typeof(h)))" begin
×
198

199
        @testset "allows_address_type on starting_address" begin
39✔
200
            @test allows_address_type(h, starting_address(h))
121✔
201
        end
202
        @testset "Hamiltonians-only tests with $(nameof(typeof(h)))" begin
×
203
            # starting_address is specific to Hamiltonians
204
            @test allows_address_type(h, starting_address(h))
121✔
205

206
            @test dimension(h) ≥ dimension(h, addr)
39✔
207

208
            # Hamiltonians can only have scalar eltype
209
            @test scalartype(h) === eltype(h)
39✔
210

211
            # Hamiltonian action on a vector
212
            v = DVec(addr => scalartype(h)(2))
78✔
213
            v1 = similar(v)
78✔
214
            mul!(v1, h, v)
39✔
215
            v2 = h * v
39✔
216
            v3 = similar(v)
78✔
217
            h(v3, v)
39✔
218
            v4 = h(v)
39✔
219
            @test v1 == v2 == v3 == v4
39✔
220
            v5 = DVec(addr => diagonal_element(h, addr))
77✔
221
            for (addr, val) in offdiagonals(h, addr)
72✔
222
                v5[addr] += val
991✔
223
            end
992✔
224
            scale!(v5, scalartype(h)(2))
39✔
225
            v5[addr] = v5[addr] # remove possible 0.0 from the diagonal
72✔
226
            @test v5 == v1
39✔
227

228
            if test_spawning && scalartype(h) <: Real
39✔
229
                # applying an operator on a PDVec uses spawn!, which requires
230
                # offdiagonals to be an AbstractVector
231
                # currently this only works for real operators as spawn! is not
232
                # implemented for complex operators
233
                pv = PDVec(addr => scalartype(h)(2))
28✔
234
                pv1 = h(pv)
28✔
235
                @test dot(pv1, h, pv) ≈ Interfaces.dot_from_right(pv1, h, pv) ≈ dot(v1, v1)
28✔
236
            end
237
        end
238
    end
239
end
240

241
"""
242
    test_hamiltonian_structure(h::AbstractHamiltonian; sizelim=20)
243

244
Test the `LOStructure` of a small Hamiltonian `h` by instantiating it as a sparse matrix and
245
checking whether the structure of the matrix is constistent with the result of
246
`LOStructure(h)` and the `eltype` is consistent with `eltype(h)`.
247

248
This function is intended to be used in automated test for small Hamiltonians where
249
instantiating the matrix is quick. A warning will print if the dimension of the Hamiltonian
250
is larger than `20`.
251

252
### Example
253
```julia-doctest
254
julia> using Rimu.InterfaceTests
255

256
julia> test_hamiltonian_structure(HubbardRealSpace(BoseFS(2,0,1)));
257
Test Summary: | Pass  Total  Time
258
structure     |    4      4  0.0s
259
```
260
"""
261
function test_hamiltonian_structure(h::AbstractHamiltonian; sizelim=20)
22✔
262
    @testset "Hamiltonian structure: $(nameof(typeof(h)))" begin
11✔
263
        d = dimension(h)
22✔
264
        d > 20 && @warn "This function is intended for small Hamiltonians. The dimension is $d."
11✔
265
        m = sparse(h; sizelim)
11✔
266
        @test eltype(m) === eltype(h)
11✔
267
        if LOStructure(h) == IsDiagonal()
11✔
268
            @test isdiag(m)
2✔
269
        elseif LOStructure(h) == IsHermitian()
10✔
270
            @test h' == h
5✔
271
            @test h' === h
5✔
272
            @test ishermitian(m)
10✔
273
        elseif LOStructure(h) == AdjointKnown()
5✔
274
            @test m' == sparse(h')
5✔
275
        end
276
        if !ishermitian(m)
11✔
277
            @test LOStructure(h) != IsHermitian()
5✔
278
            if LOStructure(h) == IsDiagonal()
5✔
UNCOV
279
                @test !isreal(m)
×
UNCOV
280
                @test !(eltype(h) <: Real)
×
281
            end
282
        end
283
    end
284
end
285
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