예제 #1
0
 def _registers(self):
     # NOTE: formats of clbit and qubit are different!
     header = self._ast['header']
     self._creg = []
     for e in header['clbit_labels']:
         for i in range(e[1]):
             self._creg.append(Register(name=e[0], index=i))
     if len(self._creg) != header['number_of_clbits']:
         raise _error.VisualizationError('internal error')
     self._qreg = []
     for e in header['qubit_labels']:
         self._qreg.append(Register(name=e[0], index=e[1]))
     if len(self._qreg) != header['number_of_qubits']:
         raise _error.VisualizationError('internal error')
예제 #2
0
 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 _error.VisualizationError("unable to find bit for operation")
     return qindex
예제 #3
0
 def _convert_mask(self, mask):
     orig_clbit_list = []
     for cr in self.orig_cregs:
         for i in range(self.orig_cregs[cr]):
             orig_clbit_list.append((cr, i))
     bit_list = [(mask >> bit) & 1
                 for bit in range(len(orig_clbit_list) - 1, -1, -1)]
     converted_mask_list = [None] * len(bit_list)
     converted_mask = 0
     for pos, bit in enumerate(reversed(bit_list)):
         new_pos = self.clbit_list.index(orig_clbit_list[pos])
         converted_mask_list[new_pos] = bit
     if None in converted_mask_list:
         raise _error.VisualizationError('Reverse mask creation failed')
     converted_mask_list = list(reversed(converted_mask_list))
     for bit in converted_mask_list:
         converted_mask = (converted_mask << 1) | bit
     return converted_mask
