Skip to content

Variational

These blocks are trainable, parametrised layers. There are two kinds:

  • Variational applies rotations about one axis and a ladder of controlled-NOT (CNOT) gates, repeated depth times.
  • StrongVariational applies the rotations RZ, RY and RZ and a ladder of CNOT gates, repeated depth times.
from eigenkit import Variational, StrongVariational

basic = Variational(depth=2, rotation="RY")
strong = StrongVariational(depth=2)

Variational

Parameter Type Default Description
depth int Required The number of repetitions.
rotation "RX" | "RY" | "RZ" "RY" The rotation gate applied to each qubit in each repetition.

Each repetition applies one rotation to each qubit, followed by a ladder of CNOT gates (CNOT(0, 1), CNOT(1, 2), ...). The total number of trainable weights is depth * n_qubits.

One repetition of the Variational block (light theme) One repetition of the Variational block (dark theme)

The block is the middle box: one RY(θ) on every qubit, then CNOT(0, 1), CNOT(1, 2), ..., and the bracket shows how many times this repeats. The encoding on the left and the measurement of each qubit on the right are not part of the block. A layer such as Basic adds them around it.

StrongVariational

Parameter Type Default Description
depth int Required The number of repetitions.

Each repetition applies RZ, RY and RZ to every qubit, followed by a ladder of CNOT gates. The total number of trainable weights is 3 * depth * n_qubits.

The StrongVariational block on two qubits (light theme) The StrongVariational block on two qubits (dark theme)

The same picture with strong in place of basic, on two qubits. Each Rot box is the three rotations RZ, RY and RZ, so it has three weights where Variational has one, and the CNOT ladder after it is unchanged. It is drawn after an RY encoding, with a single expectation value measured on the first qubit.

StrongVariational is more expressive than Variational at the same depth, but it has three times as many parameters. The block adds all the RZ gates, then all the RY gates, then all the RZ gates, in place of three rotations per qubit in turn. This lets the backends that work layer by layer apply each layer of rotations in one fast call.

Choosing the depth

Each repetition uses a new set of trainable weights. A larger depth gives more expressivity, but it adds parameters and makes training slower.

# Minimal expressivity, fast training.
Variational(depth=1, rotation="RY")

# More expressive; useful for harder classification tasks.
Variational(depth=3, rotation="RY")

depth must be positive

Both blocks check it when they are created: Variational(depth=0) and StrongVariational(depth=0) raise ValueError: depth must be positive, got 0, and so does any negative value. Variational also checks rotation at that point. Reuploading makes the same checks on depth, in_features and both of its rotation arguments.

API reference

eigenkit.configs.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 ValueError is raised otherwise.

required
rotation GateName

The rotation gate of the trainable layer: "RX", "RY" or "RZ". Default: "RY".

'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 IRFragment. Its weight and input indices start at 0, and they are shifted when the blocks are combined into a circuit.

from_dict(d) classmethod

Rebuild a block from the output of to_dict().

Parameters:

Name Type Description Default
d dict

A dictionary returned by to_dict().

required

Returns:

Type Description
'BasicVariational'

The rebuilt BasicVariational.

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 type.

eigenkit.configs.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 ValueError is raised otherwise.

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 IRFragment. Its weight and input indices start at 0, and they are shifted when the blocks are combined into a circuit.

from_dict(d) classmethod

Rebuild a block from the output of to_dict().

Parameters:

Name Type Description Default
d dict

A dictionary returned by to_dict().

required

Returns:

Type Description
'StrongVariational'

The rebuilt StrongVariational.

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 type.