configs
eigenkit.configs
The blocks that make up a circuit, and the configurations of the backends.
Blocks are combined into a circuit with Circuit(blocks=[...]):
Encodingencodes classical features as rotation angles.Variationalapplies, in each layer, one trainable rotation to every qubit, followed by a ladder of controlled-NOT (CNOT) gates.StrongVariationalapplies, in each layer, trainableRZ,RYandRZrotations to every qubit, followed by a ladder of CNOT gates.Reuploadingencodes the input several times, between trainable layers. The encoding can have a trainable scale.
A configuration selects a backend and holds its settings. Pass it to
Circuit(provider=...), or register a name for it. NumpyConfig is documented
below, and the other configurations are documented with their backends:
NumpyConfig: the reference simulator, which needs no extra dependencies (provider="numpy").PennyLaneConfigQiskitConfigQiskitAerConfig: the Qiskit Aer simulator, with the statevector and the matrix product state methods.QiskitRuntimeConfigIQMConfigBraketConfigCudaQuantumConfigTensorCircuitConfigQulacsConfigQsimConfig
The blocks and NumpyConfig are imported with this module, because they only
need NumPy. The other configurations are imported when they are first used, so
importing this module does not import PyTorch, PennyLane, Qiskit or Braket.
The quantities to measure are set with Circuit(observables=...). They are not
a block.
Example
import numpy as np
from eigenkit import Circuit, all_z
from eigenkit.configs import Encoding, Variational, NumpyConfig
circuit = Circuit(
blocks=[Encoding(in_features=3), Variational(depth=2)],
observables=all_z(3),
provider=NumpyConfig(),
)
print(circuit.spec.n_qubits, circuit.spec.n_weights) # 3 6
print(circuit(np.zeros(circuit.spec.n_weights), np.zeros(3))) # [1. 1. 1.]
To change the backend, you change one argument. provider=PennyLaneConfig(...)
runs the same blocks on PennyLane, and provider="numpy" selects the same
reference simulator by its registered name.
Encoding
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 |
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 |
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 |
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 |
Variational
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 |