예제 #4
0
    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 _, op in enumerate(self.circuit['instructions']):
            if 'conditional' in op:
                mask = int(op['conditional']['mask'], 16)
                if self.reverse_bits:
                    mask = self._convert_mask(mask)
                cl_reg = self.clbit_list[self._ffs(mask)]
                if_reg = cl_reg[0]
                pos_2 = self.img_regs[cl_reg]
                if_value = format(int(op['conditional']['val'], 16),
                                  'b').zfill(self.cregs[if_reg])[::-1]
            if op['name'] not in [
                    'measure', 'barrier', 'snapshot', 'load', 'save', 'noise'
            ]:
                nm = op['name']
                qarglist = [self.qubit_list[i] for i in op['qubits']]
                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 'conditional' in op:
                        mask = int(op['conditional']['mask'], 16)
                        if self.reverse_bits:
                            mask = self._convert_mask(mask)
                        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 == "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)}" % (
                                op["texparams"][0])
                        elif nm == "u1":
                            self._latex[pos_1][columns] = "\\gate{U_1(%s)}" % (
                                op["texparams"][0])
                        elif nm == "u2":
                            self._latex[pos_1][columns] = \
                                "\\gate{U_2\\left(%s,%s\\right)}" % (
                                    op["texparams"][0], op["texparams"][1])
                        elif nm == "u3":
                            self._latex[pos_1][columns] = (
                                "\\gate{U_3(%s,%s,%s)}" %
                                (op["texparams"][0], op["texparams"][1],
                                 op["texparams"][2]))
                        elif nm == "rx":
                            self._latex[pos_1][columns] = "\\gate{R_x(%s)}" % (
                                op["texparams"][0])
                        elif nm == "ry":
                            self._latex[pos_1][columns] = "\\gate{R_y(%s)}" % (
                                op["texparams"][0])
                        elif nm == "rz":
                            self._latex[pos_1][columns] = "\\gate{R_z(%s)}" % (
                                op["texparams"][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 == "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)}" % (
                                op["texparams"][0])
                        elif nm == "u1":
                            self._latex[pos_1][columns] = "\\gate{U_1(%s)}" % (
                                op["texparams"][0])
                        elif nm == "u2":
                            self._latex[pos_1][columns] = \
                                "\\gate{U_2\\left(%s,%s\\right)}" % (
                                    op["texparams"][0], op["texparams"][1])
                        elif nm == "u3":
                            self._latex[pos_1][columns] = (
                                "\\gate{U_3(%s,%s,%s)}" %
                                (op["texparams"][0], op["texparams"][1],
                                 op["texparams"][2]))
                        elif nm == "rx":
                            self._latex[pos_1][columns] = "\\gate{R_x(%s)}" % (
                                op["texparams"][0])
                        elif nm == "ry":
                            self._latex[pos_1][columns] = "\\gate{R_y(%s)}" % (
                                op["texparams"][0])
                        elif nm == "rz":
                            self._latex[pos_1][columns] = "\\gate{R_z(%s)}" % (
                                op["texparams"][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 'conditional' in op:
                        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 op['name'] in ['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)}" % (op["texparams"][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" % (op["texparams"][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)}" % (op["texparams"][0],
                                                           op["texparams"][1],
                                                           op["texparams"][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 op['name'] in ['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)}" % (op["texparams"][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" % (op["texparams"][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)}" %
                                (op["texparams"][0], op["texparams"][1],
                                 op["texparams"][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 'conditional' in op:
                        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 op["name"] == "measure":
                if (len(op['clbits']) != 1 or len(op['qubits']) != 1
                        or 'params' in op):
                    raise _error.VisualizationError("bad operation record")
                if 'conditional' in op:
                    raise _error.VisualizationError(
                        "If controlled measures currently not supported.")
                qname, qindex = self.total_2_register_index(
                    op['qubits'][0], self.qregs)
                cname, cindex = self.total_2_register_index(
                    op['clbits'][0], self.cregs)

                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 _error.VisualizationError(
                        'Error during Latex building: %s' % str(e))
            elif op['name'] in [
                    "barrier", 'snapshot', 'load', 'save', 'noise'
            ]:
                if self.plot_barriers:
                    qarglist = [self.qubit_list[i] for i in op['qubits']]
                    if self.reverse_bits:
                        qarglist = list(reversed(qarglist))
                    if aliases is not None:
                        qarglist = map(lambda x: aliases[x], qarglist)
                    start = self.img_regs[(qarglist[0][0], qarglist[0][1])]
                    span = len(op['qubits']) - 1
                    self._latex[start][columns] += " \\barrier{" + str(
                        span) + "}"
            else:
                raise _error.VisualizationError("bad node data")
예제 #5
0
    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.circuit['instructions']:
            # 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'
            ]
            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 = [self.qubit_list[i] for i in op['qubits']]
                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 'conditional' in op:
                        mask = int(op['conditional']['mask'], 16)
                        if self.reverse_bits:
                            mask = self._convert_mask(mask)
                        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 'conditional' in op:
                        mask = int(op['conditional']['mask'], 16)
                        if self.reverse_bits:
                            mask = self._convert_mask(mask)
                        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 'conditional' in op:
                        mask = int(op['conditional']['mask'], 16)
                        if self.reverse_bits:
                            mask = self._convert_mask(mask)
                        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['texparams']:
                    arg_str = re.sub(r'[-+]?\d*\.\d{2,}|\d{2,}',
                                     _truncate_float, 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['clbits']) != 1 or len(op['qubits']) != 1:
                    raise _error.VisualizationError("bad operation record")
                if 'conditional' in op:
                    raise _error.VisualizationError(
                        'conditional measures currently not supported.')
                qname, qindex = self.total_2_register_index(
                    op['qubits'][0], self.qregs)
                cname, cindex = self.total_2_register_index(
                    op['clbits'][0], self.cregs)
                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:
                    raise _error.VisualizationError(
                        'conditional reset currently not supported.')
                qname, qindex = self.total_2_register_index(
                    op['qubits'][0], self.qregs)
                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'] == "barrier":
                pass
            else:
                raise _error.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
예제 #6
0
    def _draw_ops(self, verbose=False):
        _force_next = 'measure barrier'.split()
        _wide_gate = 'u2 u3 cu2 cu3'.split()
        _barriers = {'coord': [], 'group': []}
        next_ops = self._ops.copy()
        next_ops.pop(0)
        this_anc = 0

        #
        # 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
        #
        for i, (op, op_next) in enumerate(
                itertools.zip_longest(self._ops, next_ops)):
            # wide gate
            if op['name'] in _wide_gate:
                _iswide = True
                gw = 2
            else:
                _iswide = False
                gw = 1
            # get qreg index
            if 'qargs' in op.keys():
                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
            else:
                q_idxs = []
            # get creg index
            if 'cargs' in op.keys():
                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
            else:
                c_idxs = []
            # find empty space to place gate
            if not _barriers['group']:
                this_anc = max([q_anchors[ii].get_index() for ii in q_idxs])
                while True:
                    if op['name'] in _force_next or (
                            'condition' in op.keys() and op['condition']) or \
                            not self._style.compress:
                        occupied = self._qreg_dict.keys()
                    else:
                        occupied = q_idxs
                    q_list = [
                        ii for ii in range(min(occupied),
                                           max(occupied) + 1)
                    ]
                    locs = [
                        q_anchors[jj].is_locatable(this_anc, gw)
                        for jj in q_list
                    ]
                    if all(locs):
                        for ii in q_list:
                            if op['name'] in [
                                    'barrier', 'snapshot', 'load', 'save',
                                    'noise'
                            ] and not self.plot_barriers:
                                q_anchors[ii].set_index(this_anc - 1, gw)
                            else:
                                q_anchors[ii].set_index(this_anc, gw)
                        break
                    else:
                        this_anc += 1
            # qreg coordinate
            q_xy = [q_anchors[ii].plot_coord(this_anc, gw) for ii in q_idxs]
            # creg coordinate
            c_xy = [c_anchors[ii].plot_coord(this_anc, gw) 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])

            if verbose:
                print(i, op)

            # rotation parameter
            if 'op' in op.keys() and hasattr(op['op'], 'param'):
                param = self.param_parse(op['op'].param, self._style.pimode)
            else:
                param = None
            # conditional gate
            if 'condition' in op.keys() and op['condition']:
                c_xy = [
                    c_anchors[ii].plot_coord(this_anc, gw)
                    for ii in self._creg_dict
                ]
                mask = 0
                for index, cbit in enumerate(self._creg):
                    if cbit.name == 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'
            ]:
                q_group = self._qreg_dict[q_idxs[0]]['group']
                if q_group not in _barriers['group']:
                    _barriers['group'].append(q_group)
                _barriers['coord'].append(q_xy[0])
                if op_next and op_next['name'] == 'barrier':
                    continue
                else:
                    if self.plot_barriers:
                        self._barrier(_barriers, this_anc)
                    _barriers['group'].clear()
                    _barriers['coord'].clear()
            #
            # draw single qubit gates
            #
            elif len(q_xy) == 1:
                disp = op['name']
                if param:
                    self._gate(q_xy[0],
                               wide=_iswide,
                               text=disp,
                               subtext='{}'.format(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'] in ['cx']:
                    self._ctrl_qubit(q_xy[0])
                    self._tgt_qubit(q_xy[1])
                # 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)
                # 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)
                # cu1 for latexmode
                elif op['name'] in ['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))
                # 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)
            #
            # 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])
                # 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)
            else:
                logger.critical('Invalid gate %s', op)
                raise _error.VisualizationError('invalid gate {}'.format(op))
        #
        # adjust window size and draw horizontal lines
        #
        max_anc = max([q_anchors[ii].get_index() for ii in self._qreg_dict])
        n_fold = (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,
                   basis=None,
                   scale=0.7,
                   filename=None,
                   style=None,
                   output=None,
                   interactive=False,
                   line_length=None):
    """Draw a quantum circuit to different formats (set by output parameter):
    0. text: ASCII art string
    1. latex: high-quality images, but heavy external software dependencies
    2. matplotlib: purely in Python with no external dependencies

    Defaults to an overcomplete basis, in order to not alter gates.

    Args:
        circuit (QuantumCircuit): the quantum circuit to draw
        basis (str): the basis to unroll to prior to drawing. Defaults to
            `"id,u0,u1,u2,u3,x,y,z,h,s,sdg,t,tdg,rx,ry,rz,cx,cy,cz,ch,crz,cu1,
            cu3,swap,ccx,cswap"` This option is deprecated and will be removed
            in the future.
        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`. 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
            (cannot inline in Jupyter). Note when used with the latex_source
            output type this has no effect
        line_length (int): sets the length of the lines generated by `text`
    Returns:
        PIL.Image: (outputs `latex` and `python`) an in-memory representation of
                   the circuit diagram.
        String: (outputs `text` and `latex_source`). The ascii art or the LaTeX
                source code.
    Raises:
        VisualizationError: when an invalid output method is selected

    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)
        plotbarrier (bool): Enable/disable drawing barriers in the output
            circuit. Defaults to True.
        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)
        reversebits (bool): When set to True reverse the bit order inside
            registers for the output visualization.

    """
    if basis is None:
        basis = ("id,u0,u1,u2,u3,x,y,z,h,s,sdg,t,tdg,rx,ry,rz,"
                 "cx,cy,cz,ch,crz,cu1,cu3,swap,ccx,cswap")
    else:
        warnings.warn('The basis kwarg is deprecated and the circuit drawer '
                      'function will not be able to adjust basis gates itself '
                      'in a future release', DeprecationWarning)

    im = None
    if not output:
        warnings.warn('The current behavior for the default output will change'
                      ' in a future release. Instead of trying latex and '
                      'falling back to mpl on failure it will just use '
                      '"text" by default', DeprecationWarning)
        try:
            im = _latex_circuit_drawer(circuit, basis, scale, filename, style)
        except (OSError, subprocess.CalledProcessError, FileNotFoundError):
            im = _matplotlib_circuit_drawer(circuit, basis, scale, filename,
                                            style)
    else:
        if output == 'text':
            reversebits = style['reversebits'] if style and 'reversebits' in style else False
            plotbarriers = style['plotbarriers'] if style and 'plotbarriers' in style else True

            return _text_circuit_drawer(circuit, filename=filename, basis=basis,
                                        line_length=line_length,
                                        reversebits=reversebits, plotbarriers=plotbarriers)
        elif output == 'latex':
            im = _latex_circuit_drawer(circuit, basis=basis, scale=scale,
                                       filename=filename, style=style)
        elif output == 'latex_source':
            return _generate_latex_source(circuit, basis=basis,
                                          filename=filename, scale=scale,
                                          style=style)
        elif output == 'mpl':
            im = _matplotlib_circuit_drawer(circuit, basis=basis, scale=scale,
                                            filename=filename, style=style)
        else:
            raise _error.VisualizationError(
                'Invalid output type %s selected. The only valid choices '
                'are latex, latex_source, text, and mpl' % output)
    if im and interactive:
        im.show()
    return im
def circuit_drawer(circuit,
                   scale=0.7,
                   filename=None,
                   style=None,
                   output=None,
                   interactive=False,
                   line_length=None,
                   plot_barriers=True,
                   reverse_bits=False):
    """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
            (cannot inline in Jupyter). Note when used with the latex_source
            output type this has no effect.
        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.

    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)
        plotbarrier (bool): Enable/disable drawing barriers in the output
            circuit. Defaults to True. This is deprecated in the style dict
            and will be removed in a future release. Use the `plot_barriers`
            kwarg instead.
        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)
        reversebits (bool): When set to True reverse the bit order inside
            registers for the output visualization. This is deprecated in the
            style dict and will be removed in a future release use the
            `reverse_bits` kwarg instead.

    """
    image = None
    if style:
        if 'reversebits' in style:
            warnings.warn(
                'The reversebits key in style is deprecated and will'
                'not work in the future. Instead use the '
                '``reverse_bits`` kwarg.', DeprecationWarning)
            reverse_bits = style.get('reversebits')
        if 'plotbarrier' in style:
            warnings.warn(
                'The plotbarrier key in style is deprecated and will'
                'not work in the future. Instead use the '
                '``plot_barriers`` kwarg.', DeprecationWarning)
            plot_barriers = style.get('plotbarrier')

    if not output:
        warnings.warn(
            'The current behavior for the default output will change'
            ' in a future release. Instead of trying latex and '
            'falling back to mpl on failure it will just use '
            '"text" by default', DeprecationWarning)
        try:
            image = _latex_circuit_drawer(circuit, scale, filename, style)
        except (OSError, subprocess.CalledProcessError, FileNotFoundError):
            if _matplotlib.HAS_MATPLOTLIB:
                image = _matplotlib_circuit_drawer(circuit, scale, filename,
                                                   style)
            else:
                raise ImportError('The default output needs matplotlib. '
                                  'Run "pip install matplotlib" before.')
    else:
        if output == 'text':
            return _text_circuit_drawer(circuit,
                                        filename=filename,
                                        line_length=line_length,
                                        reversebits=reverse_bits,
                                        plotbarriers=plot_barriers)
        elif output == 'latex':
            image = _latex_circuit_drawer(circuit,
                                          scale=scale,
                                          filename=filename,
                                          style=style,
                                          plot_barriers=plot_barriers,
                                          reverse_bits=reverse_bits)
        elif output == 'latex_source':
            return _generate_latex_source(circuit,
                                          filename=filename,
                                          scale=scale,
                                          style=style,
                                          plot_barriers=plot_barriers,
                                          reverse_bits=reverse_bits)
        elif output == 'mpl':
            image = _matplotlib_circuit_drawer(circuit,
                                               scale=scale,
                                               filename=filename,
                                               style=style,
                                               plot_barriers=plot_barriers,
                                               reverse_bits=reverse_bits)
        else:
            raise _error.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