Algebra and ordering

The Heisenberg equation of a Kerr oscillator, $\dot a = i[H, a]$ with $H = K a^{\dagger 2} a^2$, asks to move an annihilation operator past two creation operators. Using $[a, a^\dagger] = 1$ gives $\dot a = -2iK a^\dagger a^2$; the same result comes out in normal order directly:

using SecondQuantizedAlgebraa = Destroy(FockSpace(:cavity), :a)@variables K1im * commutator(K * a' * a' * a * a, a)

\[ - 2 ~ K ~ \mathit{i} a^{\dagger}aa\]

Operator expressions are kept in a canonical form at all times. Every product is reordered and reduced the moment it is formed, so like terms combine without further work.

Canonical form

Each algebra brings its own rules, and all of them apply as soon as a product is formed.

using SecondQuantizedAlgebrah = FockSpace(:cavity) ⊗ NLevelSpace(:atom, 3) ⊗ PauliSpace(:qubit) ⊗ SpinSpace(:S) ⊗ PhaseSpace(:osc)@qnumbers a::Destroy(h, 1) b::Destroy(h, 1) x::Position(h) p::Momentum(h)σ(i, j) = Transition(h, :σ, i, j, 2)τ(k) = Pauli(h, :τ, k)S(k) = Spin(h, :S, k)

Operators of different subsystems are sorted by their position in the product space.

x * a * σ(2, 1)

\[a{\sigma}^{{21}}\hat{x}\]

Each bosonic mode is normal ordered, and modes with different names are grouped by name.

b' * a' * b * a

\[a^{\dagger}ab^{\dagger}b\]

Transitions on the same system compose.

σ(1, 2) * σ(2, 3)

\[{\sigma}^{{13}}\]

Products of Pauli matrices reduce to a single Pauli matrix or a number.

τ(1) * τ(2)

\[\mathit{i} {\tau}_{{z}}\]

Spin components are sorted by axis.

S(2) * S(1)

\[-\mathit{i} {S}_{{z}} + {S}_{{x}}{S}_{{y}}\]

Position stands to the left of momentum.

p * x

\[-\mathit{i} + \hat{x}\hat{p}\]

normal_order applies the same rules explicitly, for code that expects a separate ordering step.

SecondQuantizedAlgebra.normal_order — Function
normal_order(expr::QField)

Bring expr into canonical, normal-ordered form.

Arithmetic already returns this form: *, +, -, ^, adjoint, commutator, Σ and substitute all canonicalize as they go, so normal_order leaves their results unchanged. It is there for code that expects an explicit ordering step. Formal operator functions such as cos or expim keep their form; only their polynomial arguments are ordered.

Examples

