Skip to content

Commit a73e5ae

Browse files
mtfishmanclaude
andauthored
[NDTensors] Add with_auto_fermion scope wrapper (#1726)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 831dbbf commit a73e5ae

3 files changed

Lines changed: 109 additions & 1 deletion

File tree

NDTensors/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "NDTensors"
22
uuid = "23ae76d9-e61a-49c4-8f12-3f1a16adf9cf"
3-
version = "0.4.24"
3+
version = "0.4.25"
44
authors = ["Matthew Fishman <mfishman@flatironinstitute.org>"]
55

66
[workspace]

NDTensors/src/NDTensors.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,41 @@ function disable_auto_fermion()
221221
return nothing
222222
end
223223

224+
"""
225+
NDTensors.with_auto_fermion(f, enable::Bool = true)
226+
227+
Run `f` with the auto-fermion system enabled or disabled (enabled by default),
228+
restoring the previous state of the auto-fermion system after `f` finishes.
229+
230+
This is the preferred way to temporarily enable or disable the auto-fermion
231+
system for a code block, because the previous state is restored even if `f`
232+
throws an exception (unlike a manual call to [`enable_auto_fermion`](@ref) or
233+
[`disable_auto_fermion`](@ref)).
234+
235+
# Examples
236+
237+
```julia
238+
using NDTensors: NDTensors
239+
240+
NDTensors.with_auto_fermion() do
241+
# code that requires the auto-fermion system to be enabled
242+
end
243+
244+
NDTensors.with_auto_fermion(false) do
245+
# code that requires the auto-fermion system to be disabled
246+
end
247+
```
248+
"""
249+
function with_auto_fermion(f, enable::Bool = true)
250+
previous = using_auto_fermion()
251+
enable ? enable_auto_fermion() : disable_auto_fermion()
252+
return try
253+
f()
254+
finally
255+
previous ? enable_auto_fermion() : disable_auto_fermion()
256+
end
257+
end
258+
224259
#####################################
225260
# Optional backends
226261
#
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
@eval module $(gensym())
2+
using NDTensors: NDTensors
3+
using Test: @test, @test_throws, @testset
4+
5+
@testset "NDTensors.with_auto_fermion" begin
6+
@testset "starting state $start" for start in (false, true)
7+
start ? NDTensors.enable_auto_fermion() : NDTensors.disable_auto_fermion()
8+
@test NDTensors.using_auto_fermion() == start
9+
10+
@testset "default enables auto-fermion" begin
11+
inside = Ref(false)
12+
NDTensors.with_auto_fermion() do
13+
return inside[] = NDTensors.using_auto_fermion()
14+
end
15+
@test inside[] == true
16+
@test NDTensors.using_auto_fermion() == start
17+
end
18+
19+
@testset "explicit enable=false disables auto-fermion" begin
20+
inside = Ref(true)
21+
NDTensors.with_auto_fermion(false) do
22+
return inside[] = NDTensors.using_auto_fermion()
23+
end
24+
@test inside[] == false
25+
@test NDTensors.using_auto_fermion() == start
26+
end
27+
28+
@testset "return value is propagated" begin
29+
@test NDTensors.with_auto_fermion(() -> 42) == 42
30+
@test NDTensors.with_auto_fermion(() -> 42, false) == 42
31+
@test NDTensors.using_auto_fermion() == start
32+
end
33+
34+
@testset "restores previous state after exception" begin
35+
@test_throws ErrorException NDTensors.with_auto_fermion() do
36+
return error("boom")
37+
end
38+
@test NDTensors.using_auto_fermion() == start
39+
@test_throws ErrorException NDTensors.with_auto_fermion(false) do
40+
return error("boom")
41+
end
42+
@test NDTensors.using_auto_fermion() == start
43+
end
44+
45+
@testset "nested scopes" begin
46+
inner_state = Ref{Bool}(start)
47+
NDTensors.with_auto_fermion(true) do
48+
@test NDTensors.using_auto_fermion() == true
49+
NDTensors.with_auto_fermion(false) do
50+
return inner_state[] = NDTensors.using_auto_fermion()
51+
end
52+
@test NDTensors.using_auto_fermion() == true
53+
end
54+
@test inner_state[] == false
55+
@test NDTensors.using_auto_fermion() == start
56+
end
57+
58+
@testset "nested scope restores after inner exception" begin
59+
NDTensors.with_auto_fermion(true) do
60+
@test NDTensors.using_auto_fermion() == true
61+
@test_throws ErrorException NDTensors.with_auto_fermion(false) do
62+
return error("boom")
63+
end
64+
@test NDTensors.using_auto_fermion() == true
65+
end
66+
@test NDTensors.using_auto_fermion() == start
67+
end
68+
end
69+
70+
# Leave the auto-fermion state as we found it for the rest of the suite.
71+
NDTensors.disable_auto_fermion()
72+
end
73+
end

0 commit comments

Comments
 (0)