Skip to content

Commit e766aff

Browse files
committed
improve Bloch sphere code structure and docs
1 parent 47deb2c commit e766aff

File tree

5 files changed

+208
-233
lines changed

5 files changed

+208
-233
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- Introduce `Lanczos` solver for `spectrum`. ([#476])
1111
- Add Bloch-Redfield master equation solver. ([#473])
12-
- Implement Bloch Sphere rendering. ([#472])
12+
- Implement Bloch Sphere rendering and align style with qutip. ([#472], [#480])
1313

1414
## [v0.31.1]
1515
Release date: 2025-05-16

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
1212
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
1313
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
1414
IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
15+
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
1516
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1617
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
1718
OrdinaryDiffEqCore = "bbf590c4-e513-4bbe-9b18-05decba2e5d8"
@@ -51,6 +52,7 @@ GPUArrays = "10, 11"
5152
Graphs = "1.7"
5253
IncompleteLU = "0.2"
5354
KernelAbstractions = "0.9.2"
55+
LaTeXStrings = "1.2"
5456
LinearAlgebra = "1"
5557
LinearSolve = "2, 3"
5658
Makie = "0.20, 0.21, 0.22"

ext/QuantumToolboxMakieExt.jl

Lines changed: 12 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
module QuantumToolboxMakieExt
22

33
using QuantumToolbox
4-
using LinearAlgebra: cross, deg2rad, normalize, size
5-
using Makie:
4+
import QuantumToolbox: _state_to_bloch
5+
6+
import LinearAlgebra: cross, deg2rad, normalize, size
7+
import Makie:
68
Axis,
79
Axis3,
810
Colorbar,
@@ -315,66 +317,6 @@ raw"""
315317
"""
316318
_figFromChildren(::Nothing) = throw(ArgumentError("No Figure has been found at the top of the layout hierarchy."))
317319

318-
raw"""
319-
_state_to_bloch(state::QuantumObject{<:Ket}) -> Vector{Float64}
320-
321-
Convert a pure qubit state (`Ket`) to its Bloch vector representation.
322-
323-
If the state is not normalized, it is automatically normalized before conversion.
324-
325-
# Arguments
326-
- `state`: A `Ket` representing a pure quantum state.
327-
328-
# Returns
329-
A 3-element `Vector{Float64}` representing the Bloch vector `[x, y, z]`.
330-
331-
# Throws
332-
- `ArgumentError` if the state dimension is not 2.
333-
"""
334-
function _state_to_bloch(state::QuantumObject{<:Ket})
335-
if !isapprox(norm(state), 1.0, atol = 1e-6)
336-
@warn "State is not normalized. Normalizing before Bloch vector conversion."
337-
state = normalize(state)
338-
end
339-
ψ = state.data
340-
if length(ψ) != 2
341-
error("Bloch sphere visualization is only supported for qubit states (2-level systems)")
342-
end
343-
x = 2 * real(ψ[1] * conj(ψ[2]))
344-
y = 2 * imag(ψ[1] * conj(ψ[2]))
345-
z = abs2(ψ[1]) - abs2(ψ[2])
346-
return [x, y, z]
347-
end
348-
349-
raw"""
350-
_dm_to_bloch(ρ::QuantumObject{<:Operator}) -> Vector{Float64}
351-
352-
Convert a qubit density matrix (`Operator`) to its Bloch vector representation.
353-
354-
This function assumes the input is Hermitian. If the density matrix is not Hermitian, a warning is issued.
355-
356-
# Arguments
357-
- `ρ`: A density matrix (`Operator`) representing a mixed or pure quantum state.
358-
359-
# Returns
360-
A 3-element `Vector{Float64}` representing the Bloch vector `[x, y, z]`.
361-
362-
# Throws
363-
- `ArgumentError` if the matrix dimension is not 2.
364-
"""
365-
function _dm_to_bloch::QuantumObject{<:Operator})
366-
if !ishermitian(ρ)
367-
@warn "Density matrix is not Hermitian. Results may not be meaningful."
368-
end
369-
if size(ρ, 1) != 2
370-
error("Bloch sphere visualization is only supported for qubit states (2-level systems)")
371-
end
372-
x = real(ρ[1, 2] + ρ[2, 1])
373-
y = imag(ρ[2, 1] - ρ[1, 2])
374-
z = real(ρ[1, 1] - ρ[2, 2])
375-
return [x, y, z]
376-
end
377-
378320
function _render_bloch_makie(bloch_vec::Vector{Float64}; location = nothing, kwargs...)
379321
b = Bloch()
380322
add_vectors!(b, bloch_vec)
@@ -384,97 +326,21 @@ function _render_bloch_makie(bloch_vec::Vector{Float64}; location = nothing, kwa
384326
end
385327

386328
@doc raw"""
387-
add_line!(
388-
b::QuantumToolbox.Bloch,
389-
start_point_point::QuantumToolbox.QuantumObject{<:Union{QuantumToolbox.Ket, QuantumToolbox.Bra, QuantumToolbox.Operator}},
390-
end_point::QuantumToolbox.QuantumObject{<:Union{QuantumToolbox.Ket, QuantumToolbox.Bra, QuantumToolbox.Operator}};
391-
fmt = "k"
392-
)
329+
render(b::Bloch; location=nothing)
393330
394-
Add a line between two quantum states or operators on the Bloch sphere visualization.
331+
Render the Bloch sphere visualization from the given [`Bloch`](@ref) object `b`.
395332
396333
# Arguments
397334
398-
- `b::Bloch`: The Bloch sphere object to modify.
399-
- `start_point_point::QuantumObject`: The start_point_pointing quantum state or operator. Can be a `Ket`, `Bra`, or `Operator`.
400-
- `end_point::QuantumObject`: The ending quantum state or operator. Can be a `Ket`, `Bra`, or `Operator`.
401-
- `fmt::String="k"`: (optional) A format string specifying the line style and color (default is black `"k"`).
402-
403-
# Description
404-
405-
This function converts the given quantum objects (states or operators) into their Bloch vector representations and adds a line between these two points on the Bloch sphere visualization.
406-
407-
# Example
408-
409-
```julia
410-
b = Bloch()
411-
ψ₁ = normalize(basis(2, 0) + basis(2, 1))
412-
ψ₂ = normalize(basis(2, 0) - im * basis(2, 1))
413-
add_line!(b, ψ₁, ψ₂; fmt = "r--")
414-
```
415-
"""
416-
function QuantumToolbox.add_line!(
417-
b::Bloch,
418-
p1::QuantumObject{<:Union{Ket,Bra,Operator}},
419-
p2::QuantumObject{<:Union{Ket,Bra,Operator}};
420-
fmt = "k",
421-
)
422-
coords1 = isket(p1) || isbra(p1) ? _state_to_bloch(p1) : _dm_to_bloch(p1)
423-
coords2 = isket(p2) || isbra(p2) ? _state_to_bloch(p2) : _dm_to_bloch(p2)
424-
return add_line!(b, coords1, coords2; fmt = fmt)
425-
end
426-
427-
@doc raw"""
428-
QuantumToolbox.add_states!(b::Bloch, states::QuantumObject...)
429-
430-
Add one or more quantum states to the Bloch sphere visualization by converting them into Bloch vectors.
431-
432-
# Arguments
433-
- `b::Bloch`: The Bloch sphere object to modify
434-
- `states::QuantumObject...`: One or more quantum states (Ket, Bra, or Operator)
435-
436-
# Example
437-
438-
```julia
439-
x = basis(2, 0) + basis(2, 1);
440-
y = basis(2, 0) - im * basis(2, 1);
441-
z = basis(2, 0);
442-
b = Bloch();
443-
add_states!(b, [x, y, z])
444-
```
445-
"""
446-
function QuantumToolbox.add_states!(b::Bloch, states::Vector{<:QuantumObject})
447-
vecs = map(states) do state
448-
if isket(state) || isbra(state)
449-
return _state_to_bloch(state)
450-
else
451-
return _dm_to_bloch(state)
452-
end
453-
end
454-
append!(b.vectors, [normalize(v) for v in vecs])
455-
return b.vectors
456-
end
457-
458-
@doc raw"""
459-
render(b::QuantumToolbox.Bloch; location=nothing)
460-
461-
Render the Bloch sphere visualization from the given `Bloch` object `b`.
462-
463-
# Arguments
464-
465-
- `b::QuantumToolbox.Bloch`
466-
The Bloch sphere object containing states, vectors, and settings to visualize.
467-
468-
- `location` (optional)
469-
Specifies where to display or save the rendered figure.
335+
- `b::Bloch`: The Bloch sphere object containing states, vectors, and settings to visualize.
336+
- `location`: Specifies where to display or save the rendered figure.
470337
- If `nothing` (default), the figure is displayed interactively.
471338
- If a file path (String), the figure is saved to the specified location.
472339
- Other values depend on backend support.
473340
474341
# Returns
475342
476-
- A tuple `(fig, axis)` where `fig` is the figure object and `axis` is the axis object used for plotting.
477-
These can be further manipulated or saved by the user.
343+
- A tuple `(fig, axis)` where `fig` is the figure object and `axis` is the axis object used for plotting. These can be further manipulated or saved by the user.
478344
"""
479345
function QuantumToolbox.render(b::Bloch; location = nothing)
480346
fig, ax = _setup_bloch_plot!(b, location)
@@ -859,46 +725,20 @@ function _add_labels!(b::Bloch, ax)
859725
end
860726

861727
@doc raw"""
862-
plot_bloch(::Val{:Makie}, state::QuantumObject{<:Union{Ket,Bra}}; kwargs...)
728+
plot_bloch(::Val{:Makie}, state::QuantumObject; kwargs...)
863729
864730
Plot a pure quantum state on the Bloch sphere using the `Makie` backend.
865731
866732
# Arguments
867-
- `state::QuantumObject{<:Union{Ket,Bra}}`: The quantum state to be visualized (`ket` or `bra`).
733+
- `state::QuantumObject{<:Union{Ket,Bra}}`: The quantum state ([`Ket`](@ref), [`Bra`](@ref), or [`Operator`](@ref)) to be visualized.
868734
- `kwargs...`: Additional keyword arguments passed to `_render_bloch_makie`.
869735
870-
# Details
871-
872-
Converts the state to its Bloch vector representation and renders it on the Bloch sphere.
873-
If the input is a bra, it is automatically converted to a ket before processing.
874-
875736
!!! note "Internal function"
876737
This is the `Makie`-specific implementation called by the main `plot_bloch` function.
877738
"""
878-
function QuantumToolbox.plot_bloch(::Val{:Makie}, state::QuantumObject{<:Union{Ket,Bra}}; kwargs...)
879-
state = isbra(state) ? state' : state
739+
function QuantumToolbox.plot_bloch(::Val{:Makie}, state::QuantumObject{OpType}; kwargs...) where {OpType<:Union{Ket,Bra,Operator}}
880740
bloch_vec = _state_to_bloch(state)
881741
return _render_bloch_makie(bloch_vec; kwargs...)
882742
end
883743

884-
@doc raw"""
885-
plot_bloch(::Val{:Makie}, ρ::QuantumObject{<:Operator}; kwargs...)
886-
887-
Plot a density matrix on the Bloch sphere using the Makie backend.
888-
889-
# Arguments
890-
- `ρ::QuantumObject{<:Operator}`: The density matrix to be visualized.
891-
- `kwargs...`: Additional keyword arguments passed to `_render_bloch_makie`.
892-
893-
# Details
894-
Converts the density matrix to its Bloch vector representation and renders it on the Bloch sphere.
895-
896-
!!! note "Internal function"
897-
This is the Makie-specific implementation called by the main `plot_bloch` function.
898-
"""
899-
function QuantumToolbox.plot_bloch(::Val{:Makie}, ρ::QuantumObject{<:Operator}; kwargs...)
900-
bloch_vec = _dm_to_bloch(ρ)
901-
return _render_bloch_makie(bloch_vec; kwargs...)
902-
end
903-
904744
end

src/QuantumToolbox.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import Distributed: RemoteChannel
5858
import FFTW: fft, ifft, fftfreq, fftshift
5959
import Graphs: connected_components, DiGraph
6060
import IncompleteLU: ilu
61+
import LaTeXStrings: @L_str
6162
import Pkg
6263
import Random: AbstractRNG, default_rng, seed!
6364
import SpecialFunctions: loggamma

0 commit comments

Comments
 (0)