julia> h = FockSpace(:f);julia> @qnumbers a::Destroy(h);julia> a * a'1 + a' * ajulia> normal_order(a * a')1 + a' * a

See also simplify, expand_completeness, normal_to_symmetric, symmetric_to_normal.

source

The ground-state projector is the one deliberate exception. It stays as it is, since rewriting it through completeness would multiply the number of terms in dissipators and equations of motion.

σ(1, 2) * σ(2, 1)

\[{\sigma}^{{11}}\]

Completeness is applied only on request.

expand_completeness(σ(1, 2) * σ(2, 1))

\[1 -{\sigma}^{{22}} -{\sigma}^{{33}}\]

SecondQuantizedAlgebra.expand_completeness — Function
expand_completeness(expr)

Eliminate every ground-state projector in expr through completeness.

Each projector $\sigma^{gg}$ is replaced by $1 - \sum_{k \neq g} \sigma^{kk}$. Arithmetic never does this by itself, which keeps expressions short. Expand when the remaining projectors should be the independent variables, e.g. before deriving equations for their expectation values.

Examples

julia> h = NLevelSpace(:atom, 2);julia> σ11 = Transition(h, :σ, 1, 1);julia> expand_completeness(σ11)1 - σ₂₂

See also assume_distinct_index, normal_order.

source

An expression in canonical form has its own type, which is what products, sums and commutators of operators return.

SecondQuantizedAlgebra.QAdd — Type
QAdd <: QField

Type of operator expressions that are polynomials in the operators, kept in canonical form.

Sums, products and commutators of operators return a QAdd, with every product ordered and reduced and like terms collected, so two equal polynomials compare equal. A single operator is an Op instead, and an expression that contains a formal function such as cos is a QExpr. length gives the number of terms, and sorted_arguments splits an expression into them. The type is public but not exported.

Examples

julia> using SecondQuantizedAlgebra: QAddjulia> a = Destroy(FockSpace(:cavity), :a);julia> x = a * a'1 + a' * ajulia> x isa QAdd, length(x)(true, 2)

See also QExpr, normal_order, sorted_arguments.

source

Commutators

Since both orderings of a product are already canonical, a commutator costs no more than two products and a subtraction. The Pauli matrices show both brackets at once: different components anticommute, and their commutator is the third component.

commutator(τ(1), τ(2)), anticommutator(τ(1), τ(2))
(2im * τz, 0)

For a mode, the anticommutator of $a$ and $a^\dagger$ is the symmetric combination that enters vacuum fluctuations.

anticommutator(a, a')

\[1 + 2 a^{\dagger}a\]

Finishing coefficients

Coefficients are exact numbers or Symbolics expressions, as described in Parameters and coefficients. Polynomial coefficients cancel as terms combine, while identities between functions are applied only by simplify.

@variables θsimplify((sin(θ)^2 + cos(θ)^2) * a' * a)

\[a^{\dagger}a\]

expand multiplies out products that sit inside functions of the coefficients, which are otherwise kept as written.

@variables x yexpand(exp(x * (x + y)) * a)

\[e^{x^{2} + x ~ y} a\]

SymbolicUtils.simplify — Method
simplify(expr::QField)

Simplify the scalar coefficients of expr symbolically.

Polynomial coefficients already cancel as an expression is built. simplify goes further and applies symbolic identities, such as trigonometric ones, to every coefficient, then drops the terms that vanish. Because this step is expensive, it is best used once on a final result. Formal operator functions keep their form.

Examples

julia> h = FockSpace(:f);julia> @qnumbers a::Destroy(h);julia> @variables x;julia> expr = (sin(x)^2 + cos(x)^2) * a' * a(cos(x)^2 + sin(x)^2) * a' * ajulia> simplify(expr)a' * a

See also normal_order, expand, expand_completeness.

source
SymbolicUtils.expand — Method
expand(expr::QField)

Multiply out the scalar coefficients of expr.

Polynomial coefficients are kept expanded already; expand also reaches products inside functions such as exp. Formal operator functions are not expanded.

Examples

julia> h = FockSpace(:f);julia> @qnumbers a::Destroy(h);julia> @variables x y;julia> expr = exp(x * (x + y)) * a;julia> expand(expr)exp(x^2 + x*y) * a

See also simplify, taylor.

source

Symmetric ordering

Phase-space methods such as the truncated Wigner approximation work with symmetrically ordered operators rather than normal-ordered ones. In symmetric order the photon number $a^\dagger a$ reads as $(a^\dagger a + a a^\dagger)/2 - 1/2$, so the half quantum of vacuum noise becomes explicit.

n_sym = normal_to_symmetric(a' * a)

\[\frac{-1}{2} + a^{\dagger}a\]

The conversion is exact in both directions.

symmetric_to_normal(n_sym) == a' * a
true
SecondQuantizedAlgebra.normal_to_symmetric — Function
normal_to_symmetric(expr)

Rewrite a normal-ordered expression in symmetric (Weyl) order.

The result is written with the same monomials, but each now stands for its fully symmetrized product: a' * a reads as $(a^\dagger a + a a^\dagger)/2$ and x * p as $(xp + px)/2$. This is the form phase-space methods such as the truncated Wigner approximation work with. Bosonic modes and quadratures are converted; other operators pass through unchanged. The inverse is symmetric_to_normal.

Examples

julia> hf = FockSpace(:f);julia> @qnumbers a::Destroy(hf);julia> normal_to_symmetric(a' * a)-1//2 + a' * ajulia> hp = PhaseSpace(:osc);julia> @qnumbers x::Position(hp) p::Momentum(hp);julia> normal_to_symmetric(x * p)1//2im + x * p

See also symmetric_to_normal, normal_order.

source
SecondQuantizedAlgebra.symmetric_to_normal — Function
symmetric_to_normal(expr)

Rewrite a symmetric (Weyl) ordered expression in normal order.

Each monomial of expr is read as its symmetrized product, as returned by normal_to_symmetric, and expanded back into normal order. The two functions are exact inverses.

Examples

julia> hf = FockSpace(:f);julia> @qnumbers a::Destroy(hf);julia> symmetric_to_normal(a' * a)1//2 + a' * ajulia> normal_to_symmetric(symmetric_to_normal(a' * a))a' * a

See also normal_to_symmetric, normal_order.

source