Built-in macros in blueqat 0.4.7 (or later)
We released blueqat ver. 0.4.7 and implemented Gray-code based multi-controlled gates.
# Update to latest version of blueqat
!pip install -U blueqat
Requirement already satisfied: blueqat in /opt/conda/lib/python3.9/site-packages (0.4.5)
Collecting blueqat
Downloading blueqat-0.4.7-py3-none-any.whl (66 kB)
[K |████████████████████████████████| 66 kB 444 kB/s eta 0:00:011
[?25hRequirement already satisfied: scipy>=1.5 in /opt/conda/lib/python3.9/site-packages (from blueqat) (1.6.3)
Requirement already satisfied: numpy>=1.19 in /opt/conda/lib/python3.9/site-packages (from blueqat) (1.19.5)
Installing collected packages: blueqat
Attempting uninstall: blueqat
Found existing installation: blueqat 0.4.5
Uninstalling blueqat-0.4.5:
Successfully uninstalled blueqat-0.4.5
Successfully installed blueqat-0.4.7
Activate built-in macros
To activate macros, execute import blueqat.macros
.
from blueqat import Circuit
import blueqat.macros
Now, built-in macros are available.
Draw the circuit
We add new macros for drawing the circuit. This feature requires qiskit.
Circuit().h[0].cx[0, 1].draw()
┌───┐
q_0: ┤ H ├──■──
└───┘┌─┴─┐
q_1: ─────┤ X ├
└───┘
c: 2/══════════
# In jupyter notebook, output='mpl' generates beautiful drawing.
# You may needs to run `pip install pylatexenc` before.
Circuit().h[0].cx[0, 1].draw(output='mpl')
<Figure size 206.852x204.68 with 1 Axes>
Multi-controlled gate
blueqat has ccx
and ccz
, but doesn't have multi-controlled gate. Therefore, we implemented them as macros.
Multi-controlled X, Z
c3x
, c4x
, c3z
, c4z
are available.
Circuit.c3x(c0, c1, c2, t)
: 3-controlled X
Circuit.c3z(c0, c1, c2, t)
: 3-controlled Z
Circuit.c4x(c0, c1, c2, c3, t)
: 4-controlled X
Circuit.c4z(c0, c1, c2, c3, t)
: 4-controlled Z
for c0 in [0, 1]:
for c1 in [0, 1]:
for c2 in [0, 1]:
for c3 in [0, 1]:
c = Circuit()
if c0:
c.x[0]
if c1:
c.x[1]
if c2:
c.x[2]
if c3:
c.x[3]
c.c4x(0, 1, 2, 3, 4)
result = c.m[:].shots(10)
print(f'C4x |{c0}{c1}{c2}{c3}0>')
print(f'Expected: {c0}{c1}{c2}{c3}{c0*c1*c2*c3}, Actual:', result)
C4x |00000>
Expected: 00000, Actual: Counter({'00000': 10})
C4x |00010>
Expected: 00010, Actual: Counter({'00010': 10})
C4x |00100>
Expected: 00100, Actual: Counter({'00100': 10})
C4x |00110>
Expected: 00110, Actual: Counter({'00110': 10})
C4x |01000>
Expected: 01000, Actual: Counter({'01000': 10})
C4x |01010>
Expected: 01010, Actual: Counter({'01010': 10})
C4x |01100>
Expected: 01100, Actual: Counter({'01100': 10})
C4x |01110>
Expected: 01110, Actual: Counter({'01110': 10})
C4x |10000>
Expected: 10000, Actual: Counter({'10000': 10})
C4x |10010>
Expected: 10010, Actual: Counter({'10010': 10})
C4x |10100>
Expected: 10100, Actual: Counter({'10100': 10})
C4x |10110>
Expected: 10110, Actual: Counter({'10110': 10})
C4x |11000>
Expected: 11000, Actual: Counter({'11000': 10})
C4x |11010>
Expected: 11010, Actual: Counter({'11010': 10})
C4x |11100>
Expected: 11100, Actual: Counter({'11100': 10})
C4x |11110>
Expected: 11111, Actual: Counter({'11111': 10})
It seems OK.
We also prepared arbitrary number of control gates, mcx_gray
and mcz_gray
.
Circuit.mcx_gray([controls], target)
: Multi-controlled X
Circuit.mcz_gray([controls], target)
: Multi-controlled Z
c0, c1, c2 = 1, 1, 1
for c3 in [0, 1]:
for c4 in [0, 1]:
c = Circuit().x[0, 1, 2]
if c3:
c.x[3]
if c4:
c.x[4]
c.mcx_gray([0, 1, 2, 3, 4], 5)
result = c.m[:].shots(10)
print(f'C4x |{c0}{c1}{c2}{c3}{c4}0>')
print(f'Expected: {c0}{c1}{c2}{c3}{c4}{c0*c1*c2*c3*c4}, Actual:', result)
C4x |111000>
Expected: 111000, Actual: Counter({'111000': 10})
C4x |111010>
Expected: 111010, Actual: Counter({'111010': 10})
C4x |111100>
Expected: 111100, Actual: Counter({'111100': 10})
C4x |111110>
Expected: 111111, Actual: Counter({'111111': 10})
Please note that the number of gates is grown exponentially by the number of control qubits.
Circuit().mcx_gray([0, 1, 2], 3).draw(output='mpl')
<Figure size 1411x325.08 with 1 Axes>
Circuit().mcx_gray([0, 1, 2, 3], 4).draw(output='mpl')
<Figure size 1591.6x806.68 with 1 Axes>
Circuit().mcx_gray([0, 1, 2, 3, 4], 5).draw(output='mpl')
<Figure size 1591.6x1890.28 with 1 Axes>
Multi-controlled RX, RY, RZ, R
Multi-controlled rotation macros are also available.
R-gate and RZ-gate are same except global phase. However, controlled-R and controlled-RZ are different gate.
mcrx_gray(theta, [controls], target)
: Multi-controlled RX(theta)
mcry_gray(theta, [controls], target)
: Multi-controlled RY(theta)
mcrz_gray(theta, [controls], target)
: Multi-controlled RZ(theta)
mcr_gray(theta, [controls], target)
: Multi-controlled R(theta)
from math import pi
for c0 in [0, 1]:
for c1 in [0, 1]:
for c2 in [0, 1]:
c = Circuit()
if c0:
c.x[0]
if c1:
c.x[1]
if c2:
c.x[2]
c.mcry_gray(pi / 2, [0, 1, 2], 3)
if c0 * c1 * c2 == 0:
print(f"Expect: {c0}{c1}{c2}0: 100%")
else:
print(f"Expect: {c0}{c1}{c2}0: 50%, {c0}{c1}{c2}1: 50%")
print("Actual:", c.m[3].shots(100))
Expect: 0000: 100%
Actual: Counter({'0000': 100})
Expect: 0010: 100%
Actual: Counter({'0000': 100})
Expect: 0100: 100%
Actual: Counter({'0000': 100})
Expect: 0110: 100%
Actual: Counter({'0000': 100})
Expect: 1000: 100%
Actual: Counter({'0000': 100})
Expect: 1010: 100%
Actual: Counter({'0000': 100})
Expect: 1100: 100%
Actual: Counter({'0000': 100})
Expect: 1110: 50%, 1111: 50%
Actual: Counter({'0001': 58, '0000': 42})
Multi-controlled U
U-gate can represent arbitrary 2x2 unitary gate with 4 parameters theta, phi, lambda and gamma.
We implemented mcu_gray
macro.
mcu_gray(theta, phi, lam, gamma, [controls], target)
: Multi-controlled U
from blueqat.circuit_funcs import circuit_to_unitary
c = Circuit().mcu_gray(pi / 2, pi / 4, pi / 8, pi / 16, [0, 1, 2], 3)
mcu = circuit_to_unitary(c)
c.draw(output='mpl')
<Figure size 1591.6x686.28 with 1 Axes>
import numpy as np
u = circuit_to_unitary(Circuit().u(pi / 2, pi / 4, pi / 8, pi / 16,)[0])
expected = np.eye(16, dtype=complex)
expected[7, 7] = u[0, 0]
expected[15, 7] = u[1, 0]
expected[7, 15] = u[0, 1]
expected[15, 15] = u[1, 1]
np.allclose(mcu, expected)
True