Skip to content
Pasqal Documentation

Abstract backend

Backend(name, supports_ad, support_bp, supports_adjoint, is_remote, with_measurements, native_endianness, engine, with_noise, config) dataclass

Section titled “ Backend(name, supports_ad, support_bp, supports_adjoint, is_remote, with_measurements, native_endianness, engine, with_noise, config) dataclass ”

Bases: ABC

The abstract class that defines the interface for the backends.

ATTRIBUTE DESCRIPTION
name

backend unique string identifier

TYPE: BackendName

supports_ad

whether or not the backend has a native autograd

TYPE: bool

supports_bp

whether or not the backend has a native backprop

TYPE: bool

supports_adjoint

Does the backend support native adjoint differentation.

TYPE: bool

is_remote

whether computations are executed locally or remotely on this backend, useful when using cloud platforms where credentials are needed for example.

TYPE: bool

with_measurements

whether it supports counts or not

TYPE: bool

with_noise

whether to add realistic noise or not

TYPE: bool

native_endianness

The native endianness of the backend

TYPE: Endianness

engine

The underlying (native) automatic differentiation engine of the backend.

TYPE: Engine

Converts an abstract QuantumCircuit to the native backend representation.

PARAMETER DESCRIPTION
circuit

A circuit, for example: QuantumCircuit(2, X(0))

TYPE: QuantumCircuit

RETURNS DESCRIPTION
ConvertedCircuit

A converted circuit c. You can access the original, arbstract circuit via c.abstract

ConvertedCircuit

and the converted (or backend native) circuit via c.native.

Source code in qadence/backend.py
159
160
161
162
163
164
165
166
167
168
169
170@abstractmethod
def circuit(self, circuit: QuantumCircuit) -> ConvertedCircuit:
"""Converts an abstract `QuantumCircuit` to the native backend representation.
Arguments:
circuit: A circuit, for example: `QuantumCircuit(2, X(0))`
Returns:
A converted circuit `c`. You can access the original, arbstract circuit via `c.abstract`
and the converted (or backend *native*) circuit via `c.native`.
"""
raise NotImplementedError

Convert an abstract circuit and an optional observable to their native representation.

Additionally, this function constructs an embedding function which maps from user-facing parameters to device parameters (read more on parameter embedding here).

Source code in qadence/backend.py
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253def convert(
self, circuit: QuantumCircuit, observable: list[AbstractBlock] | AbstractBlock | None = None
) -> Converted:
"""Convert an abstract circuit and an optional observable to their native representation.
Additionally, this function constructs an embedding function which maps from
user-facing parameters to device parameters (read more on parameter embedding
[here][qadence.blocks.embedding.embedding]).
"""
def check_observable(obs_obj: Any) -> AbstractBlock:
if isinstance(obs_obj, QubitOperator):
from qadence.blocks.manipulate import from_openfermion
assert len(obs_obj.terms) > 0, "Make sure to give a non-empty qubit hamiltonian"
return from_openfermion(obs_obj)
elif isinstance(obs_obj, (CompositeBlock, PrimitiveBlock, ScaleBlock)):
from qadence.blocks.utils import block_is_qubit_hamiltonian
assert block_is_qubit_hamiltonian(
obs_obj
), "Make sure the QubitHamiltonian consists only of Pauli operators X, Y, Z, I"
return obs_obj
raise TypeError(
"qubit_hamiltonian should be a Pauli-like AbstractBlock or a QubitOperator"
)
conv_circ = self.circuit(circuit)
circ_params, circ_embedding_fn = embedding(
conv_circ.abstract.block, self.config._use_gate_params, self.engine
)
params = circ_params
if observable is not None:
observable = observable if isinstance(observable, list) else [observable]
conv_obs = []
obs_embedding_fns = []
for obs in observable:
obs = check_observable(obs)
c_obs = self.observable(obs, max(circuit.n_qubits, obs.n_qubits))
obs_params, obs_embedding_fn = embedding(
c_obs.abstract, self.config._use_gate_params, self.engine
)
params.update(obs_params)
obs_embedding_fns.append(obs_embedding_fn)
conv_obs.append(c_obs)
def embedding_fn_dict(a: dict, b: dict) -> dict:
if "circuit" in b or "observables" in b:
embedding_dict = {"circuit": circ_embedding_fn(a, b), "observables": dict()}
for obs_embedding_fn in obs_embedding_fns:
embedding_dict["observables"].update(obs_embedding_fn(a, b))
else:
embedding_dict = circ_embedding_fn(a, b)
for obs_embedding_fn in obs_embedding_fns:
embedding_dict.update(obs_embedding_fn(a, b))
return embedding_dict
return Converted(conv_circ, conv_obs, embedding_fn_dict, params)
def embedding_fn(a: dict, b: dict) -> dict:
return circ_embedding_fn(a, b)
return Converted(conv_circ, None, embedding_fn, params)

