Skip to content

Support lazy QuantumOptics conversion#201

Open
DennisWayo wants to merge 5 commits into
QuantumSavory:mainfrom
DennisWayo:lazy-quantumoptics-conversion
Open

Support lazy QuantumOptics conversion#201
DennisWayo wants to merge 5 commits into
QuantumSavory:mainfrom
DennisWayo:lazy-quantumoptics-conversion

Conversation

@DennisWayo

@DennisWayo DennisWayo commented Jun 11, 2026

Copy link
Copy Markdown

This PR adds the lazy QuantumOptics conversion side for QuantumOpticsRepr(lazy=true).

It depends on the small interface change in:

qojulia/QuantumInterface.jl#83

The goal is to keep the current eager conversion path unchanged, while allowing callers to preserve expression structure when they explicitly request the lazy representation.

Example:

using QuantumSymbolics
using QuantumInterface
using QuantumOpticsBase: LazySum, LazyProduct, LazyTensor

repr = QuantumOpticsRepr(lazy=true)

express(X + Y + Z, repr) isa LazySum
express(X * (Y + Z), repr) isa LazyProduct
express(X  Y  Z, repr) isa LazyTensor

Behavior added here:

  • symbolic sums are emitted as LazySum;
  • symbolic products are emitted as LazyProduct;
  • symbolic tensor products are emitted as LazyTensor;
  • scalar factors are preserved on the lazy QuantumOptics objects;
  • the normal QuantumOpticsRepr() path still goes through the existing eager conversion behavior.

One implementation detail worth calling out: for tensor products whose factors are themselves lazy composite operators, the factor is materialized before building the LazyTensor. I did this because QuantumOpticsBase expects tensor factors that can be densified reliably. The result still gives a LazyTensor at the top level, while keeping dense(express(..., QuantumOpticsRepr(lazy=true))) consistent with the eager result.

The tests cover the target expression shapes directly:

repr = QuantumOpticsRepr(lazy=true)

@test express(X + 2Y + Z, repr) isa LazySum
@test express(X * (Y + Z), repr) isa LazyProduct
@test express(X  Y  Z, repr) isa LazyTensor
@test dense(express(X  (Y + Z), repr))  express(X  (Y + Z))

Docs were also updated with a short example showing how to request lazy conversion.

Local test command used with the companion interface branch checked out locally:

julia --project=. -e 'using Pkg; Pkg.develop(path="../QuantumInterface.jl"); Pkg.test(test_args=["general"])'

Note: CI for this PR may need the companion QuantumInterface.jl PR available, because QuantumOpticsRepr(lazy=true) is introduced there.

OSS Contributions
PennyLaneAI/pennylane#9566
PennyLaneAI/pennylane#9604
https://www.linkedin.com/posts/activity-7443523751436091392-depM?utm_source=share&utm_medium=member_desktop&rcm=ACoAABfS9T0BJJPP6KT13py3QtCdMEGtOb3Q3PE

AI Use Disclosure: Code syntax was assisted by Codex model. All handwritten code and accompanying text were thoroughly reviewed and verified by me prior to submission. I retain full responsibility for the final contribution.

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Benchmark Results (Julia v1)

