Create QuantumToolbox.jl logo
Introduction
In this tutorial, we will demonstrate how to create the logo for the QuantumToolbox.jl package. The logo represents the Wigner function of the triangular cat state, which is a linear superposition of three coherent states. The resulting Wigner function has a triangular shape that resembles the Julia logo. We will also define a custom colormap that varies based on the value of the Wigner function and the spatial coordinates, such that the three blobs corresponding to the coherent states have different colors (matching the colors of the Julia logo).
Triangular Cat State
A cat state, often referred to as a Schrödinger cat state, is a quantum state that is a superposition of two coherent states with opposite phases:
\[| \psi_{\text{cat}} \rangle = \frac{1}{\sqrt{2}} \left( | \alpha \rangle + | -\alpha \rangle \right)\]
where $| \alpha \rangle$ is a coherent state with amplitude $\alpha$.
The triangular cat state is a generalization of the standard cat state. It is a superposition of three coherent states with phases $\theta_0, \theta_1, \theta_2$ separated by $120^\circ$(or $2\pi/3$radians):
\[| \psi_{\text{tri-cat}} \rangle = \frac{1}{\sqrt{3}} \left( | \alpha_0 \rangle + | \alpha_1 \rangle + | \alpha_2 \rangle \right)\]
where $\alpha_j = \rho e^{i\theta_j}$with $\theta_j = \frac{\pi}{2} + \frac{2\pi j}{3}$and $j = 0, 1, 2$.
Wigner Function
The Wigner function $W(x, p)$is a quasi-probability distribution used in quantum mechanics to represent quantum states in phase space. It is defined as:
\[W(x, p) = \frac{1}{\pi \hbar} \int_{-\infty}^{\infty} \psi^*(x + y) \psi(x - y) e^{2ipy / \hbar} \, dy\]
where $\psi(x)$is the wave function of the quantum state, $x$is the position, $p$is the momentum, and $\hbar$is the reduced Planck constant. Unlike classical probability distributions, the Wigner function can take negative values, which indicates non-classical behavior.
Generating the Logo
First, let's load the required packages:
using QuantumToolbox
using CairoMakie
CairoMakie.activate!(type = "svg", pt_per_unit = 1)
CairoMakie.enable_only_mime!(MIME"image/svg+xml"())
Parameters
Here we define the parameters for the triangular cat state:
N = 30 # Cutoff of the Hilbert space for the harmonic oscillator
ρ = 2.5 # Amplitude of the coherent state
θ1 = π / 2
θ2 = π / 2 + 2π / 3
θ3 = π / 2 + 4π / 3
α1 = ρ * exp(im * θ1)
α2 = ρ * exp(im * θ2)
α3 = ρ * exp(im * θ3)
2.165063509461096 - 1.250000000000001im
Constructing the State
Next, we construct the triangular cat state as a normalized superposition of three coherent states:
ψ = coherent(N, α1) + coherent(N, α2) + coherent(N, α3)
normalize!(ψ)
Quantum Object: type=Ket dims=[30] size=(30,)
30-element Vector{ComplexF64}:
0.07609684210792242 + 2.6723530829796594e-20im
8.011906616501529e-18 + 8.813097278151682e-17im
-1.7626194556303364e-16 - 3.044524514270581e-16im
-4.749297694345924e-16 - 0.4854125890665235im
-1.6023813233003058e-17 + 2.243333852620428e-16im
-4.166191440580795e-16 + 3.2047626466006115e-17im
-0.6923735018977101 + 1.329180370646047e-15im
6.089049028541162e-16 + 2.72404824961052e-16im
8.011906616501529e-17 + 4.486667705240856e-16im
1.3522381766446245e-15 + 0.4818869843344701im
⋮
1.6172599173965975e-17 + 0.0024206665998124624im
1.8777906132425458e-18 - 4.569290492223528e-18im
1.5961220212561639e-18 - 3.912063777588637e-19im
0.0003432034325806673 - 2.6243279078393e-18im
-6.572267146348911e-19 - 2.8949271954155915e-19im
-7.824127555177275e-20 - 2.2689969910014095e-19im
-3.5003747457689365e-19 - 4.0804319967534345e-5im
-3.2763534137304833e-20 + 8.019730744056706e-20im
-3.080750224851052e-20 + 9.046647485673724e-21im
Defining the Grid and calculating the Wigner function
We define the grid for the Wigner function and calculate it using the wigner
function. We shift the grid in the imaginary direction to ensure that the Wigner function is centered around the origin of the figure. The wigner
function also supports the g
scaling factor, which we put here equal to $2$.
xvec = range(-ρ, ρ, 500) .* 1.5
yvec = xvec .+ (abs(imag(α1)) - abs(imag(α2))) / 2
wig = wigner(ψ, xvec, yvec, g = 2)
500×500 Matrix{Float64}:
1.2746e-6 1.40069e-6 1.53778e-6 … 1.40069e-6 1.2746e-6
1.42358e-6 1.5645e-6 1.71771e-6 1.5645e-6 1.42358e-6
1.58864e-6 1.74598e-6 1.91706e-6 1.74598e-6 1.58864e-6
1.77134e-6 1.94687e-6 2.13774e-6 1.94687e-6 1.77134e-6
1.97338e-6 2.16903e-6 2.3818e-6 2.16903e-6 1.97338e-6
2.1966e-6 2.41449e-6 2.65146e-6 … 2.41449e-6 2.1966e-6
2.443e-6 2.68545e-6 2.94913e-6 2.68545e-6 2.443e-6
2.71474e-6 2.98427e-6 3.27742e-6 2.98427e-6 2.71474e-6
3.01413e-6 3.31351e-6 3.63914e-6 3.31351e-6 3.01413e-6
3.34369e-6 3.67593e-6 4.03733e-6 3.67593e-6 3.34369e-6
⋮ ⋱
5.02397e-13 5.58105e-13 6.20755e-13 5.58105e-13 5.02397e-13
4.39263e-13 4.86875e-13 5.40279e-13 4.86875e-13 4.39263e-13
3.83717e-13 4.24285e-13 4.69654e-13 4.24285e-13 3.83717e-13
3.34972e-13 3.69444e-13 4.07859e-13 3.69444e-13 3.34972e-13
2.92299e-13 3.21515e-13 3.53945e-13 … 3.21515e-13 2.92299e-13
2.55023e-13 2.79729e-13 3.07029e-13 2.79729e-13 2.55023e-13
2.22522e-13 2.43375e-13 2.66301e-13 2.43375e-13 2.22522e-13
1.94233e-13 2.11808e-13 2.3102e-13 2.11808e-13 1.94233e-13
1.69644e-13 1.84442e-13 2.00515e-13 1.84442e-13 1.69644e-13
Plotting the Wigner function
Finally, we plot the Wigner function using the heatmap
function from the CairoMakie
package.
fig = Figure(size = (500, 500), figure_padding = 0)
ax = Axis(fig[1, 1])
heatmap!(ax, xvec, yvec, wig', colormap = :RdBu, interpolate = true, rasterize = 1)
hidespines!(ax)
hidexdecorations!(ax)
hideydecorations!(ax)
fig
Introducing some decoherence
The figure obtained above coulb be already a potential logo for the package. However, we see that the fringe patterns are more intense than the three coherent gaussian amplitudes. We can introduce some decoherence to reduce this effect. Thus, we evolve the system under the evolution of a damped quantum harmonic oscillator, which is described by the Lindblad master equation:
\[\frac{d \hat{\rho}}{dt} = -i [\hat{H}, \hat{\rho}] + \gamma \left( 2 \hat{a} \hat{\rho} \hat{a}^\dagger - \hat{a}^\dagger \hat{a} \hat{\rho} - \hat{\rho} \hat{a}^\dagger \hat{a} \right)\]
where $\hat{\rho}$ is the density matrix, $\hat{H} = \omega \hat{a}^\dagger \hat{a}$is the Hamiltonian of the harmonic oscillator ($\hbar = 1$), $\hat{a}$and $\hat{a}^\dagger$are the annihilation and creation operators, and $\gamma$is the damping rate. Thus, we initialize the system in the triangular cat state and evolve it under the Lindblad master equation, using the mesolve
function.
γ = 0.012
a = destroy(N)
H = a' * a
c_ops = [sqrt(γ) * a]
tlist = range(0, 2π, 100)
sol = mesolve(H, ψ, tlist, c_ops, progress_bar = false)
And the Wigner function becomes more uniform:
wig = wigner(sol.states[end], xvec, yvec, g = 2)
fig = Figure(size = (500, 500), figure_padding = 0)
ax = Axis(fig[1, 1])
img_wig = heatmap!(ax, xvec, yvec, wig', colormap = :RdBu, interpolate = true, rasterize = 1)
hidespines!(ax)
hidexdecorations!(ax)
hideydecorations!(ax)
fig
At this stage, we have finished to use the QuantumToolbox
package. From now on, we will use the CairoMakie
package to define custom colormaps and plot the Wigner function in a Julia logo style.
Custom Colormap
We define a custom colormap that changes depending on the Wigner function and spatial coordinates. Indeed, we want the three different colormaps, in the regions corresponding to the three coherent states, to match the colors of the Julia logo. We also want the colormap change to be smooth, so we use a Gaussian function to blend the colors. We introduce also a Wigner function dependent transparency to make the logo more appealing.
function set_color_julia(x, y, wig::T, α1, α2, α3, cmap1, cmap2, cmap3, δ) where {T}
amp1 = gaussian(x, real(α1), δ) * gaussian(y, imag(α1), δ)
amp2 = gaussian(x, real(α2), δ) * gaussian(y, imag(α2), δ)
amp3 = gaussian(x, real(α3), δ) * gaussian(y, imag(α3), δ)
c1 = get(cmap1, wig)
c2 = get(cmap2, wig)
c3 = get(cmap3, wig)
c_tot = (amp1 * c1 + amp2 * c2 + amp3 * c3) / (amp1 + amp2 + amp3)
wig_abs = abs(2 * (wig - 1 / 2))
# We introduce some non-linearity to increase the contrast
alpha = 2 * (1 / (1 + exp(-5 * wig_abs)) - 1 / 2)
return RGBAf(c_tot.r, c_tot.g, c_tot.b, alpha)
end
X, Y = meshgrid(xvec, yvec)
δ = 1.25 # Smoothing parameter for the Gaussian functions
1.25
Colormaps from the Julia colors
We define the colormaps for the three coherent states using the colors of the Julia logo. We use the cgrad
function from the CairoMakie
package to create the colormaps.
julia_red = RGBAf(0.796, 0.235, 0.2, 1.0)
julia_green = RGBAf(0.22, 0.596, 0.149, 1.0)
julia_blue = RGBAf(0.251, 0.388, 0.847, 1.0)
julia_purple = RGBAf(0.584, 0.345, 0.698, 1.0)
n_repeats = 2
cmap1 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_green, n_repeats)))
cmap2 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_red, n_repeats)))
cmap3 = cgrad(vcat(fill(julia_blue, n_repeats), fill(julia_purple, n_repeats)))
Normalizing the Wigner function and applying the custom colormap
The colormaps require the input to be in the range $[0, 1]$. We normalize the Wigner function such that the maximum value is $1$and the zeros are set to $0.5$.
vmax = maximum(wig)
wig_normalized = wig ./ (vmax * 2) .+ 1 / 2
And we now apply this custom colormap to make an image (a Matrix{RGBAf}
).
img = set_color_julia.(X, Y, wig_normalized, α1, α2, α3, Ref(cmap1), Ref(cmap2), Ref(cmap3), δ)
500×500 Array{RGBA{Float32},2} with eltype ColorTypes.RGBA{Float32}:
RGBA{Float32}(0.523498,0.311502,0.523505,6.26324f-6) … RGBA{Float32}(0.417504,0.366499,0.772491,6.26453f-6)
RGBA{Float32}(0.523498,0.311502,0.523505,7.0155f-6) RGBA{Float32}(0.417504,0.366499,0.772491,7.01701f-6)
RGBA{Float32}(0.523498,0.311502,0.523504,7.85147f-6) RGBA{Float32}(0.417504,0.366499,0.772491,7.85322f-6)
RGBA{Float32}(0.523499,0.311502,0.523504,8.7796f-6) RGBA{Float32}(0.417504,0.366499,0.772491,8.78163f-6)
RGBA{Float32}(0.523499,0.311501,0.523504,9.80911f-6) RGBA{Float32}(0.417505,0.366499,0.772491,9.81147f-6)
RGBA{Float32}(0.523499,0.311501,0.523503,1.095f-5) … RGBA{Float32}(0.417505,0.366499,0.77249,1.09527f-5)
RGBA{Float32}(0.5235,0.311501,0.523503,1.22133f-5) RGBA{Float32}(0.417505,0.366498,0.77249,1.22164f-5)
RGBA{Float32}(0.5235,0.311501,0.523502,1.36106f-5) RGBA{Float32}(0.417505,0.366498,0.77249,1.36141f-5)
RGBA{Float32}(0.523501,0.311501,0.523502,1.51548f-5) RGBA{Float32}(0.417506,0.366498,0.77249,1.51589f-5)
RGBA{Float32}(0.523501,0.311501,0.523501,1.68599f-5) RGBA{Float32}(0.417506,0.366498,0.77249,1.68645f-5)
⋮ ⋱
RGBA{Float32}(0.237399,0.49081,0.498168,1.87916f-12) RGBA{Float32}(0.2367,0.491173,0.49981,1.87295f-12)
RGBA{Float32}(0.237332,0.490852,0.498162,1.64535f-12) RGBA{Float32}(0.236658,0.491202,0.499746,1.64091f-12)
RGBA{Float32}(0.237267,0.490892,0.498157,1.43885f-12) RGBA{Float32}(0.236617,0.49123,0.499684,1.43552f-12)
RGBA{Float32}(0.237205,0.490931,0.498151,1.25744f-12) RGBA{Float32}(0.236577,0.491257,0.499625,1.25455f-12)
RGBA{Float32}(0.237145,0.490969,0.498146,1.09801f-12) … RGBA{Float32}(0.23654,0.491283,0.499568,1.09579f-12)
RGBA{Float32}(0.237087,0.491005,0.498141,9.58122f-13) RGBA{Float32}(0.236503,0.491308,0.499513,9.56568f-13)
RGBA{Float32}(0.237031,0.49104,0.498136,8.35998f-13) RGBA{Float32}(0.236468,0.491333,0.499459,8.34888f-13)
RGBA{Float32}(0.236977,0.491074,0.498131,7.29417f-13) RGBA{Float32}(0.236433,0.491356,0.499408,7.28306f-13)
RGBA{Float32}(0.236925,0.491107,0.498126,6.36158f-13) RGBA{Float32}(0.236401,0.491379,0.499358,6.35048f-13)
Final Plot
Finally, we plot the Wigner function with the custom colormap.
fig = Figure(size = (500, 500), figure_padding = 0, backgroundcolor = :transparent)
ax = Axis(fig[1, 1], backgroundcolor = :transparent)
image!(ax, img', rasterize = 1)
hidespines!(ax)
hidexdecorations!(ax)
hideydecorations!(ax)
fig
Conclusion
This tutorial demonstrates how to generate the QuantumToolbox.jl logo using the package itself and Makie.jl for visualization. The logo is a visualization of the Wigner function of a triangular cat state, with a custom colormap that highlights the different coherent states with colors matching the Julia logo.