Symbolics
In this tutorial, we show how to work with symbolic operators using MathLink.jl and Symbolics.jl. The main idea is that the coefficients of the Operator can be arbitrary Number types, we can thus use symbolic numbers from Symbolics.jl and expressions from MathLink.jl to create symbolic operators. Two PauliStrings.jl extensions are provided to facilitate the construction and manipulation of symbolic operators using MathLink.jl and Symbolics.jl.
Mathlink.jl (Wolfram Mathematica)
If you have access to Wolfram Mathematica, we recommend using MathLink.jl to create symbolic operators. The MathLink PauliStrings extension provides a MathLinkNumber type that wraps Mathematica symbolic expressions into Numbers.
Let's create a simple symbolic operator:
using MathLink
using PauliStrings
a = W`A`
b = W`B`
O = OperatorMathLink(2)
O += a, "X", 1
O += b, "Z", 1, "Z", 2
println(typeof(O))Operator{PauliString{2, UInt8}, MathLinkPauliStringsExt.MathLinkNumber}We can perform the usual operations supported for Operator
println(O)
println(O + O + 1)
println(trace_product(O, 4))(A) X1
(B) ZZ
(Complex[1.0, 0.0]) 11
(Times[2, A]) X1
(Times[2, B]) ZZ
Times[4.0, Power[Plus[Power[A, 2], Power[B, 2]], 2]]It is possible to simplify a MathLinkNumber using simplify with assumptions:
println(simplify(norm(O^2)))
println(simplify(norm(O^2); assumptions = W`Assumptions -> {A>0, B>0}`))Operators can be similarly simplified using simplify_operator.
Lets now compute a few lanczos coefficients for the initial operator $Z_1$ in the transverse field Ising model with symbolic transverse field h: Define the Ising Hamiltonian function:
function ising(h)
H = OperatorMathLink(N)
for i in 1:N
H += h, "X", i
end
for i in 1:N
H += "Z", i, "Z", mod1(i + 1, N)
end
return H
endInitialize two operators :
N = 10 #system size
# Initial operator O = X_1
O = OperatorMathLink(N)
O += 1, "X", 1
# Initialize a symbolic hamiltonian with a symbolic parameter h
h = W`h`
H = ising(h)Now we can compute the lanczos coefficients with simplification assumptions:
# Define assumptions for simplification
assumptions = W`Assumptions -> h > 0`
# Compute Lanczos coefficients
bn = lanczos(H, O, 5; assumptions=assumptions)
for b in bn
println(b)
endTimes[2, Power[2, Rational[1, 2]]]
Power[Plus[8, Times[8, Power[h, 2]]], Rational[1, 2]]
Times[2, h, Power[Times[Power[Plus[1, Power[h, 2]], -1], Plus[5, Times[2, Power[h, 2]]]], Rational[1, 2]]]
Power[Times[Power[Plus[5, Times[7, Power[h, 2]], Times[2, Power[h, 4]]], -1], Plus[64, Times[96, Power[h, 2]], Times[68, Power[h, 4]]]], Rational[1, 2]]
Times[2, Power[Times[Power[Plus[80, Times[152, Power[h, 2]], Times[133, Power[h, 4]], Times[34, Power[h, 6]]], -1], Plus[64, Times[516, Power[h, 2]], Times[587, Power[h, 4]], Times[231, Power[h, 6]], Times[96, Power[h, 8]]]], Rational[1, 2]]]These expressions can be easilly imported back into Mathematica for further manipulation, or conversion into LaTeX with TeXForm:
\[\left\{2 \sqrt{2},\sqrt{8 h^2+8},2 h \sqrt{\frac{2 h^2+5}{h^2+1}},\sqrt{\frac{68 h^4+96 h^2+64}{2 h^4+7 h^2+5}},2 \sqrt{\frac{96 h^8+231 h^6+587 h^4+516 h^2+64}{34 h^6+133 h^4+152 h^2+80}}\right\}\]
The MathLink expression can be extracted from a MathLinkNumber doing x.expression where x is a MathLinkNumber.
Symbolics.jl
The second option is to use Symbolics.jl.
Construction and basic operations
First import the necessary packages:
using Symbolics
using PauliStringsInitialize an empty 2-qubit symbolic operator:
N = 2
H = OperatorSymbolics(N)
println(typeof(H))Operator{PauliString{2, UInt8}, Complex{Num}}Now let's create a two-site Ising model, where the value of the transverse field is a symbolic variable h
@variables h
H += "Z", 1, "Z", 2
H += h, "X", 1
H += h, "X", 2We can perform the usual operations supported for Operator
println(H)
println(H + H + 0.5)
println(trace_product(H, 4))(h) 1X
(h) X1
(1.0) ZZ
(0.5) 11
(2h) 1X
(2h) X1
(2.0) ZZ
4.0(4(h^4) + (1 + 2(h^2))^2)Simplification of symbolic operators
simplify_operator can be used to simplify the coefficients of a symbolic operator.
Let's apply this to H^2:
H2 = H^2
println(H2)
println(simplify_operator(H2))(1 + 2(h^2)) 11
(0.0) ZY
(0.0) YZ
(2(h^2)) XX
(1 + 2(h^2)) 11
(2(h^2)) XXHowever, keep in mind that simplify doesn't reduce all the expressions:
H3 = H^3
println(H3)
println(simplify_operator(H3))(2(h^3) + h*(1 + 2(h^2))) 1X
(-2.0(h^2)) YY
(2(h^3) + h*(1 + 2(h^2))) X1
(1 + 2(h^2)) ZZ
(2(h^3) + h*(1 + 2(h^2))) 1X
(-2.0(h^2)) YY
(2(h^3) + h*(1 + 2(h^2))) X1
(1 + 2(h^2)) ZZAs a final example, let's calculate some commutators with another operator O
O1 = OperatorSymbolics(N)
O1 += "X", 1
O2 = commutator(H, O1)
O3 = commutator(H, O2)
println(O2)
println(O3)(2.0im) YZ
(4.0h) YY
(4.0) X1
(-4h) ZZSubstituting variables with numericald values
To substitute the variables for concrete numerical values we can use substitute_operator
O = substitute_operator(O3, Dict(h => 0.5))
println(typeof(O))
println(O)Operator{PauliString{2, UInt8}, ComplexF64}
(2.0 - 0.0im) YY
(4.0 + 0.0im) X1
(-2.0 + 0.0im) ZZ