Skip to content

Add StateVectorRepr backend with tests and documentation #120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 29 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ff40438
Update QuantumOpticsExt.jl
phantmgx May 29, 2025
4fa4eba
Add test_statevectorrepr.jl for StateVectorRepr tests
phantmgx May 30, 2025
3cb77e2
Update test_statevectorrepr.jl to use @testitem
phantmgx May 30, 2025
72622a9
Update index.md
phantmgx May 30, 2025
e9ec426
Add QuantumOptics as a weak dependency for QuantumOpticsExt
phantmgx May 30, 2025
1188360
Update CHANGELOG.md
phantmgx May 30, 2025
fac7b79
Fix UndefVarError by replacing AbstractSymbolic with AbstractQuantumO…
phantmgx May 30, 2025
119d511
Fix UndefVarError by replacing AbstractQuantumObject with SymbolicUti…
phantmgx May 30, 2025
952b77e
using SymbolicUtils
phantmgx May 30, 2025
77f30db
Update Project.toml
phantmgx May 30, 2025
125b52e
Update Project.toml
phantmgx May 30, 2025
ff4475b
Update Project.toml
phantmgx May 30, 2025
c0e0cb9
Update Project.toml
phantmgx May 30, 2025
e1d79c8
Update Project.toml
phantmgx May 30, 2025
eed6db7
Update Project.toml
phantmgx May 31, 2025
594d0bc
Update QuantumOpticsExt.jl
phantmgx May 31, 2025
e60a229
Update Project.toml
phantmgx May 31, 2025
372a768
Update Project.toml
phantmgx May 31, 2025
d21161f
Update Project.toml
phantmgx May 31, 2025
a388036
Update Project.toml
phantmgx May 31, 2025
e5263b7
Update ci.yml
phantmgx May 31, 2025
9b9f248
Update Project.toml
phantmgx May 31, 2025
e7365f3
Update ci.yml
phantmgx May 31, 2025
d63df5c
Update Project.toml
phantmgx May 31, 2025
175d5c3
Update Project.toml
phantmgx May 31, 2025
c524dde
Update Project.toml
phantmgx May 31, 2025
cc78eb5
Update ci-julia-nightly.yml
phantmgx May 31, 2025
808a8eb
Update downgrade.yml
phantmgx May 31, 2025
3d2d507
Update ci-julia-nightly.yml
phantmgx May 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/ci-julia-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ jobs:
with:
channel: ${{ matrix.version }}~${{ matrix.arch }}
- uses: julia-actions/cache@v2

# --- START OF ADDED/MODIFIED BLOCK ---
- name: Update Julia Registries (Aggressive)
run: |
julia -e 'import Pkg; Pkg.Registry.rm("General"); Pkg.Registry.add("General"); Pkg.Registry.update()'
# --- END OF ADDED/MODIFIED BLOCK ---

- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
env:
Expand All @@ -47,4 +54,4 @@ jobs:
- uses: codecov/codecov-action@v5
with:
file: lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ jobs:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: julia-actions/cache@v2
# --- MODIFIED STEP TO UPDATE JULIA REGISTRIES (AGGRESSIVE) ---
- name: Update Julia Registries (Aggressive)
run: |
julia -e 'import Pkg; Pkg.Registry.rm("General"); Pkg.Registry.add("General"); Pkg.Registry.update()'
# --- END OF MODIFIED STEP ---
- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
env:
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/downgrade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,12 @@ jobs:
with:
skip: Pkg,TOML,InteractiveUtils,Random,LinearAlgebra
- uses: julia-actions/cache@v2


- name: Update Julia Registries (Aggressive)
run: |
julia -e 'import Pkg; Pkg.Registry.rm("General"); Pkg.Registry.add("General"); Pkg.Registry.update()'


- uses: julia-actions/julia-buildpkg@v1
- uses: julia-actions/julia-runtest@v1
- uses: julia-actions/julia-runtest@v1
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# News

