Qsub quick overview
Introduction
This notebook will show you how to use Qsub to construct structured quantum programs that represents FTQC algorithms. Let's look at how to use Qsub, step by step, in the following order!
Op
andSub
- First, we will explain
Op
andSub
, which represent arbitrary quantum operations in Qsub.
- First, we will explain
- Standard predefined
Op
s:qsub.lib.std
- Next, we will introduce predefined
Op
s, which is provided in the standard library.
- Next, we will introduce predefined
- Resolving
Op
toSub
- Compile and analyze a
Sub
- The
Sub
thus created must be resolved and compiled in order to perform resource estimation and generate quantum circuits for QURI Parts. The following sections describe these resolve and compile processes.
- The
- Custom
Op
andSub
- Users can define their own
Op
andSub
, which can be used in the same way as predefinedOp
andSub
. The last section describes how to create such customOp
andSub
.
- Users can define their own
Op
and Sub
In Sub a circuit is represented as a Sub
(subroutine) object. A Sub
is defined as a sequence of operations on qubits and classical registers.
The most basic thing you can do is to define a Sub
using predefined Op
s.
from quri_parts.qsub.sub import SubBuilder
# Predefined Ops
from quri_parts.qsub.lib.std import H, CNOT, RZ
# Build a circuit for 2 qubits
b = SubBuilder(2)
q0, q1 = b.qubits
b.add_op(H, (q1,))
b.add_op(CNOT, (q0, q1))
b.add_op(RZ(-0.5), (q1,))
b.add_op(CNOT, (q0, q1))
b.add_op(RZ(0.5), (q1,))
b.add_op(H, (q1,))
sub = b.build()
from quri_parts.qsub.visualize import draw_sub
draw_sub(sub)
Some Op
s are parametric: in the above example, RZ
is a parametric Op
. It is just a function returning a (non-parametric) Op
: RZ(0.5)
is an Op
with the fixed parameter 0.5.
Standard predefined Op
s: qsub.lib.std
qsub.lib.std
package contains the following standard pre-defined Op
s.
from math import pi
from quri_parts.qsub.lib import std
print("Single qubit non-parametric gates:")
for op in [
std.X,
std.Y,
std.Z,
std.H,
std.SqrtX,
std.SqrtXdag,
std.SqrtY,
std.SqrtYdag,
std.S,
std.Sdag,
std.T,
std.Tdag,
]:
print(" ", op)
print("Single qubit parametric rotation gates:")
for op in [
std.RX,
std.RY,
std.RZ,
std.Phase,
]:
print(" ", op(pi/8))
print("Two qubit non-parametric gates:")
for op in [
std.CNOT,
std.CZ,
std.SWAP,
]:
print(" ", op)
print("Three qubit non-parametric gates:")
print(" ", std.Toffoli)
print("Measurement:")
print(" ", std.M)
print("Classical conditional branching:")
for op in [
std.Cbz,
std.Label,
]:
print(" ", op)
_ = [
"conditional",
"Inverse",
"Controlled",
"MultiControlled",
"scoped_and",
"scoped_and_clifford_t",
]
Single qubit non-parametric gates:
lib.std.X(qubits=1, registers=0)
lib.std.Y(qubits=1, registers=0)
lib.std.Z(qubits=1, registers=0)
lib.std.H(qubits=1, registers=0)
lib.std.SqrtX(qubits=1, registers=0)
lib.std.SqrtXdag(qubits=1, registers=0)
lib.std.SqrtY(qubits=1, registers=0)
lib.std.SqrtYdag(qubits=1, registers=0)
lib.std.S(qubits=1, registers=0)
lib.std.Sdag(qubits=1, registers=0)
lib.std.T(qubits=1, registers=0)
lib.std.Tdag(qubits=1, registers=0)
Single qubit parametric rotation gates:
lib.std.RX<0.39269908169872414>(qubits=1, registers=0)
lib.std.RY<0.39269908169872414>(qubits=1, registers=0)
lib.std.RZ<0.39269908169872414>(qubits=1, registers=0)
lib.std.Phase<0.39269908169872414>(qubits=1, registers=0)
Two qubit non-parametric gates:
lib.std.CNOT(qubits=2, registers=0)
lib.std.CZ(qubits=2, registers=0)
lib.std.SWAP(qubits=2, registers=0)
Three qubit non-parametric gates:
lib.std.Toffoli(qubits=3, registers=0)
Measurement:
lib.std.M(qubits=1, registers=1)
Classical conditional branching:
lib.std.Cbz(qubits=0, registers=2)
lib.std.Label(qubits=0, registers=1)