Express functionality
A principle feature of QuantumSymbolics
is to numerically represent symbolic quantum expressions in various formalisms using express
. In particular, one can translate symbolic logic to back-end toolboxes such as QuantumOptics.jl
or QuantumClifford.jl
for simulating quantum systems with great flexibiity.
As a straightforward example, consider the spin-up state $|\uparrow\rangle = |0\rangle$, the eigenstate of the Pauli operator $Z$, which can be expressed in QuantumSymbolics
as follows:
ψ = Z1
\[\left|Z_1\right\rangle\]
Using express
, we can translate this symbolic object into its numerical state vector form in QuantumOptics.jl
.
express(ψ)
Ket(dim=2)
basis: Spin(1/2)
1.0 + 0.0im
0.0 + 0.0im
By default, express
converts a quantum object with QuantumOpticRepr
. It should be noted that express
automatically caches this particular conversion of ψ
. Thus, after running the above example, the numerical representation of the spin-up state is stored in the metadata of ψ
.
ψ.metadata
QuantumSymbolics.Metadata(Dict{Tuple{AbstractRepresentation, AbstractUse}, Any}((QuantumOpticsRepr(2), UseAsState()) => Ket(dim=2)
basis: Spin(1/2)
1.0 + 0.0im
0.0 + 0.0im))
The caching feature of express
prevents a specific representation for a symbolic quantum object from being computed more than once. This becomes handy for translations of more complex operations, which can become computationally expensive. We also have the ability to express $|Z_1\rangle$ in the Clifford formalism with QuantumClifford.jl
:
express(ψ, CliffordRepr())
𝒟ℯ𝓈𝓉𝒶𝒷
+ X
𝒮𝓉𝒶𝒷
+ Z
Here, we specified an instance of CliffordRepr
in the second argument to convert ψ
into a tableau of Pauli operators containing its stabilizer and destabilizer states. Now, both the state vector and Clifford representation of ψ
have been cached:
ψ.metadata
QuantumSymbolics.Metadata(Dict{Tuple{AbstractRepresentation, AbstractUse}, Any}((QuantumOpticsRepr(2), UseAsState()) => Ket(dim=2)
basis: Spin(1/2)
1.0 + 0.0im
0.0 + 0.0im, (CliffordRepr(), UseAsState()) => MixedDestablizer 1×1))
More involved examples can be explored. For instance, say we want to apply the tensor product $X\otimes Y$ of the Pauli operators $X$ and $Y$ to the Bell state $|\Phi^{+}\rangle = \dfrac{1}{\sqrt{2}}\left(|00\rangle + |11\rangle\right)$, and numerically express the result in the quantum optics formalism. This would be done as follows:
bellstate = (Z1⊗Z1+Z2⊗Z2)/√2
tp = σˣ⊗σʸ
express(tp*bellstate)
Ket(dim=4)
basis: [Spin(1/2) ⊗ Spin(1/2)]
0.0 - 0.7071067811865475im
0.0 + 0.0im
0.0 + 0.0im
0.0 + 0.7071067811865475im
Examples of Edge Cases
For Pauli operators, additional flexibility is given for translations to the Clifford formalism. Users have the option to convert a multi-qubit Pauli operator to an observable or operation with instances of UseAsObservable
and UseAsOperation
, respectively. Take the Pauli operator $Y$, for example, which in QuantumSymbolics
is the constants Y
or σʸ
:
julia> express(σʸ, CliffordRepr(), UseAsObservable())
+ Y
julia> express(σʸ, CliffordRepr(), UseAsOperation())
sY
Another edge case is translations with QuantumOpticsRepr
, where we can additionally define a finite cutoff for bosonic states and operators, as discussed in the quantum harmonic oscillators page. The default cutoff for such objects is 2, however a different cutoff can be specified by passing an integer to QuantumOpticsRepr
in an express
call. Let us see an example with the number operator:
julia> express(N) |> dense
Operator(dim=3x3)
basis: Fock(cutoff=2)
0.0+0.0im 0.0+0.0im 0.0+0.0im
0.0+0.0im 1.0+0.0im 0.0+0.0im
0.0+0.0im 0.0+0.0im 2.0+0.0im
julia> express(N, QuantumOpticsRepr(cutoff=4)) |> dense
Operator(dim=5x5)
basis: Fock(cutoff=4)
0.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im
0.0+0.0im 1.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im
0.0+0.0im 0.0+0.0im 2.0+0.0im 0.0+0.0im 0.0+0.0im
0.0+0.0im 0.0+0.0im 0.0+0.0im 3.0+0.0im 0.0+0.0im
0.0+0.0im 0.0+0.0im 0.0+0.0im 0.0+0.0im 4.0+0.0im