expectation(circuit, observable, param_values={}, state=None, measurement=None, noise=None, mitigation=None, endianness=Endianness.BIG) abstractmethod

Section titled “ expectation(circuit, observable, param_values={}, state=None, measurement=None, noise=None, mitigation=None, endianness=Endianness.BIG) abstractmethod ”

Compute the expectation value of the circuit with the given observable.

PARAMETER DESCRIPTION
circuit

A converted circuit as returned by backend.circuit.

TYPE: ConvertedCircuit

param_values

Already embedded parameters of the circuit. See embedding for more info.

TYPE: ParamDictType DEFAULT: {}

state

Initial state.

TYPE: ArrayLike | None DEFAULT: None

measurement

Optional measurement protocol. If None, use exact expectation value with a statevector simulator.

TYPE: Measurements | None DEFAULT: None

noise

A noise model to use.

TYPE: NoiseHandler | None DEFAULT: None

endianness

Endianness of the resulting bit strings.

TYPE: Endianness DEFAULT: BIG

Source code in qadence/backend.py
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328@abstractmethod
def expectation(
self,
circuit: ConvertedCircuit,
observable: list[ConvertedObservable] | ConvertedObservable,
param_values: ParamDictType = {},
state: ArrayLike | None = None,
measurement: Measurements | None = None,
noise: NoiseHandler | None = None,
mitigation: Mitigations | None = None,
endianness: Endianness = Endianness.BIG,
) -> ArrayLike:
"""Compute the expectation value of the `circuit` with the given `observable`.
Arguments:
circuit: A converted circuit as returned by `backend.circuit`.
param_values: _**Already embedded**_ parameters of the circuit. See
[`embedding`][qadence.blocks.embedding.embedding] for more info.
state: Initial state.
measurement: Optional measurement protocol. If None, use
exact expectation value with a statevector simulator.
noise: A noise model to use.
endianness: Endianness of the resulting bit strings.
"""
raise NotImplementedError

observable(observable, n_qubits) abstractmethod

Section titled “ observable(observable, n_qubits) abstractmethod ”

Converts an abstract observable (which is just an AbstractBlock) to the native backend.

representation.

PARAMETER DESCRIPTION
observable

An observable.

TYPE: AbstractBlock

n_qubits

Number of qubits the observable covers. This is typically circuit.n_qubits.

TYPE: int

RETURNS DESCRIPTION
ConvertedObservable

A converted observable o. You can access the original, arbstract observable via

ConvertedObservable

o.abstract and the converted (or backend native) observable via o.native.

Source code in qadence/backend.py
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186@abstractmethod
def observable(self, observable: AbstractBlock, n_qubits: int) -> ConvertedObservable:
"""Converts an abstract observable (which is just an `AbstractBlock`) to the native backend.
representation.
Arguments:
observable: An observable.
n_qubits: Number of qubits the observable covers. This is typically `circuit.n_qubits`.
Returns:
A converted observable `o`. You can access the original, arbstract observable via
`o.abstract` and the converted (or backend *native*) observable via `o.native`.
"""
raise NotImplementedError

run(circuit, param_values={}, state=None, endianness=Endianness.BIG, *args, **kwargs)

Section titled “ run(circuit, param_values={}, state=None, endianness=Endianness.BIG, *args, **kwargs) ”

Run a circuit and return the resulting wave function.

PARAMETER DESCRIPTION
circuit

A converted circuit as returned by backend.circuit.

TYPE: ConvertedCircuit

param_values

Already embedded parameters of the circuit. See embedding for more info.

TYPE: dict[str, ArrayLike] DEFAULT: {}

state

Initial state.

TYPE: Tensor | None DEFAULT: None

endianness

Endianness of the resulting wavefunction.

TYPE: Endianness DEFAULT: BIG

RETURNS DESCRIPTION
ArrayLike

A list of Counter objects where each key represents a bitstring

ArrayLike

and its value the number of times it has been sampled from the given wave function.

