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:
|
supports_ad |
whether or not the backend has a native autograd
TYPE:
|
supports_bp |
whether or not the backend has a native backprop
TYPE:
|
supports_adjoint |
Does the backend support native adjoint differentation.
TYPE:
|
is_remote |
whether computations are executed locally or remotely on this backend, useful when using cloud platforms where credentials are needed for example.
TYPE:
|
with_measurements |
whether it supports counts or not
TYPE:
|
with_noise |
whether to add realistic noise or not
TYPE:
|
native_endianness |
The native endianness of the backend
TYPE:
|
engine |
The underlying (native) automatic differentiation engine of the backend.
TYPE:
|
circuit(circuit)
abstractmethod
Section titled “
circuit(circuit)
abstractmethod
”Converts an abstract QuantumCircuit to the native backend representation.
| PARAMETER | DESCRIPTION |
|---|---|
circuit
|
A circuit, for example:
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ConvertedCircuit
|
A converted circuit |
ConvertedCircuit
|
and the converted (or backend native) circuit via |
Source code in qadence/backend.py
159160161162163164165166167168169170@abstractmethoddef 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(circuit, observable=None)
Section titled “
convert(circuit, observable=None)
”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
188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253def 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
TYPE:
|
param_values
|
Already embedded parameters of the circuit. See
TYPE:
|
state
|
Initial state.
TYPE:
|
measurement
|
Optional measurement protocol. If None, use exact expectation value with a statevector simulator.
TYPE:
|
noise
|
A noise model to use.
TYPE:
|
endianness
|
Endianness of the resulting bit strings.
TYPE:
|
Source code in qadence/backend.py
304305306307308309310311312313314315316317318319320321322323324325326327328@abstractmethoddef 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:
|
n_qubits
|
Number of qubits the observable covers. This is typically
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ConvertedObservable
|
A converted observable |
ConvertedObservable
|
|
Source code in qadence/backend.py
172173174175176177178179180181182183184185186@abstractmethoddef 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
TYPE:
|
param_values
|
Already embedded parameters of the circuit. See
TYPE:
|
state
|
Initial state.
TYPE:
|
endianness
|
Endianness of the resulting wavefunction.
TYPE:
|
| 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
280281282283284285286287288289290291292293294295296297298299300301302def 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
TYPE:
|
param_values
|
Already embedded parameters of the circuit. See
TYPE:
|
n_shots
|
Number of shots to sample.
TYPE:
|
state
|
Initial state.
TYPE:
|
noise
|
A noise model to use.
TYPE:
|
mitigation
|
An error mitigation protocol to apply.
TYPE:
|
endianness
|
Endianness of the resulting bit strings.
TYPE:
|
Source code in qadence/backend.py
255256257258259260261262263264265266267268269270271272273274275276277278@abstractmethoddef 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
”
available_options()
Section titled “
available_options()
”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:
|
Source code in qadence/backend.py
5556575859606162636465def 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_config(new_config)
Section titled “
change_config(new_config)
”Change configuration with the input.
Source code in qadence/backend.py
6768697071727374def 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.")
get_param_name(blk)
Section titled “
get_param_name(blk)
”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 99100101102103104105def 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