def _build_measure(self, op, col): """Build a meter and the lines to the creg""" if op.op.condition: raise exceptions.VisualizationError( "If controlled measures currently not supported.") wire1 = self.img_regs[op.qargs[0]] if self.cregbundle: wire2 = len(self.qubit_list) cregindex = self.img_regs[op.cargs[0]] - wire2 for creg_size in self.cregs.values(): if cregindex >= creg_size: cregindex -= creg_size wire2 += 1 else: break else: wire2 = self.img_regs[op.cargs[0]] self._latex[wire1][col] = "\\meter" if self.cregbundle: self._latex[wire2][col] = "\\dstick{_{_{%s}}} \\cw \\cwx[-%s]" % ( str(cregindex), str(wire2 - wire1), ) else: self._latex[wire2][col] = "\\control \\cw \\cwx[-" + str( wire2 - wire1) + "]"
def _get_qubit_index(self, qubit): """Get the index number for a quantum bit Args: qubit (tuple): The tuple of the bit of the form (register_name, bit_number) Returns: int: The index in the bit list Raises: VisualizationError: If the bit isn't found """ for i, bit in enumerate(self.qubit_list): if qubit == bit: qindex = i break else: raise exceptions.VisualizationError("unable to find bit for operation") return qindex
def circuit_drawer(circuit, scale=0.7, filename=None, style=None, output=None, interactive=False, line_length=None, plot_barriers=True, reverse_bits=False, justify=None, vertical_compression='medium', idle_wires=True, with_layout=True, fold=None, ax=None): """Draw a quantum circuit to different formats (set by output parameter): 0. text: ASCII art TextDrawing that can be printed in the console. 1. latex: high-quality images, but heavy external software dependencies 2. matplotlib: purely in Python with no external dependencies Args: circuit (QuantumCircuit): the quantum circuit to draw scale (float): scale of image to draw (shrink if < 1) filename (str): file path to save image to style (dict or str): dictionary of style or file name of style file. This option is only used by the `mpl`, `latex`, and `latex_source` output types. If a str is passed in that is the path to a json file which contains that will be open, parsed, and then used just as the input dict. output (str): Select the output method to use for drawing the circuit. Valid choices are `text`, `latex`, `latex_source`, `mpl`. By default the 'text' drawer is used unless a user config file has an alternative backend set as the default. If the output is passed in that backend will always be used. interactive (bool): when set true show the circuit in a new window (for `mpl` this depends on the matplotlib backend being used supporting this). Note when used with either the `text` or the `latex_source` output type this has no effect and will be silently ignored. line_length (int): Deprecated. See `fold`. reverse_bits (bool): When set to True reverse the bit order inside registers for the output visualization. plot_barriers (bool): Enable/disable drawing barriers in the output circuit. Defaults to True. justify (string): Options are `left`, `right` or `none`, if anything else is supplied it defaults to left justified. It refers to where gates should be placed in the output circuit if there is an option. `none` results in each gate being placed in its own column. Currently only supported by text drawer. vertical_compression (string): `high`, `medium` or `low`. It merges the lines generated by `text` so the drawing will take less vertical room. Default is `medium`. It is ignored if output is not `text`. idle_wires (bool): Include idle wires. Default is True. with_layout (bool): Include layout information, with labels on the physical layout. fold (int): Sets pagination. It can be disabled using -1. In `text`, sets the length of the lines. This useful when the drawing does not fit in the console. If None (default), it will try to guess the console width using `shutil.get_terminal_size()`. However, if running in jupyter, the default line length is set to 80 characters. In `mpl` is the amount of operations before folding. Default is 25. ax (matplotlib.axes.Axes): An optional Axes object to be used for the visualization output. If none is specified a new matplotlib Figure will be created and used. Additionally, if specified there will be no returned Figure since it is redundant. This is only used when the ``output`` kwarg is set to use the ``mpl`` backend. It will be silently ignored with all other outputs. Returns: PIL.Image: (output `latex`) an in-memory representation of the image of the circuit diagram. matplotlib.figure: (output `mpl`) a matplotlib figure object for the circuit diagram, if the ``ax`` kwarg is not set String: (output `latex_source`). The LaTeX source code. TextDrawing: (output `text`). A drawing that can be printed as ascii art Raises: VisualizationError: when an invalid output method is selected ImportError: when the output methods requieres non-installed libraries. .. _style-dict-doc: The style dict kwarg contains numerous options that define the style of the output circuit visualization. While the style dict is used by the `mpl`, `latex`, and `latex_source` outputs some options in that are only used by the `mpl` output. These options are defined below, if it is only used by the `mpl` output it is marked as such: textcolor (str): The color code to use for text. Defaults to `'#000000'` (`mpl` only) subtextcolor (str): The color code to use for subtext. Defaults to `'#000000'` (`mpl` only) linecolor (str): The color code to use for lines. Defaults to `'#000000'` (`mpl` only) creglinecolor (str): The color code to use for classical register lines. Defaults to `'#778899'`(`mpl` only) gatetextcolor (str): The color code to use for gate text. Defaults to `'#000000'` (`mpl` only) gatefacecolor (str): The color code to use for gates. Defaults to `'#ffffff'` (`mpl` only) barrierfacecolor (str): The color code to use for barriers. Defaults to `'#bdbdbd'` (`mpl` only) backgroundcolor (str): The color code to use for the background. Defaults to `'#ffffff'` (`mpl` only) fontsize (int): The font size to use for text. Defaults to 13 (`mpl` only) subfontsize (int): The font size to use for subtext. Defaults to 8 (`mpl` only) displaytext (dict): A dictionary of the text to use for each element type in the output visualization. The default values are: { 'id': 'id', 'u0': 'U_0', 'u1': 'U_1', 'u2': 'U_2', 'u3': 'U_3', 'x': 'X', 'y': 'Y', 'z': 'Z', 'h': 'H', 's': 'S', 'sdg': 'S^\\dagger', 't': 'T', 'tdg': 'T^\\dagger', 'rx': 'R_x', 'ry': 'R_y', 'rz': 'R_z', 'reset': '\\left|0\\right\\rangle' } You must specify all the necessary values if using this. There is no provision for passing an incomplete dict in. (`mpl` only) displaycolor (dict): The color codes to use for each circuit element. The default values are: { 'id': '#F0E442', 'u0': '#E7AB3B', 'u1': '#E7AB3B', 'u2': '#E7AB3B', 'u3': '#E7AB3B', 'x': '#58C698', 'y': '#58C698', 'z': '#58C698', 'h': '#70B7EB', 's': '#E0722D', 'sdg': '#E0722D', 't': '#E0722D', 'tdg': '#E0722D', 'rx': '#ffffff', 'ry': '#ffffff', 'rz': '#ffffff', 'reset': '#D188B4', 'target': '#70B7EB', 'meas': '#D188B4' } Also, just like `displaytext` there is no provision for an incomplete dict passed in. (`mpl` only) latexdrawerstyle (bool): When set to True enable latex mode which will draw gates like the `latex` output modes. (`mpl` only) usepiformat (bool): When set to True use radians for output (`mpl` only) fold (int): The number of circuit elements to fold the circuit at. Defaults to 20 (`mpl` only) cregbundle (bool): If set True bundle classical registers (`mpl` only) showindex (bool): If set True draw an index. (`mpl` only) compress (bool): If set True draw a compressed circuit (`mpl` only) figwidth (int): The maximum width (in inches) for the output figure. (`mpl` only) dpi (int): The DPI to use for the output image. Defaults to 150 (`mpl` only) margin (list): `mpl` only creglinestyle (str): The style of line to use for classical registers. Choices are `'solid'`, `'doublet'`, or any valid matplotlib `linestyle` kwarg value. Defaults to `doublet`(`mpl` only) """ image = None config = user_config.get_config() # Get default from config file else use text default_output = 'text' if config: default_output = config.get('circuit_drawer', 'text') if default_output == 'auto': if _matplotlib.HAS_MATPLOTLIB: default_output = 'mpl' else: default_output = 'text' if output is None: output = default_output if output == 'text': return _text_circuit_drawer(circuit, filename=filename, line_length=line_length, reverse_bits=reverse_bits, plot_barriers=plot_barriers, justify=justify, vertical_compression=vertical_compression, idle_wires=idle_wires, with_layout=with_layout, fold=fold) elif output == 'latex': image = _latex_circuit_drawer(circuit, scale=scale, filename=filename, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout) elif output == 'latex_source': return _generate_latex_source(circuit, filename=filename, scale=scale, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout) elif output == 'mpl': image = _matplotlib_circuit_drawer(circuit, scale=scale, filename=filename, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, fold=fold, ax=ax) else: raise exceptions.VisualizationError( 'Invalid output type %s selected. The only valid choices ' 'are latex, latex_source, text, and mpl' % output) if image and interactive: image.show() return image
def _build_latex_array(self, aliases=None): """Returns an array of strings containing \\LaTeX for this circuit. If aliases is not None, aliases contains a dict mapping the current qubits in the circuit to new qubit names. We will deduce the register names and sizes from aliases. """ # Rename qregs if necessary if aliases: qregdata = {} for q in aliases.values(): if q[0] not in qregdata: qregdata[q[0]] = q[1] + 1 elif qregdata[q[0]] < q[1] + 1: qregdata[q[0]] = q[1] + 1 else: qregdata = self.qregs column = 1 for layer in self.ops: num_cols_used = 1 for op in layer: if op.condition: mask = self._get_mask(op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg.register pos_2 = self.img_regs[cl_reg] if_value = format(op.condition[1], 'b').zfill(self.cregs[if_reg])[::-1] if op.name not in [ 'measure', 'barrier', 'snapshot', 'load', 'save', 'noise' ]: nm = generate_latex_label(op.name).replace(" ", "\\,") qarglist = op.qargs if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) if len(qarglist) == 1: pos_1 = self.img_regs[qarglist[0]] if op.condition: mask = self._get_mask(op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg.register pos_2 = self.img_regs[cl_reg] if nm == "x": self._latex[pos_1][column] = "\\gate{X}" elif nm == "y": self._latex[pos_1][column] = "\\gate{Y}" elif nm == "z": self._latex[pos_1][column] = "\\gate{Z}" elif nm == "h": self._latex[pos_1][column] = "\\gate{H}" elif nm == "s": self._latex[pos_1][column] = "\\gate{S}" elif nm == "sdg": self._latex[pos_1][column] = "\\gate{S^\\dag}" elif nm == "t": self._latex[pos_1][column] = "\\gate{T}" elif nm == "tdg": self._latex[pos_1][column] = "\\gate{T^\\dag}" elif nm == "u0": self._latex[pos_1][ column] = "\\gate{U_0(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "u1": self._latex[pos_1][ column] = "\\gate{U_1(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "u2": self._latex[pos_1][column] = \ "\\gate{U_2\\left(%s,%s\\right)}" % ( pi_check(op.op.params[0], output='latex'), pi_check(op.op.params[1], output='latex')) elif nm == "u3": self._latex[pos_1][column] = ( "\\gate{U_3(%s,%s,%s)}" % (pi_check(op.op.params[0], output='latex'), pi_check(op.op.params[1], output='latex'), pi_check(op.op.params[2], output='latex'))) elif nm == "rx": self._latex[pos_1][ column] = "\\gate{R_x(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "ry": self._latex[pos_1][ column] = "\\gate{R_y(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "rz": self._latex[pos_1][ column] = "\\gate{R_z(%s)}" % (pi_check( op.op.params[0], output='latex')) else: self._latex[pos_1][column] = ("\\gate{%s}" % nm) gap = pos_2 - pos_1 for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_2 + i][column] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_2 + i][column] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: if nm == "x": self._latex[pos_1][column] = "\\gate{X}" elif nm == "y": self._latex[pos_1][column] = "\\gate{Y}" elif nm == "z": self._latex[pos_1][column] = "\\gate{Z}" elif nm == "h": self._latex[pos_1][column] = "\\gate{H}" elif nm == "s": self._latex[pos_1][column] = "\\gate{S}" elif nm == "sdg": self._latex[pos_1][column] = "\\gate{S^\\dag}" elif nm == "t": self._latex[pos_1][column] = "\\gate{T}" elif nm == "tdg": self._latex[pos_1][column] = "\\gate{T^\\dag}" elif nm == "u0": self._latex[pos_1][ column] = "\\gate{U_0(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "u1": self._latex[pos_1][ column] = "\\gate{U_1(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "u2": self._latex[pos_1][column] = \ "\\gate{U_2\\left(%s,%s\\right)}" % ( pi_check(op.op.params[0], output='latex'), pi_check(op.op.params[1], output='latex')) elif nm == "u3": self._latex[pos_1][column] = ( "\\gate{U_3(%s,%s,%s)}" % (pi_check(op.op.params[0], output='latex'), pi_check(op.op.params[1], output='latex'), pi_check(op.op.params[2], output='latex'))) elif nm == "rx": self._latex[pos_1][ column] = "\\gate{R_x(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "ry": self._latex[pos_1][ column] = "\\gate{R_y(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "rz": self._latex[pos_1][ column] = "\\gate{R_z(%s)}" % (pi_check( op.op.params[0], output='latex')) elif nm == "reset": self._latex[pos_1][column] = ( "\\push{\\rule{.6em}{0em}\\ket{0}\\" "rule{.2em}{0em}} \\qw") else: self._latex[pos_1][column] = ("\\gate{%s}" % nm) elif len(qarglist) == 2: pos_1 = self.img_regs[qarglist[0]] pos_2 = self.img_regs[qarglist[1]] if op.condition: pos_3 = self.img_regs[(if_reg, 0)] temp = [pos_1, pos_2, pos_3] temp.sort(key=int) bottom = temp[1] gap = pos_3 - bottom for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_3 + i][column] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_3 + i][column] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 if nm == "cx": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\targ" elif nm == "cz": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\control\\qw" elif nm == "cy": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\gate{Y}" elif nm == "ch": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\gate{H}" elif nm == "swap": self._latex[pos_1][column] = "\\qswap" self._latex[pos_2][column] = \ "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]" elif nm == "crz": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = \ "\\gate{R_z(%s)}" % (pi_check(op.op.params[0], output='latex')) elif nm == "cu1": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\control \\qw" self._latex[min(pos_1, pos_2)][column + 1] = \ "\\dstick{%s}\\qw" % (pi_check(op.op.params[0], output='latex')) self._latex[max(pos_1, pos_2)][column + 1] = "\\qw" # this is because this gate takes up 2 columns, # and we have just written to the next column num_cols_used = 2 elif nm == "cu3": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = \ "\\gate{U_3(%s,%s,%s)}" % \ (pi_check(op.op.params[0], output='latex'), pi_check(op.op.params[1], output='latex'), pi_check(op.op.params[2], output='latex')) elif nm == "rzz": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\control \\qw" # Based on the \cds command of the qcircuit package self._latex[min(pos_1, pos_2)][column + 1] = \ "*+<0em,0em>{\\hphantom{zz()}} \\POS [0,0].[%d,0]=" \ "\"e\",!C *{zz(%s)};\"e\"+ R \\qw" %\ (max(pos_1, pos_2), pi_check(op.op.params[0], output='latex')) self._latex[max(pos_1, pos_2)][column + 1] = "\\qw" num_cols_used = 2 else: temp = [pos_1, pos_2] temp.sort(key=int) if nm == "cx": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\targ" elif nm == "cz": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\control\\qw" elif nm == "cy": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\gate{Y}" elif nm == "ch": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\gate{H}" elif nm == "swap": self._latex[pos_1][column] = "\\qswap" self._latex[pos_2][column] = \ "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]" elif nm == "crz": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = \ "\\gate{R_z(%s)}" % (pi_check(op.op.params[0], output='latex')) elif nm == "cu1": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\control \\qw" self._latex[min(pos_1, pos_2)][column + 1] = \ "\\dstick{%s}\\qw" % (pi_check(op.op.params[0], output='latex')) self._latex[max(pos_1, pos_2)][column + 1] = "\\qw" num_cols_used = 2 elif nm == "cu3": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = \ ("\\gate{U_3(%s,%s,%s)}" % (pi_check(op.op.params[0], output='latex'), pi_check(op.op.params[1], output='latex'), pi_check(op.op.params[2], output='latex'))) elif nm == "rzz": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\control \\qw" # Based on the \cds command of the qcircuit package self._latex[min(pos_1, pos_2)][column + 1] = \ "*+<0em,0em>{\\hphantom{zz()}} \\POS [0,0].[%d,0]=" \ "\"e\",!C *{zz(%s)};\"e\"+ R \\qw" %\ (max(pos_1, pos_2), pi_check(op.op.params[0], output='latex')) self._latex[max(pos_1, pos_2)][column + 1] = "\\qw" num_cols_used = 2 else: start_pos = min([pos_1, pos_2]) stop_pos = max([pos_1, pos_2]) if stop_pos - start_pos >= 2: delta = stop_pos - start_pos self._latex[start_pos][column] = ( "\\multigate{%s}{%s}" % (delta, nm)) for i_pos in range(start_pos + 1, stop_pos + 1): self._latex[i_pos][column] = ( "\\ghost{%s}" % nm) else: self._latex[start_pos][column] = ( "\\multigate{1}{%s}" % nm) self._latex[stop_pos][column] = ( "\\ghost{%s}" % nm) elif len(qarglist) == 3: pos_1 = self.img_regs[qarglist[0]] pos_2 = self.img_regs[qarglist[1]] pos_3 = self.img_regs[qarglist[2]] if op.condition: pos_4 = self.img_regs[(if_reg, 0)] temp = [pos_1, pos_2, pos_3, pos_4] temp.sort(key=int) bottom = temp[2] gap = pos_4 - bottom for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_4 + i][column] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_4 + i][column] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 if nm == "ccx": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\ctrl{" + str( pos_3 - pos_2) + "}" self._latex[pos_3][column] = "\\targ" if nm == "cswap": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\qswap" self._latex[pos_3][column] = \ "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]" else: if nm == "ccx": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\ctrl{" + str( pos_3 - pos_2) + "}" self._latex[pos_3][column] = "\\targ" elif nm == "cswap": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\qswap" self._latex[pos_3][column] = \ "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]" else: start_pos = min([pos_1, pos_2, pos_3]) stop_pos = max([pos_1, pos_2, pos_3]) if stop_pos - start_pos >= 3: delta = stop_pos - start_pos self._latex[start_pos][column] = ( "\\multigate{%s}{%s}" % (delta, nm)) for i_pos in range(start_pos + 1, stop_pos + 1): self._latex[i_pos][column] = ( "\\ghost{%s}" % nm) else: self._latex[pos_1][column] = ( "\\multigate{2}{%s}" % nm) self._latex[pos_2][column] = ( "\\ghost{%s}" % nm) self._latex[pos_3][column] = ( "\\ghost{%s}" % nm) elif len(qarglist) > 3: nbits = len(qarglist) pos_array = [self.img_regs[qarglist[0]]] for i in range(1, nbits): pos_array.append(self.img_regs[qarglist[i]]) pos_start = min(pos_array) pos_stop = max(pos_array) self._latex[pos_start][column] = ( "\\multigate{%s}{%s}" % (nbits - 1, nm)) for pos in range(pos_start + 1, pos_stop + 1): self._latex[pos][column] = ("\\ghost{%s}" % nm) elif op.name == "measure": if (len(op.cargs) != 1 or len(op.qargs) != 1 or op.op.params): raise exceptions.VisualizationError( "bad operation record") if op.condition: raise exceptions.VisualizationError( "If controlled measures currently not supported.") if aliases: newq = aliases[(qname, qindex)] qname = newq[0] qindex = newq[1] pos_1 = self.img_regs[op.qargs[0]] pos_2 = self.img_regs[op.cargs[0]] try: self._latex[pos_1][column] = "\\meter" self._latex[pos_2][column] = \ "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]" except Exception as e: raise exceptions.VisualizationError( 'Error during Latex building: %s' % str(e)) elif op.name in [ 'barrier', 'snapshot', 'load', 'save', 'noise' ]: if self.plot_barriers: qarglist = op.qargs indexes = [self._get_qubit_index(x) for x in qarglist] indexes.sort() if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) first = last = indexes[0] for index in indexes[1:]: if index - 1 == last: last = index else: pos = self.img_regs[self.qubit_list[first]] self._latex[pos][ column - 1] += " \\barrier[0em]{" + str(last - first) + "}" self._latex[pos][column] = "\\qw" first = last = index pos = self.img_regs[self.qubit_list[first]] self._latex[pos][ column - 1] += " \\barrier[0em]{" + str(last - first) + "}" self._latex[pos][column] = "\\qw" else: raise exceptions.VisualizationError("bad node data") # increase the number of columns by the number of columns this layer used column += num_cols_used
def _draw_ops(self, verbose=False): _wide_gate = ['u2', 'u3', 'cu2', 'cu3', 'unitary', 'r'] _barriers = {'coord': [], 'group': []} # # generate coordinate manager # q_anchors = {} for key, qreg in self._qreg_dict.items(): 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 # prev_anc = -1 for layer in self._ops: layer_width = 1 for op in layer: if op.name in _wide_gate: 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) - (5 * pi_count) else: len_param = len(param) if len_param > len(op.name): box_width = round(len(param) / 10) # 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 if layer_width < 2: layer_width = 2 # if custom gate with a longer than standard name determine # width elif op.name not in ['barrier', 'snapshot', 'load', 'save', 'noise', 'cswap', 'swap', 'measure'] and len( op.name) >= 4: box_width = math.ceil(len(op.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) - (5 * pi_count) else: len_param = len(param) if len_param > len(op.name): box_width = round(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 for op in layer: _iswide = op.name in _wide_gate if op.name not in ['barrier', 'snapshot', 'load', 'save', 'noise', 'cswap', 'swap', 'measure', 'reset'] and len(op.name) >= 4: _iswide = True # get qreg index q_idxs = [] for qarg in op.qargs: for index, reg in self._qreg_dict.items(): if (reg['group'] == qarg.register and reg['index'] == qarg.index): q_idxs.append(index) break # get creg index c_idxs = [] for carg in op.cargs: for index, reg in self._creg_dict.items(): if (reg['group'] == carg.register and reg['index'] == carg.index): 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.name not in ['barrier', 'snapshot', 'load', 'save', 'noise']: for ii in q_idxs: q_anchors[ii].set_index(this_anc, layer_width) # qreg coordinate q_xy = [q_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset) for ii in q_idxs] # creg coordinate c_xy = [c_anchors[ii].plot_coord(this_anc, layer_width, self.x_offset) for ii in c_idxs] # 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 op.type == 'op' and hasattr(op.op, 'params'): param = self.param_parse(op.op.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.name == 'measure': vv = self._creg_dict[c_idxs[0]]['index'] self._measure(q_xy[0], c_xy[0], vv) elif op.name in ['barrier', 'snapshot', 'load', 'save', 'noise']: _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 op.name == 'initialize': vec = '[%s]' % param self._custom_multiqubit_gate(q_xy, wide=_iswide, text="|psi>", subtext=vec) elif op.name == 'unitary': # TODO(mtreinish): Look into adding the unitary to the # subtext self._custom_multiqubit_gate(q_xy, wide=_iswide, text="U") # # draw single qubit gates # elif len(q_xy) == 1: disp = op.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: # cx if op.name == 'cx': if self._style.dispcol['cx'] != '#ffffff': add_width = self._style.colored_add_width else: add_width = None self._ctrl_qubit(q_xy[0], fc=self._style.dispcol['cx'], ec=self._style.dispcol['cx']) if self._style.name != 'bw': self._tgt_qubit(q_xy[1], fc=self._style.dispcol['cx'], ec=self._style.dispcol['cx'], ac=self._style.dispcol['target'], add_width=add_width) else: self._tgt_qubit(q_xy[1], fc=self._style.dispcol['target'], ec=self._style.dispcol['cx'], ac=self._style.dispcol['cx'], add_width=add_width) # add qubit-qubit wiring self._line(qreg_b, qreg_t, lc=self._style.dispcol['cx']) # cz for latexmode elif op.name == 'cz': disp = op.name.replace('c', '') if self._style.name != 'bw': color = self._style.dispcol['multi'] self._ctrl_qubit(q_xy[0], fc=color, ec=color) else: self._ctrl_qubit(q_xy[0]) self._gate(q_xy[1], wide=_iswide, text=disp, fc=color) # add qubit-qubit wiring if self._style.name != 'bw': self._line(qreg_b, qreg_t, lc=self._style.dispcol['multi']) else: self._line(qreg_b, qreg_t, zorder=PORDER_LINE+1) # control gate elif op.name in ['cy', 'ch', 'cu3', 'cu1', 'crz']: disp = op.name.replace('c', '') color = None if self._style.name != 'bw': color = self._style.dispcol['multi'] 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) # rzz gate elif op.name == 'rzz': self._ctrl_qubit(q_xy[0]) self._ctrl_qubit(q_xy[1]) self._sidetext(qreg_b, text='zz({})'.format(param)) # add qubit-qubit wiring self._line(qreg_b, qreg_t) # swap gate elif op.name == 'swap': self._swap(q_xy[0]) self._swap(q_xy[1]) # add qubit-qubit wiring self._line(qreg_b, qreg_t, lc=self._style.dispcol['swap']) # Custom gate else: self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide, text=op.name) # # draw multi-qubit gates (n=3) # elif len(q_xy) == 3: # cswap gate if op.name == 'cswap': self._ctrl_qubit(q_xy[0], fc=self._style.dispcol['multi'], ec=self._style.dispcol['multi']) self._swap(q_xy[1]) self._swap(q_xy[2]) # add qubit-qubit wiring self._line(qreg_b, qreg_t, lc=self._style.dispcol['multi']) # ccx gate elif op.name == 'ccx': self._ctrl_qubit(q_xy[0], fc=self._style.dispcol['multi'], ec=self._style.dispcol['multi']) self._ctrl_qubit(q_xy[1], fc=self._style.dispcol['multi'], ec=self._style.dispcol['multi']) if self._style.name != 'bw': self._tgt_qubit(q_xy[2], fc=self._style.dispcol['multi'], ec=self._style.dispcol['multi'], ac=self._style.dispcol['target']) else: self._tgt_qubit(q_xy[2], 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=op.name) # draw custom multi-qubit gate elif len(q_xy) > 3: self._custom_multiqubit_gate(q_xy, c_xy, wide=_iswide, text=op.name) else: logger.critical('Invalid gate %s', op) raise exceptions.VisualizationError('invalid gate {}'.format(op)) # 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.name in ['barrier', 'snapshot', 'load', 'save', 'noise'] 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: self._cond['xmax'] = self.fold + 1 + self.x_offset self._cond['ymax'] = (n_fold + 1) * (self._cond['n_lines'] + 1) - 1 else: self._cond['xmax'] = max_anc + 1 + self.x_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)
def _build_latex_array(self, aliases=None): """Returns an array of strings containing \\LaTeX for this circuit. If aliases is not None, aliases contains a dict mapping the current qubits in the circuit to new qubit names. We will deduce the register names and sizes from aliases. """ # Rename qregs if necessary if aliases: qregdata = {} for q in aliases.values(): if q[0] not in qregdata: qregdata[q[0]] = q[1] + 1 elif qregdata[q[0]] < q[1] + 1: qregdata[q[0]] = q[1] + 1 else: qregdata = self.qregs for column, layer in enumerate(self.ops, 1): for op in layer: if op.condition: mask = self._get_mask(op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg[0] pos_2 = self.img_regs[cl_reg] if_value = format(op.condition[1], 'b').zfill(self.cregs[if_reg])[::-1] if op.name not in [ 'measure', 'barrier', 'snapshot', 'load', 'save', 'noise' ]: nm = op.name qarglist = op.qargs if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) if len(qarglist) == 1: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] if op.condition: mask = self._get_mask(op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg[0] pos_2 = self.img_regs[cl_reg] if nm == "x": self._latex[pos_1][column] = "\\gate{X}" elif nm == "y": self._latex[pos_1][column] = "\\gate{Y}" elif nm == "z": self._latex[pos_1][column] = "\\gate{Z}" elif nm == "h": self._latex[pos_1][column] = "\\gate{H}" elif nm == "s": self._latex[pos_1][column] = "\\gate{S}" elif nm == "sdg": self._latex[pos_1][column] = "\\gate{S^\\dag}" elif nm == "t": self._latex[pos_1][column] = "\\gate{T}" elif nm == "tdg": self._latex[pos_1][column] = "\\gate{T^\\dag}" elif nm == "u0": self._latex[pos_1][ column] = "\\gate{U_0(%s)}" % ( op.op.params[0]) elif nm == "u1": self._latex[pos_1][ column] = "\\gate{U_1(%s)}" % ( op.op.params[0]) elif nm == "u2": self._latex[pos_1][column] = \ "\\gate{U_2\\left(%s,%s\\right)}" % ( op.op.params[0], op.op.params[1]) elif nm == "u3": self._latex[pos_1][column] = ( "\\gate{U_3(%s,%s,%s)}" % (op.op.params[0], op.op.params[1], op.op.params[2])) elif nm == "rx": self._latex[pos_1][ column] = "\\gate{R_x(%s)}" % ( op.op.params[0]) elif nm == "ry": self._latex[pos_1][ column] = "\\gate{R_y(%s)}" % ( op.op.params[0]) elif nm == "rz": self._latex[pos_1][ column] = "\\gate{R_z(%s)}" % ( op.op.params[0]) else: self._latex[pos_1][column] = ("\\gate{%s}" % utf8tolatex(nm)) gap = pos_2 - pos_1 for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_2 + i][column] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_2 + i][column] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: if nm == "x": self._latex[pos_1][column] = "\\gate{X}" elif nm == "y": self._latex[pos_1][column] = "\\gate{Y}" elif nm == "z": self._latex[pos_1][column] = "\\gate{Z}" elif nm == "h": self._latex[pos_1][column] = "\\gate{H}" elif nm == "s": self._latex[pos_1][column] = "\\gate{S}" elif nm == "sdg": self._latex[pos_1][column] = "\\gate{S^\\dag}" elif nm == "t": self._latex[pos_1][column] = "\\gate{T}" elif nm == "tdg": self._latex[pos_1][column] = "\\gate{T^\\dag}" elif nm == "u0": self._latex[pos_1][ column] = "\\gate{U_0(%s)}" % ( op.op.params[0]) elif nm == "u1": self._latex[pos_1][ column] = "\\gate{U_1(%s)}" % ( op.op.params[0]) elif nm == "u2": self._latex[pos_1][column] = \ "\\gate{U_2\\left(%s,%s\\right)}" % ( op.op.params[0], op.op.params[1]) elif nm == "u3": self._latex[pos_1][column] = ( "\\gate{U_3(%s,%s,%s)}" % (op.op.params[0], op.op.params[1], op.op.params[2])) elif nm == "rx": self._latex[pos_1][ column] = "\\gate{R_x(%s)}" % ( op.op.params[0]) elif nm == "ry": self._latex[pos_1][ column] = "\\gate{R_y(%s)}" % ( op.op.params[0]) elif nm == "rz": self._latex[pos_1][ column] = "\\gate{R_z(%s)}" % ( op.op.params[0]) elif nm == "reset": self._latex[pos_1][column] = ( "\\push{\\rule{.6em}{0em}\\ket{0}\\" "rule{.2em}{0em}} \\qw") else: self._latex[pos_1][column] = ("\\gate{%s}" % utf8tolatex(nm)) elif len(qarglist) == 2: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])] if op.condition: pos_3 = self.img_regs[(if_reg, 0)] temp = [pos_1, pos_2, pos_3] temp.sort(key=int) bottom = temp[1] gap = pos_3 - bottom for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_3 + i][column] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_3 + i][column] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 if nm == "cx": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\targ" elif nm == "cz": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\control\\qw" elif nm == "cy": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\gate{Y}" elif nm == "ch": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\gate{H}" elif nm == "swap": self._latex[pos_1][column] = "\\qswap" self._latex[pos_2][column] = \ "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]" elif nm == "crz": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = \ "\\gate{R_z(%s)}" % (op.op.params[0]) elif nm == "cu1": self._latex[pos_1][ column - 1] = "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column - 1] = "\\control\\qw" self._latex[min(pos_1, pos_2)][column] = \ "\\dstick{%s}\\qw" % (op.op.params[0]) self._latex[max(pos_1, pos_2)][column] = "\\qw" elif nm == "cu3": self._latex[pos_1][column] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column] = \ "\\gate{U_3(%s,%s,%s)}" % (op.op.params[0], op.op.params[1], op.op.params[2]) else: temp = [pos_1, pos_2] temp.sort(key=int) if nm == "cx": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\targ" elif nm == "cz": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\control\\qw" elif nm == "cy": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\gate{Y}" elif nm == "ch": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\gate{H}" elif nm == "swap": self._latex[pos_1][column] = "\\qswap" self._latex[pos_2][column] = \ "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]" elif nm == "crz": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = \ "\\gate{R_z(%s)}" % (op.op.params[0]) elif nm == "cu1": self._latex[pos_1][ column - 1] = "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][column - 1] = "\\control\\qw" self._latex[min(pos_1, pos_2)][column] = \ "\\dstick{%s}\\qw" % (op.op.params[0]) self._latex[max(pos_1, pos_2)][column] = "\\qw" elif nm == "cu3": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = ( "\\gate{U_3(%s,%s,%s)}" % (op.op.params[0], op.op.params[1], op.op.params[2])) else: start_pos = min([pos_1, pos_2]) stop_pos = max([pos_1, pos_2]) if stop_pos - start_pos >= 2: delta = stop_pos - start_pos self._latex[start_pos][column] = ( "\\multigate{%s}{%s}" % (delta, utf8tolatex(nm))) for i_pos in range(start_pos + 1, stop_pos + 1): self._latex[i_pos][column] = ( "\\ghost{%s}" % utf8tolatex(nm)) else: self._latex[start_pos][column] = ( "\\multigate{1}{%s}" % utf8tolatex(nm)) self._latex[stop_pos][column] = ( "\\ghost{%s}" % utf8tolatex(nm)) elif len(qarglist) == 3: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])] pos_3 = self.img_regs[(qarglist[2][0], qarglist[2][1])] if op.condition: pos_4 = self.img_regs[(if_reg, 0)] temp = [pos_1, pos_2, pos_3, pos_4] temp.sort(key=int) bottom = temp[2] prev_column = [x[column - 1] for x in self._latex] for item, prev_entry in enumerate(prev_column): if 'barrier' in prev_entry: span = re.search('barrier{(.*)}', prev_entry) if span and any(i in temp for i in range( item, int(span.group(1)))): self._latex[item][column - 1] = \ prev_entry.replace( '\\barrier{', '\\barrier[-0.65em]{') gap = pos_4 - bottom for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_4 + i][column] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_4 + i][column] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 if nm == "ccx": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\ctrl{" + str( pos_3 - pos_2) + "}" self._latex[pos_3][column] = "\\targ" if nm == "cswap": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\qswap" self._latex[pos_3][column] = \ "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]" else: temp = [pos_1, pos_2, pos_3] temp.sort(key=int) prev_column = [x[column - 1] for x in self._latex] for item, prev_entry in enumerate(prev_column): if 'barrier' in prev_entry: span = re.search('barrier{(.*)}', prev_entry) if span and any(i in temp for i in range( item, int(span.group(1)))): self._latex[item][column - 1] = \ prev_entry.replace( '\\barrier{', '\\barrier[-0.65em]{') if nm == "ccx": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\ctrl{" + str( pos_3 - pos_2) + "}" self._latex[pos_3][column] = "\\targ" elif nm == "cswap": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][column] = "\\qswap" self._latex[pos_3][column] = \ "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]" else: start_pos = min([pos_1, pos_2, pos_3]) stop_pos = max([pos_1, pos_2, pos_3]) if stop_pos - start_pos >= 3: delta = stop_pos - start_pos self._latex[start_pos][column] = ( "\\multigate{%s}{%s}" % (delta, utf8tolatex(nm))) for i_pos in range(start_pos + 1, stop_pos + 1): self._latex[i_pos][column] = ( "\\ghost{%s}" % utf8tolatex(nm)) else: self._latex[pos_1][column] = ( "\\multigate{2}{%s}" % utf8tolatex(nm)) self._latex[pos_2][column] = ( "\\ghost{%s}" % utf8tolatex(nm)) self._latex[pos_3][column] = ( "\\ghost{%s}" % utf8tolatex(nm)) elif len(qarglist) > 3: nbits = len(qarglist) pos_array = [ self.img_regs[(qarglist[0][0], qarglist[0][1])] ] for i in range(1, nbits): pos_array.append(self.img_regs[(qarglist[i][0], qarglist[i][1])]) pos_start = min(pos_array) pos_stop = max(pos_array) delta = pos_stop - pos_start self._latex[pos_start][column] = ( "\\multigate{%s}{%s}" % (nbits - 1, utf8tolatex(nm))) for pos in range(pos_start + 1, pos_stop + 1): self._latex[pos][column] = ("\\ghost{%s}" % utf8tolatex(nm)) elif op.name == "measure": if (len(op.cargs) != 1 or len(op.qargs) != 1 or op.op.params): raise exceptions.VisualizationError( "bad operation record") if op.condition: raise exceptions.VisualizationError( "If controlled measures currently not supported.") qname, qindex = op.qargs[0] cname, cindex = op.cargs[0] if aliases: newq = aliases[(qname, qindex)] qname = newq[0] qindex = newq[1] pos_1 = self.img_regs[(qname, qindex)] pos_2 = self.img_regs[(cname, cindex)] try: self._latex[pos_1][column] = "\\meter" prev_column = [x[column - 1] for x in self._latex] for item, prev_entry in enumerate(prev_column): if 'barrier' in prev_entry: span = re.search('barrier{(.*)}', prev_entry) if span and (item + int(span.group(1))) - pos_1 >= 0: self._latex[item][column - 1] = \ prev_entry.replace( '\\barrier{', '\\barrier[-1.15em]{') self._latex[pos_2][column] = \ "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]" except Exception as e: raise exceptions.VisualizationError( 'Error during Latex building: %s' % str(e)) elif op.name in [ 'barrier', 'snapshot', 'load', 'save', 'noise' ]: if self.plot_barriers: qarglist = op.qargs indexes = [self._get_qubit_index(x) for x in qarglist] start_bit = self.qubit_list[min(indexes)] if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) start = self.img_regs[start_bit] span = len(op.qargs) - 1 self._latex[start][column] = "\\qw \\barrier{" + str( span) + "}" else: raise exceptions.VisualizationError("bad node data")
def _draw_ops(self, verbose=False): _wide_gate = ['u2', 'u3', 'cu2', 'cu3'] _barriers = {'coord': [], 'group': []} # # generate coordinate manager # q_anchors = {} for key, qreg in self._qreg_dict.items(): q_anchors[key] = Anchor(reg_num=self._cond['n_lines'], yind=qreg['y'], fold=self._style.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._style.fold) # # draw gates # prev_anc = -1 for layer in self._ops: layer_width = 1 for op in layer: if op.name in _wide_gate: if layer_width < 2: layer_width = 2 # if custom gate with a longer than standard name determine # width elif op.name not in [ 'barrier', 'snapshot', 'load', 'save', 'noise', 'cswap', 'swap' ] and len(op.name) >= 4: box_width = round(len(op.name) / 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 this_anc = prev_anc + 1 for op in layer: _iswide = op.name in _wide_gate if op.name not in [ 'barrier', 'snapshot', 'load', 'save', 'noise', 'cswap', 'swap' ] and len(op.name) >= 4: _iswide = True # get qreg index q_idxs = [] for qarg in op.qargs: for index, reg in self._qreg_dict.items(): if (reg['group'] == qarg[0] and reg['index'] == qarg[1]): q_idxs.append(index) break # get creg index c_idxs = [] for carg in op.cargs: for index, reg in self._creg_dict.items(): if (reg['group'] == carg[0] and reg['index'] == carg[1]): c_idxs.append(index) break for ii in q_idxs: q_anchors[ii].set_index(this_anc, layer_width) # qreg coordinate q_xy = [ q_anchors[ii].plot_coord(this_anc, layer_width) for ii in q_idxs ] # creg coordinate c_xy = [ c_anchors[ii].plot_coord(this_anc, layer_width) for ii in c_idxs ] # 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 op.type == 'op' and hasattr(op.op, 'params'): param = self.param_parse(op.op.params, self._style.pimode) else: param = None # conditional gate if op.condition: c_xy = [ c_anchors[ii].plot_coord(this_anc, layer_width) for ii in self._creg_dict ] mask = 0 for index, cbit in enumerate(self._creg): if cbit.reg == 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.name == 'measure': vv = self._creg_dict[c_idxs[0]]['index'] self._measure(q_xy[0], c_xy[0], vv) elif op.name in [ 'barrier', 'snapshot', 'load', 'save', 'noise' ]: _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) # # draw single qubit gates # elif len(q_xy) == 1: disp = op.name if param: prm = '{}'.format(param) if len(prm) < 20: self._gate(q_xy[0], wide=_iswide, text=disp, subtext=prm) else: self._gate(q_xy[0], wide=_iswide, text=disp) else: self._gate(q_xy[0], wide=_iswide, text=disp) # # draw multi-qubit gates (n=2) # elif len(q_xy) == 2: # cx if op.name == 'cx': self._ctrl_qubit(q_xy[0]) self._tgt_qubit(q_xy[1]) # add qubit-qubit wiring self._line(qreg_b, qreg_t) # cz for latexmode elif op.name == 'cz': if self._style.latexmode: self._ctrl_qubit(q_xy[0]) self._ctrl_qubit(q_xy[1]) else: disp = op.name.replace('c', '') self._ctrl_qubit(q_xy[0]) self._gate(q_xy[1], wide=_iswide, text=disp) # add qubit-qubit wiring self._line(qreg_b, qreg_t) # control gate elif op.name in ['cy', 'ch', 'cu3', 'crz']: disp = op.name.replace('c', '') self._ctrl_qubit(q_xy[0]) if param: self._gate(q_xy[1], wide=_iswide, text=disp, subtext='{}'.format(param)) else: self._gate(q_xy[1], wide=_iswide, text=disp) # add qubit-qubit wiring self._line(qreg_b, qreg_t) # cu1 for latexmode elif op.name == 'cu1': disp = op.name.replace('c', '') self._ctrl_qubit(q_xy[0]) if self._style.latexmode: self._ctrl_qubit(q_xy[1]) self._subtext(qreg_b, param) else: self._gate(q_xy[1], wide=_iswide, text=disp, subtext='{}'.format(param)) # add qubit-qubit wiring self._line(qreg_b, qreg_t) # swap gate elif op.name == 'swap': self._swap(q_xy[0]) self._swap(q_xy[1]) # add qubit-qubit wiring self._line(qreg_b, qreg_t) # Custom gate else: self._custom_multiqubit_gate(q_xy, wide=_iswide, text=op.name) # # draw multi-qubit gates (n=3) # elif len(q_xy) == 3: # cswap gate if op.name == 'cswap': self._ctrl_qubit(q_xy[0]) self._swap(q_xy[1]) self._swap(q_xy[2]) # add qubit-qubit wiring self._line(qreg_b, qreg_t) # ccx gate elif op.name == 'ccx': self._ctrl_qubit(q_xy[0]) self._ctrl_qubit(q_xy[1]) self._tgt_qubit(q_xy[2]) # add qubit-qubit wiring self._line(qreg_b, qreg_t) # custom gate else: self._custom_multiqubit_gate(q_xy, wide=_iswide, text=op.name) # draw custom multi-qubit gate elif len(q_xy) > 3: self._custom_multiqubit_gate(q_xy, wide=_iswide, text=op.name) else: logger.critical('Invalid gate %s', op) raise exceptions.VisualizationError( 'invalid gate {}'.format(op)) prev_anc = this_anc + layer_width - 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._style.fold # window size if max_anc > self._style.fold > 0: self._cond['xmax'] = self._style.fold + 1 self._cond['ymax'] = (n_fold + 1) * (self._cond['n_lines'] + 1) - 1 else: self._cond['xmax'] = max_anc + 1 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._style.fold > 0: x_coord = ii % self._style.fold + 1 y_coord = -(ii // self._style.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)
def circuit_drawer(circuit, scale=0.7, filename=None, style=None, output=None, interactive=False, plot_barriers=True, reverse_bits=False, justify=None, vertical_compression='medium', idle_wires=True, with_layout=True, fold=None, ax=None, initial_state=False, cregbundle=False): """Draw a quantum circuit to different formats (set by output parameter): **text**: ASCII art TextDrawing that can be printed in the console. **latex**: high-quality images compiled via latex. **latex_source**: raw uncompiled latex output. **matplotlib**: images with color rendered purely in Python. Args: circuit (QuantumCircuit): the quantum circuit to draw scale (float): scale of image to draw (shrink if < 1). Only used by the ``mpl``, ``latex``, and ``latex_source`` outputs. filename (str): file path to save image to style (dict or str): dictionary of style or file name of style file. This option is only used by the ``mpl`` output type. If a str is passed in that is the path to a json file which contains that will be open, parsed, and then used just as the input dict. See: :ref:`Style Dict Doc <style-dict-doc>` for more information on the contents. output (str): Select the output method to use for drawing the circuit. Valid choices are ``text``, ``latex``, ``latex_source``, ``mpl``. By default the `'text`' drawer is used unless a user config file has an alternative backend set as the default. If the output kwarg is set, that backend will always be used over the default in a user config file. interactive (bool): when set true show the circuit in a new window (for `mpl` this depends on the matplotlib backend being used supporting this). Note when used with either the `text` or the `latex_source` output type this has no effect and will be silently ignored. reverse_bits (bool): When set to True reverse the bit order inside registers for the output visualization. plot_barriers (bool): Enable/disable drawing barriers in the output circuit. Defaults to True. justify (string): Options are ``left``, ``right`` or ``none``, if anything else is supplied it defaults to left justified. It refers to where gates should be placed in the output circuit if there is an option. ``none`` results in each gate being placed in its own column. vertical_compression (string): ``high``, ``medium`` or ``low``. It merges the lines generated by the ``text`` output so the drawing will take less vertical room. Default is ``medium``. Only used by the ``text`` output, will be silently ignored otherwise. idle_wires (bool): Include idle wires (wires with no circuit elements) in output visualization. Default is True. with_layout (bool): Include layout information, with labels on the physical layout. Default is True. fold (int): Sets pagination. It can be disabled using -1. In `text`, sets the length of the lines. This useful when the drawing does not fit in the console. If None (default), it will try to guess the console width using ``shutil.get_terminal_size()``. However, if running in jupyter, the default line length is set to 80 characters. In ``mpl`` it is the number of (visual) layers before folding. Default is 25. ax (matplotlib.axes.Axes): An optional Axes object to be used for the visualization output. If none is specified a new matplotlib Figure will be created and used. Additionally, if specified there will be no returned Figure since it is redundant. This is only used when the ``output`` kwarg is set to use the ``mpl`` backend. It will be silently ignored with all other outputs. initial_state (bool): Optional. Adds ``|0>`` in the beginning of the wire. Default: ``False``. cregbundle (bool): Optional. If set True bundle classical registers. Default: ``False``. Returns: :class:`PIL.Image` or :class:`matplotlib.figure` or :class:`str` or :class:`TextDrawing`: * `PIL.Image` (output='latex') an in-memory representation of the image of the circuit diagram. * `matplotlib.figure.Figure` (output='mpl') a matplotlib figure object for the circuit diagram. * `str` (output='latex_source') The LaTeX source code for visualizing the circuit diagram. * `TextDrawing` (output='text') A drawing that can be printed as ascii art Raises: VisualizationError: when an invalid output method is selected ImportError: when the output methods requires non-installed libraries. .. _style-dict-doc: **Style Dict Details** The style dict kwarg contains numerous options that define the style of the output circuit visualization. The style dict is only used by the ``mpl`` output. The options available in the style dict are defined below: Args: textcolor (str): The color code to use for text. Defaults to `'#000000'` subtextcolor (str): The color code to use for subtext. Defaults to `'#000000'` linecolor (str): The color code to use for lines. Defaults to `'#000000'` creglinecolor (str): The color code to use for classical register lines. Defaults to `'#778899'` gatetextcolor (str): The color code to use for gate text. Defaults to `'#000000'` gatefacecolor (str): The color code to use for gates. Defaults to `'#ffffff'` barrierfacecolor (str): The color code to use for barriers. Defaults to `'#bdbdbd'` backgroundcolor (str): The color code to use for the background. Defaults to `'#ffffff'` fontsize (int): The font size to use for text. Defaults to 13 subfontsize (int): The font size to use for subtext. Defaults to 8 displaytext (dict): A dictionary of the text to use for each element type in the output visualization. The default values are:: { 'id': 'id', 'u0': 'U_0', 'u1': 'U_1', 'u2': 'U_2', 'u3': 'U_3', 'x': 'X', 'y': 'Y', 'z': 'Z', 'h': 'H', 's': 'S', 'sdg': 'S^\\dagger', 't': 'T', 'tdg': 'T^\\dagger', 'rx': 'R_x', 'ry': 'R_y', 'rz': 'R_z', 'reset': '\\left|0\\right\\rangle' } You must specify all the necessary values if using this. There is no provision for passing an incomplete dict in. displaycolor (dict): The color codes to use for each circuit element. The default values are:: { 'id': '#F0E442', 'u0': '#E7AB3B', 'u1': '#E7AB3B', 'u2': '#E7AB3B', 'u3': '#E7AB3B', 'x': '#58C698', 'y': '#58C698', 'z': '#58C698', 'h': '#70B7EB', 's': '#E0722D', 'sdg': '#E0722D', 't': '#E0722D', 'tdg': '#E0722D', 'rx': '#ffffff', 'ry': '#ffffff', 'rz': '#ffffff', 'reset': '#D188B4', 'target': '#70B7EB', 'meas': '#D188B4' } Also, just like `displaytext` there is no provision for an incomplete dict passed in. latexdrawerstyle (bool): When set to True enable latex mode which will draw gates like the `latex` output modes. usepiformat (bool): When set to True use radians for output fold (int): The number of circuit elements to fold the circuit at. Defaults to 20 cregbundle (bool): If set True bundle classical registers showindex (bool): If set True draw an index. compress (bool): If set True draw a compressed circuit figwidth (int): The maximum width (in inches) for the output figure. dpi (int): The DPI to use for the output image. Defaults to 150 margin (list): A list of margin values to adjust spacing around output image. Takes a list of 4 ints: [x left, x right, y bottom, y top]. creglinestyle (str): The style of line to use for classical registers. Choices are `'solid'`, `'doublet'`, or any valid matplotlib `linestyle` kwarg value. Defaults to `doublet` Example: .. jupyter-execute:: from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.tools.visualization import circuit_drawer q = QuantumRegister(1) c = ClassicalRegister(1) qc = QuantumCircuit(q, c) qc.h(q) qc.measure(q, c) circuit_drawer(qc) """ image = None config = user_config.get_config() # Get default from config file else use text default_output = 'text' if config: default_output = config.get('circuit_drawer', 'text') if default_output == 'auto': if _matplotlib.HAS_MATPLOTLIB: default_output = 'mpl' else: default_output = 'text' if output is None: output = default_output if output == 'text': return _text_circuit_drawer(circuit, filename=filename, reverse_bits=reverse_bits, plot_barriers=plot_barriers, justify=justify, vertical_compression=vertical_compression, idle_wires=idle_wires, with_layout=with_layout, fold=fold, initial_state=initial_state, cregbundle=cregbundle) elif output == 'latex': image = _latex_circuit_drawer(circuit, scale=scale, filename=filename, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, initial_state=initial_state, cregbundle=cregbundle) elif output == 'latex_source': return _generate_latex_source(circuit, filename=filename, scale=scale, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, initial_state=initial_state, cregbundle=cregbundle) elif output == 'mpl': image = _matplotlib_circuit_drawer(circuit, scale=scale, filename=filename, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, fold=fold, ax=ax, initial_state=initial_state, cregbundle=cregbundle) else: raise exceptions.VisualizationError( 'Invalid output type %s selected. The only valid choices ' 'are latex, latex_source, text, and mpl' % output) if image and interactive: image.show() return image
def circuit_drawer(circuit, scale=None, filename=None, style=None, output=None, interactive=False, plot_barriers=True, reverse_bits=False, justify=None, vertical_compression='medium', idle_wires=True, with_layout=True, fold=None, ax=None, initial_state=False, cregbundle=True): """Draw the quantum circuit. Use the output parameter to choose the drawing format: **text**: ASCII art TextDrawing that can be printed in the console. **matplotlib**: images with color rendered purely in Python. **latex**: high-quality images compiled via latex. **latex_source**: raw uncompiled latex output. Args: circuit (QuantumCircuit): the quantum circuit to draw scale (float): scale of image to draw (shrink if < 1.0). Only used by the `mpl`, `latex` and `latex_source` outputs. Defaults to 1.0. filename (str): file path to save image to. Defaults to None. style (dict or str): dictionary of style or file name of style json file. This option is only used by the `mpl` output type. If `style` is a str, it is used as the path to a json file which contains a style dict. The file will be opened, parsed, and then any style elements in the dict will replace the default values in the input dict. A file to be loaded must end in ``.json``, but the name entered here can omit ``.json``. For example, ``style='iqx.json'`` or ``style='iqx'``. If `style` is a dict and the ``'name'`` key is set, that name will be used to load a json file, followed by loading the other items in the style dict. For example, ``style={'name': 'iqx'}``. If `style` is not a str and `name` is not a key in the style dict, then the default value from the user config file (usually ``~/.qiskit/settings.conf``) will be used, for example, ``circuit_mpl_style = iqx``. If none of these are set, the `default` style will be used. The search path for style json files can be specified in the user config, for example, ``circuit_mpl_style_path = /home/user/styles:/home/user``. See: :class:`~qiskit.visualization.qcstyle.DefaultStyle` for more information on the contents. output (str): select the output method to use for drawing the circuit. Valid choices are ``text``, ``mpl``, ``latex``, ``latex_source``. By default the `text` drawer is used unless the user config file (usually ``~/.qiskit/settings.conf``) has an alternative backend set as the default. For example, ``circuit_drawer = latex``. If the output kwarg is set, that backend will always be used over the default in the user config file. interactive (bool): when set to true, show the circuit in a new window (for `mpl` this depends on the matplotlib backend being used supporting this). Note when used with either the `text` or the `latex_source` output type this has no effect and will be silently ignored. Defaults to False. reverse_bits (bool): when set to True, reverse the bit order inside registers for the output visualization. Defaults to False. plot_barriers (bool): enable/disable drawing barriers in the output circuit. Defaults to True. justify (string): options are ``left``, ``right`` or ``none``. If anything else is supplied, it defaults to left justified. It refers to where gates should be placed in the output circuit if there is an option. ``none`` results in each gate being placed in its own column. vertical_compression (string): ``high``, ``medium`` or ``low``. It merges the lines generated by the `text` output so the drawing will take less vertical room. Default is ``medium``. Only used by the `text` output, will be silently ignored otherwise. idle_wires (bool): include idle wires (wires with no circuit elements) in output visualization. Default is True. with_layout (bool): include layout information, with labels on the physical layout. Default is True. fold (int): sets pagination. It can be disabled using -1. In `text`, sets the length of the lines. This is useful when the drawing does not fit in the console. If None (default), it will try to guess the console width using ``shutil.get_terminal_size()``. However, if running in jupyter, the default line length is set to 80 characters. In `mpl`, it is the number of (visual) layers before folding. Default is 25. ax (matplotlib.axes.Axes): Only used by the `mpl` backend. An optional Axes object to be used for the visualization output. If none is specified, a new matplotlib Figure will be created and used. Additionally, if specified there will be no returned Figure since it is redundant. initial_state (bool): optional. Adds ``|0>`` in the beginning of the wire. Default is False. cregbundle (bool): optional. If set True, bundle classical registers. Default is True. Returns: :class:`TextDrawing` or :class:`matplotlib.figure` or :class:`PIL.Image` or :class:`str`: * `TextDrawing` (output='text') A drawing that can be printed as ascii art. * `matplotlib.figure.Figure` (output='mpl') A matplotlib figure object for the circuit diagram. * `PIL.Image` (output='latex') An in-memory representation of the image of the circuit diagram. * `str` (output='latex_source') The LaTeX source code for visualizing the circuit diagram. Raises: VisualizationError: when an invalid output method is selected ImportError: when the output methods requires non-installed libraries. Example: .. jupyter-execute:: from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.tools.visualization import circuit_drawer q = QuantumRegister(1) c = ClassicalRegister(1) qc = QuantumCircuit(q, c) qc.h(q) qc.measure(q, c) circuit_drawer(qc, output='mpl', style={'backgroundcolor': '#EEEEEE'}) """ image = None config = user_config.get_config() # Get default from config file else use text default_output = 'text' if config: default_output = config.get('circuit_drawer', 'text') if default_output == 'auto': if _matplotlib.HAS_MATPLOTLIB: default_output = 'mpl' else: default_output = 'text' if output is None: output = default_output if output == 'text': return _text_circuit_drawer(circuit, filename=filename, reverse_bits=reverse_bits, plot_barriers=plot_barriers, justify=justify, vertical_compression=vertical_compression, idle_wires=idle_wires, with_layout=with_layout, fold=fold, initial_state=initial_state, cregbundle=cregbundle) elif output == 'latex': image = _latex_circuit_drawer(circuit, filename=filename, scale=scale, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, initial_state=initial_state, cregbundle=cregbundle) elif output == 'latex_source': return _generate_latex_source(circuit, filename=filename, scale=scale, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, initial_state=initial_state, cregbundle=cregbundle) elif output == 'mpl': image = _matplotlib_circuit_drawer(circuit, scale=scale, filename=filename, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, fold=fold, ax=ax, initial_state=initial_state, cregbundle=cregbundle) else: raise exceptions.VisualizationError( 'Invalid output type %s selected. The only valid choices ' 'are text, latex, latex_source, and mpl' % output) if image and interactive: image.show() return image
def circuit_drawer(circuit, scale=0.7, filename=None, style=None, output='text', interactive=False, line_length=None, plot_barriers=True, reverse_bits=False, justify=None): """Draw a quantum circuit to different formats (set by output parameter): 0. text: ASCII art TextDrawing that can be printed in the console. 1. latex: high-quality images, but heavy external software dependencies 2. matplotlib: purely in Python with no external dependencies Args: circuit (QuantumCircuit): the quantum circuit to draw scale (float): scale of image to draw (shrink if < 1) filename (str): file path to save image to style (dict or str): dictionary of style or file name of style file. This option is only used by the `mpl`, `latex`, and `latex_source` output types. If a str is passed in that is the path to a json file which contains that will be open, parsed, and then used just as the input dict. output (TextDrawing): Select the output method to use for drawing the circuit. Valid choices are `text`, `latex`, `latex_source`, `mpl`. Note if one is not specified it will use latex and if that fails fallback to mpl. However this behavior is deprecated and in a future release the default will change. interactive (bool): when set true show the circuit in a new window (for `mpl` this depends on the matplotlib backend being used supporting this). Note when used with either the `text` or the `latex_source` output type this has no effect and will be silently ignored. line_length (int): Sets the length of the lines generated by `text` output type. This useful when the drawing does not fit in the console. If None (default), it will try to guess the console width using shutil.get_terminal_size(). However, if you're running in jupyter the default line length is set to 80 characters. If you don't want pagination at all, set `line_length=-1`. reverse_bits (bool): When set to True reverse the bit order inside registers for the output visualization. plot_barriers (bool): Enable/disable drawing barriers in the output circuit. Defaults to True. justify (string): Options are `left`, `right` or `none`, if anything else is supplied it defaults to left justified. It refers to where gates should be placed in the output circuit if there is an option. `none` results in each gate being placed in its own column. Currently only supported by text drawer. Returns: PIL.Image: (output `latex`) an in-memory representation of the image of the circuit diagram. matplotlib.figure: (output `mpl`) a matplotlib figure object for the circuit diagram. String: (output `latex_source`). The LaTeX source code. TextDrawing: (output `text`). A drawing that can be printed as ascii art Raises: VisualizationError: when an invalid output method is selected ImportError: when the output methods requieres non-installed libraries. .. _style-dict-doc: The style dict kwarg contains numerous options that define the style of the output circuit visualization. While the style dict is used by the `mpl`, `latex`, and `latex_source` outputs some options in that are only used by the `mpl` output. These options are defined below, if it is only used by the `mpl` output it is marked as such: textcolor (str): The color code to use for text. Defaults to `'#000000'` (`mpl` only) subtextcolor (str): The color code to use for subtext. Defaults to `'#000000'` (`mpl` only) linecolor (str): The color code to use for lines. Defaults to `'#000000'` (`mpl` only) creglinecolor (str): The color code to use for classical register lines `'#778899'`(`mpl` only) gatetextcolor (str): The color code to use for gate text `'#000000'` (`mpl` only) gatefacecolor (str): The color code to use for gates. Defaults to `'#ffffff'` (`mpl` only) barrierfacecolor (str): The color code to use for barriers. Defaults to `'#bdbdbd'` (`mpl` only) backgroundcolor (str): The color code to use for the background. Defaults to `'#ffffff'` (`mpl` only) fontsize (int): The font size to use for text. Defaults to 13 (`mpl` only) subfontsize (int): The font size to use for subtext. Defaults to 8 (`mpl` only) displaytext (dict): A dictionary of the text to use for each element type in the output visualization. The default values are: { 'id': 'id', 'u0': 'U_0', 'u1': 'U_1', 'u2': 'U_2', 'u3': 'U_3', 'x': 'X', 'y': 'Y', 'z': 'Z', 'h': 'H', 's': 'S', 'sdg': 'S^\\dagger', 't': 'T', 'tdg': 'T^\\dagger', 'rx': 'R_x', 'ry': 'R_y', 'rz': 'R_z', 'reset': '\\left|0\\right\\rangle' } You must specify all the necessary values if using this. There is no provision for passing an incomplete dict in. (`mpl` only) displaycolor (dict): The color codes to use for each circuit element. By default all values default to the value of `gatefacecolor` and the keys are the same as `displaytext`. Also, just like `displaytext` there is no provision for an incomplete dict passed in. (`mpl` only) latexdrawerstyle (bool): When set to True enable latex mode which will draw gates like the `latex` output modes. (`mpl` only) usepiformat (bool): When set to True use radians for output (`mpl` only) fold (int): The number of circuit elements to fold the circuit at. Defaults to 20 (`mpl` only) cregbundle (bool): If set True bundle classical registers (`mpl` only) showindex (bool): If set True draw an index. (`mpl` only) compress (bool): If set True draw a compressed circuit (`mpl` only) figwidth (int): The maximum width (in inches) for the output figure. (`mpl` only) dpi (int): The DPI to use for the output image. Defaults to 150 (`mpl` only) margin (list): `mpl` only creglinestyle (str): The style of line to use for classical registers. Choices are `'solid'`, `'doublet'`, or any valid matplotlib `linestyle` kwarg value. Defaults to `doublet`(`mpl` only) """ image = None if output == 'text': return _text_circuit_drawer(circuit, filename=filename, line_length=line_length, reverse_bits=reverse_bits, plotbarriers=plot_barriers, justify=justify) elif output == 'latex': image = _latex_circuit_drawer(circuit, scale=scale, filename=filename, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify) elif output == 'latex_source': return _generate_latex_source(circuit, filename=filename, scale=scale, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify) elif output == 'mpl': image = _matplotlib_circuit_drawer(circuit, scale=scale, filename=filename, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify) else: raise exceptions.VisualizationError( 'Invalid output type %s selected. The only valid choices ' 'are latex, latex_source, text, and mpl' % output) if image and interactive: image.show() return image
def circuit_drawer(circuit, scale=None, filename=None, style=None, output=None, interactive=False, plot_barriers=True, reverse_bits=False, justify=None, vertical_compression='medium', idle_wires=True, with_layout=True, fold=None, ax=None, initial_state=False, cregbundle=True): """Draw the quantum circuit. Use the output parameter to choose the drawing format: **text**: ASCII art TextDrawing that can be printed in the console. **matplotlib**: images with color rendered purely in Python. **latex**: high-quality images compiled via latex. **latex_source**: raw uncompiled latex output. Args: circuit (QuantumCircuit): the quantum circuit to draw scale (float): scale of image to draw (shrink if < 1.0). Only used by the `mpl`, `latex` and `latex_source` outputs. Defaults to 1.0. filename (str): file path to save image to. Defaults to None. style (dict or str): dictionary of style or file name of style json file. This option is only used by the `mpl` output type. If a str, it is used as the path to a json file which contains a style dict. The file will be opened, parsed, and then any style elements in the dict will replace the default values in the input dict. A file to be loaded must end in ``.json``, but the name entered here can omit ``.json``. For example, ``style='iqx.json'`` or ``style='iqx'``. If `style` is a dict and the ``'name'`` key is set, that name will be used to load a json file, followed by loading the other items in the style dict. For example, ``style={'name': 'iqx'}``. If `style` is not a str and `name` is not a key in the style dict, then the default value from the user config file (usually ``~/.qiskit/settings.conf``) will be used, for example, ``circuit_mpl_style = iqx``. If none of these are set, the `default` style will be used. The search path for style json files can be specified in the user config, for example, ``circuit_mpl_style_path = /home/user/styles:/home/user``. See: :ref:`Style Dict Doc <style-dict-doc>` for more information on the contents. output (str): select the output method to use for drawing the circuit. Valid choices are ``text``, ``mpl``, ``latex``, ``latex_source``. By default the `text` drawer is used unless the user config file (usually ``~/.qiskit/settings.conf``) has an alternative backend set as the default. For example, ``circuit_drawer = latex``. If the output kwarg is set, that backend will always be used over the default in the user config file. interactive (bool): when set to true, show the circuit in a new window (for `mpl` this depends on the matplotlib backend being used supporting this). Note when used with either the `text` or the `latex_source` output type this has no effect and will be silently ignored. Defaults to False. reverse_bits (bool): when set to True, reverse the bit order inside registers for the output visualization. Defaults to False. plot_barriers (bool): enable/disable drawing barriers in the output circuit. Defaults to True. justify (string): options are ``left``, ``right`` or ``none``. If anything else is supplied, it defaults to left justified. It refers to where gates should be placed in the output circuit if there is an option. ``none`` results in each gate being placed in its own column. vertical_compression (string): ``high``, ``medium`` or ``low``. It merges the lines generated by the `text` output so the drawing will take less vertical room. Default is ``medium``. Only used by the `text` output, will be silently ignored otherwise. idle_wires (bool): include idle wires (wires with no circuit elements) in output visualization. Default is True. with_layout (bool): include layout information, with labels on the physical layout. Default is True. fold (int): sets pagination. It can be disabled using -1. In `text`, sets the length of the lines. This is useful when the drawing does not fit in the console. If None (default), it will try to guess the console width using ``shutil.get_terminal_size()``. However, if running in jupyter, the default line length is set to 80 characters. In `mpl`, it is the number of (visual) layers before folding. Default is 25. ax (matplotlib.axes.Axes): Only used by the `mpl` backend. An optional Axes object to be used for the visualization output. If none is specified, a new matplotlib Figure will be created and used. Additionally, if specified there will be no returned Figure since it is redundant. initial_state (bool): optional. Adds ``|0>`` in the beginning of the wire. Default is False. cregbundle (bool): optional. If set True, bundle classical registers. Default is True. Returns: :class:`TextDrawing` or :class:`matplotlib.figure` or :class:`PIL.Image` or :class:`str`: * `TextDrawing` (output='text') A drawing that can be printed as ascii art. * `matplotlib.figure.Figure` (output='mpl') A matplotlib figure object for the circuit diagram. * `PIL.Image` (output='latex') An in-memory representation of the image of the circuit diagram. * `str` (output='latex_source') The LaTeX source code for visualizing the circuit diagram. Raises: VisualizationError: when an invalid output method is selected ImportError: when the output methods requires non-installed libraries. .. _style-dict-doc: **Style Dict Details** The style dict kwarg contains numerous options that define the style of the output circuit visualization. The style dict is only used by the `mpl` output. The options available in the style dict are defined below: Args: name (str): the name of the style. The name can be set to ``iqx``, ``bw``, ``default``, or the name of a user-created json file. This overrides the setting in the user config file (usually ``~/.qiskit/settings.conf``). textcolor (str): the color code to use for all text not inside a gate. Defaults to ``#000000`` subtextcolor (str): the color code to use for subtext. Defaults to ``#000000`` linecolor (str): the color code to use for lines. Defaults to ``#000000`` creglinecolor (str): the color code to use for classical register lines. Defaults to ``#778899`` gatetextcolor (str): the color code to use for gate text. Defaults to ``#000000`` gatefacecolor (str): the color code to use for a gate if no color specified in the 'displaycolor' dict. Defaults to ``#BB8BFF`` barrierfacecolor (str): the color code to use for barriers. Defaults to ``#BDBDBD`` backgroundcolor (str): the color code to use for the background. Defaults to ``#FFFFFF`` edgecolor (str): the color code to use for gate edges when using the `bw` style. Defaults to ``#000000``. fontsize (int): the font size to use for text. Defaults to 13. subfontsize (int): the font size to use for subtext. Defaults to 8. showindex (bool): if set to True, show the index numbers at the top. Defaults to False. figwidth (int): the maximum width (in inches) for the output figure. If set to -1, the maximum displayable width will be used. Defaults to -1. dpi (int): the DPI to use for the output image. Defaults to 150. margin (list): a list of margin values to adjust spacing around output image. Takes a list of 4 ints: [x left, x right, y bottom, y top]. Defaults to [2.0, 0.1, 0.1, 0.3]. creglinestyle (str): The style of line to use for classical registers. Choices are ``solid``, ``doublet``, or any valid matplotlib `linestyle` kwarg value. Defaults to ``doublet``. displaytext (dict): a dictionary of the text to use for certain element types in the output visualization. These items allow the use of LaTeX formatting for gate names. The 'displaytext' dict can contain any number of elements from one to the entire dict above.The default values are (`default.json`):: { 'u1': '$\\mathrm{U}_1$', 'u2': '$\\mathrm{U}_2$', 'u3': '$\\mathrm{U}_3$', 'u': 'U', 'p': 'P', 'id': 'I', 'x': 'X', 'y': 'Y', 'z': 'Z', 'h': 'H', 's': 'S', 'sdg': '$\\mathrm{S}^\\dagger$', 'sx': '$\\sqrt{\\mathrm{X}}$', 'sxdg': '$\\sqrt{\\mathrm{X}}^\\dagger$', 't': 'T', 'tdg': '$\\mathrm{T}^\\dagger$', 'dcx': 'Dcx', 'iswap': 'Iswap', 'ms': 'MS', 'r': 'R', 'rx': '$\\mathrm{R}_\\mathrm{X}$', 'ry': '$\\mathrm{R}_\\mathrm{Y}$', 'rz': '$\\mathrm{R}_\\mathrm{Z}$', 'rxx': '$\\mathrm{R}_{\\mathrm{XX}}$', 'ryy': '$\\mathrm{R}_{\\mathrm{YY}}$', 'rzx': '$\\mathrm{R}_{\\mathrm{ZX}}$', 'rzz': '$\\mathrm{R}_{\\mathrm{ZZ}}$', 'reset': '$\\left|0\\right\\rangle$', 'initialize': '$|\\psi\\rangle$' } displaycolor (dict): the color codes to use for each circuit element in the form (gate_color, text_color). Colors can also be entered without the text color, such as 'u1': '#FA74A6', in which case the text color will always be `gatetextcolor`. The `displaycolor` dict can contain any number of elements from one to the entire dict above. The default values are (`default.json`):: { 'u1': ('#FA74A6', '#000000'), 'u2': ('#FA74A6', '#000000'), 'u3': ('#FA74A6', '#000000'), 'id': ('#05BAB6', '#000000'), 'u': ('#BB8BFF', '#000000'), 'p': ('#BB8BFF', '#000000'), 'x': ('#05BAB6', '#000000'), 'y': ('#05BAB6', '#000000'), 'z': ('#05BAB6', '#000000'), 'h': ('#6FA4FF', '#000000'), 'cx': ('#6FA4FF', '#000000'), 'ccx': ('#BB8BFF', '#000000'), 'mcx': ('#BB8BFF', '#000000'), 'mcx_gray': ('#BB8BFF', '#000000), 'cy': ('#6FA4FF', '#000000'), 'cz': ('#6FA4FF', '#000000'), 'swap': ('#6FA4FF', '#000000'), 'cswap': ('#BB8BFF', '#000000'), 'ccswap': ('#BB8BFF', '#000000'), 'dcx': ('#6FA4FF', '#000000'), 'cdcx': ('#BB8BFF', '#000000'), 'ccdcx': ('#BB8BFF', '#000000'), 'iswap': ('#6FA4FF', '#000000'), 's': ('#6FA4FF', '#000000'), 'sdg': ('#6FA4FF', '#000000'), 't': ('#BB8BFF', '#000000'), 'tdg': ('#BB8BFF', '#000000'), 'sx': ('#BB8BFF', '#000000'), 'sxdg': ('#BB8BFF', '#000000') 'r': ('#BB8BFF', '#000000'), 'rx': ('#BB8BFF', '#000000'), 'ry': ('#BB8BFF', '#000000'), 'rz': ('#BB8BFF', '#000000'), 'rxx': ('#BB8BFF', '#000000'), 'ryy': ('#BB8BFF', '#000000'), 'rzx': ('#BB8BFF', '#000000'), 'reset': ('#000000', #FFFFFF'), 'target': ('#FFFFFF, '#FFFFFF'), 'measure': ('#000000', '#FFFFFF'), } Example: .. jupyter-execute:: from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit from qiskit.tools.visualization import circuit_drawer q = QuantumRegister(1) c = ClassicalRegister(1) qc = QuantumCircuit(q, c) qc.h(q) qc.measure(q, c) circuit_drawer(qc, output='mpl', style={'showindex': True}) """ image = None config = user_config.get_config() # Get default from config file else use text default_output = 'text' if config: default_output = config.get('circuit_drawer', 'text') if default_output == 'auto': if _matplotlib.HAS_MATPLOTLIB: default_output = 'mpl' else: default_output = 'text' if output is None: output = default_output if output == 'text': return _text_circuit_drawer(circuit, filename=filename, reverse_bits=reverse_bits, plot_barriers=plot_barriers, justify=justify, vertical_compression=vertical_compression, idle_wires=idle_wires, with_layout=with_layout, fold=fold, initial_state=initial_state, cregbundle=cregbundle) elif output == 'latex': image = _latex_circuit_drawer(circuit, filename=filename, scale=scale, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, initial_state=initial_state, cregbundle=cregbundle) elif output == 'latex_source': return _generate_latex_source(circuit, filename=filename, scale=scale, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, initial_state=initial_state, cregbundle=cregbundle) elif output == 'mpl': image = _matplotlib_circuit_drawer(circuit, scale=scale, filename=filename, style=style, plot_barriers=plot_barriers, reverse_bits=reverse_bits, justify=justify, idle_wires=idle_wires, with_layout=with_layout, fold=fold, ax=ax, initial_state=initial_state, cregbundle=cregbundle) else: raise exceptions.VisualizationError( 'Invalid output type %s selected. The only valid choices ' 'are text, latex, latex_source, and mpl' % output) if image and interactive: image.show() return image
def _build_latex_array(self, aliases=None): """Returns an array of strings containing \\LaTeX for this circuit. If aliases is not None, aliases contains a dict mapping the current qubits in the circuit to new qubit names. We will deduce the register names and sizes from aliases. """ columns = 1 is_occupied = [False] * self.img_width # Rename qregs if necessary if aliases: qregdata = {} for q in aliases.values(): if q[0] not in qregdata: qregdata[q[0]] = q[1] + 1 elif qregdata[q[0]] < q[1] + 1: qregdata[q[0]] = q[1] + 1 else: qregdata = self.qregs for current_op in self.ops: if current_op.condition: mask = self._get_mask(current_op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg[0] pos_2 = self.img_regs[cl_reg] if_value = format(current_op.condition[1], 'b').zfill(self.cregs[if_reg])[::-1] if current_op.name not in [ 'measure', 'barrier', 'snapshot', 'load', 'save', 'noise' ]: nm = current_op.name qarglist = current_op.qargs if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) if len(qarglist) == 1: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] if current_op.condition: mask = self._get_mask(current_op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg[0] pos_2 = self.img_regs[cl_reg] for i in range(pos_1, pos_2 + self.cregs[if_reg]): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(pos_1, pos_2 + 1): is_occupied[j] = True break if nm == "x": self._latex[pos_1][columns] = "\\gate{X}" elif nm == "y": self._latex[pos_1][columns] = "\\gate{Y}" elif nm == "z": self._latex[pos_1][columns] = "\\gate{Z}" elif nm == "h": self._latex[pos_1][columns] = "\\gate{H}" elif nm == "id": self._latex[pos_1][columns] = "\\gate{Id}" elif nm == "s": self._latex[pos_1][columns] = "\\gate{S}" elif nm == "sdg": self._latex[pos_1][columns] = "\\gate{S^\\dag}" elif nm == "t": self._latex[pos_1][columns] = "\\gate{T}" elif nm == "tdg": self._latex[pos_1][columns] = "\\gate{T^\\dag}" elif nm == "u0": self._latex[pos_1][columns] = "\\gate{U_0(%s)}" % ( current_op.op.params[0]) elif nm == "u1": self._latex[pos_1][columns] = "\\gate{U_1(%s)}" % ( current_op["op"].params[0]) elif nm == "u2": self._latex[pos_1][columns] = \ "\\gate{U_2\\left(%s,%s\\right)}" % ( current_op["op"].params[0], current_op["op"].params[1]) elif nm == "u3": self._latex[pos_1][columns] = ( "\\gate{U_3(%s,%s,%s)}" % (current_op.op.params[0], current_op.op.params[1], current_op.op.params[2])) elif nm == "rx": self._latex[pos_1][columns] = "\\gate{R_x(%s)}" % ( current_op.op.params[0]) elif nm == "ry": self._latex[pos_1][columns] = "\\gate{R_y(%s)}" % ( current_op.op.params[0]) elif nm == "rz": self._latex[pos_1][columns] = "\\gate{R_z(%s)}" % ( current_op.op.params[0]) gap = pos_2 - pos_1 for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_2 + i][columns] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_2 + i][columns] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: if not is_occupied[pos_1]: is_occupied[pos_1] = True else: columns += 1 is_occupied = [False] * self.img_width is_occupied[pos_1] = True if nm == "x": self._latex[pos_1][columns] = "\\gate{X}" elif nm == "y": self._latex[pos_1][columns] = "\\gate{Y}" elif nm == "z": self._latex[pos_1][columns] = "\\gate{Z}" elif nm == "h": self._latex[pos_1][columns] = "\\gate{H}" elif nm == "id": self._latex[pos_1][columns] = "\\gate{Id}" elif nm == "s": self._latex[pos_1][columns] = "\\gate{S}" elif nm == "sdg": self._latex[pos_1][columns] = "\\gate{S^\\dag}" elif nm == "t": self._latex[pos_1][columns] = "\\gate{T}" elif nm == "tdg": self._latex[pos_1][columns] = "\\gate{T^\\dag}" elif nm == "u0": self._latex[pos_1][columns] = "\\gate{U_0(%s)}" % ( current_op.op.params[0]) elif nm == "u1": self._latex[pos_1][columns] = "\\gate{U_1(%s)}" % ( current_op.op.params[0]) elif nm == "u2": self._latex[pos_1][columns] = \ "\\gate{U_2\\left(%s,%s\\right)}" % ( current_op.op.params[0], current_op.op.params[1]) elif nm == "u3": self._latex[pos_1][columns] = ( "\\gate{U_3(%s,%s,%s)}" % (current_op.op.params[0], current_op.op.params[1], current_op.op.params[2])) elif nm == "rx": self._latex[pos_1][columns] = "\\gate{R_x(%s)}" % ( current_op.op.params[0]) elif nm == "ry": self._latex[pos_1][columns] = "\\gate{R_y(%s)}" % ( current_op.op.params[0]) elif nm == "rz": self._latex[pos_1][columns] = "\\gate{R_z(%s)}" % ( current_op.op.params[0]) elif nm == "reset": self._latex[pos_1][columns] = ( "\\push{\\rule{.6em}{0em}\\ket{0}\\" "rule{.2em}{0em}} \\qw") elif len(qarglist) == 2: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])] if current_op.condition: pos_3 = self.img_regs[(if_reg, 0)] temp = [pos_1, pos_2, pos_3] temp.sort(key=int) top = temp[0] bottom = temp[1] for i in range(top, pos_3 + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(top, pos_3 + 1): is_occupied[j] = True break # symetric gates have angle labels if current_op.name == 'cu1': columns += 1 is_occupied = [False] * self.img_width is_occupied[top] = True gap = pos_3 - bottom for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_3 + i][columns] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_3 + i][columns] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 if nm == "cx": self._latex[pos_1][columns] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\targ" elif nm == "cz": self._latex[pos_1][columns] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\control\\qw" elif nm == "cy": self._latex[pos_1][columns] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\gate{Y}" elif nm == "ch": self._latex[pos_1][columns] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\gate{H}" elif nm == "swap": self._latex[pos_1][columns] = "\\qswap" self._latex[pos_2][columns] = \ "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]" elif nm == "crz": self._latex[pos_1][columns] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][columns] = \ "\\gate{R_z(%s)}" % (current_op.op.params[0]) elif nm == "cu1": self._latex[pos_1][ columns - 1] = "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][columns - 1] = "\\control\\qw" self._latex[min(pos_1, pos_2)][columns] = \ "\\dstick{%s}\\qw" % (current_op.op.params[0]) self._latex[max(pos_1, pos_2)][columns] = "\\qw" elif nm == "cu3": self._latex[pos_1][columns] = \ "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][columns] = \ "\\gate{U_3(%s,%s,%s)}" % (current_op.op.params[0], current_op.op.params[1], current_op.op.params[2]) else: temp = [pos_1, pos_2] temp.sort(key=int) top = temp[0] bottom = temp[1] for i in range(top, bottom + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(top, bottom + 1): is_occupied[j] = True break # symetric gates have angle labels if current_op.name == 'cu1': columns += 1 is_occupied = [False] * self.img_width is_occupied[top] = True if nm == "cx": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\targ" elif nm == "cz": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\control\\qw" elif nm == "cy": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\gate{Y}" elif nm == "ch": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\gate{H}" elif nm == "swap": self._latex[pos_1][columns] = "\\qswap" self._latex[pos_2][columns] = \ "\\qswap \\qwx[" + str(pos_1 - pos_2) + "]" elif nm == "crz": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = \ "\\gate{R_z(%s)}" % (current_op.op.params[0]) elif nm == "cu1": self._latex[pos_1][ columns - 1] = "\\ctrl{" + str(pos_2 - pos_1) + "}" self._latex[pos_2][columns - 1] = "\\control\\qw" self._latex[min(pos_1, pos_2)][columns] = \ "\\dstick{%s}\\qw" % (current_op.op.params[0]) self._latex[max(pos_1, pos_2)][columns] = "\\qw" elif nm == "cu3": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = ( "\\gate{U_3(%s,%s,%s)}" % (current_op.op.params[0], current_op.op.params[1], current_op.op.params[2])) elif len(qarglist) == 3: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])] pos_3 = self.img_regs[(qarglist[2][0], qarglist[2][1])] if current_op.condition: pos_4 = self.img_regs[(if_reg, 0)] temp = [pos_1, pos_2, pos_3, pos_4] temp.sort(key=int) top = temp[0] bottom = temp[2] for i in range(top, pos_4 + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(top, pos_4 + 1): is_occupied[j] = True break prev_column = [x[columns - 1] for x in self._latex] for item, prev_entry in enumerate(prev_column): if 'barrier' in prev_entry: span = re.search('barrier{(.*)}', prev_entry) if span and any(i in temp for i in range( item, int(span.group(1)))): self._latex[item][columns - 1] = \ prev_entry.replace( '\\barrier{', '\\barrier[-0.65em]{') gap = pos_4 - bottom for i in range(self.cregs[if_reg]): if if_value[i] == '1': self._latex[pos_4 + i][columns] = \ "\\control \\cw \\cwx[-" + str(gap) + "]" gap = 1 else: self._latex[pos_4 + i][columns] = \ "\\controlo \\cw \\cwx[-" + str(gap) + "]" gap = 1 if nm == "ccx": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\ctrl{" + str( pos_3 - pos_2) + "}" self._latex[pos_3][columns] = "\\targ" if nm == "cswap": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\qswap" self._latex[pos_3][columns] = \ "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]" else: temp = [pos_1, pos_2, pos_3] temp.sort(key=int) top = temp[0] bottom = temp[2] for i in range(top, bottom + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(top, bottom + 1): is_occupied[j] = True break prev_column = [x[columns - 1] for x in self._latex] for item, prev_entry in enumerate(prev_column): if 'barrier' in prev_entry: span = re.search('barrier{(.*)}', prev_entry) if span and any(i in temp for i in range( item, int(span.group(1)))): self._latex[item][columns - 1] = \ prev_entry.replace( '\\barrier{', '\\barrier[-0.65em]{') if nm == "ccx": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\ctrl{" + str( pos_3 - pos_2) + "}" self._latex[pos_3][columns] = "\\targ" if nm == "cswap": self._latex[pos_1][columns] = "\\ctrl{" + str( pos_2 - pos_1) + "}" self._latex[pos_2][columns] = "\\qswap" self._latex[pos_3][columns] = \ "\\qswap \\qwx[" + str(pos_2 - pos_3) + "]" elif current_op.name == "measure": if (len(current_op.cargs) != 1 or len(current_op.qargs) != 1 or current_op.op.params): raise exceptions.VisualizationError("bad operation record") if current_op.condition: raise exceptions.VisualizationError( "If controlled measures currently not supported.") qname, qindex = current_op.qargs[0] cname, cindex = current_op.cargs[0] if aliases: newq = aliases[(qname, qindex)] qname = newq[0] qindex = newq[1] pos_1 = self.img_regs[(qname, qindex)] pos_2 = self.img_regs[(cname, cindex)] for i in range(pos_1, pos_2 + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(pos_1, pos_2 + 1): is_occupied[j] = True break try: self._latex[pos_1][columns] = "\\meter" prev_column = [x[columns - 1] for x in self._latex] for item, prev_entry in enumerate(prev_column): if 'barrier' in prev_entry: span = re.search('barrier{(.*)}', prev_entry) if span and (item + int(span.group(1))) - pos_1 >= 0: self._latex[item][columns - 1] = \ prev_entry.replace( '\\barrier{', '\\barrier[-1.15em]{') self._latex[pos_2][columns] = \ "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]" except Exception as e: raise exceptions.VisualizationError( 'Error during Latex building: %s' % str(e)) elif current_op.name in [ 'barrier', 'snapshot', 'load', 'save', 'noise' ]: if self.plot_barriers: qarglist = current_op.qargs indexes = [self._get_qubit_index(x) for x in qarglist] start_bit = self.qubit_list[min(indexes)] if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) start = self.img_regs[start_bit] span = len(current_op.qargs) - 1 for i in range(start, start + span + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(start, start + span + 1): is_occupied[j] = True break self._latex[start][columns] = "\\qw \\barrier{" + str( span) + "}" else: raise exceptions.VisualizationError("bad node data")
def _get_image_depth(self, aliases=None): """Get depth information for the circuit. Args: aliases (dict): dict mapping the current qubits in the circuit to new qubit names. Returns: int: number of columns in the circuit int: total size of columns in the circuit Raises: VisualizationError: if trying to draw unsupported gates """ columns = 2 # wires in the beginning and end is_occupied = [False] * self.img_width max_column_width = {} for op in self.ops: # useful information for determining row spacing boxed_gates = [ 'u0', 'u1', 'u2', 'u3', 'x', 'y', 'z', 'h', 's', 'sdg', 't', 'tdg', 'rx', 'ry', 'rz', 'ch', 'cy', 'crz', 'cu3', 'id' ] target_gates = ['cx', 'ccx'] if op.name in boxed_gates: self.has_box = True if op.name in target_gates: self.has_target = True # useful information for determining column widths and final image # scaling if op.name not in ['measure', 'reset', 'barrier']: qarglist = op.qargs if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) if len(qarglist) == 1: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] if op.condition: mask = self._get_mask(op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg[0] pos_2 = self.img_regs[cl_reg] for i in range(pos_1, pos_2 + self.cregs[if_reg]): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(pos_1, pos_2 + 1): is_occupied[j] = True break else: if is_occupied[pos_1] is False: is_occupied[pos_1] = True else: columns += 1 is_occupied = [False] * self.img_width is_occupied[pos_1] = True elif len(qarglist) == 2: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])] if op.condition: mask = self._get_mask(op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg[0] pos_3 = self.img_regs[(if_reg, 0)] if pos_1 > pos_2: for i in range(pos_2, pos_3 + self.cregs[if_reg]): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(pos_2, pos_3 + 1): is_occupied[j] = True break else: for i in range(pos_1, pos_3 + self.cregs[if_reg]): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(pos_1, pos_3 + 1): is_occupied[j] = True break # symetric gates have angle labels if op.name in ['cu1']: columns += 1 is_occupied = [False] * self.img_width is_occupied[max(pos_1, pos_2)] = True else: temp = [pos_1, pos_2] temp.sort(key=int) top = temp[0] bottom = temp[1] for i in range(top, bottom + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(top, bottom + 1): is_occupied[j] = True break # symetric gates have angle labels if op.name in ['cu1']: columns += 1 is_occupied = [False] * self.img_width is_occupied[top] = True elif len(qarglist) == 3: pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])] pos_3 = self.img_regs[(qarglist[2][0], qarglist[2][1])] if op.condition: mask = self._get_mask(op.condition[0]) cl_reg = self.clbit_list[self._ffs(mask)] if_reg = cl_reg[0] pos_4 = self.img_regs[(if_reg, 0)] temp = [pos_1, pos_2, pos_3, pos_4] temp.sort(key=int) top = temp[0] bottom = temp[2] for i in range(top, pos_4 + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(top, pos_4 + 1): is_occupied[j] = True break else: temp = [pos_1, pos_2, pos_3] temp.sort(key=int) top = temp[0] bottom = temp[2] for i in range(top, bottom + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(top, bottom + 1): is_occupied[j] = True break # update current column width arg_str_len = 0 for arg in op.op.params: arg_str = re.sub(r'[-+]?\d*\.\d{2,}|\d{2,}', _truncate_float, str(arg)) arg_str_len += len(arg_str) if columns not in max_column_width: max_column_width[columns] = 0 max_column_width[columns] = max(arg_str_len, max_column_width[columns]) elif op.name == "measure": if len(op.cargs) != 1 or len(op.qargs) != 1: raise exceptions.VisualizationError("bad operation record") if op.condition: raise exceptions.VisualizationError( 'conditional measures currently not supported.') qname, qindex = op.qargs[0] cname, cindex = op.cargs[0] if aliases: newq = aliases[(qname, qindex)] qname = newq[0] qindex = newq[1] pos_1 = self.img_regs[(qname, qindex)] pos_2 = self.img_regs[(cname, cindex)] temp = [pos_1, pos_2] temp.sort(key=int) [pos_1, pos_2] = temp for i in range(pos_1, pos_2 + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(pos_1, pos_2 + 1): is_occupied[j] = True break # update current column width if columns not in max_column_width: max_column_width[columns] = 0 elif op.name == "reset": if 'conditional' in op and op.condition: raise exceptions.VisualizationError( 'conditional reset currently not supported.') qname, qindex = op.qargs[0] if aliases: newq = aliases[(qname, qindex)] qname = newq[0] qindex = newq[1] pos_1 = self.img_regs[(qname, qindex)] if is_occupied[pos_1] is False: is_occupied[pos_1] = True else: columns += 1 is_occupied = [False] * self.img_width is_occupied[pos_1] = True elif op.name in ["barrier", 'snapshot', 'load', 'save', 'noise']: if self.plot_barriers: qarglist = op.qargs indexes = [self._get_qubit_index(x) for x in qarglist] start_bit = self.qubit_list[min(indexes)] if aliases is not None: qarglist = map(lambda x: aliases[x], qarglist) start = self.img_regs[start_bit] span = len(op.qargs) - 1 for i in range(start, start + span + 1): if is_occupied[i] is False: is_occupied[i] = True else: columns += 1 is_occupied = [False] * self.img_width for j in range(start, start + span + 1): is_occupied[j] = True break # update current column width if columns not in max_column_width: max_column_width[columns] = 0 else: raise exceptions.VisualizationError("bad node data") # every 3 characters is roughly one extra 'unit' of width in the cell # the gate name is 1 extra 'unit' # the qubit/cbit labels plus initial states is 2 more # the wires poking out at the ends is 2 more sum_column_widths = sum(1 + v / 3 for v in max_column_width.values()) return columns + 1, math.ceil(sum_column_widths) + 4