Skip to content

Approximation

oqd_trical.light_matter.compiler.approximate

FirstOrderLambDickeApprox

Bases: RewriteRule

Applies the Lamb-Dicke approximation to first order.

Attributes:

Name Type Description
cutoff float

Lamb-Dicke parameter cutoff below which approximation is applied.

Source code in src\oqd_trical\light_matter\compiler\approximate.py
class FirstOrderLambDickeApprox(RewriteRule):
    """
    Applies the Lamb-Dicke approximation to first order.

    Attributes:
        cutoff (float): Lamb-Dicke parameter cutoff below which approximation is applied.
    """

    def __init__(self, cutoff=1):
        super().__init__()
        self.cutoff = cutoff

        self.approximated_operators = []

    def map_Displacement(self, model):
        if isinstance(model.alpha.amplitude, MathNum):
            if np.abs(model.alpha.amplitude.value) < self.cutoff:
                self.approximated_operators.append(model)

                alpha_conj = model.alpha.conj()
                return Identity(subsystem=model.subsystem) + (
                    model.alpha * Creation(subsystem=model.subsystem)
                    - alpha_conj * Annihilation(subsystem=model.subsystem)
                )

SecondOrderLambDickeApprox

Bases: RewriteRule

Applies the Lamb-Dicke approximation to second order.

Attributes:

Name Type Description
cutoff float

Lamb-Dicke parameter cutoff below which approximation is applied.

Source code in src\oqd_trical\light_matter\compiler\approximate.py
class SecondOrderLambDickeApprox(RewriteRule):
    """
    Applies the Lamb-Dicke approximation to second order.

    Attributes:
        cutoff (float): Lamb-Dicke parameter cutoff below which approximation is applied.
    """

    def __init__(self, cutoff=1):
        super().__init__()

        self.cutoff = cutoff

        self.approximated_operators = []

    def map_Displacement(self, model):
        if isinstance(model.alpha.amplitude, MathNum):
            if np.abs(model.alpha.amplitude.value) < self.cutoff:
                self.approximated_operators.append(model)

                alpha_conj = model.alpha.conj()
                return (
                    Identity(subsystem=model.subsystem)
                    + (
                        model.alpha * Creation(subsystem=model.subsystem)
                        - alpha_conj * Annihilation(subsystem=model.subsystem)
                    )
                    + ConstantCoefficient(value=1 / 2)
                    * (
                        model.alpha * Creation(subsystem=model.subsystem)
                        - alpha_conj * Annihilation(subsystem=model.subsystem)
                    )
                    * (
                        model.alpha * Creation(subsystem=model.subsystem)
                        - alpha_conj * Annihilation(subsystem=model.subsystem)
                    )
                )

RotatingWaveApprox

Bases: RewriteRule

Applies the rotating wave approximation.

Attributes:

Name Type Description
cutoff float

Frequency cutoff above which approximation is applied.

Source code in src\oqd_trical\light_matter\compiler\approximate.py
class RotatingWaveApprox(RewriteRule):
    """
    Applies the rotating wave approximation.

    Attributes:
        cutoff (float): Frequency cutoff above which approximation is applied.
    """

    def __init__(self, cutoff):
        super().__init__()

        self.cutoff = cutoff
        self.current_time = 0

    def map_AtomicEmulatorGate(self, model):
        hamiltonian = Post(
            _RotatingWaveApproxHelper(
                cutoff=self.cutoff,
                start_time=self.current_time,
                duration=model.duration,
            )
        )(model.hamiltonian)

        self.current_time += model.duration
        return model.__class__(hamiltonian=hamiltonian, duration=model.duration)

RotatingReferenceFrame

Bases: RewriteRule

Moves to an interaction picture with a rotating frame of reference.

Attributes:

Name Type Description
frame Operator

Operator that defines the rotating frame of reference

