Symbolic terms¶
Symop represents symbolic operator expressions using a small set of core term objects. These objects separate three related but distinct ideas:
general ordered operator words
normal-ordered monomials
coefficient-bearing ket- and density-like terms
This page introduces the main classes:
Setup¶
import symop.viz as viz
from symop.core.operators import ModeOp
from symop.core.monomial import Monomial
from symop.core.terms.op_term import OpTerm
from symop.core.terms.ket_term import KetTerm
from symop.core.terms.density_term import DensityTerm
from symop.modes.labels import ModeLabel
from symop.modes.labels.path import Path
from symop.modes.labels.polarization import Polarization
from symop.modes.envelopes import GaussianEnvelope
env = GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0)
mode_a = ModeOp(
label=ModeLabel(
path=Path("A"),
polarization=Polarization.H(),
envelope=env,
),
user_label="a",
)
mode_b = ModeOp(
label=ModeLabel(
path=Path("B"),
polarization=Polarization.H(),
envelope=env,
),
user_label="b",
)
Operator words with OpTerm¶
symop.core.terms.op_term.OpTerm stores a general ordered product of
ladder operators together with a complex coefficient.
op_term = OpTerm(
ops=(mode_a.cre, mode_b.ann, mode_a.ann),
coeff=2.0 + 1.0j,
)
viz.display(op_term)
OpTerm(ops=(LadderOp(kind=<OperatorKind.CRE: 'adag'>, mode=ModeOp(label=ModeLabel(path=Path(name='A'), polarization=Polarization(jones=((1+0j), 0j)), envelope=GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0, phi0=0.0)), user_label='a', display_index=1)), LadderOp(kind=<OperatorKind.ANN: 'a'>, mode=ModeOp(label=ModeLabel(path=Path(name='B'), polarization=Polarization(jones=((1+0j), 0j)), envelope=GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0, phi0=0.0)), user_label='b', display_index=2)), LadderOp(kind=<OperatorKind.ANN: 'a'>, mode=ModeOp(label=ModeLabel(path=Path(name='A'), polarization=Polarization(jones=((1+0j), 0j)), envelope=GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0, phi0=0.0)), user_label='a', display_index=1))), coeff=(2+1j))
Unlike a normal-ordered object, an OpTerm preserves the explicit operator
order. This makes it useful for intermediate symbolic manipulations and
adjoint operations.
op_term.adjoint()
OpTerm(ops=(LadderOp(kind=<OperatorKind.CRE: 'adag'>, mode=ModeOp(label=ModeLabel(path=Path(name='A'), polarization=Polarization(jones=((1+0j), 0j)), envelope=GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0, phi0=0.0)), user_label='a', display_index=1)), LadderOp(kind=<OperatorKind.CRE: 'adag'>, mode=ModeOp(label=ModeLabel(path=Path(name='B'), polarization=Polarization(jones=((1+0j), 0j)), envelope=GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0, phi0=0.0)), user_label='b', display_index=2)), LadderOp(kind=<OperatorKind.ANN: 'a'>, mode=ModeOp(label=ModeLabel(path=Path(name='A'), polarization=Polarization(jones=((1+0j), 0j)), envelope=GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0, phi0=0.0)), user_label='a', display_index=1))), coeff=(2-1j))
Normal-ordered monomials¶
symop.core.monomial.Monomial stores creators and annihilators
separately.
mon = Monomial(
creators=(mode_a.cre, mode_b.cre),
annihilators=(mode_b.ann,),
)
viz.display(mon)
This representation is structurally richer than a raw operator word. It makes
queries such as is_creator_only, is_identity, and mode_ops easy and
stable.
mon.is_creator_only, mon.is_identity, mon.mode_ops
(False,
False,
(ModeOp(label=ModeLabel(path=Path(name='A'), polarization=Polarization(jones=((1+0j), 0j)), envelope=GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0, phi0=0.0)), user_label='a', display_index=1),
ModeOp(label=ModeLabel(path=Path(name='B'), polarization=Polarization(jones=((1+0j), 0j)), envelope=GaussianEnvelope(omega0=1.0, sigma=1.0, tau=0.0, phi0=0.0)), user_label='b', display_index=2)))
Ket-like terms¶
symop.core.terms.ket_term.KetTerm combines a scalar coefficient with a
single monomial.
ket_term = KetTerm(2.0, mon)
viz.display(ket_term)
ket_term.creation_count, ket_term.annihilation_count, ket_term.total_degree
(2, 1, 3)
Density-like terms¶
symop.core.terms.density_term.DensityTerm stores a coefficient and two
monomials, one acting on the left and one on the right.
left = Monomial(creators=(mode_a.cre,), annihilators=())
right = Monomial(creators=(), annihilators=(mode_b.ann,))
density_term = DensityTerm(1.0, left, right)
viz.display(density_term)
This is the natural structural form for density-operator bookkeeping and related symbolic manipulations.
density_term.is_creator_only_left, density_term.is_annihilator_only_right
(True, True)
Choosing between the term types¶
Use symop.core.terms.op_term.OpTerm when the explicit operator order
matters.
Use symop.core.monomial.Monomial when you want a normal-ordered
creator/annihilator decomposition.
Use symop.core.terms.ket_term.KetTerm when you need a scalar
coefficient attached to one monomial.
Use symop.core.terms.density_term.DensityTerm when you need separate
left and right monomials.