Add lazy QuantumOpticsRepr express output#203
Open
GrovyleX wants to merge 1 commit into
Open
Conversation
With `QuantumOpticsRepr(lazy=true)`, symbolic operator sums, products, and tensor products express to `LazySum`, `LazyProduct`, and `LazyTensor`, and commutators and anticommutators to lazy sums of products. A `LazyTensor` stores only the non-identity factors, preserving the local tensor structure instead of materializing dense matrices. The default eager behaviour is untouched. Includes tests under test/general and a docs section. Part of qojulia/QuantumOptics.jl#521
Contributor
Benchmark Results (Julia v1)Time benchmarks
Memory benchmarks
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #203 +/- ##
==========================================
- Coverage 68.53% 67.46% -1.08%
==========================================
Files 21 21
Lines 982 1008 +26
==========================================
+ Hits 673 680 +7
- Misses 309 328 +19 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this does
express(x, QuantumOpticsRepr())has always built eager dense/sparse operators. This adds anopt-in lazy path -
express(x, QuantumOpticsRepr(lazy=true))- that keeps the structure of thesymbolic expression by emitting QuantumOpticsBase's lazy operator types instead of materializing
matrices:
LazySumLazyProductLazyTensorLazySumofLazyProductsThe default is untouched: with
lazy=false(plainQuantumOpticsRepr()) every method fallsstraight back to the existing eager conversion, so
express(x)behaves exactly as before. This isthe QuantumSymbolics half of qojulia/QuantumOptics.jl#521; the
lazyfield onQuantumOpticsRepritself is a companion QuantumInterface PR (qojulia/QuantumInterface.jl#85).
How it works
Five
express_nolookupmethods inext/QuantumOpticsExt/QuantumOpticsExt.jl, one per symbolicoperator type (
SAddOperator,SMulOperator,STensorOperator,SCommutator,SAnticommutator). I tried to make the output look like what you'd assemble by hand inQuantumOptics.jl - a Hamiltonian written as a sum of local tensor terms comes out as a
LazySumof
LazyTensors. Two things I was deliberate about:LazySum.factors, read straight from theSAddterm→coefficient dict,so
2X + 3Ystays a genuinely weighted sum rather than folding the2and3into theoperators.
LazyTensorstores only its non-identity factors.tensor(X, I)becomesLazyTensor(b, [1], (σx,))- the identity on the second subsystem is left implicit, which iswhat
LazyTensoris for and where the structure/memory win comes from. If a factor can't sit ona single subsystem (e.g. an expressed two-qubit gate on a composite basis), that one tensor
product falls back to the eager
⊗- the "where the basis structure supports it" clause from theissue.
Scalar prefactors didn't need their own method:
prefactorscalingsalready lifts them outsymbolically, and multiplying a lazy operator by a number carries them through. I didn't touch any
existing conversion method.
Tests & docs
test/general/lazy_express_tests.jlcovers each operator type, the identity-omission,commutators/anticommutators, the Fock cutoff still applying under
lazy=true, the eagerfallback, and
dense(lazy) ≈ eagerfor every case. It builds the symbolic expressions directly,so it's deterministic. Against a QuantumInterface without the
lazyfield it skips with a note,so it stays green on the registry version and runs in full once the field is present.
docs/src/express.mdgets a short "Lazy operator output" section.Pkg.test()locally on Julia 1.12.6 - green, including Aqua and the doctests.Cross-repo note
This uses the
lazyfield thatQuantumOpticsReprgains in the companion QuantumInterface PR(qojulia/QuantumInterface.jl#85). The extension reads it defensively (
hasproperty), so this PRloads and stays fully eager against the released QuantumInterface and resolves from the registry —
the lazy output switches on once that field ships (a dev'd checkout locally, or QuantumInterface
≥0.4.3). No
[sources]pin or compat bump, so the two PRs don't block each other for CI.CHANGELOG
Part of qojulia/QuantumOptics.jl#521
is flagged as we are slowly transitioning to enforced formatting. Please do not worry about or address older formatting issues -- keep your PR just focused on your planned
contribution.
If you are submitting for a bug bounty:
Part of qojulia/QuantumOptics.jl#521
is flagged as we are slowly transitioning to enforced formatting. Please do not worry about or address older formatting issues -- keep your PR just focused on your planned
contribution.
If you are submitting for a bug bounty:
AI disclosure
I used AI to help analyze the codebase and draft some of the implementation, but the design calls
were mine - coefficients into
LazySum.factors, the identity-omission inLazyTensor, the eagerfallback for multi-subsystem factors - and I checked them against QuantumOpticsBase's lazy-operator
semantics. I wrote and ran the tests, debugged what broke, and went through the whole diff before
opening this. I understand every line and I'm happy to walk through any of it.