Skip to content

Commit 5ca807f

Browse files
authored
[ITensors] [ENHANCMENT] Introduce Algorithm type for selecting algorithm backends (#886)
* Use new `Algorithm` type in `contract(::MPO, ::MPS)` and `truncate!(::MPS/MPO)`.
1 parent 96db6a2 commit 5ca807f

12 files changed

Lines changed: 109 additions & 24 deletions

File tree

ITensorGPU/test/test_cumpo.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ using ITensors, ITensorGPU, Test
101101
psi = randomCuMPS(sites)
102102
psi_out = contract(K, psi; maxdim=1)
103103
@test inner(phi', psi_out) inner(phi', K, psi)
104-
@test_throws ArgumentError contract(K', psi, method="fakemethod")
104+
@test_throws MethodError contract(K', psi, method="fakemethod")
105105

106106
badsites = [Index(2, "Site") for n in 1:(N + 1)]
107107
badpsi = randomCuMPS(badsites)

NEWS.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@ Note that as of Julia v1.5, in order to see deprecation warnings you will need t
66

77
After we release v1 of the package, we will start following [semantic versioning](https://semver.org).
88

9+
ITensors v0.3.1 Release Notes
10+
=============================
11+
12+
Bugs:
13+
14+
Enhancements:
15+
16+
- Introduce `Algorithm` type for selecting algorithm backends (#886)
17+
918
ITensors v0.3.0 Release Notes
10-
==============================
19+
=============================
1120

1221
Bugs:
1322

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ITensors"
22
uuid = "9136182c-28ba-11e9-034c-db9fb085ebd5"
33
authors = ["Matthew Fishman <mfishman@flatironinstitute.org>", "Miles Stoudenmire <mstoudenmire@flatironinstitute.org>"]
4-
version = "0.3.0"
4+
version = "0.3.1"
55

66
[deps]
77
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"

src/ITensors.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ include("imports.jl")
103103
#
104104
include("global_variables.jl")
105105

106+
#####################################
107+
# Algorithm type for selecting
108+
# different algorithm backends
109+
# (for internal or advanced usage)
110+
#
111+
include("algorithm.jl")
112+
106113
#####################################
107114
# Index and IndexSet
108115
#

src/algorithm.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""
2+
Algorithm
3+
4+
A type representing an algorithm backend for a function.
5+
6+
For example, ITensor provides multiple backend algorithms for contracting
7+
an MPO with an MPS, which internally are selected with an `Algorithm` type.
8+
9+
This allows users to extend functions in ITensor with new algorithms, but
10+
use the same interface.
11+
"""
12+
struct Algorithm{Alg} end
13+
14+
Algorithm(s) = Algorithm{Symbol(s)}()
15+
algorithm(::Algorithm{Alg}) where {Alg} = string(Alg)
16+
17+
show(io::IO, alg::Algorithm) = print(io, "Algorithm type ", algorithm(alg))
18+
print(io::IO, ::Algorithm{Alg}) where {Alg} = print(io, Alg)
19+
20+
"""
21+
@Algorithm_str
22+
23+
A convenience macro for writing [`Algorithm`](@ref) types, typically used when
24+
adding methods to a function in ITensor that supports multiple algorithm
25+
backends (like contracting an MPO with an MPS).
26+
"""
27+
macro Algorithm_str(s)
28+
return :(Algorithm{$(Expr(:quote, Symbol(s)))})
29+
end

src/imports.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import Base:
4848
map!,
4949
ndims,
5050
permutedims,
51+
print,
5152
promote_rule,
5253
push!,
5354
resize!,

src/mps/abstractmps.jl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1500,7 +1500,11 @@ Perform a truncation of all bonds of an MPS/MPO,
15001500
using the truncation parameters (cutoff,maxdim, etc.)
15011501
provided as keyword arguments.
15021502
"""
1503-
function truncate!(M::AbstractMPS; kwargs...)
1503+
function truncate!(M::AbstractMPS; alg="frobenius", kwargs...)
1504+
return truncate!(Algorithm(alg), M; kwargs...)
1505+
end
1506+
1507+
function truncate!(::Algorithm"frobenius", M::AbstractMPS; kwargs...)
15041508
N = length(M)
15051509

15061510
# Left-orthogonalize all tensors to make

src/mps/mpo.jl

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -479,28 +479,23 @@ end
479479

480480
(A::MPO)(ψ::MPS; kwargs...) = apply(A, ψ; kwargs...)
481481

482-
function contract(A::MPO, ψ::MPS; kwargs...)
483-
method = get(kwargs, :method, "densitymatrix")
482+
function contract(A::MPO, ψ::MPS; alg="densitymatrix", kwargs...)
483+
if haskey(kwargs, :method)
484+
# Backwards compatibility, use `method`.
485+
alg = get(kwargs, :method, "densitymatrix")
486+
end
484487

485488
# Keyword argument deprecations
486-
if method == "DensityMatrix"
489+
if alg == "DensityMatrix"
487490
@warn "In contract, method DensityMatrix is deprecated in favor of densitymatrix"
488-
method = "densitymatrix"
491+
alg = "densitymatrix"
489492
end
490-
491-
if method == "Naive"
492-
@warn "In contract, method Naive is deprecated in favor of naive"
493-
method = "naive"
493+
if alg == "Naive"
494+
@warn "In contract, `alg=\"Naive\"` is deprecated in favor of `alg=\"naive\"`"
495+
alg = "naive"
494496
end
495497

496-
if method == "densitymatrix"
497-
= _contract_densitymatrix(A, ψ; kwargs...)
498-
elseif method == "naive"
499-
= _contract_naive(A, ψ; kwargs...)
500-
else
501-
throw(ArgumentError("Method $method not supported"))
502-
end
503-
return
498+
return contract(Algorithm(alg), A, ψ; kwargs...)
504499
end
505500

506501
contract_mpo_mps_doc = """
@@ -555,7 +550,7 @@ contract(ψ::MPS, A::MPO; kwargs...) = contract(A, ψ; kwargs...)
555550

556551
#@doc (@doc contract(::MPO, ::MPS)) *(::MPO, ::MPS)
557552

558-
function _contract_densitymatrix(A::MPO, ψ::MPS; kwargs...)::MPS
553+
function contract(::Algorithm"densitymatrix", A::MPO, ψ::MPS; kwargs...)::MPS
559554
n = length(A)
560555
n != length(ψ) &&
561556
throw(DimensionMismatch("lengths of MPO ($n) and MPS ($(length(ψ))) do not match"))
@@ -636,7 +631,7 @@ function _contract_densitymatrix(A::MPO, ψ::MPS; kwargs...)::MPS
636631
return ψ_out
637632
end
638633

639-
function _contract_naive(A::MPO, ψ::MPS; kwargs...)::MPS
634+
function contract(::Algorithm"naive", A::MPO, ψ::MPS; kwargs...)::MPS
640635
truncate = get(kwargs, :truncate, true)
641636

642637
N = length(A)

test/algorithm.jl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using ITensors
2+
using Test
3+
4+
@testset "Algorithm" begin
5+
alg = ITensors.Algorithm("X")
6+
7+
@test alg isa ITensors.Algorithm"X"
8+
@test alg == ITensors.Algorithm"X"()
9+
10+
s = siteinds("S=1/2", 4)
11+
A = MPO(s, "Id")
12+
ψ = randomMPS(s)
13+
14+
@test_throws MethodError contract(alg, A, ψ)
15+
@test_throws MethodError contract(A, ψ; method="X")
16+
@test_throws MethodError contract(A, ψ; alg="X")
17+
@test contract(ITensors.Algorithm("densitymatrix"), A, ψ) A * ψ
18+
@test contract(ITensors.Algorithm("naive"), A, ψ) A * ψ
19+
@test contract(A, ψ; alg="densitymatrix") A * ψ
20+
@test contract(A, ψ; method="densitymatrix") A * ψ
21+
@test contract(A, ψ; alg="naive") A * ψ
22+
@test contract(A, ψ; method="naive") A * ψ
23+
24+
B = copy(A)
25+
truncate!(ITensors.Algorithm("frobenius"), B)
26+
@test A B
27+
28+
B = copy(A)
29+
truncate!(B; alg="frobenius")
30+
@test A B
31+
32+
# Custom algorithm
33+
function ITensors.truncate!(::ITensors.Algorithm"my_new_algorithm", A::MPO; cutoff=1e-15)
34+
return "my_new_algorithm was called with cutoff $cutoff"
35+
end
36+
cutoff = 1e-5
37+
res = truncate!(A; alg="my_new_algorithm", cutoff=cutoff)
38+
@test res == "my_new_algorithm was called with cutoff $cutoff"
39+
end

test/mpo.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ end
203203
psi = randomMPS(sites)
204204
psi_out = contract(K, psi; maxdim=1)
205205
@test inner(phi', psi_out) inner(phi', K, psi)
206-
@test_throws ArgumentError contract(K, psi; method="fakemethod")
206+
@test_throws MethodError contract(K, psi; method="fakemethod")
207207

208208
badsites = [Index(2, "Site") for n in 1:(N + 1)]
209209
badpsi = randomMPS(badsites)

0 commit comments

Comments
 (0)