core
eigenkit.core
The internal circuit layer of eigenkit.
This package re-exports the classes and functions that users need, and it registers the default backends when it is imported.
The entry points are:
Circuitcreates a circuit that can be run.CircuitBuilderbuilds a circuit one gate at a time.AngleEncoding,BasicVariational,StrongVariational,Reuploading,CustomBlockandassemblecombine blocks into a circuit.X,Y,Z,all_z,from_stringandObservablebuild observables.PennyLaneConfig,QiskitConfigand the other configurations hold the settings of each backend.registergives a configuration a name, so that it can be used again.BaseQuantumSolveris the base class of every solver that computes its result in a single call.
The top-level provider= argument accepts a registered name, a configuration
dataclass, or a backend instance.
AmplitudeEncoding
dataclass
Encode a classical vector as the amplitudes of a quantum state.
The vector is padded with zeros to the next power of two. With
normalize=True, the default, it is also rescaled to norm 1. The number of
qubits follows from the length of the vector: it is
max(1, ceil(log2(len(amplitudes)))).
The block adds a single AmplitudeEncoding gate. The data field of the gate
holds the prepared amplitudes as a flat tuple, and each backend loads them with
its own state preparation method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
amplitudes
|
object
|
The vector to load, as an array-like. Its length sets the
number of qubits, and it is padded with zeros to the next power of
two. A |
required |
normalize
|
bool
|
If |
True
|
Example
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
'IRFragment'
|
The gates of the block, as an |
from_dict(d)
classmethod
Rebuild a block from the output of to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
A dictionary returned by |
required |
Returns:
| Type | Description |
|---|---|
'AmplitudeEncoding'
|
The rebuilt |
required_qubits()
Return the number of qubits that the padded vector needs.
It is ceil(log2(len(amplitudes))), and at least 1.
to_dict()
Return a description of this block that can be saved as JSON.
When a saved model is loaded, the type key selects the block class whose
from_dict() rebuilds the block.
Returns:
| Type | Description |
|---|---|
dict
|
The fields of the block, and its |
AngleEncoding
dataclass
Encode in_features data values as single-qubit rotations.
Feature i sets the angle of one rotation on qubit i, so the block uses the
qubits 0 to in_features - 1. This matters only when the block is combined
with others. A circuit has as many qubits as its widest block, and when another
block in the list needs more qubits, this block leaves the extra qubits
unchanged.
The block takes in_features inputs and no weights.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
in_features
|
int
|
The number of features to encode, one per qubit. It must be
positive, and a |
required |
rotation
|
GateName
|
The rotation gate: |
'RY'
|
scale
|
float
|
A constant factor applied to every input angle. It is useful when
the data is normalised to |
1.0
|
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
The qubits with an index of in_features or more are left unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
IRFragment
|
The gates of the block, as an |
from_dict(d)
classmethod
Rebuild a block from the output of to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
A dictionary returned by |
required |
Returns:
| Type | Description |
|---|---|
'AngleEncoding'
|
The rebuilt |
required_qubits()
Return in_features, because the block uses one qubit per feature.
to_dict()
Return a description of this block that can be saved as JSON.
When a saved model is loaded, the type key selects the block class whose
from_dict() rebuilds the block.
Returns:
| Type | Description |
|---|---|
dict
|
The fields of the block, and its |
BaseQuantumSolver
Bases: ABC
Base class for quantum solvers that compute a result in a single call.
Unlike BaseQuantumEstimator, a solver
has no training phase and no fitted state, and it does not follow the
scikit-learn estimator interface. It receives a mathematical problem directly
in solve() and returns a structured result object.
Four classes inherit from it: HHL,
IQAE, QAOA and
VQE.
PortfolioRiskEstimator does
not, by design. It is a scikit-learn-style estimator with fit(),
estimate() and var_at(), and it has no solve() method. As a result,
isinstance(x, BaseQuantumSolver) tells you whether an object can be given a
problem directly, and it returns False for the estimator.
Each subclass sets its own provider default in its signature and passes it to
this class. All of them use "numpy". Two of the modes of IQAE, a callable
oracle and shot_mode="provider", need provider="pennylane".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
ProviderSpec
|
The backend to use: a registered name ( |
'numpy'
|
Example
solve(*args, **kwargs)
abstractmethod
Compute and return the solution.
Each subclass declares the signature that its problem needs. HHL takes a
matrix and a right-hand side, IQAE takes an oracle, QAOA takes a problem,
and VQE takes a Hamiltonian and the number of qubits.
BasicVariational
dataclass
depth trainable layers of single-qubit rotations and entangling gates.
Each layer applies one trainable rotation to every qubit, then a controlled-NOT
(CNOT) gate from each qubit to the next one. The block takes
depth * n_qubits weights and no inputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
int
|
The number of layers. It must be positive, and a |
required |
rotation
|
GateName
|
The rotation gate of the trainable layer: |
'RY'
|
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
The layers act on every qubit of the circuit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
IRFragment
|
The gates of the block, as an |
from_dict(d)
classmethod
Rebuild a block from the output of to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
A dictionary returned by |
required |
Returns:
| Type | Description |
|---|---|
'BasicVariational'
|
The rebuilt |
required_qubits()
Return 1, because the block extends to all the qubits of the circuit.
to_dict()
Return a description of this block that can be saved as JSON.
When a saved model is loaded, the type key selects the block class whose
from_dict() rebuilds the block.
Returns:
| Type | Description |
|---|---|
dict
|
The fields of the block, and its |
Circuit
A compiled circuit, ready to evaluate.
It holds a CircuitSpec, the observables to measure and a compiled backend
handle. The circuit is compiled once, when the instance is created, and every
call reuses the compiled handle. The instance does not store weights: you pass
the weights at each call.
This is the NumPy interface. The top-level Circuit(...) function of the
package returns this class for interface="numpy" and a TorchCircuit for
interface="torch".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
CircuitSpec
|
The circuit to run, usually built with |
required |
observables
|
ObservableLike
|
What to measure. |
None
|
provider
|
ProviderSpec
|
The backend that runs the circuit. It can be a registered name
( |
'numpy'
|
interface
|
Interface
|
How a call is evaluated. With |
'numpy'
|
Example
import numpy as np
from eigenkit import Circuit, Encoding, Variational, all_z
circuit = Circuit(
blocks=[Encoding(in_features=2), Variational(depth=1)],
observables=all_z(2),
)
# The circuit stores no weights, so you pass them at every call.
weights = np.zeros(circuit.spec.n_weights)
values = circuit(weights, np.array([0.1, 0.2]))
# Gradients, without PyTorch.
grad = circuit.jacobian(weights, np.array([0.1, 0.2]))
draw(*, decimals=3)
Return a text drawing of the circuit, over several lines.
The drawing does not depend on the provider: it is built from the
CircuitSpec, not from the compiled backend object. See eigenkit.core.draw
for the details of the layout.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
decimals
|
int
|
The number of significant digits shown for a numeric gate
angle. Default: |
3
|
Returns:
| Type | Description |
|---|---|
str
|
The drawing, as a single string that contains newlines. |
draw_mpl(**kwargs)
Draw the circuit as a matplotlib figure, and return (fig, ax).
Gates are drawn as labelled boxes and controls as filled dots, and each
measured wire (from self.observables) ends with a measurement symbol.
As with draw(), the picture is built from the CircuitSpec and the
observables, not from the compiled backend, so it does not depend on the
provider.
Pass style="eigen" for the brand colours (each gate is coloured by its
kind: rotations, H and block gates, and measurements), or
style="roles" to colour the outline of each gate by its role (encoding,
trainable or fixed). The default is black on white. Each style has a
"-dark" variant (for example "eigen-dark") for dark backgrounds, and
"eigen-universal" is a single image that works on both.
matplotlib is an optional dependency. Install it with eigenkit[viz].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Any
|
Arguments passed to
|
{}
|
Returns:
| Name | Type | Description |
|---|---|---|
fig_ax |
tuple
|
The matplotlib |
dry_run_info()
Describe the prepared circuit in a dictionary, without submitting it.
It is available only on backends whose CompiledCircuit provides a
dry_run_info method. Currently, these are Braket (on its local simulator
as well as on cloud devices), Qiskit Runtime and IQM. It is useful to check
the size of the circuit, the gate counts after transpilation, the number of
shots and the number of circuits that each call runs, before you submit to
a cloud simulator or a quantum processing unit (QPU). It does not estimate a
price.
jacobian(weights, inputs=None, *, input_grad=False)
Return the gradient of the expectation values with respect to the weights.
It returns d<O>/d(weights), of shape (n_weights,) for a single
observable or (n_observables, n_weights) for a list of observables, like
the output of __call__(). Pass a single 1-D inputs sample. For a batch,
call it once for each row.
The NumPy interface can compute every gradient without PyTorch. This method uses the same sequence of gradient methods as the variational optimisation tools and the PyTorch interface. It uses the backend's own differentiation when the backend has one (the analytic adjoint method of the NumPy simulator, the differentiation of PennyLane, and so on), and otherwise the parameter-shift rule, which works on any backend.
With input_grad=True, it returns (weight_jacobian, input_jacobian),
where input_jacobian is d<O>/d(inputs), with the same leading shape.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
ndarray
|
The weight vector, of shape |
required |
inputs
|
ndarray | None
|
One 1-D sample, of shape |
None
|
input_grad
|
bool
|
If True, also return the jacobian with respect to the
inputs. Default: |
False
|
Returns:
| Name | Type | Description |
|---|---|---|
jacobian |
ndarray | tuple[ndarray, ndarray]
|
The weight
jacobian, or |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
On a hardware backend whose configuration leaves
|
probabilities(weights, inputs=None)
Return the measurement distribution over all 2**n_qubits basis states.
The basis states are ordered with qubit 0 as the most significant bit.
The distribution is used to decode samples. For example, the quantum
approximate optimisation algorithm (QAOA) reads the most probable
bitstrings from the optimised state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
ndarray
|
The weight vector, of shape |
required |
inputs
|
ndarray | None
|
One 1-D sample. |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
The probabilities of all basis states, of shape |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
On a backend that has neither a |
resources(**kwargs)
Report the resources that the circuit uses once transpiled for its target.
It reports the native gate counts, the number of two-qubit gates and the two-qubit depth, the physical qubits chosen by the layout, the number of two-qubit gates added by routing (compared with the same circuit on the native gates with all-to-all connectivity), and the success probability predicted by the error rates of the target. Nothing is submitted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Any
|
Arguments passed to the backend, for example
|
{}
|
Returns:
| Type | Description |
|---|---|
dict
|
A dictionary. See |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
On backends that do not transpile for a device,
which includes every simulator. To inspect a device locally, use
Qiskit Runtime or IQM with a fake |
sample(weights, inputs=None)
Return the raw measurement histogram, which maps each bitstring to a count.
It is what a sampling backend measured, before any averaging. These are
the counts behind probabilities(), and it is the only form that stays
usable when the circuit has too many qubits for a dense distribution. In
each bitstring, qubit 0 is the most significant bit, so "100" means
that qubit 0 was measured in state 1.
Only sampling backends can return a histogram, because it needs a finite
number of shots. Exact statevector simulators raise an error instead of
making up a histogram. Use probabilities() with those.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
ndarray
|
The weight vector, of shape |
required |
inputs
|
ndarray | None
|
One 1-D sample. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
counts |
dict[str, int]
|
The number of shots for each measured bitstring. The counts add up to the number of shots set for the backend. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
On backends that do not sample. This includes every exact simulator, which has no shots to report. |
statevector(weights, inputs=None, initial_state=None)
Return the full complex statevector after the circuit runs.
It is a flat array of length 2**n_qubits, ordered with qubit 0 as the
most significant bit. A 2-D inputs batch returns an array of shape
(B, 2**n_qubits). With initial_state, a normalised flat statevector in
the same order, the evolution starts from that state instead of |0…0⟩.
Reading a state out and passing it back in this way is the basic operation
behind the state carried over in quantum reservoirs and behind amplitude
encoding.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
ndarray
|
The weight vector, of shape |
required |
inputs
|
ndarray | None
|
A 1-D sample, or a 2-D batch. |
None
|
initial_state
|
ndarray | None
|
The state to start the evolution
from, instead of |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
The statevector, of shape |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
On backends without access to the statevector, which is the case for most quantum processing unit (QPU) and cloud backends. |
submit(weights, inputs=None)
Submit a job without waiting for it, and return a JobHandle.
handle.result() returns the expectation value of each observable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
ndarray
|
The weight vector, of shape |
required |
inputs
|
ndarray | None
|
One 1-D sample. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
handle |
JobHandle
|
A handle for the submitted job. |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If the |
transpiled_circuit(**kwargs)
Return the qiskit.QuantumCircuit that a hardware backend submits.
The circuit is transpiled for the target of the backend. Use it to draw the
circuit (.draw("mpl")) or to inspect it.
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
On backends that do not transpile for a device. |
zero_state_probabilities(weights, inputs)
Compute zero_state_probability() for every row of a batch of inputs.
inputs has shape (B, n_inputs), and the result is an array of shape
(B,) of all-zeros probabilities. Backends that provide a batched
zero_state_probabilities (such as the NumPy simulator) compute the whole
batch at once. The other backends call the single-sample method once for
each row. This is what lets QuantumKernel
build a fidelity matrix without a Python loop over pairs of samples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
ndarray
|
The weight vector, of shape |
required |
inputs
|
ndarray
|
A batch, of shape |
required |
Returns:
| Type | Description |
|---|---|
ndarray
|
One all-zeros probability for each row, as an array of shape |
zero_state_probability(weights, inputs=None)
Return the probability of measuring the all-zeros state after the circuit.
It is useful for quantities based on fidelity: quantum kernels built from
inversion circuits, swap tests and the Bures distance. Each backend
computes it in its own way. PennyLane returns qml.probs(...)[0], the
Qiskit and NumPy simulators return the squared amplitude of the all-zeros
basis state, Braket uses its own probability result, and IQM and Qiskit
Runtime estimate it from shots. This method does not go through the
Observable path, because the value is not the expectation value of a
Pauli operator.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
weights
|
ndarray
|
The weight vector, of shape |
required |
inputs
|
ndarray | None
|
One 1-D sample. |
None
|
Returns:
| Type | Description |
|---|---|
float
|
The probability, a float in |
Raises:
| Type | Description |
|---|---|
NotImplementedError
|
If the active backend does not provide
|
CircuitBuilder
Build a CircuitSpec one gate at a time.
Example
qc = CircuitBuilder(n_qubits=3)
weights = qc.add_weights(6)
inputs = qc.add_inputs(3)
for qubit in range(3):
qc.ry(inputs[qubit], qubit=qubit)
for depth in range(2):
for qubit in range(3):
qc.ry(weights[depth * 3 + qubit], qubit=qubit)
for qubit in range(2):
qc.cnot(qubit, qubit + 1)
spec = qc.build()
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being built. Every qubit
index that a gate uses must be between |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
n_inputs
property
The number of input features that add_inputs() has reserved so far.
The built CircuitSpec has the same number.
n_qubits
property
The number of qubits of the circuit, as given to the constructor.
Every qubit index that a gate uses must be smaller than this number, and the number never changes.
n_weights
property
The number of trainable weights that add_weights() has reserved so far.
The built CircuitSpec has the same number.
add_inputs(count)
Reserve count input features and return references to them.
This is the counterpart of add_weights() for data instead of trainable
parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
count
|
int
|
The number of input features to reserve. |
required |
Returns:
| Type | Description |
|---|---|
list[InputRef]
|
One |
add_weights(count)
Reserve count trainable weights and return references to them.
Pass a returned WeightRef wherever a gate takes an angle. The indices
are local to this builder and start at 0. When the block is combined
with others, assemble shifts them to their positions in the whole
circuit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
count
|
int
|
The number of weights to reserve. |
required |
Returns:
| Type | Description |
|---|---|
list[WeightRef]
|
One |
build()
Return the current state of the builder as an immutable CircuitSpec.
cnot(control, target)
Add a controlled-NOT (CNOT) gate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
control
|
int
|
The qubit that controls the flip. |
required |
target
|
int
|
The qubit that is flipped. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
cphase(angle, control, target)
Add a controlled phase shift gate.
The gate is symmetric: the control and the target play the same role.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle
|
ParameterLike
|
The phase. It can be a number or a symbolic reference. |
required |
control
|
int
|
One of the two qubits. |
required |
target
|
int
|
The other qubit. The gate acts in the same way if the two qubits are exchanged. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
cry(angle, control, target)
Add a controlled RY gate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle
|
ParameterLike
|
The rotation angle. It can be a number or a symbolic reference. |
required |
control
|
int
|
The qubit that controls the rotation. |
required |
target
|
int
|
The qubit that is rotated. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
h(qubit)
Add a Hadamard gate.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
mcx(*qubits)
Add a multi-controlled X gate.
All the qubits except the last one are controls.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*qubits
|
int
|
Two or more distinct qubits. The controls come first, and the target is the last one. |
()
|
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than two qubits are given, or if a qubit is repeated. |
mcz(*qubits)
Add a multi-controlled Z gate.
All the qubits except the last one are controls.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*qubits
|
int
|
Two or more distinct qubits. The controls come first, and the target is the last one. |
()
|
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than two qubits are given, or if a qubit is repeated. |
pauli_exponential(paulis, angle, coefficient=1.0)
Add the exponential of a product of Pauli operators.
The gate is exp(-i * coefficient * angle * P), where P is the product of
paulis. Each element of paulis is a pair (op, qubit), where op is
"X", "Y" or "Z", and the qubits are distinct.
This is the Trotter building block that the quantum approximate
optimisation algorithm (QAOA) needs for its cost and mixer layers, and that
the unitary coupled-cluster singles and doubles (UCCSD) ansatz needs for
its excitation operators. It is built from the core gates only. First,
H gates (for X) and RX(π/2) gates (for Y) change each factor to the
Z basis. Then a ladder of controlled-NOT (CNOT) gates accumulates the
parity on the last qubit, and a central RZ(2 * coefficient * angle) is
applied (because RZ(φ) = exp(-i φ Z / 2)). Finally, the inverse of the
first steps is applied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
paulis
|
Sequence[tuple[str, int]]
|
The Pauli product, as |
required |
angle
|
ParameterLike
|
The rotation angle. It can be a number or a symbolic reference. |
required |
coefficient
|
float
|
A number that multiplies the angle. This is where the
weight of a Hamiltonian term goes. Default: |
1.0
|
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
phase_shift(angle, qubit)
Add a phase shift gate R(φ).
The gate multiplies |1⟩ by e^(iφ) and leaves |0⟩ unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle
|
ParameterLike
|
The phase |
required |
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
rx(angle, qubit)
Add a rotation about the X axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle
|
ParameterLike
|
The rotation angle. It can be a number, or a |
required |
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
ry(angle, qubit)
Add a rotation about the Y axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle
|
ParameterLike
|
The rotation angle. It can be a number, or a |
required |
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
rz(angle, qubit)
Add a rotation about the Z axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
angle
|
ParameterLike
|
The rotation angle. It can be a number, or a |
required |
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
s(qubit)
Add an S gate, which is a quarter turn about the Z axis.
Its inverse is sdg().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
sdg(qubit)
Add an S-dagger gate (Sdg), which is the inverse of s().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
swap(qubit0, qubit1)
Add a SWAP gate, which exchanges the states of two qubits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit0
|
int
|
The first qubit. |
required |
qubit1
|
int
|
The second qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
to_block()
Wrap the current state of the builder in a CustomBlock.
This is useful to build a part of a circuit one gate at a time, and then to
combine it with other blocks. When the blocks are assembled, the indices of
the WeightRef and InputRef objects of this block are shifted to their
positions in the whole circuit.
x(qubit)
Add a Pauli X gate, which is a bit flip.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
z(qubit)
Add a Pauli Z gate, which is a phase flip.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The target qubit. |
required |
Returns:
| Type | Description |
|---|---|
'CircuitBuilder'
|
This builder, so that calls can be chained. |
CircuitSpec
dataclass
A whole circuit as data.
It holds the list of gates, the number of qubits, and the lengths of the weight
and input vectors that the gates refer to. Every provider compiles this object,
and assemble builds it from a list of blocks. It holds no weights and no
observables: the weights are passed at each call, and the observables are set
by the Circuit that wraps the spec.
Attributes:
| Name | Type | Description |
|---|---|---|
n_qubits |
int
|
The number of qubits of the circuit. |
n_weights |
int
|
The length of the weight vector that the gates refer to
through |
n_inputs |
int
|
The length of the input vector that the gates refer to through
|
gates |
tuple[Gate, ...]
|
The gates, in the order in which they are applied. |
CostWarning
Bases: UserWarning
Warning issued before a submission to a paid quantum backend.
A paid backend is a quantum processing unit (QPU) or a cloud simulator that charges for use. The first compilation for such a device issues this warning, so that costs cannot build up without the user noticing.
CustomBlock
dataclass
A block made from the gates of a CircuitBuilder.
CircuitBuilder.to_block() creates it. It is useful when you want to write a
part of a circuit gate by gate and combine it with the standard blocks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits that the builder was given, which is also the number of qubits that this block needs. It must be positive. |
required |
gates
|
tuple[Gate, ...]
|
The gates that the builder added, in the order in which they are applied. |
required |
n_weights
|
int
|
The number of trainable weights that these gates use. It must not be negative. |
required |
n_inputs
|
int
|
The number of input features that these gates use. It must not be negative. |
required |
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
IRFragment
|
The gates of the block, as an |
required_qubits()
Return n_qubits, the number of qubits that the builder was given.
Grover
dataclass
The Grover operator Q = A · S₀ · A† · S_ψ₁ used for amplitude estimation.
This is the operator that iterative quantum amplitude estimation (IQAE) uses.
The block builds it from a state-preparation oracle A, given as a
CircuitSpec, and from these standard parts:
S_ψ₁flips the phase of the ancilla qubit, which is the last qubit. It is the gateZ(n-1).A†is the adjoint of the oracle. It uses the same weights and inputs asA.S₀is the reflection about the all-zero state:X^⊗n → MCZ → X^⊗n, whereMCZis a multi-controlledZgate.Ais the oracle.
The gates are applied to the state in this order, from left to right:
A and A† share their weights and inputs, so
fragment.n_weights == a_circuit.n_weights: the count is not doubled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
a_circuit
|
CircuitSpec
|
The state-preparation oracle |
required |
Example
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
The oracle A and its adjoint A† share their weights and inputs, so these
are not counted twice.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
'IRFragment'
|
The gates of the block, as an |
from_dict(d)
classmethod
Rebuild a block from the output of to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
A dictionary returned by |
required |
Returns:
| Type | Description |
|---|---|
'Grover'
|
The rebuilt |
required_qubits()
Return the number of qubits of the oracle.
The operator adds no qubits of its own.
to_dict()
Return a description of this block that can be saved as JSON.
When a saved model is loaded, the type key selects the block class whose
from_dict() rebuilds the block.
Returns:
| Type | Description |
|---|---|
dict
|
The fields of the block, and its |
JobHandle
Bases: Protocol
A handle to a job running on a quantum processing unit (QPU) or in the cloud.
compiled.submit(...) returns it without waiting for the job. Call .result()
to wait for the job and combine its results.
result()
Wait until the job finishes, then return its expectation values.
The shape follows the same rule as
CompiledCircuit.run():
(n_obs,) for a single sample, and (B, n_obs) for a batch.
status()
Return the state of the job as the provider reports it, without waiting.
The strings are the provider's own. For example, Braket returns
"CREATED", "QUEUED", "RUNNING", "COMPLETED", "FAILED" or
"CANCELLED". Compare them within one provider, not across providers.
NumpyConfig
dataclass
Configuration for the reference NumPy simulator.
It has no settings yet. It exists so that Circuit(provider=NumpyConfig())
works in the same way as with the configurations of the other backends.
make_backend()
Build the backend that this configuration describes.
The provider layer calls it when a configuration is passed as provider=.
There is no reason to call it directly.
Returns:
| Type | Description |
|---|---|
'NumpySimulator'
|
The |
NumpySimulator
The provider for the reference NumPy statevector simulator.
It is registered automatically as "numpy". It uses only NumPy and no
optional dependency, so it is always available.
It declares gradient_method = "adjoint", so the gradient code of the core
package uses
NumpyCompiled.jacobian()
(analytic, in reverse mode, with one forward pass and one backward pass
whatever the number of parameters) instead of the parameter-shift rule, whose
cost is O(n_params).
capabilities
property
What this backend supports.
It runs every gate of the library, evaluates a batch of inputs in one
call, returns exact expectation values only (it does not sample shots),
and has no limit on the number of qubits. See
Capabilities.
__init__(config=None, name='numpy')
Build the backend from a device configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
NumpyConfig
|
The device settings. Default: |
None
|
name
|
str
|
The registry name, used in error messages. Default:
|
'numpy'
|
compile(circuit, observables)
Prepare circuit for repeated evaluation of observables.
A Circuit calls it once and reuses the result for every call, so the
expensive work belongs here.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
circuit
|
CircuitSpec
|
The circuit to prepare. |
required |
observables
|
Sequence[Observable]
|
The observables to measure. |
required |
Returns:
| Type | Description |
|---|---|
NumpyCompiled
|
The prepared circuit, as a |
Observable
dataclass
A Hermitian operator to measure, written as a sum of Pauli terms.
You can build one with the z, x and y methods for a single Pauli
operator on one qubit, with from_string for a whole sum, or with the X,
Y and Z functions of eigenkit.core.observables, which support
arithmetic.
Attributes:
| Name | Type | Description |
|---|---|---|
terms |
tuple[PauliTerm, ...]
|
The Pauli terms of the sum. It can be empty: |
from_string(text)
classmethod
Parse a sum of Pauli terms written as a string.
Examples of such strings are "0.5 Z0 X1 + 0.3 Y2" and "-Z0 + Z1".
The grammar is as follows. The terms are joined by + or -. Each term
starts with an optional numeric coefficient, in plain or scientific
notation (1e-3 is accepted). The coefficient is followed by an optional
* and by one or more [XYZ]<qubit> operators on distinct qubits. Any
amount of whitespace is accepted, including none.
Every part of the string must be a valid term, and every term must contain
Pauli operators. A constant term ("0.5 + Z0", "0.5 I") raises an error
instead of being dropped from the sum: an Observable holds only Pauli
terms, and the constant must be kept next to it as an offset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The string to parse. |
required |
Returns:
| Type | Description |
|---|---|
'Observable'
|
The parsed observable. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
x(qubit)
classmethod
Return the observable X on the single qubit qubit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The index of the qubit. |
required |
y(qubit)
classmethod
Return the observable Y on the single qubit qubit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The index of the qubit. |
required |
z(qubit)
classmethod
Return the observable Z on the single qubit qubit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The index of the qubit. |
required |
QubitUnitary
dataclass
Apply any unitary matrix to the given qubits.
The matrix is stored in the data field of the gate as a nested tuple, so that
the Gate stays hashable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unitary
|
object
|
A |
required |
wires
|
tuple[int, ...]
|
The target qubits, in the order that the matrix expects. |
required |
Example
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
'IRFragment'
|
The gates of the block, as an |
from_dict(d)
classmethod
Rebuild a block from the output of to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
A dictionary returned by |
required |
Returns:
| Type | Description |
|---|---|
'QubitUnitary'
|
The rebuilt |
required_qubits()
Return max(wires) + 1, one more than the highest target qubit.
to_dict()
Return a description of this block that can be saved as JSON.
When a saved model is loaded, the type key selects the block class whose
from_dict() rebuilds the block.
Returns:
| Type | Description |
|---|---|
dict
|
The fields of the block, and its |
Reuploading
dataclass
Data reuploading: the input is encoded several times, between trainable layers.
The block repeats an encoding of the input followed by a variational layer,
depth times. Each encoding can have a trainable scale for each feature and
repetition.
The arguments give two patterns:
- Standard reuploading (the default; Pérez-Salinas et al. 2020). The same
input is encoded
depthtimes, with new variational weights between the encodings. - Trainable feature scaling (
trainable_scale=True; Schuld et al. 2021). Each encoding rotation takes the angleλ_{d,i} * x_i, where each pair of repetitiondand featureihas its own trainableλ_{d,i}.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
in_features
|
int
|
The total number of input features. It must be positive. |
required |
depth
|
int
|
The number of times the whole sequence is repeated. It must be positive. |
required |
encoding_rotation
|
GateName
|
The rotation gate of the encoding: |
'RY'
|
variational_rotation
|
GateName
|
The rotation gate of the variational layer: |
'RY'
|
variational_type
|
str
|
|
'basic'
|
trainable_scale
|
bool
|
If |
False
|
Weight count
- With
variational_type="basic"and no trainable scale, the block hasdepth * in_featuresweights. - With
variational_type="strong"and no trainable scale, it has3 * depth * in_featuresweights. trainable_scale=Trueaddsdepth * in_featuresweights.
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
IRFragment
|
The gates of the block, as an |
from_dict(d)
classmethod
Rebuild a block from the output of to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
A dictionary returned by |
required |
Returns:
| Type | Description |
|---|---|
'Reuploading'
|
The rebuilt |
required_qubits()
Return in_features: one qubit for each feature.
to_dict()
Return a description of this block that can be saved as JSON.
When a saved model is loaded, the type key selects the block class whose
from_dict() rebuilds the block.
Returns:
| Type | Description |
|---|---|
dict
|
The fields of the block, and its |
S0
dataclass
Reflection about the all-zero state |0…0⟩, built as X^⊗n → MCZ → X^⊗n.
The block applies X to every qubit, then a multi-controlled Z gate (MCZ)
on all of them, then X to every qubit again. It acts on the qubits 0 to
n_qubits - 1, which are all the qubits of the circuit unless another block in
the list needs more. This reflection is the S₀ part of the Grover operator
used by iterative quantum amplitude estimation (IQAE). The
Grover block adds the same gates itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the reflection. Every one of them takes part. It must be positive. |
required |
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
'IRFragment'
|
The gates of the block, as an |
from_dict(d)
classmethod
Rebuild a block from the output of to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
A dictionary returned by |
required |
Returns:
| Type | Description |
|---|---|
'S0'
|
The rebuilt |
required_qubits()
Return n_qubits, the number of qubits that the reflection acts on.
to_dict()
Return a description of this block that can be saved as JSON.
When a saved model is loaded, the type key selects the block class whose
from_dict() rebuilds the block.
Returns:
| Type | Description |
|---|---|
dict
|
The fields of the block, and its |
StrongVariational
dataclass
depth trainable layers of RZ, RY and RZ rotations and entangling gates.
Each layer applies the rotations RZ, RY and RZ to every qubit, then a
controlled-NOT (CNOT) gate from each qubit to the next one. The block is
modelled on PennyLane's StronglyEntanglingLayers.
The gates are added one layer at a time: all the RZ rotations, then all the
RY rotations, then all the RZ rotations, then the CNOT gates. They are not
added as three rotations per qubit. The result is the same, because rotations
on different qubits commute. The layered order lets the backends that support
it apply each layer of rotations in one fast call, in place of 3 * n_qubits
calls on single qubits.
The block takes 3 * depth * n_qubits weights and no inputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
depth
|
int
|
The number of layers. It must be positive, and a |
required |
build(n_qubits)
Build the gates of this block for a circuit with n_qubits qubits.
The layers act on every qubit of the circuit.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit being assembled, which is the number of qubits of the widest block in the list. |
required |
Returns:
| Type | Description |
|---|---|
IRFragment
|
The gates of the block, as an |
from_dict(d)
classmethod
Rebuild a block from the output of to_dict().
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
d
|
dict
|
A dictionary returned by |
required |
Returns:
| Type | Description |
|---|---|
'StrongVariational'
|
The rebuilt |
required_qubits()
Return 1, because the block extends to all the qubits of the circuit.
to_dict()
Return a description of this block that can be saved as JSON.
When a saved model is loaded, the type key selects the block class whose
from_dict() rebuilds the block.
Returns:
| Type | Description |
|---|---|
dict
|
The fields of the block, and its |
VariationalResult
dataclass
Bases: ValueEquality
Outcome of minimize_expectation().
The result is read-only. Assigning to a field raises FrozenInstanceError, and
writing into an array field raises ValueError. This prevents a mistyped =
(instead of ==) or an in-place edit from leaving a result whose scalar fields
describe a different run from the array it holds. To get a writable copy of the
array, use np.array(result.field).
Results compare by value, including their arrays. They are not hashable, because a result is a collection of numbers and not a key, and a correct hash of a float array is expensive to compute.
Attributes:
| Name | Type | Description |
|---|---|---|
optimal_value |
float
|
The lowest expectation value reached. When the observable is a Hamiltonian, it is the estimated ground-state energy. |
optimal_parameters |
ndarray
|
The weights that produced this value, of shape
|
n_iterations |
int
|
The number of iterations reported by the SciPy optimiser.
When there is no such count (a custom callable, |
n_evaluations |
int
|
The number of circuit evaluations that the optimiser made.
With a SciPy method it is usually higher than |
success |
bool
|
Whether the run converged. A SciPy optimiser reports it. A
custom callable reports it only if it returns
|
message |
str
|
The termination message of the optimiser. For a custom callable that reported nothing, it gives the cost before and after the run. |
history |
tuple[float, ...]
|
The expectation value at every evaluation, in order. Plot it to see whether the run converged or stalled. It is a tuple, so nothing can be appended to it after the run. |
__post_init__()
Make the array field read-only.
Freezing the dataclass prevents a field from being reassigned, but it does not
prevent writing into the array that the field holds, and a result that has been
written into still reports the scalar values of the original run. The result
therefore keeps its own copy, so the array it was built from can still be
changed by the caller. To get a writable copy, use
np.array(result.optimal_parameters).
X(qubit)
Return Pauli X on qubit, as an expression that can be added and scaled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The index of the qubit. |
required |
Returns:
| Type | Description |
|---|---|
PauliExpr
|
The expression. |
Y(qubit)
Return Pauli Y on qubit, as an expression that can be added and scaled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The index of the qubit. |
required |
Returns:
| Type | Description |
|---|---|
PauliExpr
|
The expression. |
Z(qubit)
Return Pauli Z on qubit, as an expression that can be added and scaled.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
qubit
|
int
|
The index of the qubit. |
required |
Returns:
| Type | Description |
|---|---|
PauliExpr
|
The expression. |
__getattr__(name)
Return the objects that are re-exported only when they are first accessed.
These are the backend classes and configurations. Because of this, importing
core does not import any framework until one is needed.
adjoint(circuit)
Reverse the order of the gates and invert each gate.
The transform does not depend on the provider. It returns another CircuitSpec
that any backend can compile, so the transform does not have to be written
again for each backend.
Each type of gate is inverted as follows:
- Rotations with parameters (
RX,RY,RZ,PhaseShift,CRY,CPHASE): the angle parameters are negated. - Gates without parameters (
H,X,Z,CNOT,SWAP,MCZ,MCX): they are copied unchanged, because applying them twice gives the identity.SandSdgare not their own inverse, so each one is replaced by the other. QubitUnitary(U): the stored matrix is replaced by its conjugate transposeU†. It is computed without NumPy, so that the intermediate representation stays pure Python.ControlledQubitUnitary(U): the target unitary (data[0]) is replaced by its conjugate transpose, and the control values (data[1]) are kept unchanged.AmplitudeEncoding: the transform flipsgate.adjointand leaves the inversion to the backend. PennyLane, for example, applies the conjugate transpose of the state-preparation unitary. The Qiskit backend does not support this adjoint:Circuitrejects such a circuit with aValueError, and the backend itself raisesNotImplementedError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
circuit
|
CircuitSpec
|
The circuit to invert. |
required |
Returns:
| Type | Description |
|---|---|
CircuitSpec
|
The inverted circuit, with the gates in reverse order. |
all_z(n_qubits)
Return one Z observable for each qubit.
This is useful as a default measurement.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
n_qubits
|
int
|
The number of qubits of the circuit. |
required |
Returns:
| Type | Description |
|---|---|
list[Observable]
|
One |
assemble(blocks)
Combine blocks into a single CircuitSpec.
A CircuitBuilder can take the place of a block. It is replaced by the result
of its to_block(), so a part of a circuit written gate by gate can go
directly in the list.
The blocks are combined as follows:
n_qubitsis the largestrequired_qubits()of the blocks.- The weights and the inputs of the blocks are placed one after the other, in the order of the blocks.
- The local
WeightRefandInputRefindices of each block are shifted by the number of weights and inputs of the blocks before it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
blocks
|
Iterable[Block | CircuitBuilder]
|
The blocks to combine, in the order in which they are applied. Any
of them can be a |
required |
Returns:
| Type | Description |
|---|---|
CircuitSpec
|
One |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
from_string(text)
Parse an observable from a string.
This function is a shortcut for Observable.from_string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The string to parse. |
required |
Returns:
| Type | Description |
|---|---|
Observable
|
The parsed observable. |
minimize_expectation(circuit, *, initial_parameters=None, optimizer='L-BFGS-B', max_iterations=None, tol=None, random_state=42, callback=None)
Minimise <H>(θ) for a circuit whose parameters are all variational.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
circuit
|
Circuit
|
A core NumPy |
required |
initial_parameters
|
ndarray | None
|
The starting |
None
|
optimizer
|
Optimizer
|
The name of a |
'L-BFGS-B'
|
max_iterations
|
int | None
|
The maximum number of iterations. It is passed to SciPy as
|
None
|
tol
|
float | None
|
The tolerance, passed to |
None
|
random_state
|
int | None
|
The seed for the random starting point, which also seeds the
perturbations of |
42
|
callback
|
Callable[[ndarray], None] | None
|
An optional function called after every iteration with the
current parameters. It is passed to SciPy, and |
None
|
Returns:
| Type | Description |
|---|---|
VariationalResult
|
A |
Example
from eigenkit import Circuit, Variational
from eigenkit.core.ir import Observable
from eigenkit.core.variational import minimize_expectation
# One qubit, one trainable rotation, H = Z. The minimum is -1.
circuit = Circuit(
blocks=[Variational(depth=1)],
observables=Observable.from_string("Z0"),
provider="numpy",
)
result = minimize_expectation(circuit, random_state=42)
print(round(result.optimal_value, 6)) # -1.0
print(result.success, result.n_iterations) # True 4
register(name, provider_or_config)
Register a backend, or a configuration that can build one, under name.
Later calls to Circuit(..., provider=name) then use that backend. If a
configuration is passed, its make_backend() method is called to build the
backend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name to register. |
required |
provider_or_config
|
Provider | object
|
A backend instance, or a
configuration with a |
required |
register_lazy(name, loader)
Register a backend under name without importing its package yet.
loader is called the first time the name is looked up, and its result is
kept for later lookups. The optional backends are registered in this way, so
that naming them imports nothing.
It replaces whatever name currently refers to, as register does. If the
registration were skipped when the name was already taken, a caller could not
replace a built-in backend with a lazy one, and would get no sign that the
loader had been ignored.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name to register. |
required |
loader
|
Callable[[], Provider]
|
A function with no arguments that returns the backend. It is called the first time the name is looked up. |
required |
registered_names()
Return every provider name that get accepts, including the lazy ones.