The Ansatz
class
The Lattice
type
A Lattice
is a graph that reprents the connectivity pattern between different physical sites. Its vertices are Lane
s and wherever an edge exists between two Lane
s, it means that those two sites can interact locally. A Lattice
is constructed by passing a Graph
and a dictionary mapping Lane
s to the original graph's vertices:
julia> using Graphs
julia> graph = path_graph(4)
{4, 3} undirected simple Int64 graph
julia> lattice = Lattice(graph, Dict([lane"1" => 1, lane"2" => 2, lane"3" => 3, lane"4" => lane"4"]))
ERROR: MethodError: no method matching nv(::Dict{Lane{1}, Any})
The function `nv` exists, but no method is defined for this combination of argument types.
Closest candidates are:
nv(!Matched::Lattice)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/Lattice.jl:116
nv(!Matched::TreeWidthSolver.MaskedBitGraph{INT}) where INT
@ TreeWidthSolver ~/.julia/packages/TreeWidthSolver/7H21e/src/bitgraphs.jl:26
nv(!Matched::Graphs.Test.GenericDiGraph)
@ Graphs ~/.julia/packages/Graphs/1ALGD/src/Test/Test.jl:88
...
Because the kind of graph topologies we use are quite common, we provide some shortcuts:
julia> lattice = Lattice(Val(:chain), 4)
Lattice(Lane[Lane{1}((1,)), Lane{1}((2,)), Lane{1}((3,)), Lane{1}((4,))], Graphs.SimpleGraphs.SimpleGraph{Int64}(3, [[2], [1, 3], [2, 4], [3]]))
julia> lattice = Lattice(Val(:grid), 3, 5)
ERROR: MethodError: no method matching Lattice(::Val{:grid}, ::Int64, ::Int64)
The type `Lattice` exists, but no method is defined for this combination of argument types when trying to construct it.
Closest candidates are:
Lattice(::Any, ::Any)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/Lattice.jl:47
Lattice(!Matched::Val{:rectangular}, ::Any, ::Any; periodic)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/Lattice.jl:194
Lattice(!Matched::Val{:lieb}, ::Any, ::Any)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/Lattice.jl:205
...
julia> lattice = Lattice(Val(:lieb), 2, 2)
Lattice(Lane[Lane{2}((1, 1)), Lane{2}((1, 2)), Lane{2}((1, 3)), Lane{2}((1, 4)), Lane{2}((1, 5)), Lane{2}((2, 1)), Lane{2}((2, 3)), Lane{2}((2, 5)), Lane{2}((3, 1)), Lane{2}((3, 2)) … Lane{2}((3, 4)), Lane{2}((3, 5)), Lane{2}((4, 1)), Lane{2}((4, 3)), Lane{2}((4, 5)), Lane{2}((5, 1)), Lane{2}((5, 2)), Lane{2}((5, 3)), Lane{2}((5, 4)), Lane{2}((5, 5))], Graphs.SimpleGraphs.SimpleGraph{Int64}(24, [[2, 6], [1, 3], [2, 4, 7], [3, 5], [4, 8], [1, 9], [3, 11], [5, 13], [6, 10, 14], [9, 11] … [11, 13], [8, 12, 16], [9, 17], [11, 19], [13, 21], [14, 18], [17, 19], [15, 18, 20], [19, 21], [16, 20]]))
The Ansatz
type
A Ansatz
is a Quantum
Tensor Network with a fixed graph structure, represented by a Lattice
.
julia> lattice = Lattice(Val(:chain), 4)
Lattice(Lane[Lane{1}((1,)), Lane{1}((2,)), Lane{1}((3,)), Lane{1}((4,))], Graphs.SimpleGraphs.SimpleGraph{Int64}(3, [[2], [1, 3], [2, 4], [3]]))
julia> tn = TensorNetwork([
Tensor(rand(2,2), (:p1, :v12)),
Tensor(rand(2,2,4), (:p2, :v12, :v23)),
Tensor(rand(2,4,2), (:p3, :v23, :v34)),
Tensor(rand(2,2), (:p4, :v34)),
])
TensorNetwork (#tensors=4, #inds=7)
julia> qtn = Quantum(tn, Dict([site"1" => :p1, site"2" => :p2, site"3" => :p3, site"4" => :p4]))
Quantum (inputs=0, outputs=4)
julia> ansatz = Ansatz(qtn, lattice)
Ansatz (inputs=0, outputs=4)
Just as Quantum
adds information to a TensorNetwork
on how to map open indices to input/output physical sites, a Ansatz
teaches a Quantum
on how to map Lattice
Lane
s to Tensor
s.
julia> tensors(ansatz; at=lane"1")
2×2 Tensor{Float64, 2, Matrix{Float64}}:
0.797867 0.807897
0.112541 0.768081
Because ...
julia> inds(ansatz; bond=(lane"1", lane"2"))
:v12
Time Evolution
[evolve!
] is a high-level wrapper for different methods used for time-evolution.
Note
In other Tensor Network and Quantum Computing libraries, you may know evolve!
by the name of apply!
or apply
. Given that the word "apply" has many semantic acceptions, we believe that "evolve" fits better to its purpose.
julia> gate = Gate([0 1; 1 0], [site"1", site"1'"])
Gate([0 1; 1 0], Site[1, 1'])
julia> evolve!(tn, gate)
ERROR: MethodError: no method matching evolve!(::TensorNetwork, ::Gate)
The function `evolve!` exists, but no method is defined for this combination of argument types.
Closest candidates are:
evolve!(!Matched::Tenet.AbstractAnsatz, ::Any; threshold, maxdim, normalize, kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/Ansatz.jl:417
evolve!(!Matched::Canonical, !Matched::Tenet.AbstractMPS, !Matched::Tenet.AbstractMPO; kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/MPS.jl:640
evolve!(!Matched::MixedCanonical, !Matched::Tenet.AbstractMPS, !Matched::Tenet.AbstractMPO; kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/MPS.jl:628
...
When applying a multi-site gate, there are different numerical methods that can be used for approximate evolution of states. As of the time of writing, only the "Simple Update" algorithm is implemented in simple_update!
but we plan to implement other methods like "Full Update" algorithm in the future.
Tip
evolve!
is just a wrapper over different numerical methods for evolving states. You're free to call simple_update!
directly if you want.
Warning
Currently, only 2-site gates are supported.
For example, this is how you would evolve / apply a two-site local operator using both evolve!](/api/ansatz#Tenet.evolve!-Tuple{Tenet.AbstractAnsatz,%20Any}) and [
simple_update!:
julia> evolve!(tn, Gate(rand(2,2,2,2), [site"1", site"2", site"1'", site"2'"]))
ERROR: MethodError: no method matching evolve!(::TensorNetwork, ::Gate)
The function `evolve!` exists, but no method is defined for this combination of argument types.
Closest candidates are:
evolve!(!Matched::Tenet.AbstractAnsatz, ::Any; threshold, maxdim, normalize, kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/Ansatz.jl:417
evolve!(!Matched::Canonical, !Matched::Tenet.AbstractMPS, !Matched::Tenet.AbstractMPO; kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/MPS.jl:640
evolve!(!Matched::MixedCanonical, !Matched::Tenet.AbstractMPS, !Matched::Tenet.AbstractMPO; kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/MPS.jl:628
...
julia> simple_update!(tn, Gate(rand(2,2,2,2), [site"1", site"2", site"1'", site"2'"]))
ERROR: MethodError: no method matching simple_update!(::TensorNetwork, ::Gate)
The function `simple_update!` exists, but no method is defined for this combination of argument types.
Closest candidates are:
simple_update!(!Matched::Tenet.AbstractAnsatz, ::Gate; threshold, maxdim, kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/Ansatz.jl:449
As you operate on a Ansatz
, it will make sure that the Lattice
topology is preserve through different operations. So a two-site Gate
between non-connected Lane
s is forbidden:
julia> evolve!(tn, Gate(rand(2,2,2,2), [site"1", site"4", site"1'", site"4'"])) # this errors
ERROR: MethodError: no method matching evolve!(::TensorNetwork, ::Gate)
The function `evolve!` exists, but no method is defined for this combination of argument types.
Closest candidates are:
evolve!(!Matched::Tenet.AbstractAnsatz, ::Any; threshold, maxdim, normalize, kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/Ansatz.jl:417
evolve!(!Matched::Canonical, !Matched::Tenet.AbstractMPS, !Matched::Tenet.AbstractMPO; kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/MPS.jl:640
evolve!(!Matched::MixedCanonical, !Matched::Tenet.AbstractMPS, !Matched::Tenet.AbstractMPO; kwargs...)
@ Tenet ~/work/Tenet.jl/Tenet.jl/src/MPS.jl:628
...
DocumenterMermaid.MermaidScriptBlock([...])