From b859ebf192428d05921ecda8db75e7adc494cfa8 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Sun, 29 Oct 2023 00:18:28 +0800 Subject: [PATCH 1/2] new bloch --- Project.toml | 3 + examples/bloch.jl | 55 +++++++++ examples/constgates.png | Bin 5693 -> 16573 bytes src/YaoPlots.jl | 7 ++ src/bloch.jl | 254 ++++++++++++++++++++++++++++++++++++++++ src/vizcircuit.jl | 4 + test/bloch.jl | 42 +++++++ test/runtests.jl | 4 + 8 files changed, 369 insertions(+) create mode 100644 examples/bloch.jl create mode 100644 src/bloch.jl create mode 100644 test/bloch.jl diff --git a/Project.toml b/Project.toml index d358f20..0ab26f8 100644 --- a/Project.toml +++ b/Project.toml @@ -3,11 +3,14 @@ uuid = "32cfe2d9-419e-45f2-8191-2267705d8dbc" version = "0.8.1" [deps] +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Luxor = "ae8d54c2-7ccd-5906-9d76-62fc9837b5bc" +Thebes = "8b424ff8-82f5-59a4-86a6-de3761897198" Yao = "5872b779-8223-5990-8dd0-5abbb0748c8c" [compat] Luxor = "3" +Thebes = "0.9" Yao = "0.8" julia = "1" diff --git a/examples/bloch.jl b/examples/bloch.jl new file mode 100644 index 0000000..afde3ef --- /dev/null +++ b/examples/bloch.jl @@ -0,0 +1,55 @@ +using YaoPlots, Yao +using LinearAlgebra: axpy! + +function commutator(x, y; ishermitian=false) + res = x * y + if ishermitian + return res - res' + else + return res - y * x + end +end +function anticommutator(x, y; ishermitian=false) + res = x * y + if ishermitian + return res + res' + else + return res + y * x + end +end + +# single step master equation +function mestep(rho::DensityMatrix{D}, h, Ls, dt) where D + res = copy(rho.state) + # The im*[ρ, H] term. + # NOTE: transposed storage is faster + reg = arrayreg(copy(rho.state)'; nlevel=size(rho.state, 2)) + apply!(reg, h) + axpy!(dt * im, reg.state' - reg.state, res) + for L in Ls + # the LρL' term + axpy!(dt, apply(rho, L).state, res) + # the -(ρL'L + L'Lρ)/2 term + reg = arrayreg(copy(rho.state)'; nlevel=size(rho.state, 2)) + apply!(reg, L' * L) + axpy!(-0.5dt, reg.state, res) + axpy!(-0.5dt, reg.state', res) + end + return DensityMatrix(res) +end + +function simulate(t; dt=0.02, dissiplation=0.2, filename=nothing) + reg0 = zero_state(1) |> H + rho = density_matrix(reg0) + h = Z # rotate around Z + Ls = [sqrt(dissiplation) * ConstGate.Pd] # dissipation + states = ["|+⟩"=>rho] + for t = 0:dt:t + rho = mestep(rho, h, Ls, dt) + @show sum(abs2, rho.state - rho.state') + push!(states, ""=>rho) + end + return bloch_sphere(states...; filename) +end + +simulate(π/2; filename=joinpath(@__DIR__, "constgates.png")) \ No newline at end of file diff --git a/examples/constgates.png b/examples/constgates.png index 2e618cefa2b1276d5b410cef1fb793b2e7165ed5..555a69bdda1eb6ccef6232b8b3df7f6eeeb044aa 100644 GIT binary patch literal 16573 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 literal 5693 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 z h%ibppU3r#dg&Y6$Eg`j!KxiAG0)yitLRg zJ|ti<2XTw(qS~9?%Yl4id-mBZ`_FDSq7NB9KMvxVtm{Vwiqxl2(ou)^`q*KTLOG{z zB>q|CnmUXcwZh|+u*jE60}`f&pH3ri{-rm@NfQlsI#`8|(Csu2{VQblsussH_8hhr z-N!0;a)m)oWsqog(f^)1pNi%#%`Lu_-~>TCkTjZE1~0co zkKz%_yViO3KBj##Bb1!;^g17*^S1~D9d401ej&VIJ%cd3j}DcUjBHGJOitOrppRHt z4U&+B=%5tii_U_!GoZM0pf~_nM%u0ZA`9G-yWMA*scR`dhp<0--UfmB3yCL^()$L= zy$0J^mC2|8{=7ILaa5%=F{;@g+dox1$$J-=tCFH+r!_UnbnF|5*8c zpGNJNN*6vCef*|BDY&k-h5NtPy#EP}2213BH5|pG{u+Tw`Y~moUJn2&>~&Ht?UeNn zupB?1-Ah3}qXASdS#g230ywn@kJh^|^HaLn7cv;WogI_{vNXXiX;}HS#>~Ic>4q>* zmSDG@O8?`&3C|2pY5Y)i`twSmhW?XWMIO{a>%E*hCC z`p_(J0=>TpwEU5+jNszp%1lm6OY`cF`3sp&q?3)+7E|Q%l89gc#~Cafb7ezA!yNF4 z3k&P&>N2siDx+uSc-4A=gG0fvN<((V-X;m35Lvl?pAw=`5lgcwCa9)sXc!+A6{Xhv zjM8Hg7}yAMkV|DIeHz3L89Pdd{e51#3D})W`tv7=UVB@Kc$eY2%jRZnfKTjMsMIfu zDyO77G2F9A+1!EM(KQzs4J?R5@gjunSRWWX;+Ky0-oZhkUOLB;PC!&+V7(BD9Uf{c zcgM(%iIUw@jrQB=Pu})<3@*Z#q}{y2UhrGXww;eFj?Td1aK!MDlJXVH&6*!J(nprq zrtZ9seOEp`aJ#Xn$bFTUTK>L!qAL~Ed43eC6pT4G=e*i$MGc%9Br83MhW7y|RQ?qw z#nUVDx*`{Z?pP&(mYdhp{E-z2sshJ0a9nAX|1f6%I+JDUv%<+w{jXW1Vq#(}nga3t z16mrlykQQ)FU^hx-x5@R%~19x@yZ@kyqSb6USw{3VtVa7fqDFR-ukV8Hk*rkIcUET zvX9*WWN&mW7(K{n(|r7mQL1Mf@_8;Db%V`^=Qx~ysU1<*{cW#Zziwh~J_mv#5F8C| zv~7n?w|=lKGx7giUj7?-@pm^(e@i3kQylGTr98@!{zyq+&VgZp7Fgv}V=>A<=I&G$ z)+3`nej(ncWp@Ce<+Ef*F0ypZD{&fS;#K#qyE0TQ=kDUv#rqW=D2ZZ+&_oRzyx>3aI~>JWG-+d{LSIz#~5^T>>wjBA({c+H4!<*006=Z0{lO{4*Q#u|Mvy? z|H5N`RYoQHzY1{`?lZQ*9Di4czf*t3`R?nMkU6Sat26ciP8XIQ5~pKyR}xS;as1_P zn87Ta>NJN>6`E7)bYcJ))gx%Wd}X(1ya7yHR%7{QBcmDy&;hK1EkL{{$Dg}tx%Aw$UYhTHN4sEm6zOI%#}M4g>%uo_2?$(%7z4@q#y!?wPT)%&K6c))cN9dKtW( zv=Sx;tGxly7jxG6#+7yuKHI+XXfaBI0W>Uy9NgI?`Pe00$nY{Tay|h7XF_wLBtOY? gG4+5`|NVz@pu8p!@g}C5oOnD5c3WQqqjo>!Px$g&&Hw-a diff --git a/src/YaoPlots.jl b/src/YaoPlots.jl index da453d4..8b82aaa 100644 --- a/src/YaoPlots.jl +++ b/src/YaoPlots.jl @@ -2,8 +2,14 @@ module YaoPlots using Yao import Luxor +import Thebes +using Luxor: @layer, Point +using Thebes: Point3D, project +using Yao.YaoBlocks.DocStringExtensions +using LinearAlgebra: tr export CircuitStyles, CircuitGrid, circuit_canvas, vizcircuit, darktheme!, lighttheme! +export bloch_sphere, BlochStyles export plot plot(;kwargs...) = x->plot(x;kwargs...) @@ -11,5 +17,6 @@ plot(blk::AbstractBlock; kwargs...) = vizcircuit(blk; kwargs...) include("helperblock.jl") include("vizcircuit.jl") +include("bloch.jl") end diff --git a/src/bloch.jl b/src/bloch.jl new file mode 100644 index 0000000..1f2ab3c --- /dev/null +++ b/src/bloch.jl @@ -0,0 +1,254 @@ +module BlochStyles + using Luxor + # generic config + const lw = Ref(1.0) + const textsize = Ref(16.0) + const fontfamily = Ref("monospace") + const background_color = Ref("transparent") + const color = Ref("#000000") + + # bloch sphere config + const ball_size = Ref(100) + const dot_size = Ref(3) + const eye_point = Ref((500, 200, 200)) + + # axes config + const axes_lw = Ref(1.0) + const axes_colors = ["#000000", "#000000", "#000000"] + const axes_texts = ["x", "y", "z"] + + # state display config + const show_projection_lines = Ref(false) + const show_angle_texts = Ref(false) + const show_line = Ref(true) + const show01 = Ref(false) +end + +""" +$TYPEDSIGNATURES + +Draw a bloch sphere, with the inputs being a list of `string => state` pairs, +where the string is a label for the state and a state can be a complex vector of size 2, a Yao register or `DensityMatrix`. +If you want to get a raw drawing, use `draw_bloch_sphere` instead. + +### Keyword Arguments +Note: The default values can be specified in submodule `BlochStyles`. + +- `textsize`: the size of the text +- `color`: the color of the drawing +- `drawing_size`: the size of the drawing +- `offset_x`: the offset of the drawing in x direction +- `offset_y`: the offset of the drawing in y direction +- `filename`: the filename of the output file, if not specified, a temporary file will be used +- `format`: the format of the output file, if not specified, the format will be inferred from the filename +- `fontfamily`: the font family of the text +- `background_color`: the background color of the drawing +- `lw`: the line width of the drawing +- `eye_point`: the eye point of the drawing +- `extra_kwargs`: extra keyword arguments passed to `draw_bloch_sphere` + - `dot_size`: the size of the dot + - `ball_size`: the size of the ball + - `show_projection_lines`: whether to show the projection lines + - `show_angle_texts`: whether to show the angle texts + - `show_line`: whether to show the line + - `show01`: whether to show the 0 and 1 states + - `colors`: the colors of the states + - `axes_lw`: the line width of the axes + - `axes_textsize`: the size of the axes texts + - `axes_colors`: the colors of the axes + - `axes_texts`: the texts of the axes + +### Examples + +```jldoctest +julia> using YaoPlots, Yao, Luxor + +julia> bloch_sphere("|ψ⟩"=>rand_state(1), "ρ"=>density_matrix(rand_state(2), 1)); +``` +""" +function bloch_sphere(states...; + textsize=BlochStyles.textsize[], + color = BlochStyles.color[], + drawing_size = 500, + offset_x = 0, + offset_y = 0, + filename = nothing, + format = :svg, + fontfamily = BlochStyles.fontfamily[], + background_color = BlochStyles.background_color[], + lw = BlochStyles.lw[], + eye_point = BlochStyles.eye_point[], + extra_kwargs...) + + # file format + if filename === nothing + if format == :pdf + _format = tempname()*".pdf" + else + _format = format + end + else + _format = filename + end + # Set up the drawing canvas + Luxor.Drawing(drawing_size, drawing_size, _format) + Luxor.origin(drawing_size/2 + offset_x, drawing_size/2 + offset_y) + Luxor.background(background_color) + Luxor.sethue(color) + Luxor.fontsize(textsize) + fontfamily !== nothing && Luxor.fontface(fontfamily) + Luxor.setline(lw) + Thebes.eyepoint(eye_point...) + + draw_bloch_sphere(states...; eye_point, extra_kwargs...) + + # Save the drawing to a file + Luxor.finish() + Luxor.preview() +end + +# draw bloch sphere at the origin +function draw_bloch_sphere(states::Pair{<:AbstractString}...; + dot_size=BlochStyles.dot_size[], + ball_size=BlochStyles.ball_size[], + eye_point=BlochStyles.eye_point[], + show_projection_lines = BlochStyles.show_projection_lines[], + show_angle_texts = BlochStyles.show_angle_texts[], + show_line = BlochStyles.show_line[], + show01 = BlochStyles.show01[], + colors = fill(BlochStyles.color[], length(states)), + extra_kwargs... + ) + # get coordinate of a state + getcoo(x) = Point3D(ball_size .* state_to_cartesian(x)) + + # ball + Luxor.circle(Point(0, 0), ball_size, :stroke) + + # equator + nstep = 100 + equator_points = map(LinRange(0, 2π*(1-1/nstep), nstep)) do ϕ + project(Point3D(ball_size .* polar_to_cartesian(1.0, π/2, ϕ))) + end + Luxor.line.(equator_points[1:2:end], equator_points[2:2:end], :stroke) + + # show axes + axes3D(ball_size*3 ÷ 2; extra_kwargs...) + + # show 01 states + if show01 + for (txt, point) in [("|0⟩", [1, 0.0im]), ("|1⟩", [0.0im, 1])] + p = getcoo(point) + @layer begin + Luxor.sethue(BlochStyles.color[]) + if Thebes.distance(Point3D(0, 0, 0), Point3D(eye_point...)) < Thebes.distance(p, Point3D(eye_point...)) + Luxor.setopacity(0.3) + end + show_point(txt, project(p); dot_size, text_offset=Point(10, 0), show_line=false) + end + end + end + + # show points + for ((txt, point), color) in zip(states, colors) + p = getcoo(point) + @layer begin + Luxor.sethue(color) + if Thebes.distance(Point3D(0, 0, 0), Point3D(eye_point...)) < Thebes.distance(p, Point3D(eye_point...)) + Luxor.setopacity(0.3) + end + show_point(txt, project(p); dot_size, text_offset=Point(10, 0), show_line=show_line) + end + if show_projection_lines + # show θ + ratio = 0.2 + sz = project(Point3D(0, 0, ball_size*ratio)) + if show_angle_texts + Luxor.move(sz) + Luxor.arc2r(Point(0, 0), sz, project(p) * ratio, :stroke) + Luxor.text("θ", sz - Point(0, ball_size*0.07)) + end + # show equator projection and ϕ + equatorp = Point3D(p[1], p[2], 0) + sx = project(Point3D(ball_size*ratio, 0, 0)) + + if show_angle_texts + Luxor.move(sx) + Luxor.carc2r(Point(0, 0), sx, project(equatorp) * ratio, :stroke) + Luxor.text("ϕ", sx - Point(ball_size*0.12, 0)) + end + + @layer begin + Luxor.setdash("dot") + Luxor.setline(1) + Luxor.line(project(p), project(equatorp), :stroke) + Luxor.line(Point(0, 0), project(equatorp), :stroke) + end + end + end +end + +function show_point(txt, p; dot_size, text_offset, show_line) + Luxor.circle(p, dot_size, :fill) + Luxor.text(txt, p + text_offset) + show_line && Luxor.line(Point(0, 0), p, :stroke) +end + +function polar_to_cartesian(r, θ, ϕ) + x = r * sin(θ) * cos(ϕ) + y = r * sin(θ) * sin(ϕ) + z = r * cos(θ) + return x, y, z +end + +function cartesian_to_polar(x, y, z) + r = sqrt(x^2 + y^2 + z^2) + θ = acos(z/r) + ϕ = atan(y, x) + return r, θ, ϕ +end + +function state_to_polar(state::AbstractVector{Complex{T}}) where T + @assert length(state) == 2 + r = norm(state) + ϕ = iszero(state[1]) ? zero(T) : angle(state[2]/state[1]) + θ = 2 * atan(abs(state[2]), abs(state[1])) + return r, θ, ϕ +end +state_to_cartesian(state) = polar_to_cartesian(state_to_polar(state)...) + +# Draw labelled 3D axes with length `n`. +function axes3D(n::Int; + axes_lw = BlochStyles.axes_lw[], + axes_textsize = BlochStyles.textsize[], + axes_colors = BlochStyles.axes_colors, + axes_texts = BlochStyles.axes_texts, + ) + @layer begin + Luxor.fontsize(axes_textsize) + Luxor.setline(axes_lw) + for i = 1:3 + axis1 = project(Point3D(0.1, 0.1, 0.1)) + axis2 = [0.1, 0.1, 0.1] + axis2[i] = n + axis2 = project(Point3D(axis2...)) + Luxor.sethue(axes_colors[i]) + if (axis1 !== nothing) && (axis2 !== nothing) && !isapprox(axis1, axis2) + Luxor.arrow(axis1, axis2) + Luxor.label(axes_texts[i], :N, axis2, offset=10) + end + end + end +end + +# Interace to Yao +function state_to_polar(reg::AbstractRegister{2}) + @assert nqudits(reg) == 1 "Only single qubit register is allowed to plot on bloch sphere. If you want to plot a subsystem as a mixed state, please construct a density matrix first with `density_matrix`." + @assert nbatch(reg) == 1 || nbatch(reg) == Yao.NoBatch() "Only single batch register is allowed to plot on bloch sphere." + return state_to_polar(statevec(reg)) +end + +function state_to_cartesian(reg::DensityMatrix{2}) + @assert nqudits(reg) == 1 "Only single qubit density matrix is allowed to plot on bloch sphere" + return real(tr(reg.state * mat(X))), real(tr(reg.state * mat(Y))), real(tr(reg.state * mat(Z))) +end diff --git a/src/vizcircuit.jl b/src/vizcircuit.jl index fbe77a7..08476eb 100644 --- a/src/vizcircuit.jl +++ b/src/vizcircuit.jl @@ -499,9 +499,13 @@ vizcircuit(; kwargs...) = c->vizcircuit(c; kwargs...) function darktheme!() const CircuitStyles.linecolor[] = "#FFFFFF" const CircuitStyles.textcolor[] = "#FFFFFF" + const BlochStyles.color[] = "#FFFFFF" + BlochStyles.axes_colors .= ["#FFFFFF", "#FFFFFF", "#FFFFFF"] end function lighttheme!() const CircuitStyles.linecolor[] = "#000000" const CircuitStyles.textcolor[] = "#000000" + const BlochStyles.color[] = "#000000" + BlochStyles.axes_colors .= ["#000000", "#000000", "#000000"] end diff --git a/test/bloch.jl b/test/bloch.jl new file mode 100644 index 0000000..39c487c --- /dev/null +++ b/test/bloch.jl @@ -0,0 +1,42 @@ +using YaoPlots, Test +using LinearAlgebra: normalize!, eigen +using Luxor: Drawing +using Yao + +@testset "spherical coo" begin + for i=1:10 + x = randn(3) + @test collect(YaoPlots.polar_to_cartesian(YaoPlots.cartesian_to_polar(x...)...)) ≈ x + end +end + +@testset "state to polar" begin + nx, ny, nz = normalize!(randn(3)) + sigma = nx * X + ny * Y + nz * Z + m = Matrix(sigma) + E, U = eigen(m) + @test collect(YaoPlots.state_to_cartesian(U[:, 2])) ≈ [nx, ny, nz] + @test collect(YaoPlots.state_to_cartesian(U[:, 1])) ≈ -[nx, ny, nz] + + reg = rand_state(1) + @test collect(YaoPlots.state_to_cartesian(reg)) ≈ collect(YaoPlots.state_to_cartesian(density_matrix(reg))) +end + +@testset "bloch" begin + @test bloch_sphere("|ψ⟩"=>[2.2, 0.3im+0.3]; show_projection_lines=true, + show_angle_texts=true, show_line=true, show01=true) isa Drawing + # dark theme + darktheme!() + @test bloch_sphere("|ψ⟩"=>[2.2, 0.3im+0.3]; show_projection_lines=true, + show_angle_texts=true, show_line=true, show01=true) isa Drawing +end + +@testset "draw reg" begin + @test bloch_sphere("|ψ⟩"=>rand_state(1)) isa Drawing +end + +@testset "draw density matrix" begin + rho = density_matrix(rand_state(2), 1) + @test bloch_sphere("ρ"=>rho) isa Drawing + bloch_sphere("|ψ⟩"=>rand_state(1), "ρ"=>density_matrix(rand_state(2), 1)) +end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index 666ad66..27a917f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,4 +7,8 @@ end @testset "vizcircuit" begin include("vizcircuit.jl") +end + +@testset "bloch" begin + include("bloch.jl") end \ No newline at end of file From ca6558b452f59928f31374dd729c703651505f18 Mon Sep 17 00:00:00 2001 From: GiggleLiu Date: Sun, 29 Oct 2023 00:41:27 +0800 Subject: [PATCH 2/2] update README --- README.md | 13 +++++++++++++ examples/bloch.jl | 3 +-- examples/bloch.png | Bin 0 -> 8949 bytes examples/constgates.png | Bin 16573 -> 5693 bytes examples/mesolve.png | Bin 0 -> 13556 bytes src/bloch.jl | 2 +- 6 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 examples/bloch.png create mode 100644 examples/mesolve.png diff --git a/README.md b/README.md index 3602de8..ec5d9cd 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,19 @@ If you are using a Pluto/Jupyter notebook, Atom/VSCode editor, you should see th ![qft](examples/qft.png) +## Example 2: Visualize a single qubit +```julia +using YaoPlots, Yao + +reg = zero_state(1) |> Rx(π/8) |> Rx(π/8) +rho = density_matrix(ghz_state(2), 1) + +bloch_sphere("|ψ⟩"=>reg, "ρ"=>rho; show_projection_lines=true) +``` + +Similarly, you will see +![bloch](examples/bloch.png) + See more [examples](examples/circuits.jl). ### Adjusting the plot attributes diff --git a/examples/bloch.jl b/examples/bloch.jl index afde3ef..3ad1e12 100644 --- a/examples/bloch.jl +++ b/examples/bloch.jl @@ -46,10 +46,9 @@ function simulate(t; dt=0.02, dissiplation=0.2, filename=nothing) states = ["|+⟩"=>rho] for t = 0:dt:t rho = mestep(rho, h, Ls, dt) - @show sum(abs2, rho.state - rho.state') push!(states, ""=>rho) end return bloch_sphere(states...; filename) end -simulate(π/2; filename=joinpath(@__DIR__, "constgates.png")) \ No newline at end of file +simulate(π/2; filename=joinpath(@__DIR__, "mesolve.png")) \ No newline at end of file diff --git a/examples/bloch.png b/examples/bloch.png new file mode 100644 index 0000000000000000000000000000000000000000..babf07b656c65a359c2522206a213935285050fc GIT binary patch literal 8949 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 SM^MkP04z*xOe&2$pZpI=J!Uun literal 0 HcmV?d00001 diff --git a/examples/constgates.png b/examples/constgates.png index 555a69bdda1eb6ccef6232b8b3df7f6eeeb044aa..2e618cefa2b1276d5b410cef1fb793b2e7165ed5 100644 GIT binary patch literal 5693 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 z h%ibppU3r#dg&Y6$Eg`j!KxiAG0)yitLRg zJ|ti<2XTw(qS~9?%Yl4id-mBZ`_FDSq7NB9KMvxVtm{Vwiqxl2(ou)^`q*KTLOG{z zB>q|CnmUXcwZh|+u*jE60}`f&pH3ri{-rm@NfQlsI#`8|(Csu2{VQblsussH_8hhr z-N!0;a)m)oWsqog(f^)1pNi%#%`Lu_-~>TCkTjZE1~0co zkKz%_yViO3KBj##Bb1!;^g17*^S1~D9d401ej&VIJ%cd3j}DcUjBHGJOitOrppRHt z4U&+B=%5tii_U_!GoZM0pf~_nM%u0ZA`9G-yWMA*scR`dhp<0--UfmB3yCL^()$L= zy$0J^mC2|8{=7ILaa5%=F{;@g+dox1$$J-=tCFH+r!_UnbnF|5*8c zpGNJNN*6vCef*|BDY&k-h5NtPy#EP}2213BH5|pG{u+Tw`Y~moUJn2&>~&Ht?UeNn zupB?1-Ah3}qXASdS#g230ywn@kJh^|^HaLn7cv;WogI_{vNXXiX;}HS#>~Ic>4q>* zmSDG@O8?`&3C|2pY5Y)i`twSmhW?XWMIO{a>%E*hCC z`p_(J0=>TpwEU5+jNszp%1lm6OY`cF`3sp&q?3)+7E|Q%l89gc#~Cafb7ezA!yNF4 z3k&P&>N2siDx+uSc-4A=gG0fvN<((V-X;m35Lvl?pAw=`5lgcwCa9)sXc!+A6{Xhv zjM8Hg7}yAMkV|DIeHz3L89Pdd{e51#3D})W`tv7=UVB@Kc$eY2%jRZnfKTjMsMIfu zDyO77G2F9A+1!EM(KQzs4J?R5@gjunSRWWX;+Ky0-oZhkUOLB;PC!&+V7(BD9Uf{c zcgM(%iIUw@jrQB=Pu})<3@*Z#q}{y2UhrGXww;eFj?Td1aK!MDlJXVH&6*!J(nprq zrtZ9seOEp`aJ#Xn$bFTUTK>L!qAL~Ed43eC6pT4G=e*i$MGc%9Br83MhW7y|RQ?qw z#nUVDx*`{Z?pP&(mYdhp{E-z2sshJ0a9nAX|1f6%I+JDUv%<+w{jXW1Vq#(}nga3t z16mrlykQQ)FU^hx-x5@R%~19x@yZ@kyqSb6USw{3VtVa7fqDFR-ukV8Hk*rkIcUET zvX9*WWN&mW7(K{n(|r7mQL1Mf@_8;Db%V`^=Qx~ysU1<*{cW#Zziwh~J_mv#5F8C| zv~7n?w|=lKGx7giUj7?-@pm^(e@i3kQylGTr98@!{zyq+&VgZp7Fgv}V=>A<=I&G$ z)+3`nej(ncWp@Ce<+Ef*F0ypZD{&fS;#K#qyE0TQ=kDUv#rqW=D2ZZ+&_oRzyx>3aI~>JWG-+d{LSIz#~5^T>>wjBA({c+H4!<*006=Z0{lO{4*Q#u|Mvy? z|H5N`RYoQHzY1{`?lZQ*9Di4czf*t3`R?nMkU6Sat26ciP8XIQ5~pKyR}xS;as1_P zn87Ta>NJN>6`E7)bYcJ))gx%Wd}X(1ya7yHR%7{QBcmDy&;hK1EkL{{$Dg}tx%Aw$UYhTHN4sEm6zOI%#}M4g>%uo_2?$(%7z4@q#y!?wPT)%&K6c))cN9dKtW( zv=Sx;tGxly7jxG6#+7yuKHI+XXfaBI0W>Uy9NgI?`Pe00$nY{Tay|h7XF_wLBtOY? gG4+5`|NVz@pu8p!@g}C5oOnD5c3WQqqjo>!Px$g&&Hw-a literal 16573 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 diff --git a/examples/mesolve.png b/examples/mesolve.png new file mode 100644 index 0000000000000000000000000000000000000000..87da785f1fb5a97a004c107042a437671852a8a2 GIT binary patch literal 13556 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 bloch_sphere("|ψ⟩"=>rand_state(1), "ρ"=>density_matrix(rand_state(2), function bloch_sphere(states...; textsize=BlochStyles.textsize[], color = BlochStyles.color[], - drawing_size = 500, + drawing_size = 300, offset_x = 0, offset_y = 0, filename = nothing,