Source code in src\oqd_trical\light_matter\compiler\approximate.py
class RotatingReferenceFrame(RewriteRule):
    """
    Moves to an interaction picture with a rotating frame of reference.

    Attributes:
        frame (Operator): [`Operator`][oqd_trical.light_matter.interface.operator.Operator] that defines the rotating frame of reference
    """

    def __init__(self, frame_specs):
        super().__init__()

        self.frame_specs = frame_specs

    @cached_property
    def system(self):
        return list(self.frame_specs.keys())

    def _complete_operator(self, op, subsystem):
        return reduce(
            lambda x, y: x @ y,
            [op if subsystem == s else Identity(subsystem=s) for s in self.system],
        )

    @cached_property
    def frame(self):
        ops = []
        for subsystem, energy in self.frame_specs.items():
            if subsystem[0] == "E":
                ops.extend(
                    [
                        ConstantCoefficient(value=e)
                        * self._complete_operator(
                            KetBra(ket=n, bra=n, subsystem=subsystem), subsystem
                        )
                        for n, e in enumerate(energy)
                    ]
                )
            else:
                ops.append(
                    ConstantCoefficient(value=energy)
                    * self._complete_operator(
                        Creation(subsystem=subsystem)
                        * Annihilation(subsystem=subsystem),
                        subsystem,
                    )
                )

        return reduce(lambda x, y: x + y, ops)

    def map_AtomicEmulatorCircuit(self, model):
        return model.__class__(frame=self.frame, sequence=model.sequence)

    def map_AtomicEmulatorGate(self, model):
        return model.__class__(
            hamiltonian=model.hamiltonian - self.frame, duration=model.duration
        )

    def map_KetBra(self, model):
        return (
            WaveCoefficient(
                amplitude=1,
                frequency=self.frame_specs[model.subsystem][model.ket]
                - self.frame_specs[model.subsystem][model.bra],
                phase=0,
            )
            * model
        )

    def map_Displacement(self, model):
        alpha = model.alpha
        return model.__class__(
            alpha=alpha.__class__(
                amplitude=alpha.amplitude,
                frequency=alpha.frequency + self.frame_specs[model.subsystem],
                phase=alpha.phase,
            ),
            subsystem=model.subsystem,
        )

    def map_Annihilation(self, model):
        return (
            WaveCoefficient(
                amplitude=1, frequency=self.frame_specs[model.subsystem], phase=0
            )
            * model
        )

    def map_Creation(self, model):
        return (
            WaveCoefficient(
                amplitude=1, frequency=-self.frame_specs[model.subsystem], phase=0
            )
            * model
        )

AdiabaticElimination

Bases: RewriteRule

Moves to an interaction picture with a rotating frame of reference.

Attributes:

Name Type Description
eliminated_spec Tuple[int, str]

Specification of state of a subsystem to eliminate.

Source code in src\oqd_trical\light_matter\compiler\approximate.py
class AdiabaticElimination(RewriteRule):
    """
    Moves to an interaction picture with a rotating frame of reference.

    Attributes:
        eliminated_spec (Tuple[int,str]): Specification of state of a subsystem to eliminate.
    """

    # TODO currently non universal formulation for AdiabaticElimination
    def __init__(self, eliminated_specs):
        super().__init__()

        warnings.warn(
            "Caution required when using adiabatic elimination, system needs to be put in the appropriate rotating reference frame."
        )

        self._eliminated_specs = eliminated_specs

        self.matrix_elements = []

    @cached_property
    def eliminated_specs(self):
        return self._eliminated_specs

    @cached_property
    def eliminated_state(self):
        return self.eliminated_specs[0]

    @cached_property
    def eliminated_subsystem(self):
        return self.eliminated_specs[1]

    @property
    def diagonal(self):
        diagonal = list(
            filter(lambda x: x[0] == self.eliminated_state, self.matrix_elements)
        )

        if diagonal:
            return diagonal

        raise ValueError(
            "Failed to apply adiabatic elimination: Diagonal matrix element of eliminated state is zero."
        )

    @property
    def nondiagonal(self):
        return list(
            filter(lambda x: x[0] != self.eliminated_state, self.matrix_elements)
        )

    def map_AtomicEmulatorGate(self, model):
        adiabatic_elimination_helper = _GetMatrixElements(self.eliminated_specs)
        Post(adiabatic_elimination_helper)(model.hamiltonian)
        self.matrix_elements = adiabatic_elimination_helper.matrix_elements

    def map_KetBra(self, model):
        if model.subsystem != self.eliminated_subsystem:
            return

        if model.ket == self.eliminated_state and model.bra == self.eliminated_state:
            return PrunedOperator()

        if model.ket == self.eliminated_state:
            return -reduce(
                lambda x, y: x + y,
                [
                    (ConstantCoefficient(value=0.5) * c / self.diagonal[0][1]).conj()
                    * KetBra(ket=i, bra=model.bra, subsystem=model.subsystem)
                    for (i, c) in self.nondiagonal
                ],
            )

        if model.bra == self.eliminated_state:
            return -reduce(
                lambda x, y: x + y,
                [
                    (ConstantCoefficient(value=0.5) * c / self.diagonal[0][1])
                    * KetBra(ket=model.ket, bra=i, subsystem=model.subsystem)
                    for (i, c) in self.nondiagonal
                ],
            )