Block system
qadence offers a block-based system to construct quantum circuits in a flexible manner.
AbstractBlock
dataclass
Bases: ABC
Base class for both primitive and composite blocks
| ATTRIBUTE | DESCRIPTION |
|---|---|
name |
A human-readable name attached to the block type. Notice, this is the same for all the class instances so it cannot be used for identifying different blocks
TYPE:
|
qubit_support |
The qubit support of the block expressed as a tuple of integers
TYPE:
|
tag |
A tag identifying a particular instance of the block which can be used for identification and pretty printing
TYPE:
|
eigenvalues |
The eigenvalues of the matrix representing the block. This is used mainly for primitive blocks and it's needed for generalized parameter shift rule computations. Currently unused.
TYPE:
|
is_identity: bool
property
Identity predicate for blocks.
n_qubits()
The number of qubits in the whole system. A block acting on qubit N would has at least n_qubits >= N + 1.
n_supports()
qubit_support()
The indices of the qubit(s) the block is acting on. Qadence uses the ordering [0..,N-1] for qubits.
Primitive blocks
ControlBlock(control, target_block)
Bases: PrimitiveBlock
The abstract ControlBlock
Source code in qadence/blocks/primitive.py
ParametricBlock
Bases: PrimitiveBlock
Parameterized primitive blocks
num_parameters()
abstractmethod
The number of parameters required by the block
This is a class property since the number of parameters is defined automatically before instantiating the operation. Also, this could correspond to a larger number of actual user-facing parameters since any parameter expression is allowed
Examples: - RX operation has 1 parameter - U operation has 3 parameters - HamEvo has 2 parameters (generator and time evolution)
Source code in qadence/blocks/primitive.py
ParametricControlBlock(control, target_block)
Bases: ParametricBlock
The abstract parametrized ControlBlock
Source code in qadence/blocks/primitive.py
PrimitiveBlock(qubit_support)
Bases: AbstractBlock
Primitive blocks represent elementary unitary operations such as single/multi-qubit gates or
Hamiltonian evolution. See qadence.operations for a full list of
primitive blocks.
Source code in qadence/blocks/primitive.py
digital_decomposition()
Decomposition into purely digital gates
This method returns a decomposition of the Block in a combination of purely digital single-qubit and two-qubit 'gates', by manual/custom knowledge of how this can be done efficiently. :return:
Source code in qadence/blocks/primitive.py
ScaleBlock(block, parameter)
Bases: ParametricBlock
Scale blocks are created when multiplying a block by a number or parameter.
Example:
Source code in qadence/blocks/primitive.py
TimeEvolutionBlock
Bases: ParametricBlock
Simple time evolution block with time-independent Hamiltonian
This class is just a convenience class which is used to label blocks which contains simple time evolution with time-independent Hamiltonian operators
Analog blocks
To learn how to use analog blocks and how to mix digital & analog blocks, check out the digital-analog section of the documentation.
Examples on how to use digital-analog blocks can be found in the *examples folder of the qadence repo:
- Fit a simple sinus:
examples/digital-analog/fit-sin.py - Solve a QUBO:
examples/digital-analog/qubo.py
AnalogChain(blocks)
dataclass
Bases: AnalogComposite
A chain of analog blocks. Needed because analog blocks require
stricter validation than the general ChainBlock.
AnalogChains can only be constructed from AnalogKron blocks or
globally supported, primitive, analog blocks (like WaitBlocks and
ConstantAnalogRotations).
Automatically constructed by the chain
function if only analog blocks are given.
Example:
from qadence import X, chain, wait
b = chain(wait(200), wait(200))
print(type(b)) # this is an `AnalogChain`
b = chain(X(0), wait(200))
print(type(b)) # this is a general `ChainBlock`
Source code in qadence/blocks/analog.py
AnalogKron(blocks, interaction=Interaction.NN)
dataclass
Bases: AnalogComposite
Stack analog blocks vertically (i.e. in time). Needed because analog require
stricter validation than the general KronBlock.
AnalogKrons can only be constructed from non-global, analog blocks
with the same duration.
Source code in qadence/blocks/analog.py
ConstantAnalogRotation
dataclass
Bases: AnalogBlock
Implements a constant analog rotation with interaction dictated by the chosen Hamiltonian
H = ∑ᵢ(hΩ/2 sin(φ)*Xᵢ - cos(φ)*Yᵢ - hδnᵢ) + Hᵢₙₜ.
To construct this block you can use of the following convenience wrappers:
- The general rotation operation AnalogRot
- Shorthands for rotatins around an axis:
AnalogRX,
AnalogRY,
AnalogRZ
Can be used with add_interaction.
WARNING: do not use ConstantAnalogRotation with alpha as differentiable parameter - use
the convenience wrappers mentioned above.
WaitBlock
dataclass
Bases: AnalogBlock
Waits. In real interacting quantum devices, it means letting the system evolve freely according to the time-dependent Schrodinger equation. With emulators, this block is translated to an appropriate interaction Hamiltonian, for example, an Ising interation
Hᵢₙₜ = ∑ᵢⱼ C₆/rᵢⱼ⁶ nᵢnⱼ
or an XY-interaction
Hᵢₙₜ = ∑ᵢⱼ C₃/rⱼⱼ³ (XᵢXⱼ + ZᵢZⱼ)
with nᵢ = (1-Zᵢ)/2.
To construct this block, use the wait function.
Can be used with add_interaction.
Composite blocks
chain(*args)
Chain blocks sequentially. On digital backends this can be interpreted loosely as a matrix mutliplication of blocks. In the analog case it chains blocks in time.
| PARAMETER | DESCRIPTION |
|---|---|
*args |
Blocks to chain. Can also be a generator.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ChainBlock
|
ChainBlock |
Example:
from qadence import X, Y, chain
b = chain(X(0), Y(0))
# or use a generator
b = chain(X(i) for i in range(3))
print(b)
Source code in qadence/blocks/utils.py
kron(*args)
Stack blocks vertically. On digital backends this can be intepreted loosely as a kronecker product of blocks. In the analog case it executes blocks parallel in time.
| PARAMETER | DESCRIPTION |
|---|---|
*args |
Blocks to kron. Can also be a generator.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
KronBlock
|
KronBlock |
Example:
from qadence import X, Y, kron
b = kron(X(0), Y(1))
# or use a generator
b = kron(X(i) for i in range(3))
print(b)
Source code in qadence/blocks/utils.py
add(*args)
Sums blocks.
| PARAMETER | DESCRIPTION |
|---|---|
*args |
Blocks to add. Can also be a generator.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
AddBlock
|
AddBlock |
Example:
from qadence import X, Y, add
b = add(X(0), Y(0))
# or use a generator
b = add(X(i) for i in range(3))
print(b)
Source code in qadence/blocks/utils.py
AddBlock(blocks)
ChainBlock(blocks)
Bases: CompositeBlock
Chains blocks sequentially. Constructed via chain
Source code in qadence/blocks/composite.py
CompositeBlock
Bases: AbstractBlock
Block which composes multiple blocks into one larger block (which can again be composed).
Composite blocks are constructed via chain,
kron, and add.
KronBlock(blocks)
Bases: CompositeBlock
Stacks blocks horizontally. Constructed via kron.
Source code in qadence/blocks/composite.py
Converting blocks to matrices
block_to_tensor(block, values={}, qubit_support=None, use_full_support=True, tensor_type=TensorType.DENSE, endianness=Endianness.BIG)
Convert a block into a torch tensor.
| PARAMETER | DESCRIPTION |
|---|---|
block |
The block to convert.
TYPE:
|
values |
A optional dict with values for parameters.
TYPE:
|
qubit_support |
The qubit_support of the block.
TYPE:
|
use_full_support |
True infers the total number of qubits.
TYPE:
|
tensor_type |
the target tensor type.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Tensor
|
A torch.Tensor. |
Examples:
from qadence import hea, hamiltonian_factory, Z, block_to_tensor
block = hea(2,2)
print(block_to_tensor(block))
# In case you have a diagonal observable, you can use
obs = hamiltonian_factory(2, detuning = Z)
print(block_to_tensor(obs, tensor_type="SparseDiagonal"))
tensor([[[ 0.5034+0.1645j, -0.2575-0.4773j, -0.1863-0.2398j, -0.5771+0.0125j],
[ 0.0301-0.4791j, 0.5561+0.0912j, -0.5891-0.2234j, -0.1547-0.1766j],
[-0.1238-0.5348j, -0.3862-0.0394j, 0.2656+0.1068j, -0.1997-0.6528j],
[-0.3733-0.2200j, -0.1777-0.4539j, 0.0268-0.6544j, 0.3337+0.1853j]]],
grad_fn=<UnsafeViewBackward0>)
tensor(indices=tensor([[0, 3],
[0, 3]]),
values=tensor([ 2.+0.j, -2.+0.j]),
size=(4, 4), nnz=2, layout=torch.sparse_coo)