Source code in qadence/backend.py
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302def run(
self,
circuit: ConvertedCircuit,
param_values: dict[str, ArrayLike] = {},
state: Tensor | None = None,
endianness: Endianness = Endianness.BIG,
*args: Any,
**kwargs: Any,
) -> ArrayLike:
"""Run a circuit and return the resulting wave function.
Arguments:
circuit: A converted circuit as returned by `backend.circuit`.
param_values: _**Already embedded**_ parameters of the circuit. See
[`embedding`][qadence.blocks.embedding.embedding] for more info.
state: Initial state.
endianness: Endianness of the resulting wavefunction.
Returns:
A list of Counter objects where each key represents a bitstring
and its value the number of times it has been sampled from the given wave function.
"""
raise NotImplementedError

sample(circuit, param_values={}, n_shots=1000, state=None, noise=None, mitigation=None, endianness=Endianness.BIG) abstractmethod

Section titled “ sample(circuit, param_values={}, n_shots=1000, state=None, noise=None, mitigation=None, endianness=Endianness.BIG) abstractmethod ”

Sample bit strings.

PARAMETER DESCRIPTION
circuit

A converted circuit as returned by backend.circuit.

TYPE: ConvertedCircuit

param_values

Already embedded parameters of the circuit. See embedding for more info.

TYPE: dict[str, Tensor] DEFAULT: {}

n_shots

Number of shots to sample.

TYPE: int DEFAULT: 1000

state

Initial state.

TYPE: ArrayLike | None DEFAULT: None

noise

A noise model to use.

TYPE: NoiseHandler | None DEFAULT: None

mitigation

An error mitigation protocol to apply.

TYPE: Mitigations | None DEFAULT: None

endianness

Endianness of the resulting bit strings.

TYPE: Endianness DEFAULT: BIG

Source code in qadence/backend.py
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278@abstractmethod
def sample(
self,
circuit: ConvertedCircuit,
param_values: dict[str, Tensor] = {},
n_shots: int = 1000,
state: ArrayLike | None = None,
noise: NoiseHandler | None = None,
mitigation: Mitigations | None = None,
endianness: Endianness = Endianness.BIG,
) -> list[Counter]:
"""Sample bit strings.
Arguments:
circuit: A converted circuit as returned by `backend.circuit`.
param_values: _**Already embedded**_ parameters of the circuit. See
[`embedding`][qadence.blocks.embedding.embedding] for more info.
n_shots: Number of shots to sample.
state: Initial state.
noise: A noise model to use.
mitigation: An error mitigation protocol to apply.
endianness: Endianness of the resulting bit strings.
"""
raise NotImplementedError

BackendConfiguration(_use_gate_params=True, use_sparse_observable=False, use_gradient_checkpointing=False, use_single_qubit_composition=False, transpilation_passes=None) dataclass

Section titled “ BackendConfiguration(_use_gate_params=True, use_sparse_observable=False, use_gradient_checkpointing=False, use_single_qubit_composition=False, transpilation_passes=None) dataclass ”

Return as a string the available fields with types of the configuration.

RETURNS DESCRIPTION
str

a string with all the available fields, one per line

TYPE: str

Source code in qadence/backend.py
55
56
57
58
59
60
61
62
63
64
65def available_options(self) -> str:
"""Return as a string the available fields with types of the configuration.
Returns:
str: a string with all the available fields, one per line
"""
conf_msg = ""
for _field in fields(self):
if not _field.name.startswith("_"):
conf_msg += f"Name: {_field.name} - Type: {_field.type} - Current value: {getattr(self, _field.name)} - Default value: {_field.default}\n"
return conf_msg

Change configuration with the input.

Source code in qadence/backend.py
67
68
69
70
71
72
73
74def change_config(self, new_config: dict) -> None:
"""Change configuration with the input."""
for key, value in new_config.items():
if hasattr(self, key):
setattr(self, key, value)
else:
raise ValueError(f"Warning: '{key}' is not a valid configuration attribute.")

Return parameter names for the current backend.

Depending on which backend is in use this function returns either UUIDs or expressions of parameters.

Source code in qadence/backend.py
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105def get_param_name(self, blk: AbstractBlock) -> Tuple[str, ...]:
"""Return parameter names for the current backend.
Depending on which backend is in use this
function returns either UUIDs or expressions of parameters.
"""
param_ids: Tuple
# FIXME: better type hiearchy?
types = (TimeEvolutionBlock, ParametricBlock, ConstantAnalogRotation, InteractionBlock)
if not isinstance(blk, types):
raise TypeError(f"Can not infer param name from {type(blk)}")
else:
if self._use_gate_params:
param_ids = tuple(blk.parameters.uuids())
else:
param_ids = tuple(map(stringify, blk.parameters.expressions()))
return param_ids