## [Unreleased]
### Added
- New `StateVectorRepr` backend for converting symbolic quantum objects to numerical vectors/matrices using `QuantumOpticsRepr` (Conversion of symbolic objects to base linear algebra objects (vectors, matrices, sparse matrices, etc)) (#118).

## v0.4.10 - 2025-05-11

- Polish `Base.show` methods for application products and scaled quantum objects.
Expand Down
4 changes: 2 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ QuantumOpticsBase = "4f57444f-1401-5e15-980d-4471b28d5678"

[extensions]
MixedCliffordOpticsExt = ["QuantumClifford", "QuantumOpticsBase"]
QuantumCliffordExt = "QuantumClifford"
QuantumOpticsExt = "QuantumOpticsBase"
QuantumCliffordExt = ["QuantumClifford"]
QuantumOpticsExt = ["QuantumOpticsBase"]

[compat]
Latexify = "0.16"
Expand Down
15 changes: 15 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,18 @@ express(MixedState(X1)/2+SProjector(Z1)/2, CliffordRepr())
!!! warning "Stabilizer state expressions"

The state written as $\frac{|Z₁⟩⊗|Z₁⟩+|Z₂⟩⊗|Z₂⟩}{√2}$ is a well known stabilizer state, namely a Bell state. However, automatically expressing it as a stabilizer is a prohibitively expensive computational operation in general. We do not perform that computation automatically. If you want to ensure that states you define can be automatically converted to tableaux for Clifford simulations, avoid using summation of kets. On the other hand, in all of our Clifford Monte-Carlo simulations, `⊗` is fully supported, as well as [`projector`](@ref), [`MixedState`](@ref), [`StabilizerState`](@ref), and summation of density matrices.

## Backends

`QuantumSymbolics.jl` supports multiple numerical backends via the `express` API. In addition to structured representations like `QuantumOpticsRepr` and `CliffordRepr`, the new `StateVectorRepr` backend converts symbolic objects to basic linear algebra objects:

```julia
julia> express(X1, StateVectorRepr())
2-element Vector{ComplexF64}:
0.7071067811865475 + 0.0im
0.7071067811865475 + 0.0im

julia> express(Z1, StateVectorRepr())
2×2 Matrix{ComplexF64}:
1.0+0.0im 0.0+0.0im
0.0+0.0im -1.0+0.0im
27 changes: 27 additions & 0 deletions ext/QuantumOpticsExt/QuantumOpticsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import QuantumSymbolics: express, express_nolookup
using TermInterface
using TermInterface: isexpr, head, operation, arguments, metadata

using SymbolicUtils

const _b2 = SpinBasis(1//2)
const _l0 = spinup(_b2)
const _l1 = spindown(_b2)
Expand Down Expand Up @@ -100,4 +102,29 @@ express_nolookup(s::SOuterKetBra, r::QuantumOpticsRepr) = projector(express(s.ke

include("should_upstream.jl")

"""
StateVectorRepr(config=nothing)

A custom backend for `QuantumSymbolics.express`. Converts symbolic quantum
objects into Julia's `Vector{ComplexF64}` (kets) or `Matrix{ComplexF64}` (operators).

Internally uses `QuantumOptics.QuantumOpticsRepr` and extracts `.data`.
An optional `config` (e.g., `(cutoff=4,)`) is forwarded to `QuantumOptics.QuantumOpticsRepr`.
"""
struct StateVectorRepr
cutoff::Int
StateVectorRepr(cutoff::Int) = new(cutoff)
StateVectorRepr(; cutoff::Int = 0) = new(cutoff)
end

function QuantumSymbolics.express(sym_obj::SymbolicUtils.Symbolic, backend::StateVectorRepr)
qo_repr = if backend.config isa Nothing
QuantumOptics.QuantumOpticsRepr()
else
QuantumOptics.QuantumOpticsRepr(backend.config...)
end
qo_obj = QuantumSymbolics.express(sym_obj, qo_repr)
return qo_obj.data
end

end
13 changes: 12 additions & 1 deletion test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
[deps]
QuantumSavory = "b2e4b478-f7b5-4b07-94a2-11c52b7b515a"
QuantumSymbolics = "efa7fd63-0460-4890-beb7-be1bbdfbaeae"
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
Expand All @@ -9,7 +11,6 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
QuantumClifford = "0525e862-1e90-11e9-3e4d-1b39d7109de1"
QuantumInterface = "5717a53b-5d69-4fa3-b976-0bf2f97ca1e5"
QuantumOptics = "6e0679c1-51ea-5a7c-ac74-d61b76210b0c"
QuantumOpticsBase = "4f57444f-1401-5e15-980d-4471b28d5678"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
Expand All @@ -20,3 +21,13 @@ Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
TermInterface = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"



[compat]
julia = "1"
QuantumSavory = "0.5"
QuantumSymbolics = "0.4"

[targets]
test = ["Test", "TestItemRunner", "QuantumSavory", "QuantumClifford", "QuantumInterface", "QuantumOpticsBase", "SymbolicUtils", "TermInterface"]
37 changes: 37 additions & 0 deletions test/test_statevectorrepr.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using QuantumSymbolics
using QuantumOptics
using QuantumSavory

@testitem "StateVectorRepr Conversion Tests" begin
# Test: Symbolic Ket (X1) conversion
sym_X1_test = QuantumSavory.X1
qo_X1_data = QuantumOptics.express(sym_X1_test, QuantumOptics.QuantumOpticsRepr()).data
sv_X1_data = express(sym_X1_test, StateVectorRepr())
@test sv_X1_data isa Vector{ComplexF64}
@test isapprox(sv_X1_data, qo_X1_data)
@test length(sv_X1_data) == 2

# Test: Symbolic Operator (Z1) conversion
sym_Z1_test = QuantumSavory.Z1
qo_Z1_data = QuantumOptics.express(sym_Z1_test, QuantumOptics.QuantumOpticsRepr()).data
sv_Z1_data = express(sym_Z1_test, StateVectorRepr())
@test sv_Z1_data isa Matrix{ComplexF64}
@test isapprox(sv_Z1_data, qo_Z1_data)
@test size(sv_Z1_data) == (2, 2)

# Test: Product operator (X1 * Y2) conversion
sym_XY_test = QuantumSavory.X1 * QuantumSavory.Y2
qo_XY_data = QuantumOptics.express(sym_XY_test, QuantumOptics.QuantumOpticsRepr()).data
sv_XY_data = express(sym_XY_test, StateVectorRepr())
@test sv_XY_data isa Matrix{ComplexF64}
@test isapprox(sv_XY_data, qo_XY_data)
@test size(sv_XY_data) == (4, 4)

# Test: Bosonic operator (N) with custom cutoff
sym_N_test = QuantumSavory.N
qo_N_cutoff4_data = QuantumOptics.express(sym_N_test, QuantumOptics.QuantumOpticsRepr(cutoff=4)).data
sv_N_cutoff4_data = express(sym_N_test, StateVectorRepr(cutoff=4))
@test sv_N_cutoff4_data isa Matrix{ComplexF64}
@test isapprox(sv_N_cutoff4_data, qo_N_cutoff4_data)
@test size(sv_N_cutoff4_data) == (5, 5)
end
Loading