Transpilation
Contains functions that operate on blocks and circuits to transpile
them to new blocks/circuits.
transpile(*fs)
AbstractBlock
or QuantumCircuit
transpilation.
Compose functions that accept a circuit/block and returns a circuit/block.
PARAMETER | DESCRIPTION |
---|---|
*fs |
composable functions that either map blocks to blocks
(
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
|
Composed function. |
Examples:
Flatten a block of nested chains and krons:
from qadence import *
from qadence.transpile import transpile, flatten, scale_primitive_blocks_only
b = chain(2 * chain(chain(X(0), Y(0))), kron(kron(X(0), X(1))))
print(b)
# both flatten and scale_primitive_blocks_only are functions that accept and
# return a block
t = transpile(flatten, scale_primitive_blocks_only)(b)
print(t)
We also proved a decorator to easily turn a function Callable[[AbstractBlock], AbstractBlock]
into a Callable[[QuantumCircuit], QuantumCircuit]
to be used in circuit transpilation.
from qadence import *
from qadence.transpile import transpile, blockfn_to_circfn, flatten
# We want to pass this circuit to `transpile` instead of a block,
# so we need functions that map from a circuit to a circuit.
circ = QuantumCircuit(2, chain(chain(X(0), chain(X(1)))))
@blockfn_to_circfn
def fn(block):
# un-decorated function accepts a block and returns a block
return block * block
transp = transpile(
# the decorated function accepts a circuit and returns a circuit
fn,
# already existing functions can also be decorated
blockfn_to_circfn(flatten)
)
print(transp(circ))
Source code in qadence/transpile/transpile.py
chain_single_qubit_ops(block)
Transpile a chain of krons into a kron of chains of single qubit operations.
Examples:
from qadence import hea
from qadence.transpile.block import chain_single_qubit_ops
# Consider a single HEA layer
block = hea(2,1)
print(block)
# After applying chain_single_qubit_ops, we get:
print(chain_single_qubit_ops(block))
ChainBlock(0,1) [tag: HEA]
├── ChainBlock(0,1)
│ ├── KronBlock(0,1)
│ │ ├── RX(0) [params: ['theta_0']]
│ │ └── RX(1) [params: ['theta_1']]
│ ├── KronBlock(0,1)
│ │ ├── RY(0) [params: ['theta_2']]
│ │ └── RY(1) [params: ['theta_3']]
│ └── KronBlock(0,1)
│ ├── RX(0) [params: ['theta_4']]
│ └── RX(1) [params: ['theta_5']]
└── ChainBlock(0,1)
└── KronBlock(0,1)
└── CNOT(0, 1)
ChainBlock(0,1)
├── KronBlock(0,1)
│ ├── ChainBlock(0)
│ │ ├── RX(0) [params: ['theta_0']]
│ │ ├── RY(0) [params: ['theta_2']]
│ │ └── RX(0) [params: ['theta_4']]
│ └── ChainBlock(1)
│ ├── RX(1) [params: ['theta_1']]
│ ├── RY(1) [params: ['theta_3']]
│ └── RX(1) [params: ['theta_5']]
└── ChainBlock(0,1)
└── KronBlock(0,1)
└── CNOT(0, 1)
Source code in qadence/transpile/block.py
scale_primitive_blocks_only(block, scale=None)
Push the scale all the way down into the leaves of the block tree.
When given a scaled CompositeBlock consisting of several PrimitiveBlocks.
PARAMETER | DESCRIPTION |
---|---|
block |
The block to be transpiled.
TYPE:
|
scale |
An optional scale parameter. Only to be used for recursive calls internally.
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
AbstractBlock
|
A block of the same type where the scales have been moved into the subblocks.
TYPE:
|
Examples:
There are two different cases:
ChainBlock
s/KronBlock
s: Only the first subblock needs to be scaled because chains/krons
represent multiplications.
from qadence import chain, X, RX
from qadence.transpile import scale_primitive_blocks_only
b = 2 * chain(X(0), RX(0, "theta"))
print(b)
# After applying scale_primitive_blocks_only
print(scale_primitive_blocks_only(b))
[mul: 2]
└── ChainBlock(0)
├── X(0)
└── RX(0) [params: ['theta']]
ChainBlock(0)
├── [mul: 2.000]
│ └── X(0)
└── RX(0) [params: ['theta']]
AddBlock
s: Consider 2 * add(X(0), RX(0, "theta")). The scale needs to be added to all
subblocks. We get add(2 * X(0), 2 * RX(0, "theta")).
from qadence import add, X, RX
from qadence.transpile import scale_primitive_blocks_only
b = 2 * add(X(0), RX(0, "theta"))
print(b)
# After applying scale_primitive_blocks_only
print(scale_primitive_blocks_only(b))
[mul: 2]
└── AddBlock(0)
├── X(0)
└── RX(0) [params: ['theta']]
AddBlock(0)
├── [mul: 2.000]
│ └── X(0)
└── [mul: 2.000]
└── RX(0) [params: ['theta']]
Source code in qadence/transpile/block.py
set_trainable(blocks, value=True, inplace=True)
Set the trainability of all parameters in a block to a given value.
PARAMETER | DESCRIPTION |
---|---|
blocks |
Block or list of blocks for which to set the trainable attribute
TYPE:
|
value |
The value of the trainable attribute to assign to the input blocks
TYPE:
|
inplace |
Whether to modify the block(s) in place or not. Currently, only
TYPE:
|
RAISES | DESCRIPTION |
---|---|
|
if the |
RETURNS | DESCRIPTION |
---|---|
|
AbstractBlock | list[AbstractBlock]: the input block or list of blocks with the trainable attribute set to the given value |
Source code in qadence/transpile/block.py
validate(block)
Moves a block from global to local qubit numbers by adding PutBlocks.
Reassigns qubit locations appropriately.
Example
from qadence.blocks import chain
from qadence.operations import X
from qadence.transpile import validate
x = chain(chain(X(0)), chain(X(1)))
print(x)
print(validate(x))
ChainBlock(0,1)
├── ChainBlock(0)
│ └── X(0)
└── ChainBlock(1)
└── X(1)
ChainBlock(0,1)
├── put on (0)
│ └── ChainBlock(0)
│ └── put on (0)
│ └── X(0)
└── put on (1)
└── ChainBlock(0)
└── put on (0)
└── X(0)