qoolqit.execution
execution
Section titled “
execution
”Execute quantum programs on QPUs or local/remote emulators.
Modules:
-
BackendType–A module gathering all available backends.
-
backends–Backends to run quantum programs on local/remote emulators and QPUs.
-
compilation_functions– -
job–Job submission and results retrieval on local/remote emulators and QPUs.
-
sequence_compiler–
Classes:
-
BitStrings–Stores bitstrings sampled from the state at the evaluation times.
-
CorrelationMatrix–Stores the correlation matrix for the current state.
-
EmulationConfig–Configures an emulation on a backend.
-
Energy–Stores the energy of the system at the evaluation times.
-
EnergySecondMoment–Stores the expectation value of
H(t)^2at the evaluation times. -
EnergyVariance–Stores the variance of the Hamiltonian at the evaluation times.
-
Expectation–Stores the expectation of the given operator on the current state.
-
Fidelity–Stores the fidelity with a pure state at the evaluation times.
-
Job–Abstract representation of an asynchronous job or task.
-
LocalEmulator–Run QoolQit
QuantumPrograms on a Pasqal local emulator backends. -
Occupation–Stores the occupation number of an eigenstate on each qudit.
-
QPU–Execute QoolQit QuantumPrograms on Pasqal quantum processing units.
-
RemoteEmulator–Run QoolQit
QuantumPrograms on a Pasqal remote emulator backends. -
Results–A collection of results.
-
StateResult–Stores the quantum state at the evaluation times.
Functions:
-
get_batch_id–Return the batch ID associated with a remote job.
-
retrieve_remote_job–Retrieve a previously submitted remote job by its identifiers.
Attributes:
-
JobStatus(TypeAlias) –Alias for :class:
~pulser.backend.remote.JobStatus.
JobStatus: TypeAlias = remote.JobStatus
module-attribute
Section titled “
JobStatus: TypeAlias = remote.JobStatus
module-attribute
”Alias for :class:~pulser.backend.remote.JobStatus.
Terminal states (where :meth:Job.has_ended returns True):
- :attr:
~remote.JobStatus.DONE - :attr:
~remote.JobStatus.ERROR - :attr:
~remote.JobStatus.CANCELED
-
API reference
qoolqit.execution
executionJobget_status
BitStrings(*, evaluation_times: Sequence[float] | None = None, num_shots: int | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None)
Section titled “
BitStrings(*, evaluation_times: Sequence[float] | None = None, num_shots: int | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None)
”Stores bitstrings sampled from the state at the evaluation times.
Error rates are taken from the NoiseModel passed to the backend via the EmulationConfig. The bitstrings are stored as a Counter[str].
Parameters:
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to sample bitstrings.
If left as None, uses the default_evaluation_times of the
backend's EmulationConfig.
num_shots
Section titled “ num_shots
”int | None, default:None)
–How many bitstrings to sample each time this observable
is computed. If left as None, will use default_num_shots
of the backend's EmulationConfig.
one_state
Section titled “ one_state
”Eigenstate | None, default:None)
–The eigenstate that measures to 1. Can be left undefined if the state's eigenstates form a known eigenbasis with a defined "one state".
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
num_shots(int | None) –How many bitstrings to sample each time this observable is computed.
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/default_observables.py
def __init__( self, *, evaluation_times: Sequence[float] | None = None, num_shots: int | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__( evaluation_times=evaluation_times, tag_suffix=tag_suffix ) # Relies on the validation in the setter self.num_shots = num_shots self.one_state = one_state
num_shots: int | None
property
writable
Section titled “
num_shots: int | None
property
writable
”How many bitstrings to sample each time this observable is computed.
Warning
The default value for this parameter was changed from 1000 to None
in Pulser v1.7. When left as None, it now relies on
EmulationConfig.default_num_shots to decide how many shots to
take.
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, config: EmulationConfig, state: State, **kwargs: Any) -> Counter[str]
Section titled “
apply(*, config: EmulationConfig, state: State, **kwargs: Any) -> Counter[str]
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply( self, *, config: EmulationConfig, state: State, **kwargs: Any,) -> Counter[str]: """Calculates the observable to store in the Results.""" return state.sample( num_shots=( self._num_shots if self._num_shots is not None else config.default_num_shots ), one_state=self.one_state, p_false_pos=config.noise_model.p_false_pos, p_false_neg=config.noise_model.p_false_neg, )
CorrelationMatrix(*, evaluation_times: Sequence[float] | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None)
Section titled “
CorrelationMatrix(*, evaluation_times: Sequence[float] | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None)
”Stores the correlation matrix for the current state.
The correlation matrix is calculated as
[[<φ(t)|n_i n_j|φ(t)> for j in qubits] for i in qubits]
where n_k = |one_state><one_state|.
Parameters:
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to compute the
correlation matrix. If left as None, uses the
default_evaluation_times of the backend's EmulationConfig.
one_state
Section titled “ one_state
”Eigenstate | None, default:None)
–The eigenstate to measure the population of in the correlation matrix. Can be left undefined if the state's eigenstates form a known eigenbasis with a defined "one state".
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/default_observables.py
def __init__( self, *, evaluation_times: Sequence[float] | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__( evaluation_times=evaluation_times, tag_suffix=tag_suffix ) self.one_state = one_state
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> list[list]
Section titled “
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> list[list]
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply( self, *, state: State, hamiltonian: Operator, **kwargs: Any) -> list[list]: """Calculates the observable to store in the Results."""
@functools.cache def calc_expectation(qudit_ids: frozenset[int]) -> Any: return self._get_number_operator( qudit_ids, state.n_qudits, state.eigenstates, self.one_state or state.infer_one_state(), type(hamiltonian), ).expect(state)
return [ [ calc_expectation(frozenset((i, j))) for j in range(state.n_qudits) ] for i in range(state.n_qudits) ]
EmulationConfig(*, callbacks: Sequence[Callback] = (), observables: Sequence[Observable] = (), default_evaluation_times: Sequence[SupportsFloat] | Literal['Full'] = (1.0,), initial_state: StateType | None = None, with_modulation: bool = False, interaction_matrix: ArrayLike | None = None, prefer_device_noise_model: bool = False, noise_model: NoiseModel | None = None, n_trajectories: int | None = None, default_num_shots: int = 1000, **backend_options: Any)
Section titled “
EmulationConfig(*, callbacks: Sequence[Callback] = (), observables: Sequence[Observable] = (), default_evaluation_times: Sequence[SupportsFloat] | Literal['Full'] = (1.0,), initial_state: StateType | None = None, with_modulation: bool = False, interaction_matrix: ArrayLike | None = None, prefer_device_noise_model: bool = False, noise_model: NoiseModel | None = None, n_trajectories: int | None = None, default_num_shots: int = 1000, **backend_options: Any)
”Configures an emulation on a backend.
Note
Parameters:
observables
Section titled “ observables
”Sequence[Observable], default:())
–A sequence of observables to compute at specific evaluation times. The observables without specified evaluation times will use this configuration's 'default_evaluation_times'.
callbacks
Section titled “ callbacks
”Sequence[Callback], default:())
–A general callback that is not an observable. Observables must be fed into the observables arg, since they all interact with the Results, and are subject to additional validation. Unlike observables, these are called at every emulation step.
default_evaluation_times
Section titled “ default_evaluation_times
”Sequence[SupportsFloat] | Literal['Full'], default:(1.0,))
–The default times at which observables are computed. Can be a sequence of unique relative times between 0 (the start of the sequence) and 1 (the end of the sequence), in ascending order. Can also be specified as "Full", in which case every step in the emulation will also be an evaluation time.
initial_state
Section titled “ initial_state
”StateType | None, default:None)
–The initial state from which emulation starts. If
specified, the state type needs to be compatible with the emulator
backend (i.e. it must match
EmulatorBackend.config_type.state_type).
If left undefined, defaults to starting with all qudits in the
ground state.
with_modulation
Section titled “ with_modulation
”bool, default:False)
–Whether to emulate the sequence with the programmed input or the expected output.
interaction_matrix
Section titled “ interaction_matrix
”ArrayLike | None, default:None)
–An optional interaction matrix to replace the interaction terms in the Hamiltonian. For an N-qudit system, must be an NxN symmetric matrix where entry (i, j) dictates the interaction coefficient between qudits i and j, ie it replaces the C_n/r_{ij}^n term.
prefer_device_noise_model
Section titled “ prefer_device_noise_model
”bool, default:False)
–If True, uses the noise model of the sequence's device (if the sequence's device has one), regardless of the noise model given with this configuration.
noise_model
Section titled “ noise_model
”NoiseModel | None, default:None)
–An optional noise model to emulate the sequence with.
Ignored if the sequence's device has default noise model and
prefer_device_noise_model=True.
n_trajectories
Section titled “ n_trajectories
”int | None, default:None)
–The number of trajectories to average over when the emulation includes stochastic noise or is using a Monte Carlo solver. When left undefined:
(1) If 'prefer_device_noise_model=False', tries to use the (now
deprecated) value of NoiseModel.runs. If that is also not
defined, defaults to 1 trajectory.
(2) If 'prefer_device_noise_model=True', defaults to 40 trajectories.
default_num_shots
Section titled “ default_num_shots
”int, default:1000)
–The default number of shots for BitStrings, used
whenever the observable doesn't define its own. Defaults to 1000.
-
API reference
qoolqit.execution
executionEmulationConfigfrom_abstract_repr
Methods:
-
from_abstract_repr–Deserialize an EmulationConfig from an abstract JSON object.
-
is_evaluation_time–Assesses whether a relative time is an evaluation time.
-
is_time_in_evaluation_times–Checks if a time is within a collection of evaluation times.
-
operator_type–The preferred operator type to use with this config class.
-
state_type–The preferred state type to use with this config class.
-
to_abstract_repr–Serialize
EmulationConfigto a JSON formatted str. -
with_changes–Returns a copy of the config with the given changes.
Attributes:
-
callbacks(Sequence[Callback]) –A sequence of callbacks that are not observables.
-
default_evaluation_times(NDArray[floating[Any]] | Literal['Full']) –The default times at which observables are computed.
-
default_num_shots(int) –The default number of shots for
BitStrings. -
initial_state(StateType | None) –A custom initial state from which emulation starts.
-
interaction_matrix(AbstractArray | None) –An interaction matrix to replace the Hamiltonian interaction terms.
-
n_trajectories(int) –The number of trajectories to average over (when applicable).
-
noise_model(NoiseModel) –A custom noise model to emulate the sequence with.
-
observables(Sequence[Observable]) –A sequence of observables to compute at specific evaluation times.
-
prefer_device_noise_model(bool) –Whether to use the noise model of the sequence's
Device. -
with_modulation(bool) –Whether to emulate the sequence with output modulation effects.
Source code in pulser/backend/config.py
def __init__( self, *, callbacks: Sequence[Callback] = (), observables: Sequence[Observable] = (), # Default evaluation times for observables that don't specify one default_evaluation_times: Sequence[SupportsFloat] | Literal["Full"] = ( 1.0, ), initial_state: StateType | None = None, # Default is ggg... with_modulation: bool = False, interaction_matrix: ArrayLike | None = None, prefer_device_noise_model: bool = False, noise_model: NoiseModel | None = None, n_trajectories: int | None = None, default_num_shots: int = 1000, **backend_options: Any,) -> None: """Initializes the EmulationConfig.""" obs_tags = [] if not observables and not callbacks: warnings.warn( f"{self.__class__.__name__!r} was initialized without any " "observables. The corresponding emulation results will be" " empty.", stacklevel=2, ) for cb in callbacks: if isinstance(cb, Observable): raise TypeError( "All entries in 'callbacks' must not be instances of " "Observable, since those go in 'observables'." ) if not isinstance(cb, Callback): raise TypeError( "All entries in 'callbacks' must be instances of " f"Callback. Instead, got instance of type {type(cb)}." ) for obs in observables: if not isinstance(obs, Observable): raise TypeError( "All entries in 'observables' must be instances of " f"Observable. Instead, got instance of type {type(obs)}." ) obs_tags.append(obs.tag) repeated_tags = [k for k, v in Counter(obs_tags).items() if v > 1] if repeated_tags: raise ValueError( "Some of the provided 'observables' share identical tags. Use " "'tag_suffix' when instantiating multiple instances of the " "same observable so they can be distinguished. " f"Repeated tags found: {repeated_tags}" )
if not ( isinstance(default_evaluation_times, str) and default_evaluation_times == "Full" ): eval_times_arr = Observable._validate_eval_times( list(map(float, default_evaluation_times)) ) default_evaluation_times = cast(Sequence[float], eval_times_arr)
if initial_state is not None and not isinstance(initial_state, State): raise TypeError( "When defined, 'initial_state' must be an instance of State;" f" got object of type {type(initial_state)} instead." )
if interaction_matrix is not None: interaction_matrix = pm.AbstractArray(interaction_matrix) _shape = interaction_matrix.shape if len(_shape) != 2 or _shape[0] != _shape[1]: raise ValueError( "'interaction_matrix' must be a square matrix. Instead, " f"an array of shape {_shape} was given." ) if ( initial_state is not None and _shape[0] != initial_state.n_qudits ): raise ValueError( f"The received interaction matrix of shape {_shape} is " "incompatible with the received initial state of " f"{initial_state.n_qudits} qudits." ) matrix_arr = interaction_matrix.as_array(detach=True) if not np.allclose(matrix_arr, matrix_arr.transpose()): raise ValueError( "The received interaction matrix is not symmetric." ) if np.any(np.diag(matrix_arr) != 0): warnings.warn( "The received interaction matrix has non-zero values in " "its diagonal; keep in mind that these values are " "ignored.", stacklevel=2, )
if noise_model is None: noise_model = NoiseModel() elif not isinstance(noise_model, NoiseModel): raise TypeError( "When defined, 'noise_model' must be a NoiseModel instance," f" not {type(noise_model)}." )
if ( n_trajectories is not None and noise_model.runs is not None and n_trajectories != noise_model.runs ): raise ValueError( "`EmulationConfig.n_trajectories` and `NoiseModel.runs` " "can't be simultaneously defined. Please favour using only" " `EmulationConfig.n_trajectories`." )
if n_trajectories is None: if prefer_device_noise_model: n_trajectories = DEFAULT_N_TRAJECTORIES else: n_trajectories = ( noise_model.runs if noise_model.runs is not None else 1 )
if n_trajectories < 1 or n_trajectories != int(n_trajectories): raise ValueError( "`n_trajectories` must be a strictly positive integer, " f"not {n_trajectories}." )
super().__init__( callbacks=tuple(callbacks), observables=tuple(observables), default_evaluation_times=default_evaluation_times, initial_state=initial_state, with_modulation=bool(with_modulation), interaction_matrix=interaction_matrix, prefer_device_noise_model=bool(prefer_device_noise_model), noise_model=noise_model, n_trajectories=int(n_trajectories), default_num_shots=int(default_num_shots), **backend_options, )
callbacks: Sequence[Callback]
instance-attribute
Section titled “
callbacks: Sequence[Callback]
instance-attribute
”A sequence of callbacks that are not observables.
default_evaluation_times: NDArray[np.floating[Any]] | Literal['Full']
instance-attribute
Section titled “
default_evaluation_times: NDArray[np.floating[Any]] | Literal['Full']
instance-attribute
”The default times at which observables are computed.
default_num_shots: int
instance-attribute
Section titled “
default_num_shots: int
instance-attribute
”The default number of shots for BitStrings.
initial_state: StateType | None
instance-attribute
Section titled “
initial_state: StateType | None
instance-attribute
”A custom initial state from which emulation starts.
interaction_matrix: pm.AbstractArray | None
instance-attribute
Section titled “
interaction_matrix: pm.AbstractArray | None
instance-attribute
”An interaction matrix to replace the Hamiltonian interaction terms.
n_trajectories: int
instance-attribute
Section titled “
n_trajectories: int
instance-attribute
”The number of trajectories to average over (when applicable).
noise_model: NoiseModel
instance-attribute
Section titled “
noise_model: NoiseModel
instance-attribute
”A custom noise model to emulate the sequence with.
observables: Sequence[Observable]
instance-attribute
Section titled “
observables: Sequence[Observable]
instance-attribute
”A sequence of observables to compute at specific evaluation times.
prefer_device_noise_model: bool
instance-attribute
Section titled “
prefer_device_noise_model: bool
instance-attribute
”Whether to use the noise model of the sequence's Device.
with_modulation: bool
instance-attribute
Section titled “
with_modulation: bool
instance-attribute
”Whether to emulate the sequence with output modulation effects.
from_abstract_repr(obj_str: str) -> EmulationConfig
classmethod
Section titled “
from_abstract_repr(obj_str: str) -> EmulationConfig
classmethod
”Deserialize an EmulationConfig from an abstract JSON object.
Parameters:
obj_str
Section titled “ obj_str
”str)
–The JSON string representing the config encoded in the abstract JSON format.
Returns:
-
EmulationConfig(EmulationConfig) –The EmulationConfig instance.
Source code in pulser/backend/config.py
@classmethoddef from_abstract_repr(cls, obj_str: str) -> EmulationConfig: """Deserialize an EmulationConfig from an abstract JSON object.
Args: obj_str (str): The JSON string representing the config encoded in the abstract JSON format.
Returns: EmulationConfig: The EmulationConfig instance. """ if not isinstance(obj_str, str): raise TypeError( "The serialized EmulationConfig must be given as a string. " f"Instead, got object of type {type(obj_str)}." ) validate_abstract_repr(obj_str, "config") return _deserialize_emulation_config( json.loads(obj_str), cls, cls.state_type, cls.operator_type, )
is_evaluation_time(t: float, tol: float = 1e-06) -> bool
Section titled “
is_evaluation_time(t: float, tol: float = 1e-06) -> bool
”Assesses whether a relative time is an evaluation time.
Source code in pulser/backend/config.py
def is_evaluation_time(self, t: float, tol: float = 1e-6) -> bool: """Assesses whether a relative time is an evaluation time.""" return ( self.default_evaluation_times == "Full" and 0.0 <= t <= 1.0 ) or ( self.is_time_in_evaluation_times( t, self.default_evaluation_times, tol=tol ) )
is_time_in_evaluation_times(t: float, evaluation_times: ArrayLike, tol: float = 1e-06) -> bool
staticmethod
Section titled “
is_time_in_evaluation_times(t: float, evaluation_times: ArrayLike, tol: float = 1e-06) -> bool
staticmethod
”Checks if a time is within a collection of evaluation times.
Source code in pulser/backend/config.py
@staticmethoddef is_time_in_evaluation_times( t: float, evaluation_times: ArrayLike, tol: float = 1e-6) -> bool: """Checks if a time is within a collection of evaluation times.""" return 0.0 <= t <= 1.0 and bool( np.any(np.abs(np.array(evaluation_times, dtype=float) - t) <= tol) )
operator_type() -> Type[Operator]
Section titled “
operator_type() -> Type[Operator]
”The preferred operator type to use with this config class.
Source code in pulser/backend/config.py
@classpropertydef operator_type(cls) -> Type[Operator]: """The preferred operator type to use with this config class.""" return cls._operator_type
state_type() -> Type[State]
Section titled “
state_type() -> Type[State]
”The preferred state type to use with this config class.
Source code in pulser/backend/config.py
@classpropertydef state_type(cls) -> Type[State]: """The preferred state type to use with this config class.""" return cls._state_type
to_abstract_repr(skip_validation: bool = False) -> str
Section titled “
to_abstract_repr(skip_validation: bool = False) -> str
”Serialize EmulationConfig to a JSON formatted str.
Source code in pulser/backend/config.py
def to_abstract_repr(self, skip_validation: bool = False) -> str: """Serialize `EmulationConfig` to a JSON formatted str.""" obj_str = json.dumps(self, cls=AbstractReprEncoder) if not skip_validation: validate_abstract_repr(obj_str, "config") return obj_str
with_changes(**changes: Any) -> Self
Section titled “
with_changes(**changes: Any) -> Self
”Returns a copy of the config with the given changes.
Source code in pulser/backend/config.py
def with_changes(self: Self, **changes: Any) -> Self: """Returns a copy of the config with the given changes.""" return type(self)(**(self._backend_options | changes))
Energy(*, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
Section titled “
Energy(*, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
”Stores the energy of the system at the evaluation times.
The energy is calculated as the expectation value of the Hamiltonian,
i.e. <φ(t)|H(t)|φ(t)>.
Parameters:
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to compute the energy.
If left as None, uses the default_evaluation_times of the
backend's EmulationConfig.
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/observable.py
def __init__( self, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__() self.evaluation_times = ( self._validate_eval_times(evaluation_times) if evaluation_times is not None else None ) self._tag_suffix = tag_suffix
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> Any
Section titled “
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> Any
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply( self, *, state: State, hamiltonian: Operator, **kwargs: Any) -> Any: """Calculates the observable to store in the Results.""" return hamiltonian.expect(state)
EnergySecondMoment(*, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
Section titled “
EnergySecondMoment(*, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
”Stores the expectation value of H(t)^2 at the evaluation times.
Useful for computing the variance when averaging over many executions of the program.
Parameters:
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to compute the variance.
If left as None, uses the default_evaluation_times of the
backend's EmulationConfig.
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/observable.py
def __init__( self, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__() self.evaluation_times = ( self._validate_eval_times(evaluation_times) if evaluation_times is not None else None ) self._tag_suffix = tag_suffix
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> Any
Section titled “
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> Any
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply( self, *, state: State, hamiltonian: Operator, **kwargs: Any) -> Any: """Calculates the observable to store in the Results.""" # This works for state vectors and density matrices and avoids # squaring the hamiltonian h_state = hamiltonian.apply_to(state) identity = hamiltonian.from_operator_repr( eigenstates=state.eigenstates, n_qudits=state.n_qudits, operations=[(1.0, [])], ) return identity.expect(h_state)
EnergyVariance(*, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
Section titled “
EnergyVariance(*, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
”Stores the variance of the Hamiltonian at the evaluation times.
The variance of the Hamiltonian at time t is calculated by
<φ(t)|H(t)^2|φ(t)> - <φ(t)|H(t)|φ(t)>^2
Parameters:
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to compute the variance.
If left as None, uses the default_evaluation_times of the
backend's EmulationConfig.
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/observable.py
def __init__( self, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__() self.evaluation_times = ( self._validate_eval_times(evaluation_times) if evaluation_times is not None else None ) self._tag_suffix = tag_suffix
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> Any
Section titled “
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> Any
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply( self, *, state: State, hamiltonian: Operator, **kwargs: Any) -> Any: """Calculates the observable to store in the Results.""" # This works for state vectors and density matrices and avoids # squaring the hamiltonian h_state = hamiltonian.apply_to(state) identity = hamiltonian.from_operator_repr( eigenstates=state.eigenstates, n_qudits=state.n_qudits, operations=[(1.0, [])], ) return identity.expect(h_state) - hamiltonian.expect(state) ** 2
Expectation(operator: Operator, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
Section titled “
Expectation(operator: Operator, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
”Stores the expectation of the given operator on the current state.
Parameters:
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to compute the
expectation value. If left as None, uses the
default_evaluation_times of the backend's EmulationConfig.
operator
Section titled “ operator
”Operator)
–The operator to measure. Must be of the appropriate type for the backend.
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/default_observables.py
def __init__( self, operator: Operator, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__( evaluation_times=evaluation_times, tag_suffix=tag_suffix ) if not isinstance(operator, Operator): raise TypeError( "'operator' must be an Operator instance;" f" got {type(operator)} instead." ) self.operator = operator
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, state: State, **kwargs: Any) -> Any
Section titled “
apply(*, state: State, **kwargs: Any) -> Any
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply(self, *, state: State, **kwargs: Any) -> Any: """Calculates the observable to store in the Results.""" return self.operator.expect(state)
Fidelity(state: State, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
Section titled “
Fidelity(state: State, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
”Stores the fidelity with a pure state at the evaluation times.
The fidelity uses the overlap between the given state and the state of
the system at each evaluation time. For pure states, this corresponds
to |<ψ|φ(t)>|^2 for the given state |ψ> and the state |φ(t)>
obtained by time evolution.
Parameters:
state
Section titled “ state
”State)
–The state |ψ>. Note that this must be of an appropriate type
for the backend.
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to compute the fidelity.
If left as None, uses the default_evaluation_times of the
backend's EmulationConfig.
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/default_observables.py
def __init__( self, state: State, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__( evaluation_times=evaluation_times, tag_suffix=tag_suffix ) if not isinstance(state, State): raise TypeError( f"'state' must be a State instance; got {type(state)} instead." ) self.state = state
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, state: State, **kwargs: Any) -> Any
Section titled “
apply(*, state: State, **kwargs: Any) -> Any
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply(self, *, state: State, **kwargs: Any) -> Any: """Calculates the observable to store in the Results.""" return self.state.overlap(state)Abstract representation of an asynchronous job or task.
A :class:Job tracks the lifecycle of a unit of work submitted
for execution. It provides methods to inspect its state, wait for
its result, and cancel it.
Lifecycle::
PENDING -> RUNNING -> DONE -> ERROR -> CANCELEDConcrete backend implementations (:class:_LocalJob,
:class:_RemoteJob) must override all abstract methods.
The leading underscore in their names indicates that they are
internal to the library and must not be instantiated or
referenced directly by library consumers.
Instead, obtain a :class:Job from a backend submission
function such as backend.run(program).
Note
-
API reference
qoolqit.execution
executionretrieve_remote_job
-
API reference
qoolqit.execution
executionget_batch_id
Methods:
-
cancel–Request cancellation of the job.
-
get_status–Return the current lifecycle state of the job.
-
has_ended–Return whether the job has reached a terminal state.
-
job_id–Return the unique identifier of the job.
-
results–Block until the job completes and return its result.
cancel() -> None
abstractmethod
Section titled “
cancel() -> None
abstractmethod
”Request cancellation of the job.
Has no effect if the job has already reached a terminal state.
After a successful cancellation, :meth:get_status returns
:attr:~remote.JobStatus.CANCELED and :meth:has_ended returns
True.
Note
Source code in qoolqit/execution/job.py
@abstractmethoddef cancel(self) -> None: """Request cancellation of the job.
Has no effect if the job has already reached a terminal state. After a successful cancellation, :meth:`get_status` returns :attr:`~remote.JobStatus.CANCELED` and :meth:`has_ended` returns ``True``.
Note: Some implementations do not support cancellation. In that case this method is a no-op and the job status will never be :attr:`~remote.JobStatus.CANCELED`. """ ...
get_status() -> JobStatus
abstractmethod
Section titled “
get_status() -> JobStatus
abstractmethod
”Return the current lifecycle state of the job.
Returns:
-
JobStatus(JobStatus) –The current state of the job.
Source code in qoolqit/execution/job.py
@abstractmethoddef get_status(self) -> JobStatus: """Return the current lifecycle state of the job.
Returns: JobStatus: The current state of the job. """ ...
has_ended() -> bool
Section titled “
has_ended() -> bool
”Return whether the job has reached a terminal state.
A job has ended when its status is one of
:attr:~remote.JobStatus.DONE, :attr:~remote.JobStatus.ERROR, or
:attr:~remote.JobStatus.CANCELED.
Returns:
-
bool(bool) –Trueif the job is in a terminal state, -
bool–Falseotherwise.
Source code in qoolqit/execution/job.py
def has_ended(self) -> bool: """Return whether the job has reached a terminal state.
A job has ended when its status is one of :attr:`~remote.JobStatus.DONE`, :attr:`~remote.JobStatus.ERROR`, or :attr:`~remote.JobStatus.CANCELED`.
Returns: bool: ``True`` if the job is in a terminal state, ``False`` otherwise. """ return self.get_status() in { JobStatus.DONE, JobStatus.ERROR, JobStatus.CANCELED, }
job_id() -> str
abstractmethod
Section titled “
job_id() -> str
abstractmethod
”Return the unique identifier of the job.
For remote jobs this is the UUID used to track the job in the PASQAL Cloud Portal. For local jobs this is currently an empty string.
Returns:
-
str(str) –A string uniquely identifying this job.
Source code in qoolqit/execution/job.py
@abstractmethoddef job_id(self) -> str: """Return the unique identifier of the job.
For remote jobs this is the UUID used to track the job in the PASQAL Cloud Portal. For local jobs this is currently an empty string.
Returns: str: A string uniquely identifying this job. """ ...
results(timeout: float = math.inf) -> ResultType
abstractmethod
Section titled “
results(timeout: float = math.inf) -> ResultType
abstractmethod
”Block until the job completes and return its result.
Waits until the job reaches a terminal state, then returns the result. Polling strategy (interval, backoff) is delegated to the underlying connection.
Parameters:
timeout
Section titled “ timeout
”float, default:inf)
–Maximum seconds to wait.
Defaults to math.inf (wait indefinitely).
Returns:
-
ResultType(ResultType) –The result produced by the job.
Raises:
-
TimeoutError–If the job does not complete within timeout seconds.
-
JobFailedError–If the job reached a failed or error state.
-
JobCancelledError–If the job was cancelled.
Source code in qoolqit/execution/job.py
@abstractmethoddef results(self, timeout: float = math.inf) -> ResultType: """Block until the job completes and return its result.
Waits until the job reaches a terminal state, then returns the result. Polling strategy (interval, backoff) is delegated to the underlying connection.
Args: timeout (float): Maximum seconds to wait. Defaults to ``math.inf`` (wait indefinitely).
Returns: ResultType: The result produced by the job.
Raises: TimeoutError: If the job does not complete within *timeout* seconds. JobFailedError: If the job reached a failed or error state. JobCancelledError: If the job was cancelled. """ ...
LocalEmulator(*, backend_type: type[EmulatorBackend] = QutipBackendV2, emulation_config: EmulationConfig | None = None, num_shots: int | None = None)
Section titled “
LocalEmulator(*, backend_type: type[EmulatorBackend] = QutipBackendV2, emulation_config: EmulationConfig | None = None, num_shots: int | None = None)
”Run QoolQit QuantumPrograms on a Pasqal local emulator backends.
This class serves as a primary interface between tools written using QoolQit (including solvers) and local emulator backends.
Parameters:
backend_type
Section titled “ backend_type
”type, default:QutipBackendV2)
–backend type. Must be a subtype of pulser.backend.EmulatorBackend.
emulation_config
Section titled “ emulation_config
”EmulationConfig, default:None)
–optional configuration object emulators.
num_shots
Section titled “ num_shots
”int, default:None)
–number of bitstring samples to collect from the final quantum state.
Examples:
from qoolqit.execution import LocalEmulator, BackendTypebackend = LocalEmulator(backend_type=BackendType.QutipBackendV2)result = backend.run(program)Methods:
-
default_emulation_config–Return a unique emulation config for all emulators.
-
run–Run a compiled QuantumProgram and return the results.
-
validate_emulation_config–Returns a valid config for emulator backends, if needed.
Source code in qoolqit/execution/backends.py
def __init__( self, *, backend_type: type[EmulatorBackend] = QutipBackendV2, emulation_config: EmulationConfig | None = None, num_shots: int | None = None,) -> None: """Instantiates a LocalEmulator.""" super().__init__(num_shots=num_shots) if not issubclass(backend_type, EmulatorBackend): raise TypeError( "Error in `LocalEmulator`: `backend_type` must be a EmulatorBackend type." ) self._backend_type = backend_type self._emulation_config = self.validate_emulation_config(emulation_config)
default_emulation_config() -> EmulationConfig
Section titled “
default_emulation_config() -> EmulationConfig
”Return a unique emulation config for all emulators.
Defaults to a configuration that asks for the final bitstring, sampled num_shots times.
Source code in qoolqit/execution/backends.py
def default_emulation_config(self) -> EmulationConfig: """Return a unique emulation config for all emulators.
Defaults to a configuration that asks for the final bitstring, sampled `num_shots` times. """ return EmulationConfig(observables=(BitStrings(num_shots=self._num_shots),))
run(program: QuantumProgram) -> job.Job[Results]
Section titled “
run(program: QuantumProgram) -> job.Job[Results]
”Run a compiled QuantumProgram and return the results.
Source code in qoolqit/execution/backends.py
def run(self, program: QuantumProgram) -> job.Job[Results]: """Run a compiled QuantumProgram and return the results.""" self._backend = self._backend_type(program.compiled_sequence, config=self._emulation_config) results = self._backend.run() assert isinstance(results, Results) return job._LocalJob(results)
validate_emulation_config(emulation_config: EmulationConfig | None) -> EmulationConfig
Section titled “
validate_emulation_config(emulation_config: EmulationConfig | None) -> EmulationConfig
”Returns a valid config for emulator backends, if needed.
Parameters:
emulation_config
Section titled “ emulation_config
”EmulationConfig | None)
–optional base configuration class for all emulators backends. If no config is provided to an emulator backend, the backend default will used.
Source code in qoolqit/execution/backends.py
def validate_emulation_config( self, emulation_config: EmulationConfig | None) -> EmulationConfig: """Returns a valid config for emulator backends, if needed.
Args: emulation_config: optional base configuration class for all emulators backends. If no config is provided to an emulator backend, the backend default will used. """ if emulation_config is None: emulation_config = self.default_emulation_config() else: has_bitstrings = any( isinstance(obs, BitStrings) for obs in emulation_config.observables ) if not has_bitstrings: updated_obs = (*emulation_config.observables, BitStrings(num_shots=self._num_shots)) emulation_config = emulation_config.with_changes(observables=updated_obs)
if self._num_shots is not None: emulation_config = emulation_config.with_changes(default_num_shots=self._num_shots)
return emulation_config
Occupation(*, evaluation_times: Sequence[float] | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None)
Section titled “
Occupation(*, evaluation_times: Sequence[float] | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None)
”Stores the occupation number of an eigenstate on each qudit.
For every qudit i, calculates <φ(t)|n_i|φ(t)>, where
n_i = |one_state><one_state|.
Parameters:
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to compute the
correlation matrix. If left as None, uses the
default_evaluation_times of the backend's EmulationConfig.
one_state
Section titled “ one_state
”Eigenstate | None, default:None)
–The eigenstate to measure the population of. Can be left undefined if the state's eigenstates form a known eigenbasis with a defined "one state".
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/default_observables.py
def __init__( self, *, evaluation_times: Sequence[float] | None = None, one_state: Eigenstate | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__( evaluation_times=evaluation_times, tag_suffix=tag_suffix ) self.one_state = one_state
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> list
Section titled “
apply(*, state: State, hamiltonian: Operator, **kwargs: Any) -> list
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply( self, *, state: State, hamiltonian: Operator, **kwargs: Any) -> list: """Calculates the observable to store in the Results.""" return [ CorrelationMatrix._get_number_operator( frozenset((i,)), state.n_qudits, state.eigenstates, self.one_state or state.infer_one_state(), type(hamiltonian), ).expect(state) for i in range(state.n_qudits) ]
QPU(*, connection: RemoteConnection, num_shots: int | None = None)
Section titled “
QPU(*, connection: RemoteConnection, num_shots: int | None = None)
”Execute QoolQit QuantumPrograms on Pasqal quantum processing units.
This class provides the primary interface for running quantum programs on actual QPU hardware. It requires authenticated credentials through a connection object to submit and execute programs on remote quantum processors.
Parameters:
connection
Section titled “ connection
”RemoteConnection)
–Authenticated connection to the remote QPU backend.
num_shots
Section titled “ num_shots
”int | None, default:None)
–Number of bitstring samples to collect from the final quantum state.
Examples:
Using Pasqal Cloud:
from pulser_pasqal import PasqalCloudfrom qoolqit.execution import QPU
connection = PasqalCloud( username="your_username", password="your_password", project_id="your_project_id")backend = QPU(connection=connection)remote_results = backend.submit(program)Using Atos MyQML:
from pulser_myqlm import PulserQLMConnectionfrom qoolqit.execution import QPU
connection = PulserQLMConnection()backend = QPU(connection=connection)results = backend.run(program)Note
Methods:
-
run–Run a compiled QuantumProgram and return a job handler.
-
validate_connection–Validate the required connection to instantiate a RemoteBackend.
Source code in qoolqit/execution/backends.py
def __init__( self, *, connection: RemoteConnection, num_shots: int | None = None,) -> None: """Instantiates a QPU backend.""" self._backend_type = QPUBackend self._connection = self.validate_connection(connection) if num_shots is None: raise ValueError( """Number of shots must be provided to use the QPU backend. Please specify `num_shots` when creating the QPU instance. For example: QPU(connection=..., num_shots=100)""", ) self._config = BackendConfig(default_num_shots=num_shots)
run(program: QuantumProgram) -> job.Job[Results]
Section titled “
run(program: QuantumProgram) -> job.Job[Results]
”Run a compiled QuantumProgram and return a job handler.
The returned handler Job can be used to retrieve results with job.results()
Parameters:
program
Section titled “ program
”QuantumProgram)
–the compiled quantum program to run.
Source code in qoolqit/execution/backends.py
def run(self, program: QuantumProgram) -> job.Job[Results]: """Run a compiled QuantumProgram and return a job handler.
The returned handler `Job` can be used to retrieve results with `job.results()`
Args: program (QuantumProgram): the compiled quantum program to run. """ self._backend = self._backend_type( program.compiled_sequence, connection=self._connection, config=self._config ) remote_results = self._backend.run(wait=False) # If in open-batch mode, the job should be the last one in the batch ? return job._RemoteJob._from_remote_results(remote_results, -1)
validate_connection(connection: RemoteConnection) -> RemoteConnection
staticmethod
Section titled “
validate_connection(connection: RemoteConnection) -> RemoteConnection
staticmethod
”Validate the required connection to instantiate a RemoteBackend.
Remote emulators and QPUs require a pulser.backend.remote.RemoteConnection or derived
to send jobs. Validation also happens inside the backend. Early validation just makes the
error easier to understand.
Source code in qoolqit/execution/backends.py
@staticmethoddef validate_connection(connection: RemoteConnection) -> RemoteConnection: """Validate the required connection to instantiate a RemoteBackend.
Remote emulators and QPUs require a `pulser.backend.remote.RemoteConnection` or derived to send jobs. Validation also happens inside the backend. Early validation just makes the error easier to understand. """ if not isinstance(connection, RemoteConnection): raise TypeError(f"""Error in `PulserRemoteBackend`: `connection` must be of type {RemoteConnection}.""") return connection
RemoteEmulator(*, backend_type: type[RemoteEmulatorBackend] = EmuFreeBackendV2, connection: RemoteConnection, emulation_config: EmulationConfig | None = None, num_shots: int | None = None)
Section titled “
RemoteEmulator(*, backend_type: type[RemoteEmulatorBackend] = EmuFreeBackendV2, connection: RemoteConnection, emulation_config: EmulationConfig | None = None, num_shots: int | None = None)
”Run QoolQit QuantumPrograms on a Pasqal remote emulator backends.
This class serves as a primary interface between tools written using QoolQit (including solvers)
and remote emulator backends.
The behavior is similar to LocalEmulator, but here, requires credentials through
a connection to submit/run a program.
To get your credentials and to create a connection object, please refer to the Pasqal Cloud
interface documentation (external).
Parameters:
backend_type
Section titled “ backend_type
”type, default:EmuFreeBackendV2)
–backend type. Must be a subtype of
pulser_pasqal.backends.RemoteEmulatorBackend.
connection
Section titled “ connection
”RemoteConnection)
–connection to execute the program on remote backends.
emulation_config
Section titled “ emulation_config
”EmulationConfig, default:None)
–optional configuration object emulators.
num_shots
Section titled “ num_shots
”int, default:None)
–number of bitstring samples to collect from the final quantum state.
Examples:
from pulser_pasqal import PasqalCloudfrom qoolqit.execution import RemoteEmulator, BackendTypeconnection = PasqalCloud(username=..., password=..., project_id=...)backend = RemoteEmulator(backend_type=BackendType.EmuFreeBackendV2, connection=connection)remote_results = backend.submit(program)results = backend.run(program)Methods:
-
default_emulation_config–Return a unique emulation config for all emulators.
-
run–Run a compiled QuantumProgram and return a job handler.
-
validate_connection–Validate the required connection to instantiate a RemoteBackend.
-
validate_emulation_config–Returns a valid config for emulator backends, if needed.
Source code in qoolqit/execution/backends.py
def __init__( self, *, backend_type: type[RemoteEmulatorBackend] = EmuFreeBackendV2, connection: RemoteConnection, emulation_config: EmulationConfig | None = None, num_shots: int | None = None,) -> None: """Instantiates a RemoteEmulator.""" super().__init__(num_shots=num_shots) if not issubclass(backend_type, RemoteEmulatorBackend): raise TypeError( "Error in `RemoteEmulator`: `backend_type` must be a RemoteEmulatorBackend type." ) self._backend_type = backend_type self._connection = self.validate_connection(connection) self._emulation_config = self.validate_emulation_config(emulation_config)
default_emulation_config() -> EmulationConfig
Section titled “
default_emulation_config() -> EmulationConfig
”Return a unique emulation config for all emulators.
Defaults to a configuration that asks for the final bitstring, sampled num_shots times.
Source code in qoolqit/execution/backends.py
def default_emulation_config(self) -> EmulationConfig: """Return a unique emulation config for all emulators.
Defaults to a configuration that asks for the final bitstring, sampled `num_shots` times. """ return EmulationConfig(observables=(BitStrings(num_shots=self._num_shots),))
run(program: QuantumProgram) -> job.Job[Results]
Section titled “
run(program: QuantumProgram) -> job.Job[Results]
”Run a compiled QuantumProgram and return a job handler.
The returned handler Job can be used to retrieve results with job.results()
Parameters:
program
Section titled “ program
”QuantumProgram)
–the compiled quantum program to run.
Source code in qoolqit/execution/backends.py
def run(self, program: QuantumProgram) -> job.Job[Results]: """Run a compiled QuantumProgram and return a job handler.
The returned handler `Job` can be used to retrieve results with `job.results()`
Args: program (QuantumProgram): the compiled quantum program to run. """ # Instantiate backend self._backend = self._backend_type( program.compiled_sequence, connection=self._connection, config=self._emulation_config, ) remote_results = self._backend.run(wait=False) # If in open-batch mode, the job should be the last one in the batch ? return job._RemoteJob._from_remote_results(remote_results, -1)
validate_connection(connection: RemoteConnection) -> RemoteConnection
staticmethod
Section titled “
validate_connection(connection: RemoteConnection) -> RemoteConnection
staticmethod
”Validate the required connection to instantiate a RemoteBackend.
Remote emulators and QPUs require a pulser.backend.remote.RemoteConnection or derived
to send jobs. Validation also happens inside the backend. Early validation just makes the
error easier to understand.
Source code in qoolqit/execution/backends.py
@staticmethoddef validate_connection(connection: RemoteConnection) -> RemoteConnection: """Validate the required connection to instantiate a RemoteBackend.
Remote emulators and QPUs require a `pulser.backend.remote.RemoteConnection` or derived to send jobs. Validation also happens inside the backend. Early validation just makes the error easier to understand. """ if not isinstance(connection, RemoteConnection): raise TypeError(f"""Error in `PulserRemoteBackend`: `connection` must be of type {RemoteConnection}.""") return connection
validate_emulation_config(emulation_config: EmulationConfig | None) -> EmulationConfig
Section titled “
validate_emulation_config(emulation_config: EmulationConfig | None) -> EmulationConfig
”Returns a valid config for emulator backends, if needed.
Parameters:
emulation_config
Section titled “ emulation_config
”EmulationConfig | None)
–optional base configuration class for all emulators backends. If no config is provided to an emulator backend, the backend default will used.
Source code in qoolqit/execution/backends.py
def validate_emulation_config( self, emulation_config: EmulationConfig | None) -> EmulationConfig: """Returns a valid config for emulator backends, if needed.
Args: emulation_config: optional base configuration class for all emulators backends. If no config is provided to an emulator backend, the backend default will used. """ if emulation_config is None: emulation_config = self.default_emulation_config() else: has_bitstrings = any( isinstance(obs, BitStrings) for obs in emulation_config.observables ) if not has_bitstrings: updated_obs = (*emulation_config.observables, BitStrings(num_shots=self._num_shots)) emulation_config = emulation_config.with_changes(observables=updated_obs)
if self._num_shots is not None: emulation_config = emulation_config.with_changes(default_num_shots=self._num_shots)
return emulation_config
Results(atom_order: tuple[str, ...], total_duration: int)
dataclass
Section titled “
Results(atom_order: tuple[str, ...], total_duration: int)
dataclass
”A collection of results.
Parameters:
atom_order
Section titled “ atom_order
”tuple[str, ...])
–The order of the atoms/qudits in the results.
total_duration
Section titled “ total_duration
”int)
–The total duration of the sequence, in ns.
Methods:
-
aggregate–Aggregate a Sequence of Results objects into a single Results.
-
from_abstract_repr–Deserializes a Results object from json.
-
get_result–Get the a specific result at a given time.
-
get_result_tags–Get a list of results tags present in this object.
-
get_result_times–Get a list of times for which the given result has been stored.
-
get_tagged_results–Gets the results for every tag.
-
to_abstract_repr–Serializes this object into a json string.
Attributes:
-
atom_order(tuple[str, ...]) –The order of the atoms/qudits in the results.
-
final_bitstrings(dict[str, int]) –The bitstrings at the end of the sequence, if available.
-
final_state(State) –The state at the end of the sequence, if available.
-
total_duration(int) –The total duration of the sequence, in ns.
atom_order: tuple[str, ...]
instance-attribute
Section titled “
atom_order: tuple[str, ...]
instance-attribute
”The order of the atoms/qudits in the results.
final_bitstrings: dict[str, int]
property
Section titled “
final_bitstrings: dict[str, int]
property
”The bitstrings at the end of the sequence, if available.
final_state: State
property
Section titled “
final_state: State
property
”The state at the end of the sequence, if available.
total_duration: int
instance-attribute
Section titled “
total_duration: int
instance-attribute
”The total duration of the sequence, in ns.
aggregate(results_to_aggregate: typing.Sequence[Results], **aggregation_functions: Callable[[Any], Any]) -> Results
classmethod
Section titled “
aggregate(results_to_aggregate: typing.Sequence[Results], **aggregation_functions: Callable[[Any], Any]) -> Results
classmethod
”Aggregate a Sequence of Results objects into a single Results.
This is meant to accumulate the results of several runs with different noise trajectories into a single averaged Results. By default, results are averaged, with the exception of BitStrings, where the counters are joined. StateResult and EnergyVariance are not supported by default.
Warning
Parameters:
results_to_aggregate
Section titled “ results_to_aggregate
”Sequence[Results])
–The list of Results to aggregate
Other Parameters:
-
observable_tag–Overrides the default aggregator. The argument name should be the tag of the Observable. The value is a Callable taking a list of the type to aggregate. Note that this does not override the default aggregation behaviour of the aggregated results.
Returns:
-
Results–The averaged Results object
Source code in pulser/backend/results.py
@classmethoddef aggregate( cls, results_to_aggregate: typing.Sequence[Results], **aggregation_functions: Callable[[Any], Any],) -> Results: """Aggregate a Sequence of Results objects into a single Results.
This is meant to accumulate the results of several runs with different noise trajectories into a single averaged Results. By default, results are averaged, with the exception of BitStrings, where the counters are joined. StateResult and EnergyVariance are not supported by default.
Warning: The ability to access a result from an observable instance (e.g. via Results.get_result(obs)) is only preserved if all aggregated results originated from the same observable instance. When that is not the case, the aggregated result can still be accessed via the observable's tag.
Args: results_to_aggregate: The list of Results to aggregate
Keyword Args: observable_tag: Overrides the default aggregator. The argument name should be the tag of the Observable. The value is a Callable taking a list of the type to aggregate. Note that this does not override the default aggregation behaviour of the aggregated results.
Returns: The averaged Results object """ if len(results_to_aggregate) == 0: raise ValueError("No results to aggregate.") result_0 = results_to_aggregate[0] if len(results_to_aggregate) == 1: return result_0
all_tags = set().union( *[set(x.get_result_tags()) for x in results_to_aggregate] ) common_tags = all_tags.intersection( *[set(x.get_result_tags()) for x in results_to_aggregate] )
for results in results_to_aggregate: if results._results and (not results._aggregation_methods): raise NotImplementedError( ( "You're trying to aggregate results from pulser<1.6," "aggregation is not supported in this case." ) ) for tag, uid in results._tagmap.items(): if tag not in common_tags and not ( results._aggregation_methods[uid].value in (AggregationMethod.SKIP, AggregationMethod.SKIP_WARN) ): raise ValueError( "You're trying to aggregate incompatible results: " f"result `{tag}` is not present in all results, " "but it's not marked to be skipped." ) if not all( { tag: results._aggregation_methods[results._find_uuid(tag)] for tag in common_tags } == { tag: result_0._aggregation_methods[result_0._find_uuid(tag)] for tag in common_tags } for results in results_to_aggregate ): raise ValueError( "You're trying to aggregate incompatible results: " "they do not all contain the same aggregation functions." ) if not all( results.atom_order == result_0.atom_order for results in results_to_aggregate ): raise ValueError( "You're trying to aggregate incompatible results: " "they do not all have the same atom order." ) if not all( results.total_duration == result_0.total_duration for results in results_to_aggregate ): raise ValueError( "You're trying to aggregate incompatible results: " "they do not all have the same sequence duration." ) aggregated = Results( atom_order=result_0.atom_order, total_duration=result_0.total_duration, ) for tag in common_tags: default_aggregation_method = result_0._aggregation_methods[ result_0._tagmap[tag] ] aggregation_method = aggregation_functions.get( tag, default_aggregation_method ) if ( aggregation_method is AggregationMethod.SKIP or aggregation_method is AggregationMethod.SKIP_WARN ): if aggregation_method is AggregationMethod.SKIP_WARN: with warnings.catch_warnings(): warnings.simplefilter("once") warnings.warn(f"Skipping aggregation of `{tag}`.") continue aggregation_function: Any = ( AGGREGATOR_MAPPING[aggregation_method] if isinstance(aggregation_method, AggregationMethod) else aggregation_method ) evaluation_times = results_to_aggregate[0].get_result_times(tag) if not all( results.get_result_times(tag) == evaluation_times for results in results_to_aggregate ): raise ValueError( "The Results come from " "incompatible simulations: " f"the times for `{tag}` are not all the same." )
_uuids = set(res._tagmap[tag] for res in results_to_aggregate) if len(_uuids) == 1: # Preserve the UUID when all results share the same uid = list(_uuids)[0] else: # Otherwise, create a new one uid = uuid.uuid4()
for t in result_0.get_result_times(tag): v = aggregation_function( [ result.get_result(tag, t) for result in results_to_aggregate ] )
aggregated._store_raw( uuid=uid, tag=tag, time=t, value=v, aggregation_method=default_aggregation_method, )
return aggregated
from_abstract_repr(repr: str) -> Results
classmethod
Section titled “
from_abstract_repr(repr: str) -> Results
classmethod
”Deserializes a Results object from json.
Returns:
-
Results–The deserialized Results object.
Source code in pulser/backend/results.py
@classmethoddef from_abstract_repr(cls, repr: str) -> Results: """Deserializes a Results object from json.
Returns: The deserialized Results object. """ validate_abstract_repr(repr, "results") d = json.loads(repr) return cls._from_abstract_repr(d)
get_result(observable: Observable | str, time: float) -> Any
Section titled “
get_result(observable: Observable | str, time: float) -> Any
”Get the a specific result at a given time.
Parameters:
observable
Section titled “ observable
”Observable | str)
–The observable instance used to calculate the result or its tag.
float)
–Relative time at which to get the result.
Returns:
-
Any–The result.
Source code in pulser/backend/results.py
def get_result(self, observable: Observable | str, time: float) -> Any: """Get the a specific result at a given time.
Args: observable: The observable instance used to calculate the result or its tag. time: Relative time at which to get the result.
Returns: The result. """ obs_uuid = self._find_uuid(observable) try: ind = self._times[obs_uuid].index(time) return self._results[obs_uuid][ind] except (KeyError, ValueError): raise ValueError( f"{observable!r} is not available at time {time}." )
get_result_tags() -> list[str]
Section titled “
get_result_tags() -> list[str]
”Get a list of results tags present in this object.
Source code in pulser/backend/results.py
def get_result_tags(self) -> list[str]: """Get a list of results tags present in this object.""" return list(self._tagmap.keys())
get_result_times(observable: Observable | str) -> list[float]
Section titled “
get_result_times(observable: Observable | str) -> list[float]
”Get a list of times for which the given result has been stored.
Parameters:
observable
Section titled “ observable
”Observable | str)
–The observable instance used to calculate the result or its tag.
Returns:
-
list[float]–List of relative times.
Source code in pulser/backend/results.py
def get_result_times(self, observable: Observable | str) -> list[float]: """Get a list of times for which the given result has been stored.
Args: observable: The observable instance used to calculate the result or its tag.
Returns: List of relative times. """ return list(self._times[self._find_uuid(observable)])
get_tagged_results() -> dict[str, list[Any]]
Section titled “
get_tagged_results() -> dict[str, list[Any]]
”Gets the results for every tag.
Returns:
-
dict[str, list[Any]]–A mapping between a tag and the results associated to it,
-
dict[str, list[Any]]–at every evaluation time.
Source code in pulser/backend/results.py
def get_tagged_results(self) -> dict[str, list[Any]]: """Gets the results for every tag.
Returns: A mapping between a tag and the results associated to it, at every evaluation time. """ return { tag: list(self._results[uuid_]) for tag, uuid_ in self._tagmap.items() }
to_abstract_repr(skip_validation: bool = False) -> str
Section titled “
to_abstract_repr(skip_validation: bool = False) -> str
”Serializes this object into a json string.
Numpy arrays and torch Tensors are converted into lists, and their original class is lost forever.
Parameters:
skip_validation
Section titled “ skip_validation
”bool, default:False)
–Whether to skip validating the json against the schema used for deserialization.
Returns:
-
str–The json string
Source code in pulser/backend/results.py
def to_abstract_repr(self, skip_validation: bool = False) -> str: """Serializes this object into a json string.
Numpy arrays and torch Tensors are converted into lists, and their original class is lost forever.
Args: skip_validation: Whether to skip validating the json against the schema used for deserialization.
Returns: The json string """ abstr_str = json.dumps( self._to_abstract_repr(), cls=AbstractReprEncoder ) if not skip_validation: validate_abstract_repr(abstr_str, "results") return abstr_str
StateResult(*, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
Section titled “
StateResult(*, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None)
”Stores the quantum state at the evaluation times.
Parameters:
evaluation_times
Section titled “ evaluation_times
”Sequence[float] | None, default:None)
–The relative times at which to store the state.
If left as None, uses the default_evaluation_times of the
backend's EmulationConfig.
tag_suffix
Section titled “ tag_suffix
”str | None, default:None)
–An optional suffix to append to the tag. Needed if multiple instances of the same observable are given to the same EmulationConfig.
Methods:
-
__call__–Specifies a call to the observable at a specific time.
-
apply–Calculates the observable to store in the Results.
Attributes:
-
tag(str) –Label for the observable, used to index the Results object.
-
uuid(UUID) –A universal unique identifier for this instance.
Source code in pulser/backend/observable.py
def __init__( self, *, evaluation_times: Sequence[float] | None = None, tag_suffix: str | None = None,): """Initializes the observable.""" super().__init__() self.evaluation_times = ( self._validate_eval_times(evaluation_times) if evaluation_times is not None else None ) self._tag_suffix = tag_suffix
tag: str
property
Section titled “
tag: str
property
”Label for the observable, used to index the Results object.
Within a Results instance, all computed observables must have different tags.
Returns:
-
str–The tag of the observable.
uuid: uuid.UUID
property
Section titled “
uuid: uuid.UUID
property
”A universal unique identifier for this instance.
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
Section titled “
__call__(config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results) -> None
”Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator.
By default it calls apply() to compute a result and put it in Results
if t in self.evaluation_times.
It can be overloaded to define general callbacks that don't put results
in the Results object.
Parameters:
config
Section titled “ config
”EmulationConfig)
–The config object passed to the backend.
float)
–The relative time as a float between 0 and 1.
state
Section titled “ state
”State)
–The current state.
hamiltonian
Section titled “ hamiltonian
”Operator)
–The Hamiltonian at this time.
result
Section titled “ result
”Results)
–The Results object to store the result in.
Source code in pulser/backend/observable.py
def __call__( self, config: EmulationConfig, t: float, state: State, hamiltonian: Operator, result: Results,) -> None: """Specifies a call to the observable at a specific time.
This is called after each time step performed by the emulator. By default it calls `apply()` to compute a result and put it in Results if t in self.evaluation_times. It can be overloaded to define general callbacks that don't put results in the Results object.
Args: config: The config object passed to the backend. t: The relative time as a float between 0 and 1. state: The current state. hamiltonian: The Hamiltonian at this time. result: The Results object to store the result in. """ time_tol = ( (0.5 / result.total_duration) if result.total_duration else 1e-6 ) if ( self.evaluation_times is not None and config.is_time_in_evaluation_times( t, self.evaluation_times, tol=time_tol ) ) or ( self.evaluation_times is None and config.is_evaluation_time(t, tol=time_tol) ): value_to_store = self.apply( config=config, state=state, hamiltonian=hamiltonian ) result._store(observable=self, time=t, value=value_to_store)
apply(*, state: StateType, **kwargs: Any) -> StateType
Section titled “
apply(*, state: StateType, **kwargs: Any) -> StateType
”Calculates the observable to store in the Results.
Source code in pulser/backend/default_observables.py
def apply(self, *, state: StateType, **kwargs: Any) -> StateType: """Calculates the observable to store in the Results.""" return copy.deepcopy(state)
get_batch_id(job: Job[Results]) -> str
Section titled “
get_batch_id(job: Job[Results]) -> str
”Return the batch ID associated with a remote job.
Temporary utility for cases where batch_id must be persisted
and later passed to :func:retrieve_remote_job. Will be
deprecated once RemoteConnection supports direct job lookup
by job ID alone.
Parameters:
(Job[Results])
–Any :class:Job instance.
Returns:
-
str(str) –The batch ID if job is a :class:
_RemoteJob, -
str–otherwise an empty string.
Source code in qoolqit/execution/job.py
def get_batch_id(job: Job[Results]) -> str: """Return the batch ID associated with a remote job.
Temporary utility for cases where *batch_id* must be persisted and later passed to :func:`retrieve_remote_job`. Will be deprecated once ``RemoteConnection`` supports direct job lookup by job ID alone.
Args: job (Job[Results]): Any :class:`Job` instance.
Returns: str: The batch ID if *job* is a :class:`_RemoteJob`, otherwise an empty string. """ if isinstance(job, _RemoteJob): return job._batch_id return ""
retrieve_remote_job(connection: remote.RemoteConnection, job_id: str, *, batch_id: str = '') -> Job[Results]
Section titled “
retrieve_remote_job(connection: remote.RemoteConnection, job_id: str, *, batch_id: str = '') -> Job[Results]
”Retrieve a previously submitted remote job by its identifiers.
Use this to reconnect to a job in a new session, or to monitor a job submitted outside the current context.
Note
Parameters:
connection
Section titled “ connection
”RemoteConnection)
–The remote connection through which to query the job.
job_id
Section titled “ job_id
”str)
–The UUID of the job to retrieve.
batch_id
Section titled “ batch_id
”str, default:'')
–The batch identifier the job belongs to. Defaults to an empty string.
Returns:
Source code in qoolqit/execution/job.py
def retrieve_remote_job( connection: remote.RemoteConnection, job_id: str, *, batch_id: str = "",) -> Job[Results]: """Retrieve a previously submitted remote job by its identifiers.
Use this to reconnect to a job in a new session, or to monitor a job submitted outside the current context.
Note: The *batch_id* argument is required by some ``RemoteConnection`` implementations (e.g. ``PasqalCloudConnection``) to query job progress. Use :func:`get_batch_id` to recover the batch ID from an existing :class:`Job` if needed.
This dependency on *batch_id* is temporary and will be removed once ``RemoteConnection`` supports direct lookup by job ID alone.
Args: connection (remote.RemoteConnection): The remote connection through which to query the job. job_id (str): The UUID of the job to retrieve. batch_id (str): The batch identifier the job belongs to. Defaults to an empty string.
Returns: Job[Results]: A :class:`_RemoteJob` connected to the specified job. """ return _RemoteJob(connection, job_id, batch_id=batch_id)