# -*- coding: utf-8 -*-
# This code is part of PyQpanda.
#
# (C) Copyright Origin Quantum 2018-2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""circuit visualization backend."""
import collections
import fractions
import itertools
import logging
import math
import numpy as np
from .circuit_style import *
from pyqpanda.pyQPanda import GateType
from pyqpanda.pyQPanda import NodeType
try:
from matplotlib import get_backend
from matplotlib import patches
from matplotlib import pyplot as plt
plt.switch_backend('agg')
HAS_MATPLOTLIB = True
except ImportError:
HAS_MATPLOTLIB = False
from .pi_check import *
logger = logging.getLogger(__name__)
WID = 0.65
HIG = 0.65
DEFAULT_SCALE = 4.3
PORDER_GATE = 5
PORDER_LINE = 3
PORDER_REGLINE = 2
PORDER_GRAY = 3
PORDER_TEXT = 6
PORDER_SUBP = 4
my_qubit = 'qubit'
my_cbit = 'cbit'
[文档]
class Anchor:
def __init__(self, reg_num, yind, fold):
self.__yind = yind
#self.__fold = fold
self.__fold = 0.0
self.__reg_num = reg_num
self.__gate_placed = []
[文档]
self.gate_anchor = 0
[文档]
self.last_h_pos = 0.0
[文档]
self.max_x_pos = fold
self.__flod_cnt = 0
[文档]
def get_fold_info(self):
return self.__fold, self.__flod_cnt
[文档]
def set_fold_info(self, target_fold, fold_cnt):
self.__fold = target_fold
self.__flod_cnt = fold_cnt
[文档]
def update_fold_info(self, index, gate_width, x_offset, layer_offset):
tmp_x_pos = index - self.__fold + 1 + 0.5 * \
(gate_width - 1) + x_offset + layer_offset
if tmp_x_pos > self.max_x_pos:
#self.b_fold = True
self.__fold = index
self.__flod_cnt += 1
# else:
# self.b_fold = False
[文档]
def plot_coord(self, index, gate_width, x_offset, layer_offset, last_h_pos):
test_x_pos = index - self.__fold + 1 + 0.5 * \
(gate_width - 1) + x_offset + layer_offset
h_pos = index - self.__fold + 1
# if self.__fold == h_pos:
# if last_h_pos > (h_pos + gate_width * 3):
if test_x_pos > self.max_x_pos:
self.b_fold = True
self.__fold = index
self.__flod_cnt += 1
# if last_h_pos > h_pos:
# self.b_fold = True
# check folding
# if self.__fold > 0:
if True:
# test_pos = index % self.__fold + 1 + 0.5 * ((2 * gate_width) - 1) + x_offset
# if test_pos > 29:
# if h_pos + (gate_width - 1) > self.__fold:
# if last_h_pos > (h_pos + gate_width * 3):
if self.b_fold:
# if self.b_fold:
# index += self.__fold - (h_pos - 1)
tmp_offset = x_offset
else:
tmp_offset = x_offset + layer_offset
x_pos = index - self.__fold + 1 + 0.5 * (gate_width - 1)
#y_pos = self.__yind - (index // self.__fold) * (self.__reg_num + 1)
y_pos = self.__yind - (self.__flod_cnt) * (self.__reg_num + 1)
else:
x_pos = index + 1 + 0.5 * (gate_width - 1)
y_pos = self.__yind
# could have been updated, so need to store
self.gate_anchor = index
# self.last_h_pos = h_pos
return x_pos + tmp_offset, y_pos
[文档]
def is_locatable(self, index, gate_width):
hold = [index + i for i in range(gate_width)]
for p in hold:
if p in self.__gate_placed:
return False
return True
[文档]
def set_index(self, index, gate_width):
# h_pos = index - self.__fold + 1
# if h_pos + (gate_width - 1) > self.__fold:
# _index = index + self.__fold - (h_pos - 1)
# else:
_index = index
#_index = index - self.__fold
for ii in range(math.floor(gate_width)):
if _index + ii not in self.__gate_placed:
self.__gate_placed.append(_index + ii)
self.__gate_placed.sort()
[文档]
def get_index(self):
if self.__gate_placed:
return self.__gate_placed[-1] + 1
return 0
[文档]
class MatplotlibDrawer:
def __init__(self, qregs, cregs, ops,
scale=1.0, style=None, plot_barriers=True,
reverse_bits=False, layout=None, fold=25, ax=None):
if not HAS_MATPLOTLIB:
raise ImportError('The class MatplotlibDrawer needs matplotlib. '
'To install, run "pip install matplotlib".')
self._ast = None
self._scale = DEFAULT_SCALE * scale
self._creg = []
self._qreg = []
self._registers(cregs, qregs)
self._ops = ops
self._qreg_dict = collections.OrderedDict()
self._creg_dict = collections.OrderedDict()
self._cond = {
'n_lines': 0,
'xmax': 0,
'ymax': 0,
}
'''
config = user_config.get_config()
if config and (style is None):
config_style = config.get('circuit_mpl_style', 'default')
if config_style == 'default':
self._style = DefaultStyle()
elif config_style == 'Q1':
self._style = BWStyle()
elif style is False:
self._style = BWStyle()
else:
self._style = DefaultStyle()
'''
self._style = DefaultStyle()
[文档]
self.plot_barriers = plot_barriers
[文档]
self.reverse_bits = reverse_bits
[文档]
self.layout = layout
[文档]
self.layer_offset = 0.0
[文档]
self.layer_offset_recode = []
'''
if style:
if isinstance(style, dict):
self._style.set_style(style)
elif isinstance(style, str):
with open(style, 'r') as infile:
dic = json.load(infile)
self._style.set_style(dic)
'''
if ax is None:
self.return_fig = True
self.figure = plt.figure()
self.figure.patch.set_facecolor(color=self._style.bg)
self.ax = self.figure.add_subplot(111)
else:
self.return_fig = True
self.ax = ax
self.figure = ax.get_figure()
'''else:
self.return_fig = False
self.ax = ax
self.figure = ax.get_figure()
'''
if self.fold < 2:
self.fold = -1
self.ax.axis('off')
self.ax.set_aspect('equal')
self.ax.tick_params(labelbottom=False, labeltop=False,
labelleft=False, labelright=False)
def _registers(self, creg, qreg):
self._creg = []
for r in creg:
self._creg.append(r)
self._qreg = []
for r in qreg:
self._qreg.append(r)
@property
[文档]
def ast(self):
return self._ast
def _custom_multiqubit_gate(self, xy, cxy=None, fc=None, wide=True, text=None,
subtext=None):
xpos = min([x[0] for x in xy])
ypos = min([y[1] for y in xy])
ypos_max = max([y[1] for y in xy])
if cxy:
ypos = min([y[1] for y in cxy])
if wide:
if subtext:
boxes_length = round(max([len(text), len(subtext)]) / 7) or 1
else:
boxes_length = math.ceil(len(text) / 7) or 1
boxes_length = 1
wid = WID * 2.5 * boxes_length
else:
wid = WID
if fc:
_fc = fc
else:
if self._style.name != 'Q1':
if self._style.gc != DefaultStyle().gc:
_fc = self._style.gc
else:
_fc = self._style.dispcol['multi']
_ec = self._style.dispcol['multi']
else:
_fc = self._style.gc
qubit_span = abs(ypos) - abs(ypos_max) + 1
height = HIG + (qubit_span - 1)
box = patches.Rectangle(
xy=(xpos - 0.5 * wid, ypos - .5 * HIG),
width=wid, height=height,
fc=_fc,
ec=self._style.dispcol['multi'],
linewidth=1.5, zorder=PORDER_GATE)
self.ax.add_patch(box)
# Annotate inputs
for bit, y in enumerate([x[1] for x in xy]):
self.ax.text(xpos - 0.45 * wid, y, str(0-y), ha='left', va='center',
fontsize=self._style.fs, color=self._style.gt,
clip_on=True, zorder=PORDER_TEXT)
if text:
# If the string length is too long,
# use '\n' and '...'
disp_text = ''
font_hight = self._style.fs *0.0351
text_hight = font_hight
for i in range(len(text)):
if i %5==0:
disp_text +='\n'
text_hight +=font_hight
if text_hight >=height:
disp_text+='...'
break
disp_text +=text[i]
if subtext:
self.ax.text(xpos, ypos + 0.4 * height, disp_text, ha='center',
va='center', fontsize=self._style.fs,
color=self._style.gt, clip_on=True,
zorder=PORDER_TEXT)
self.ax.text(xpos, ypos + 0.2 * height, subtext, ha='center',
va='center', fontsize=self._style.sfs,
color=self._style.sc, clip_on=True,
zorder=PORDER_TEXT)
else:
self.ax.text(xpos, ypos + .5 * (qubit_span - 1), disp_text,
ha='center',
va='center',
fontsize=self._style.fs,
color=self._style.gt,
clip_on=True,
zorder=PORDER_TEXT,
wrap=True)
def _gate(self, xy, fc=None, wide=False, text=None, subtext=None):
xpos, ypos = xy
tmp_text = text
if (text is not None) and (len(tmp_text) > 4) and (tmp_text[-4:] == '.dag'):
tmp_text = tmp_text[:-4]
if wide:
if subtext:
subtext_len = len(subtext)
if '$\\pi$' in subtext:
pi_count = subtext.count('pi')
subtext_len = subtext_len - (4 * pi_count)
boxes_wide = round(max(subtext_len, len(text)) / 10, 1) or 1
wid = WID * 1.5 * boxes_wide
else:
boxes_wide = round(len(text) / 10) or 1
wid = WID * 2.2 * boxes_wide
if wid < WID:
wid = WID
else:
wid = WID
if fc:
_fc = fc
elif self._style.gc != DefaultStyle().gc:
_fc = self._style.gc
elif tmp_text and tmp_text in self._style.dispcol:
_fc = self._style.dispcol[tmp_text]
else:
_fc = self._style.gc
box = patches.Rectangle(
xy=(xpos - 0.5 * wid, ypos - 0.5 * HIG), width=wid, height=HIG,
fc=_fc, ec=self._style.edge_color, linewidth=1.5, zorder=PORDER_GATE)
self.ax.add_patch(box)
if text:
font_size = self._style.fs
sub_font_size = self._style.sfs
# check if gate is not unitary
if text in ['RESET']:
disp_color = self._style.not_gate_lc
sub_color = self._style.not_gate_lc
font_size = self._style.math_fs
else:
disp_color = self._style.gt
sub_color = self._style.sc
if text in self._style.disptex:
disp_text = "${}$".format(self._style.disptex[text])
else:
disp_text = text
if subtext:
self.ax.text(xpos, ypos + 0.15 * HIG, disp_text, ha='center',
va='center', fontsize=font_size,
color=disp_color, clip_on=True,
zorder=PORDER_TEXT)
self.ax.text(xpos, ypos - 0.3 * HIG, subtext, ha='center',
va='center', fontsize=sub_font_size,
color=sub_color, clip_on=True,
zorder=PORDER_TEXT)
else:
self.ax.text(xpos, ypos, disp_text, ha='center', va='center',
fontsize=font_size,
color=disp_color,
clip_on=True,
zorder=PORDER_TEXT)
def _subtext(self, xy, text):
xpos, ypos = xy
self.ax.text(xpos, ypos - 0.3 * HIG, text, ha='center', va='top',
fontsize=self._style.sfs,
color=self._style.tc,
clip_on=True,
zorder=PORDER_TEXT)
def _sidetext(self, xy, text):
xpos, ypos = xy
# 0.15 = the initial gap, each char means it needs to move
# another 0.0375 over
xp = xpos + 0.15 + (0.0375 * len(text))
self.ax.text(xp, ypos + HIG, text, ha='center', va='top',
fontsize=self._style.sfs,
color=self._style.tc,
clip_on=True,
zorder=PORDER_TEXT)
def _line(self, xy0, xy1, lc=None, ls=None, zorder=PORDER_LINE):
x0, y0 = xy0
x1, y1 = xy1
if lc is None:
linecolor = self._style.lc
else:
linecolor = lc
if ls is None:
linestyle = 'solid'
else:
linestyle = ls
if linestyle == 'doublet':
theta = np.arctan2(np.abs(x1 - x0), np.abs(y1 - y0))
dx = 0.05 * WID * np.cos(theta)
dy = 0.05 * WID * np.sin(theta)
self.ax.plot([x0 + dx, x1 + dx], [y0 + dy, y1 + dy],
color=linecolor,
linewidth=2,
linestyle='solid',
zorder=zorder)
self.ax.plot([x0 - dx, x1 - dx], [y0 - dy, y1 - dy],
color=linecolor,
linewidth=2,
linestyle='solid',
zorder=zorder)
else:
self.ax.plot([x0, x1], [y0, y1],
color=linecolor,
linewidth=2,
linestyle=linestyle,
zorder=zorder)
def _reset(self, qxy):
qx, qy = qxy
self._gate(qxy, fc=self._style.dispcol['RESET'])
# add measure symbol
arc = patches.Arc(xy=(qx, qy - 0.15 * HIG), width=WID * 0.7,
height=HIG * 0.7, theta1=0, theta2=180, fill=False,
ec=self._style.not_gate_lc, linewidth=2,
zorder=PORDER_GATE)
self.ax.add_patch(arc)
self.ax.plot([qx, qx + 0.35 * WID],
[qy - 0.15 * HIG, qy + 0.20 * HIG],
color=self._style.not_gate_lc, linewidth=2, zorder=PORDER_GATE)
def _measure(self, qxy, cxy, cid):
qx, qy = qxy
cx, cy = cxy
self._gate(qxy, fc=self._style.dispcol['meas'])
# add measure symbol
arc = patches.Arc(xy=(qx, qy - 0.15 * HIG), width=WID * 0.7,
height=HIG * 0.7, theta1=0, theta2=180, fill=False,
ec=self._style.not_gate_lc, linewidth=2,
zorder=PORDER_GATE)
self.ax.add_patch(arc)
self.ax.plot([qx, qx + 0.35 * WID],
[qy - 0.15 * HIG, qy + 0.20 * HIG],
color=self._style.not_gate_lc, linewidth=2, zorder=PORDER_GATE)
# arrow
self._line(qxy, [cx, cy + 0.35 * WID], lc=self._style.cc,
ls=self._style.cline)
arrowhead = patches.Polygon(((cx - 0.20 * WID, cy + 0.35 * WID),
(cx + 0.20 * WID, cy + 0.35 * WID),
(cx, cy)),
fc=self._style.cc,
ec=None)
self.ax.add_artist(arrowhead)
# target
if self._style.bundle:
self.ax.text(cx + .15, cy + .1, str(cid), ha='left', va='bottom',
fontsize=0.8 * self._style.fs,
color=self._style.tc,
clip_on=True,
zorder=PORDER_TEXT)
def _conds(self, xy, istrue=False):
xpos, ypos = xy
if istrue:
_fc = self._style.lc
else:
_fc = self._style.gc
box = patches.Circle(xy=(xpos, ypos), radius=WID * 0.15,
fc=_fc, ec=self._style.lc,
linewidth=1.5, zorder=PORDER_GATE)
self.ax.add_patch(box)
def _ctrl_qubit(self, xy, fc=None, ec=None):
if self._style.gc != DefaultStyle().gc:
fc = self._style.gc
ec = self._style.gc
if fc is None:
fc = self._style.lc
if ec is None:
ec = self._style.lc
xpos, ypos = xy
box = patches.Circle(xy=(xpos, ypos), radius=WID * 0.15,
fc=fc, ec=ec,
linewidth=1.5, zorder=PORDER_GATE)
self.ax.add_patch(box)
[文档]
def get_op_color(self, op_name):
tmp_op_name = op_name
if (tmp_op_name is not None) and (len(tmp_op_name) > 4) and (tmp_op_name[-4:] == '.dag'):
tmp_op_name = tmp_op_name[:-4]
if tmp_op_name in ['U1', 'U2', 'U3', 'U4', 'CU']:
color_str = 'U4'
elif tmp_op_name in ['X', 'Y', 'Z']:
color_str = 'X'
elif tmp_op_name in ['I']:
color_str = 'I'
elif tmp_op_name in ['X1', 'Y1', 'Z1', 'RX', 'RY', 'RZ', 'RPhi']:
color_str = 'X1'
elif tmp_op_name in ['CNOT', 'CPHASE', 'CZ']:
color_str = 'CNOT'
elif tmp_op_name in ['H', 'S', 'T']:
color_str = 'H'
elif tmp_op_name in ['SWAP', 'ISWAP', 'ISWAPTheta', 'SQISWAP']:
color_str = 'SWAP'
else:
color_str = 'multi'
return color_str
[文档]
def set_multi_ctrl_bits(self, ctrl_state, num_ctrl_qubits, qbit, color_str):
# convert op.ctrl_state to bit string and reverse
cstate = "{0:b}".format(ctrl_state).rjust(num_ctrl_qubits, '0')[::-1]
for i in range(num_ctrl_qubits):
# Make facecolor of ctrl bit the box color if closed and bkgrnd if open
fc_open_close = (self._style.dispcol[color_str] if cstate[i] == '1'
else self._style.bg)
self._ctrl_qubit(qbit[i], fc=fc_open_close,
ec=self._style.dispcol[color_str])
def _tgt_qubit(self, xy, fc=None, ec=None, ac=None,
add_width=None):
if self._style.gc != DefaultStyle().gc:
fc = self._style.gc
ec = self._style.gc
if fc is None:
fc = self._style.dispcol['target']
if ec is None:
ec = self._style.lc
if ac is None:
ac = self._style.lc
if add_width is None:
add_width = 0.35
linewidth = 2
if self._style.dispcol['target'] == '#ffffff':
add_width = self._style.colored_add_width
xpos, ypos = xy
box = patches.Circle(xy=(xpos, ypos), radius=HIG * 0.35,
fc=fc, ec=ec, linewidth=linewidth,
zorder=PORDER_GATE)
self.ax.add_patch(box)
# add '+' symbol
self.ax.plot([xpos, xpos], [ypos - add_width * HIG,
ypos + add_width * HIG],
color=ac, linewidth=linewidth, zorder=PORDER_GATE + 1)
self.ax.plot([xpos - add_width * HIG, xpos + add_width * HIG],
[ypos, ypos], color=ac, linewidth=linewidth,
zorder=PORDER_GATE + 1)
def _swap(self, xy, color, fc=None, ec=None, ac=None, add_width=None):
xpos, ypos = xy
self.ax.plot([xpos - 0.20 * WID, xpos + 0.20 * WID],
[ypos - 0.20 * WID, ypos + 0.20 * WID],
color=color, linewidth=2, zorder=PORDER_LINE + 1)
self.ax.plot([xpos - 0.20 * WID, xpos + 0.20 * WID],
[ypos + 0.20 * WID, ypos - 0.20 * WID],
color=color, linewidth=2, zorder=PORDER_LINE + 1)
def _swap_gate(self, q_xy, gate_type, param, dagger, ctrl_qubits=0):
font_size = self._style.sfs + 1
if gate_type == GateType.ISWAP_THETA_GATE:
swap_sub_text = '{}'.format(param)
#font_size = self._style.sfs
elif gate_type == GateType.ISWAP_GATE:
swap_sub_text = 'iSWAP'
elif gate_type == GateType.SQISWAP_GATE:
swap_sub_text = 'SqiSWAP'
if dagger:
if gate_type == GateType.ISWAP_THETA_GATE:
if swap_sub_text[0] == '-':
swap_sub_text = swap_sub_text[1:]
else:
swap_sub_text = '-' + swap_sub_text
else:
swap_sub_text = swap_sub_text + '.dag'
if gate_type == GateType.ISWAP_THETA_GATE:
swap_sub_text = "{}".format(swap_sub_text)
else:
swap_sub_text = "${}$".format(self._style.disptex[swap_sub_text])
self._iswap(q_xy[ctrl_qubits], self._style.dispcol['ISWAP'],
fc=self._style.dispcol['ISWAP'], ec=self._style.dispcol['ISWAP'],
subtext=swap_sub_text, font_size=font_size)
self._iswap(q_xy[ctrl_qubits + 1], self._style.dispcol['ISWAP'],
fc=self._style.dispcol['ISWAP'], ec=self._style.dispcol['ISWAP'],
subtext=swap_sub_text, font_size=font_size)
def _iswap(self, xy, color, subtext, fc=None, ec=None, ac=None, add_width=None, font_size=None):
xpos, ypos = xy
if self._style.gc != DefaultStyle().gc:
fc = self._style.gc
ec = self._style.gc
if fc is None:
fc = self._style.dispcol['target']
if ec is None:
ec = self._style.lc
if ac is None:
ac = self._style.lc
if add_width is None:
add_width = 0.35
linewidth = 2
if self._style.dispcol['target'] == '#ffffff':
add_width = self._style.colored_add_width
box = patches.Circle(xy=(xpos, ypos), radius=HIG * 0.5,
fc=fc, ec=ec, linewidth=linewidth,
zorder=PORDER_GATE)
self.ax.add_patch(box)
arc_up = patches.Arc(xy=(xpos, ypos), width=WID * 0.8,
height=HIG * 0.8, theta1=30, theta2=150, fill=False,
ec=self._style.not_gate_lc, linewidth=1.5,
zorder=PORDER_GATE)
self.ax.add_patch(arc_up)
arc_down = patches.Arc(xy=(xpos, ypos), width=WID * 0.8,
height=HIG * 0.8, theta1=210, theta2=330, fill=False,
ec=self._style.not_gate_lc, linewidth=1.5,
zorder=PORDER_GATE)
self.ax.add_patch(arc_down)
self.ax.plot([xpos - 0.22, xpos - 0.20],
[ypos + 0.15, ypos + 0.22],
color=self._style.not_gate_lc, linewidth=1, zorder=PORDER_GATE)
self.ax.plot([xpos + 0.20, xpos + 0.22],
[ypos - 0.22, ypos - 0.15],
color=self._style.not_gate_lc, linewidth=1, zorder=PORDER_GATE)
# angle
if font_size == None:
font_size = self._style.fs
sub_color = self._style.sc
self.ax.text(xpos, ypos-0.03, subtext, ha='center',
va='center', fontsize=font_size,
color=sub_color, clip_on=True,
zorder=PORDER_TEXT)
def _barrier(self, config, anc):
xys = config['coord']
group = config['group']
for xy in xys:
xpos, ypos = xy
self.ax.plot(
[xpos, xpos],
[ypos + 0.5, ypos - 0.5],
linewidth=1,
linestyle="dashed",
color=self._style.lc,
zorder=PORDER_TEXT,
)
box = patches.Rectangle(
xy=(xpos - (0.3 * WID), ypos - 0.5),
width=0.6 * WID,
height=1,
fc=self._style.bc,
ec=None,
alpha=0.6,
linewidth=1.5,
zorder=PORDER_GRAY,
)
self.ax.add_patch(box)
def _linefeed_mark(self, xy):
xpos, ypos = xy
self.ax.plot([xpos - .1, xpos - .1],
[ypos, ypos - self._cond['n_lines'] + 1],
color=self._style.lc, zorder=PORDER_LINE)
self.ax.plot([xpos + .1, xpos + .1],
[ypos, ypos - self._cond['n_lines'] + 1],
color=self._style.lc, zorder=PORDER_LINE)
[文档]
def draw(self, filename=None, verbose=False):
self._draw_regs()
self._draw_ops(verbose)
_xl = - self._style.margin[0]
_xr = self._cond['xmax'] + self._style.margin[1]
_yb = - self._cond['ymax'] - self._style.margin[2] + 1 - 0.5
_yt = self._style.margin[3] + 0.5
self.ax.set_xlim(_xl, _xr)
self.ax.set_ylim(_yb, _yt)
# update figure size
fig_w = _xr - _xl
fig_h = _yt - _yb
if self._style.figwidth < 0.0:
self._style.figwidth = fig_w * self._scale * self._style.fs / 72 / WID
self.figure.set_size_inches(
self._style.figwidth, self._style.figwidth * fig_h / fig_w)
if filename:
self.figure.savefig(filename, dpi=self._style.dpi,
bbox_inches='tight')
plt.close(self.figure)
if self.return_fig:
if get_backend() in ['module://ipykernel.pylab.backend_inline',
'nbAgg']:
plt.close(self.figure)
return self.figure
def _draw_regs(self):
len_longest_label = 0
# quantum register
for ii, reg in enumerate(self._qreg):
if len(self._qreg) > 1:
if self.layout is None:
label = '${{{name}}}_{{{index}}}$'.format(name='q',
index=reg)
else:
label = '${{{name}}}_{{{index}}} \\mapsto {{{physical}}}$'.format(
name=self.layout[reg.index].register.name,
index=self.layout[reg.index].index,
physical=reg.index)
else:
label = '${{{name}}}_{{{index}}}$'.format(name='q', index=reg)
if len(label) > len_longest_label:
len_longest_label = len(label)
pos = -ii
self._qreg_dict[reg] = {
'y': pos,
'label': label,
'index': reg,
'group': my_qubit
# 'group': reg.register
}
self._cond['n_lines'] += 1
# classical register
if self._creg:
n_creg = self._creg.copy()
n_creg.pop(0)
idx = 0
y_off = -len(self._qreg)
for ii, (reg, nreg) in enumerate(itertools.zip_longest(
self._creg, n_creg)):
pos = y_off - idx
if self._style.bundle:
label = '${}$'.format('c')
self._creg_dict[ii] = {
'y': pos,
'label': label,
'index': reg,
'group': my_cbit
# 'group': reg.register
}
if (reg != nreg and nreg):
continue
else:
label = '${}_{{{}}}$'.format('c', reg)
self._creg_dict[ii] = {
'y': pos,
'label': label,
'index': reg,
'group': my_cbit
# 'group': reg.register
}
if len(label) > len_longest_label:
len_longest_label = len(label)
self._cond['n_lines'] += 1
idx += 1
# 7 is the length of the smallest possible label
self.x_offset = -.5 + 0.18 * (len_longest_label - 7)
def _draw_regs_sub(self, n_fold, feedline_l=False, feedline_r=False):
if n_fold < len(self.layer_offset_recode):
#self._cond['xmax'] = self.fold + self.x_offset + 1 - 0.1 + self.layer_offset_recode[n_fold] + 1.5
self._cond['xmax'] = 30.5
# quantum register
for qreg in self._qreg_dict.values():
if n_fold == 0:
label = qreg['label']
else:
label = qreg['label']
y = qreg['y'] - n_fold * (self._cond['n_lines'] + 1)
self.ax.text(self.x_offset - 0.2, y, label, ha='right', va='center',
fontsize=1.25 * self._style.fs,
color=self._style.tc,
clip_on=True,
zorder=PORDER_TEXT)
self._line([self.x_offset + 0.2, y], [self._cond['xmax'], y],
zorder=PORDER_REGLINE)
self._line([self.x_offset + 1.6, y], [self._cond['xmax'] + 1, y],
zorder=PORDER_REGLINE)
# classical register
this_creg_dict = {}
for creg in self._creg_dict.values():
if n_fold == 0:
label = creg['label']
else:
label = creg['label']
y = creg['y'] - n_fold * (self._cond['n_lines'] + 1)
if y not in this_creg_dict.keys():
this_creg_dict[y] = {'val': 1, 'label': label}
else:
this_creg_dict[y]['val'] += 1
for y, this_creg in this_creg_dict.items():
# bundle
if this_creg['val'] > 1:
self.ax.plot([self.x_offset + 0.4, self.x_offset + 0.5], [y - .1, y + .1],
color=self._style.cc,
zorder=PORDER_LINE)
'''
self.ax.text(self.x_offset + 1.0, y + .1, str(this_creg['val']), ha='left',
va='bottom',
fontsize=0.8 * self._style.fs,
color=self._style.tc,
clip_on=True,
zorder=PORDER_TEXT)
'''
self.ax.text(self.x_offset + 0.4, y + .1, str(this_creg['val']), ha='left',
va='bottom',
fontsize=0.8 * self._style.fs,
color=self._style.tc,
clip_on=True,
zorder=PORDER_TEXT)
self.ax.text(self.x_offset - 0.2, y, this_creg['label'], ha='right', va='center',
fontsize=1.5 * self._style.fs,
color=self._style.tc,
clip_on=True,
zorder=PORDER_TEXT)
self._line([self.x_offset + 0.2, y], [self._cond['xmax'], y], lc=self._style.cc,
ls=self._style.cline, zorder=PORDER_REGLINE)
self._line([self.x_offset + 1.5, y], [self._cond['xmax'] + 2, y], lc=self._style.cc,
ls=self._style.cline, zorder=PORDER_REGLINE)
# lf line
if feedline_r:
#self._linefeed_mark((self.fold + self.x_offset + 1 - 0.1 + self.layer_offset_recode[n_fold],
# - n_fold * (self._cond['n_lines'] + 1)))
self._linefeed_mark((self._cond['xmax'],
- n_fold * (self._cond['n_lines'] + 1)))
if feedline_l:
self._linefeed_mark((self.x_offset + 0.3,
- n_fold * (self._cond['n_lines'] + 1)))
def _rzz(self, qxy, param, qreg_b, qreg_t):
color = self._style.dispcol['multi']
self._ctrl_qubit(qxy[0], fc=color, ec=color)
self._ctrl_qubit(qxy[1], fc=color, ec=color)
self._sidetext(qreg_b, text='zz({})'.format(param))
# add qubit-qubit wiring
self._line(qreg_b, qreg_t, lc=color)
def _cu1(self, qxy, param, qreg_b, qreg_t):
color = self._style.dispcol['multi']
self._ctrl_qubit(qxy[0], fc=color, ec=color)
self._ctrl_qubit(qxy[1], fc=color, ec=color)
self._sidetext(qreg_b, text='U1 ({})'.format(param))
# add qubit-qubit wiring
self._line(qreg_b, qreg_t, lc=color)
def _cnot(self, q_xy, qreg_b, qreg_t, num_ctrl_qubits=1):
if self._style.dispcol['CNOT'] != '#ffffff':
add_width = self._style.colored_add_width
else:
add_width = None
# if 0 == num_ctrl_qubits:
# self.set_multi_ctrl_bits(1, num_ctrl_qubits, q_xy, 'CNOT')
# else:
# self.set_multi_ctrl_bits((2**num_ctrl_qubits) - 1, num_ctrl_qubits, q_xy, 'CNOT')
self.set_multi_ctrl_bits(
(2**num_ctrl_qubits) - 1, num_ctrl_qubits, q_xy, 'CNOT')
if self._style.name != 'Q1':
self._tgt_qubit(q_xy[num_ctrl_qubits], fc=self._style.dispcol['CNOT'],
ec=self._style.dispcol['CNOT'],
ac=self._style.dispcol['target'],
add_width=add_width)
else:
self._tgt_qubit(q_xy[num_ctrl_qubits], fc=self._style.dispcol['target'],
ec=self._style.dispcol['CNOT'],
ac=self._style.dispcol['CNOT'],
add_width=add_width)
# add qubit-qubit wiring
self._line(qreg_b, qreg_t, lc=self._style.dispcol['CNOT'])
def _cz(self, q_xy, qreg_b, qreg_t):
disp = 'CZ'
if self._style.name != 'Q1':
color = self._style.dispcol['CZ']
self._ctrl_qubit(q_xy[0], fc=color, ec=color)
self._gate(q_xy[1], wide=False, text=disp, fc=color)
else:
self._ctrl_qubit(q_xy[0])
self._gate(q_xy[1], wide=False, text=disp, fc=color)
# add qubit-qubit wiring
if self._style.name != 'Q1':
self._line(qreg_b, qreg_t, lc=color)
else:
self._line(qreg_b, qreg_t, zorder=PORDER_LINE + 1)
def _draw_ops(self, verbose=False):
_wide_gate = [GateType.RX_GATE, GateType.RY_GATE, GateType.RZ_GATE, GateType.U1_GATE, GateType.U2_GATE,
GateType.U3_GATE, GateType.U4_GATE, GateType.CU_GATE, GateType.CPHASE_GATE, GateType.ISWAP_THETA_GATE,
GateType.U3_GATE, GateType.U4_GATE, GateType.CU_GATE, GateType.CPHASE_GATE, GateType.ISWAP_THETA_GATE,
GateType.RXX_GATE, GateType.RYY_GATE, GateType.RZZ_GATE, GateType.RZX_GATE, GateType.RPHI_GATE]
_barriers = {'coord': [], 'group': []}
#
# generate coordinate manager
#
q_anchors = {}
for key, qreg in self._qreg_dict.items():
key = qreg['index']
q_anchors[key] = Anchor(reg_num=self._cond['n_lines'],
yind=qreg['y'],
fold=self.fold)
c_anchors = {}
for key, creg in self._creg_dict.items():
c_anchors[key] = Anchor(reg_num=self._cond['n_lines'],
yind=creg['y'],
fold=self.fold)
#
# draw gates
#
n_fold = 0
my_offset = 0.0
prev_anc = -1
for layer in self._ops:
layer_width = 1
my_offset_tmp = 0.0
occupied_qubits = []
for op in layer:
# If one of the standard wide gates
if op.m_gate_type in _wide_gate:
if layer_width < 2:
layer_width = 2
if int(op.m_gate_type) >= 0:
param = self.param_parse(op.m_params)
if '$\\pi$' in param:
pi_count = param.count('pi')
len_param = len(param) - (4 * pi_count)
else:
len_param = len(param)
if len_param > len(op.m_name):
box_width = math.floor(len(param) / 10) + 0.25
#box_width = math.ceil(len(param) / 10)
if op.m_name == 'unitary':
box_width = 2
# If more than 4 characters min width is 2
if box_width <= 1:
box_width = 2
if layer_width < box_width:
if box_width > 2:
layer_width = box_width
else:
layer_width = 2
continue
# If custom ControlledGate
elif op.m_gate_type in [GateType.RPHI_GATE, GateType.CPHASE_GATE]:
# if op.type == 'op' and hasattr(op.op, 'params'):
if int(op.m_gate_type) >= 0 and len(op.m_params) > 0:
param = self.param_parse(op.m_params)
if '$\\pi$' in param:
pi_count = param.count('pi')
len_param = len(param) - (4 * pi_count)
else:
len_param = len(param)
if len_param > len(op.m_name):
box_width = math.floor(len_param / 5.5)
layer_width = box_width
continue
# if custom gate with a longer than standard name determine
# width
'''
elif op.m_gate_type not in [34, 26, -1, -2] and len(op.m_name) >= 4:
box_width = math.ceil(len(op.m_name) / 6)
# handle params/subtext longer than op names
if op.type == 'op' and hasattr(op.op, 'params'):
param = self.param_parse(op.op.params)
if '$\\pi$' in param:
pi_count = param.count('pi')
len_param = len(param) - (4 * pi_count)
else:
len_param = len(param)
if len_param > len(op.m_name):
box_width = math.floor(len(param) / 8)
# If more than 4 characters min width is 2
if box_width <= 1:
box_width = 2
if layer_width < box_width:
if box_width > 2:
layer_width = box_width * 2
else:
layer_width = 2
continue
# If more than 4 characters min width is 2
layer_width = math.ceil(box_width * WID * 2.5)
'''
this_anc = prev_anc + 1
cur_layer_max_x_pos = 0.0
for op in layer:
_iswide = op.m_gate_type in _wide_gate
# if op.m_gate_type not in [34, 26, -1, -2]:
# _iswide = True
# get qreg index
q_idxs = []
for qarg in (op.m_control_qubits.to_list()):
for index, reg in self._qreg_dict.items():
qubit_index = qarg.get_phy_addr()
if (reg['index'] == qubit_index):
q_idxs.append(qubit_index)
break
for qarg in op.m_target_qubits.to_list():
for index, reg in self._qreg_dict.items():
qubit_index = qarg.get_phy_addr()
if (reg['index'] == qubit_index):
q_idxs.append(qubit_index)
break
# get creg index
c_idxs = []
for carg in op.m_cbits:
for index, reg in self._creg_dict.items():
if (reg['index'] == carg):
c_idxs.append(index)
break
# Only add the gate to the anchors if it is going to be plotted.
# This prevents additional blank wires at the end of the line if
# the last instruction is a barrier type
if self.plot_barriers or \
op.m_gate_type not in [GateType.BARRIER_GATE]:
for ii in q_idxs:
q_anchors[ii].set_index(this_anc, layer_width)
# append new occupied-qubit
list = q_idxs
lmin = min(list)
lmax = max(list) + 1
if op.m_node_type == NodeType.MEASURE_GATE:
lmax = len(q_anchors)
if op.m_gate_type in [GateType.ORACLE_GATE, GateType.TWO_QUBIT_GATE]:
layer_width = 2
for hh in range(lmin, lmax):
if hh in occupied_qubits:
my_offset_tmp += 0.9*layer_width
my_offset += my_offset_tmp
break
for q in range(lmin, lmax):
occupied_qubits += [q]
# if op.m_node_type == NodeType.MEASURE_GATE:
# lmax = len(q_anchors)
# for q in range(lmin,lmax):
# occupied_qubits += [q]
# for ii in q_idxs:
# if q_anchors[ii].b_fold:
# my_offset_tmp = 0.0
# self.layer_offset = 0.0
# q_anchors[ii].b_fold = False
# break
# qreg coordinate
q_xy = [q_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset + my_offset_tmp, self.layer_offset, q_anchors[ii].last_h_pos)
for ii in q_idxs]
if len(q_xy) > 0:
x0, y0 = q_xy[0]
if x0 > cur_layer_max_x_pos:
cur_layer_max_x_pos = x0
# for ii in range(0, len(q_anchors)):
# q_anchors[ii].last_h_pos = x0
# for index, reg in self._creg_dict.items():
# c_anchors[index].update_fold_info(this_anc, layer_width, self.x_offset + my_offset_tmp, self.layer_offset)
# creg coordinate
c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset + my_offset_tmp, self.layer_offset, c_anchors[ii].last_h_pos)
for ii in c_idxs]
# if len(c_xy) > 0:
# x0, y0 = c_xy[0]
# for ii in range(0, len(c_anchors)):
# c_anchors[ii].last_h_pos = x0
# tmp_b_first_time = True
# for ii in q_anchors:
# if q_anchors[ii].b_fold:
# if tmp_b_first_time:
# tmp_b_first_time = False
# self.layer_offset_recode.append(self.layer_offset)
# self.layer_offset = 0.0
# q_anchors[ii].b_fold = False
# bottom and top point of qreg
qreg_b = min(q_xy, key=lambda xy: xy[1])
qreg_t = max(q_xy, key=lambda xy: xy[1])
# update index based on the value from plotting
this_anc = q_anchors[q_idxs[0]].gate_anchor
# if verbose:
# print(op)
if int(op.m_gate_type) >= 0 and len(op.m_params) > 0:
param = self.param_parse(op.m_params)
else:
param = None
# conditional gate
'''
if op.condition:
c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset) for
ii in self._creg_dict]
mask = 0
for index, cbit in enumerate(self._creg):
if cbit.register == op.condition[0]:
mask |= (1 << index)
val = op.condition[1]
# cbit list to consider
fmt_c = '{{:0{}b}}'.format(len(c_xy))
cmask = list(fmt_c.format(mask))[::-1]
# value
fmt_v = '{{:0{}b}}'.format(cmask.count('1'))
vlist = list(fmt_v.format(val))[::-1]
# plot conditionals
v_ind = 0
xy_plot = []
for xy, m in zip(c_xy, cmask):
if m == '1':
if xy not in xy_plot:
if vlist[v_ind] == '1' or self._style.bundle:
self._conds(xy, istrue=True)
else:
self._conds(xy, istrue=False)
xy_plot.append(xy)
v_ind += 1
creg_b = sorted(xy_plot, key=lambda xy: xy[1])[0]
self._subtext(creg_b, hex(val))
self._line(qreg_t, creg_b, lc=self._style.cc,
ls=self._style.cline)
'''
#
# draw special gates
#
if op.m_node_type == NodeType.MEASURE_GATE:
vv = self._creg_dict[c_idxs[0]]['index']
self._measure(q_xy[0], c_xy[0], vv)
#this_anc = this_anc + 1
elif op.m_node_type == NodeType.RESET_NODE:
self._gate(q_xy[0], text='RESET')
elif op.m_gate_type in [GateType.BARRIER_GATE]:
_barriers = {'coord': [], 'group': []}
for index, qbit in enumerate(q_idxs):
q_group = self._qreg_dict[qbit]['group']
if q_group not in _barriers['group']:
_barriers['group'].append(q_group)
_barriers['coord'].append(q_xy[index])
if self.plot_barriers:
self._barrier(_barriers, this_anc)
elif len(op.m_control_qubits.to_list()) > 0:
disp = op.m_name
num_ctrl_qubits = len(op.m_control_qubits.to_list())
num_qargs = len(q_xy) - num_ctrl_qubits
# set the ctrl qbits to open or closed
color_str = self.get_op_color(op.m_name)
self.set_multi_ctrl_bits(
(2**num_ctrl_qubits) - 1, num_ctrl_qubits, q_xy, color_str)
# add qubit-qubit wiring
self._line(qreg_b, qreg_t,
lc=self._style.dispcol[color_str])
if num_qargs == 1:
if param:
self._gate(q_xy[num_ctrl_qubits], wide=_iswide,
text=disp,
fc=self._style.dispcol[color_str],
subtext='{}'.format(param))
else:
fcx = op.m_name if op.m_name in self._style.dispcol else 'multi'
self._gate(q_xy[num_ctrl_qubits], wide=_iswide, text=disp,
fc=self._style.dispcol[fcx])
elif num_qargs == 2:
# CNOT
if op.m_gate_type == GateType.CNOT_GATE:
#self._cnot(q_xy, qreg_b, qreg_t, num_ctrl_qubits+1)
color = self._style.dispcol['CNOT']
if self._style.name != 'Q1':
self._line(qreg_b, qreg_t,
lc=color)
else:
self._line(qreg_b, qreg_t,
zorder=PORDER_LINE + 1)
cx_xy = q_xy[num_ctrl_qubits:]
self._cnot(cx_xy, qreg_b, qreg_t)
# cz for latexmode
elif op.m_gate_type == GateType.CZ_GATE:
disp = op.m_name
if self._style.name != 'Q1':
color = self._style.dispcol['CZ']
self._ctrl_qubit(q_xy[num_ctrl_qubits],
fc=color,
ec=color)
self._ctrl_qubit(q_xy[num_ctrl_qubits + 1],
fc=color,
ec=color)
else:
self._ctrl_qubit(q_xy[num_ctrl_qubits])
self._ctrl_qubit(q_xy[num_ctrl_qubits + 1])
# add qubit-qubit wiring
if self._style.name != 'Q1':
self._line(qreg_b, qreg_t,
lc=color)
else:
self._line(qreg_b, qreg_t,
zorder=PORDER_LINE + 1)
cz_xy = q_xy[num_ctrl_qubits:]
self._cz(cz_xy, qreg_b, qreg_t)
# control gate
elif op.m_gate_type in [GateType.CU_GATE, GateType.CPHASE_GATE]:
disp = op.m_name
color = None
if self._style.name != 'Q1':
if op.m_name == 'CPHASE':
color = self._style.dispcol['CPHASE']
else:
color = self._style.dispcol['U4']
self._ctrl_qubit(
q_xy[num_ctrl_qubits], fc=color, ec=color)
if param:
self._gate(q_xy[num_ctrl_qubits + 1], wide=_iswide,
text=disp,
fc=color,
subtext='{}'.format(param))
else:
self._gate(q_xy[num_ctrl_qubits + 1], wide=_iswide, text=disp,
fc=color)
# add qubit-qubit wiring
self._line(qreg_b, qreg_t, lc=color)
# swap gate
elif op.m_gate_type == GateType.SWAP_GATE:
self._swap(q_xy[num_ctrl_qubits],
self._style.dispcol['SWAP'])
self._swap(q_xy[num_ctrl_qubits + 1],
self._style.dispcol['SWAP'])
# add qubit-qubit wiring
self._line(qreg_b, qreg_t,
lc=self._style.dispcol['SWAP'])
# iswap gate
elif op.m_gate_type in [GateType.ISWAP_THETA_GATE, GateType.ISWAP_GATE, GateType.SQISWAP_GATE]:
self._swap_gate(
q_xy, op.m_gate_type, param, op.m_is_dagger, ctrl_qubits=num_ctrl_qubits)
# add qubit-qubit wiring
self._line(qreg_b, qreg_t,
lc=self._style.dispcol['ISWAP'])
# self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide,
# fc=self._style.dispcol[op.m_name],
# text=op.m_name)
# Custom gate
elif op.m_gate_type in [GateType.RXX_GATE, GateType.RYY_GATE, GateType.RZZ_GATE, GateType.RZX_GATE]:
self._custom_multiqubit_gate(q_xy, c_xy, wide=True,
text=op.m_gate_type, subtext=f"{param}")
else:
self._custom_multiqubit_gate(q_xy, c_xy, wide=True,
text='Unitary')
else:
self._custom_multiqubit_gate(
q_xy[num_ctrl_qubits:], wide=True, fc=self._style.dispcol['Unitary'],
text=disp)
#
# draw single qubit gates
#
elif len(q_xy) == 1:
disp = op.m_name
if param:
self._gate(q_xy[0], wide=_iswide, text=disp,
subtext=str(param))
else:
self._gate(q_xy[0], wide=_iswide, text=disp)
#
# draw multi-qubit gates (n=2)
#
elif len(q_xy) == 2:
# CNOT
if op.m_gate_type == GateType.CNOT_GATE:
self._cnot(q_xy, qreg_b, qreg_t, 1)
# cz for latexmode
elif op.m_gate_type == GateType.CZ_GATE:
self._cz(q_xy, qreg_b, qreg_t)
# control gate
elif op.m_gate_type in [GateType.CU_GATE, GateType.CPHASE_GATE]:
disp = op.m_name
color = None
if self._style.name != 'Q1':
if op.m_name == 'CPHASE':
color = self._style.dispcol['CPHASE']
else:
color = self._style.dispcol['U4']
self._ctrl_qubit(q_xy[0], fc=color, ec=color)
if param:
self._gate(q_xy[1], wide=_iswide,
text=disp,
fc=color,
subtext='{}'.format(param))
else:
self._gate(q_xy[1], wide=_iswide, text=disp,
fc=color)
# add qubit-qubit wiring
self._line(qreg_b, qreg_t, lc=color)
# swap gate
elif op.m_gate_type == GateType.SWAP_GATE:
self._swap(q_xy[0], self._style.dispcol['SWAP'])
self._swap(q_xy[1], self._style.dispcol['SWAP'])
# add qubit-qubit wiring
self._line(qreg_b, qreg_t,
lc=self._style.dispcol['SWAP'])
# iswap gate
elif op.m_gate_type in [GateType.ISWAP_THETA_GATE, GateType.ISWAP_GATE, GateType.SQISWAP_GATE]:
self._swap_gate(q_xy, op.m_gate_type,
param, op.m_is_dagger)
# add qubit-qubit wiring
self._line(qreg_b, qreg_t,
lc=self._style.dispcol['ISWAP'])
# Custom gate
elif op.m_gate_type in [GateType.RXX_GATE, GateType.RYY_GATE, GateType.RZZ_GATE, GateType.RZX_GATE]:
disp = op.m_name
self._custom_multiqubit_gate(q_xy, c_xy, wide=True,
text=disp, subtext=str(param))
else:
self._custom_multiqubit_gate(q_xy, c_xy, wide=True,
text='Unitary')
#
# draw multi-qubit gates (n=3)
#
elif op.m_gate_type == GateType.ORACLE_GATE:
self._custom_multiqubit_gate(q_xy, c_xy, wide=True,
text=op.m_name)
elif len(q_xy) in range(3, 6):
# Unitary
self._custom_multiqubit_gate(q_xy, c_xy, wide=True,
text='Unitary')
'''
if op.m_name == 'cswap':
self._ctrl_qubit(q_xy[0],
fc=self._style.dispcol['multi'],
ec=self._style.dispcol['multi'])
self._swap(q_xy[1], self._style.dispcol['multi'])
self._swap(q_xy[2], self._style.dispcol['multi'])
# add qubit-qubit wiring
self._line(qreg_b, qreg_t, lc=self._style.dispcol['multi'])
# ccx gate
elif op.m_name == 'ccx' or op.m_name == 'c3x' or op.m_name == 'c4x':
num_ctrl_qubits = op.op.num_ctrl_qubits
# set the ctrl qbits to open or closed
self.set_multi_ctrl_bits(op.op.ctrl_state, num_ctrl_qubits, q_xy, 'multi')
if self._style.name != 'Q1':
self._tgt_qubit(q_xy[num_ctrl_qubits], fc=self._style.dispcol['multi'],
ec=self._style.dispcol['multi'],
ac=self._style.dispcol['target'])
else:
self._tgt_qubit(q_xy[num_ctrl_qubits], fc=self._style.dispcol['target'],
ec=self._style.dispcol['multi'],
ac=self._style.dispcol['multi'])
# add qubit-qubit wiring
self._line(qreg_b, qreg_t, lc=self._style.dispcol['multi'])
# custom gate
else:
self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide,
text=getattr(op.op, 'label', None) or op.m_name)
'''
# draw custom multi-qubit gate
elif len(q_xy) > 5:
self._custom_multiqubit_gate(q_xy, c_xy, wide=True,
text='Unitary')
else:
print('Invalid gate %s', op.m_name)
# layer end
tmp_b_first_time = True
cur_fold = 0
cur_fold_cnt = 0
bb_fold = False
for ii in q_anchors:
if q_anchors[ii].b_fold:
if tmp_b_first_time:
tmp_b_first_time = False
self.layer_offset_recode.append(self.layer_offset)
self.layer_offset = 0.0
n_fold += 1
cur_fold, cur_fold_cnt = q_anchors[ii].get_fold_info()
bb_fold = True
q_anchors[ii].b_fold = False
if bb_fold:
for index, reg in self._qreg_dict.items():
q_anchors[index].set_fold_info(cur_fold, cur_fold_cnt)
for index, reg in self._creg_dict.items():
c_anchors[index].set_fold_info(cur_fold, cur_fold_cnt)
c_anchors[index].b_fold = False
# c_anchors[index].update_fold_info(this_anc, layer_width, self.x_offset + my_offset_tmp, self.layer_offset)
self.layer_offset += my_offset_tmp
# for ii in range(0, len(q_anchors)):
for ii in (q_anchors):
q_anchors[ii].last_h_pos = cur_layer_max_x_pos
# for ii in range(0, len(c_anchors)):
for ii in (c_anchors):
c_anchors[ii].last_h_pos = cur_layer_max_x_pos
# layer end
# tmp_b_first_time = True
# for ii in q_anchors:
# if q_anchors[ii].b_fold:
# # my_offset_tmp = 0.0
# if tmp_b_first_time:
# tmp_b_first_time = False
# # self.layer_offset_recode.append(self.layer_offset)
# # self.layer_offset = 0.0
# q_anchors[ii].b_fold = False
# # break
# adjust the column if there have been barriers encountered, but not plotted
barrier_offset = 0
if not self.plot_barriers:
# only adjust if everything in the layer wasn't plotted
barrier_offset = -1 if all([op.m_gate_type in
[GateType.BARRIER_GATE]
for op in layer]) else 0
prev_anc = this_anc + layer_width + barrier_offset - 1
#
# adjust window size and draw horizontal lines
#
anchors = [q_anchors[ii].get_index() for ii in self._qreg_dict]
if anchors:
max_anc = max(anchors)
else:
max_anc = 0
# n_fold = max(0, max_anc - 1) // self.fold
# window size if max_anc > self.fold > 0:
if max_anc > 20 > 0:
self._cond['xmax'] = self.fold + 1 + self.x_offset + my_offset
#self._cond['xmax'] = 30.0
self._cond['ymax'] = (n_fold + 1) * (self._cond['n_lines'] + 1) - 1
else:
self._cond['xmax'] = max_anc + 1 + self.x_offset + my_offset
self._cond['ymax'] = self._cond['n_lines']
# add horizontal lines
for ii in range(n_fold + 1):
feedline_r = (n_fold > 0 and n_fold > ii)
feedline_l = (ii > 0)
self._draw_regs_sub(ii, feedline_l, feedline_r)
# draw gate number
if self._style.index:
for ii in range(max_anc):
if self.fold > 0:
x_coord = ii % self.fold + 1
y_coord = - (ii // self.fold) * \
(self._cond['n_lines'] + 1) + 0.7
else:
x_coord = ii + 1
y_coord = 0.7
self.ax.text(x_coord, y_coord, str(ii + 1), ha='center',
va='center', fontsize=self._style.sfs,
color=self._style.tc, clip_on=True,
zorder=PORDER_TEXT)
@staticmethod
[文档]
def param_parse(v):
# create an empty list to store the parameters in
param_parts = [None] * len(v)
for i, e in enumerate(v):
try:
param_parts[i] = pi_check(e, output='mpl', ndigits=3)
except TypeError:
param_parts[i] = str(e)
if param_parts[i].startswith('-'):
param_parts[i] = '$-$' + param_parts[i][1:]
param_parts = ', '.join(param_parts)
return param_parts
@staticmethod
@staticmethod
[文档]
def fraction(val, base=np.pi, n=100, tol=1e-5):
abs_val = abs(val)
for i in range(1, n):
for j in range(1, n):
if math.isclose(abs_val, i / j * base, rel_tol=tol):
if val < 0:
i *= -1
return fractions.Fraction(i, j)
return None