Skip to content

The callback mechanism

Since the desired output of the emulator can be quite user dependent, EMU-MPS uses a callback mechanism to specify its output. The available callbacks, together with examples for how to create them are on this page. How to use created callbacks to obtain results from an emulation is shown in the example notebooks (here).

The following default callbacks are available:

StateResult

Bases: Callback

Store the quantum state in whatever format the backend provides

PARAMETER DESCRIPTION
evaluation_times

the times at which to store the state

TYPE: set[int]

Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int]):
    super().__init__(evaluation_times)

BitStrings

Bases: Callback

Store bitstrings sampled from the current state. Error rates are taken from the config passed to the run method of the backend. The bitstrings are stored as a Counter[str].

PARAMETER DESCRIPTION
evaluation_times

the times at which to sample bitstrings

TYPE: set[int]

num_shots

how many bitstrings to sample each time this observable is computed

TYPE: int DEFAULT: 1000

Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int], num_shots: int = 1000):
    super().__init__(evaluation_times)
    self.num_shots = num_shots

Fidelity

Bases: Callback

Store \(<ψ|φ(t)>\) for the given state \(|ψ>\), and the state \(|φ(t)>\) obtained by time evolution.

PARAMETER DESCRIPTION
evaluation_times

the times at which to compute the fidelity

TYPE: set[int]

state

the state |ψ>. Note that this must be of appropriate type for the backend

TYPE: State

Examples:

>>> state = State.from_state_string(...) #see State API
>>> fidelity = Fidelity([400], state) #measure fidelity on state at t=400ns
Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int], state: State):
    super().__init__(evaluation_times)
    global _fidelity_counter
    _fidelity_counter += 1
    self.index = _fidelity_counter
    self.state = state

Expectation

Bases: Callback

Store the expectation of the given operator on the current state (i.e. \(\langle φ(t)|\mathrm{operator}|φ(t)\rangle\)).

PARAMETER DESCRIPTION
evaluation_times

the times at which to compute the expectation

TYPE: set[int]

operator

the operator to measure. Must be of appropriate type for the backend.

TYPE: Operator

Examples:

>>> op = Operator.from_operator_string(...) #see Operator API
>>> expectation = Expectation([400], op) #measure the expecation of op at t=400ns
Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int], operator: Operator):
    super().__init__(evaluation_times)
    global _expectation_counter
    _expectation_counter += 1
    self.index = _expectation_counter
    self.operator = operator

CorrelationMatrix

Bases: Callback

Store the correlation matrix for the current state. Requires specification of the basis used in the emulation https://pulser.readthedocs.io/en/stable/conventions.html It currently supports - the rydberg basis ('r','g') - the xy basis ('0', '1') and returns

[[<φ(t)|n_i n_j|φ(t)> for j in qubits] for i in qubits]

n_i being the operator that projects qubit i onto the state that measures as 1. The diagonal of this matrix is the QubitDensity. The correlation matrix is stored as a list of lists.

PARAMETER DESCRIPTION
evaluation_times

the times at which to compute the correlation matrix

TYPE: set[int]

basis

the basis used by the sequence

TYPE: tuple[str, ...]

nqubits

the number of qubits in the Register

TYPE: int

Notes

See the API for Operator.from_operator_string for an example of what to do with basis and nqubits.

Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int], basis: tuple[str, ...], nqubits: int):
    super().__init__(evaluation_times)
    self.operators: list[list[Operator]] | None = None
    self.basis = set(basis)
    if self.basis == {"r", "g"}:
        self.op_string = "rr"
    elif self.basis == {"0", "1"}:
        self.op_string = "11"
    else:
        raise ValueError("Unsupported basis provided")
    self.nqubits = nqubits

QubitDensity

Bases: Callback

Requires specification of the basis used in the emulation https://pulser.readthedocs.io/en/stable/conventions.html It currently supports - the rydberg basis ('r','g') - the xy basis ('0', '1') and returns

[<φ(t)|n_i|φ(t)> for i in qubits]

n_i being the operator that projects qubit i onto the state that measures as 1. The qubit density is stored as a list.

PARAMETER DESCRIPTION
evaluation_times

the times at which to compute the density

TYPE: set[int]

basis

the basis used by the sequence

TYPE: tuple[str, ...]

nqubits

the number of qubits in the Register

TYPE: int

Notes

See the API for State.from_state_string for an example of what to do with basis and nqubits.

Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int], basis: tuple[str, ...], nqubits: int):
    super().__init__(evaluation_times)
    self.operators: list[Operator] | None = None
    self.basis = set(basis)
    if self.basis == {"r", "g"}:
        self.op_string = "rr"
    elif self.basis == {"0", "1"}:
        self.op_string = "11"
    else:
        raise ValueError("Unsupported basis provided")
    self.nqubits = nqubits

Energy

Bases: Callback

Store the expectation value of the current Hamiltonian (i.e. \(\langle φ(t)|H(t)|φ(t) \rangle\))

PARAMETER DESCRIPTION
evaluation_times

the times at which to compute the expectation

TYPE: set[int]

Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int]):
    super().__init__(evaluation_times)

SecondMomentOfEnergy

Bases: Callback

Store the expectation value \(\langle φ(t)|H(t)^2|φ(t)\rangle\). Useful for computing the variance when averaging over many executions of the program.

PARAMETER DESCRIPTION
evaluation_times

the times at which to compute the variance

TYPE: set[int]

Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int]):
    super().__init__(evaluation_times)

EnergyVariance

Bases: Callback

Store the variance of the current Hamiltonian (i.e. \(\langle φ(t)|H(t)^2|φ(t)\rangle - \langle φ(t)|H(t)|φ(t)\rangle^2\))

PARAMETER DESCRIPTION
evaluation_times

the times at which to compute the variance

TYPE: set[int]

Source code in emu_base/base_classes/default_callbacks.py
def __init__(self, evaluation_times: set[int]):
    super().__init__(evaluation_times)

Defining your own callbacks

Most commonly desired information can be obtained using the classes documented above

  • arbitrary observables can be measured using Expectation
  • fidelities on arbitrary states can be computed using Fidelity
  • Information about the time dependent states and Hamiltonians is available via StateResult, Energy etc.

If additional behaviour is desired (e.g. the kurtosis of the energy, or entanglement entropy), the user can subclass the Callback class to implement any behaviour only depending on the parameters of its __call__ method (see here). Computation of the entanglement entropy, for example, cannot be done in a backend-independent manner, so it is unlikely to ever make it into the above default list. However, we do intend to define backend-specific callbacks in the future, which would belong to the API of a specific backend. Callbacks that can be implemented in a backend-independent manner can be added to the above list upon popular request.