Time benchmarks
main b23fbfd... main / b23fbfd...
creation/ket 30 ± 0 ns 30 ± 0 ns 1 ± 0
creation/large_trees/10_layers 0.784 ± 0.022 ms 0.813 ± 0.03 ms 0.964 ± 0.045
creation/large_trees/50_layers 0.0346 ± 0.0045 s 0.0377 ± 0.0043 s 0.918 ± 0.16
creation/op 30 ± 0 ns 30 ± 0 ns 1 ± 0
creation/super_op 30 ± 0 ns 30 ± 0 ns 1 ± 0
express/clifford/simple_ket 1.29 ± 0.06 μs 1.29 ± 0.063 μs 1 ± 0.067
express/clifford/simple_observable 2.31 ± 0.18 μs 2.32 ± 0.21 μs 0.995 ± 0.12
express/optics/pauli_op_4 6.38 ± 0.35 μs 6.67 ± 0.38 μs 0.957 ± 0.076
express/optics/pauli_state_8 2.55 ± 0.11 μs 2.57 ± 0.14 μs 0.992 ± 0.069
express/optics/simple_ket 1.21 ± 0.081 μs 1.23 ± 0.09 μs 0.984 ± 0.097
express/optics/simple_op 1.39 ± 0.12 μs 1.41 ± 0.11 μs 0.985 ± 0.11
linalg/anticommutator 0.341 ± 0.021 μs 0.351 ± 0.029 μs 0.972 ± 0.1
linalg/commutator 0.361 ± 0.02 μs 0.401 ± 0.02 μs 0.9 ± 0.067
linalg/conjugate 0.05 ± 0.01 μs 0.05 ± 0.01 μs 1 ± 0.28
linalg/dagger 0.05 ± 0.01 μs 0.05 ± 0.01 μs 1 ± 0.28
linalg/inverse 0.041 ± 0.01 μs 0.05 ± 0.01 μs 0.82 ± 0.26
linalg/ptrace 12.9 ± 0.28 μs 12.1 ± 0.27 μs 1.06 ± 0.033
linalg/trace 0.05 ± 0.01 μs 0.04 ± 0.01 μs 1.25 ± 0.4
linalg/transpose 0.05 ± 0.01 μs 0.05 ± 0.01 μs 1 ± 0.28
manipulation/expand/commutator 1.59 ± 0.24 ms 1.58 ± 0.24 ms 1 ± 0.21
manipulation/expand/distribution 1.48 ± 0.1 ms 1.48 ± 0.1 ms 0.999 ± 0.098
manipulation/simplify/applicable_rules 4.62 ± 0.1 ms 4.65 ± 0.085 ms 0.994 ± 0.029
manipulation/simplify/commutator 0.0378 ± 0.00061 ms 0.0371 ± 0.00062 ms 1.02 ± 0.024
manipulation/simplify/irrelevant_rules 0.743 ± 0.017 ms 0.746 ± 0.018 ms 0.995 ± 0.033
operations/addition/ket 1.38 ± 0.059 μs 1.27 ± 0.06 μs 1.09 ± 0.069
operations/addition/op 1.2 ± 0.059 μs 1.21 ± 0.06 μs 0.992 ± 0.069
operations/multiplication/bra_ket 1.15 ± 0.03 μs 1.12 ± 0.02 μs 1.03 ± 0.032
operations/multiplication/bra_op 1.14 ± 0.03 μs 1.2 ± 0.03 μs 0.95 ± 0.034
operations/multiplication/inner 1.15 ± 0.03 μs 1.12 ± 0.021 μs 1.03 ± 0.033
operations/multiplication/many 8.32 ± 0.2 μs 8.11 ± 0.2 μs 1.03 ± 0.035
operations/multiplication/op 1 ± 0.031 μs 1.01 ± 0.039 μs 0.991 ± 0.049
operations/multiplication/op_ket 1.23 ± 0.03 μs 1.17 ± 0.03 μs 1.05 ± 0.037
operations/multiplication/outer 1.16 ± 0.03 μs 1.18 ± 0.039 μs 0.984 ± 0.041
operations/scaling/ket 0.07 ± 0 μs 0.07 ± 0 μs 1 ± 0
operations/scaling/op 0.07 ± 0 μs 0.07 ± 0 μs 1 ± 0
operations/tensor/ket 0.921 ± 0.021 μs 0.941 ± 0.021 μs 0.979 ± 0.031
operations/tensor/many 8.45 ± 0.24 μs 8.44 ± 0.22 μs 1 ± 0.039
operations/tensor/op 0.921 ± 0.02 μs 0.931 ± 0.03 μs 0.989 ± 0.038
time_to_load 1.66 ± 0.0015 s 1.63 ± 0.0096 s 1.02 ± 0.0061
Memory benchmarks
main b23fbfd... main / b23fbfd...
creation/ket 0 allocs: 0 B 0 allocs: 0 B
creation/large_trees/10_layers 11.6 k allocs: 0.283 MB 11.6 k allocs: 0.283 MB 1
creation/large_trees/50_layers 0.662 M allocs: 13 MB 0.662 M allocs: 13 MB 1
creation/op 0 allocs: 0 B 0 allocs: 0 B
creation/super_op 0 allocs: 0 B 0 allocs: 0 B
express/clifford/simple_ket 16 allocs: 0.641 kB 16 allocs: 0.641 kB 1
express/clifford/simple_observable 0.06 k allocs: 2.66 kB 0.06 k allocs: 2.66 kB 1
express/optics/pauli_op_4 0.055 k allocs: 3.72 kB 0.055 k allocs: 3.72 kB 1
express/optics/pauli_state_8 31 allocs: 1.27 kB 31 allocs: 1.27 kB 1
express/optics/simple_ket 20 allocs: 0.75 kB 20 allocs: 0.75 kB 1
express/optics/simple_op 26 allocs: 1.09 kB 26 allocs: 1.09 kB 1
linalg/anticommutator 11 allocs: 0.438 kB 11 allocs: 0.438 kB 1
linalg/commutator 11 allocs: 0.438 kB 11 allocs: 0.438 kB 1
linalg/conjugate 3 allocs: 0.125 kB 3 allocs: 0.125 kB 1
linalg/dagger 3 allocs: 0.125 kB 3 allocs: 0.125 kB 1
linalg/inverse 3 allocs: 0.125 kB 3 allocs: 0.125 kB 1
linalg/ptrace 0.098 k allocs: 3.56 kB 0.098 k allocs: 3.56 kB 1
linalg/trace 3 allocs: 0.125 kB 3 allocs: 0.125 kB 1
linalg/transpose 3 allocs: 0.125 kB 3 allocs: 0.125 kB 1
manipulation/expand/commutator 14.5 k allocs: 0.454 MB 14.5 k allocs: 0.454 MB 1
manipulation/expand/distribution 15.4 k allocs: 0.492 MB 15.4 k allocs: 0.492 MB 1
manipulation/simplify/applicable_rules 0.0501 M allocs: 1.69 MB 0.0501 M allocs: 1.69 MB 1
manipulation/simplify/commutator 0.444 k allocs: 14.1 kB 0.444 k allocs: 14.1 kB 1
manipulation/simplify/irrelevant_rules 8.51 k allocs: 0.268 MB 8.51 k allocs: 0.268 MB 1
operations/addition/ket 25 allocs: 1.48 kB 25 allocs: 1.48 kB 1
operations/addition/op 25 allocs: 1.48 kB 25 allocs: 1.48 kB 1
operations/multiplication/bra_ket 12 allocs: 0.453 kB 12 allocs: 0.453 kB 1
operations/multiplication/bra_op 13 allocs: 0.484 kB 13 allocs: 0.484 kB 1
operations/multiplication/inner 12 allocs: 0.453 kB 12 allocs: 0.453 kB 1
operations/multiplication/many 0.083 k allocs: 3.17 kB 0.083 k allocs: 3.17 kB 1
operations/multiplication/op 12 allocs: 0.469 kB 12 allocs: 0.469 kB 1
operations/multiplication/op_ket 13 allocs: 0.484 kB 13 allocs: 0.484 kB 1
operations/multiplication/outer 13 allocs: 0.484 kB 13 allocs: 0.484 kB 1
operations/scaling/ket 4 allocs: 0.156 kB 4 allocs: 0.156 kB 1
operations/scaling/op 4 allocs: 0.156 kB 4 allocs: 0.156 kB 1
operations/tensor/ket 12 allocs: 0.469 kB 12 allocs: 0.469 kB 1
operations/tensor/many 0.078 k allocs: 3.44 kB 0.078 k allocs: 3.44 kB 1
operations/tensor/op 12 allocs: 0.469 kB 12 allocs: 0.469 kB 1
time_to_load 0.149 k allocs: 11.2 kB 0.149 k allocs: 11.2 kB 1

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.28%. Comparing base (2c395ba) to head (b23fbfd).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #201      +/-   ##
==========================================
+ Coverage   68.53%   69.28%   +0.75%     
==========================================
  Files          21       21              
  Lines         982     1006      +24     
==========================================
+ Hits          673      697      +24     
  Misses        309      309              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant