diff --git a/qiskit/compiler/transpiler.py b/qiskit/compiler/transpiler.py index 7a8c64b71170..a8849669d317 100644 --- a/qiskit/compiler/transpiler.py +++ b/qiskit/compiler/transpiler.py @@ -589,7 +589,7 @@ def _layout_from_raw(initial_layout, circuit): if all(isinstanceint(elem) for elem in initial_layout): initial_layout = Layout.from_intlist(initial_layout, *circuit.qregs) elif all(elem is None or isinstance(elem, Qubit) for elem in initial_layout): - initial_layout = Layout.from_qubit_list(initial_layout) + initial_layout = Layout.from_qubit_list(initial_layout, *circuit.qregs) elif isinstance(initial_layout, dict): initial_layout = Layout(initial_layout) else: diff --git a/qiskit/transpiler/basepasses.py b/qiskit/transpiler/basepasses.py index 2ffc84516028..52361e6ccc9a 100644 --- a/qiskit/transpiler/basepasses.py +++ b/qiskit/transpiler/basepasses.py @@ -128,9 +128,10 @@ def __call__(self, circuit, property_set=None): if isinstance(result, DAGCircuit): result_circuit = dag_to_circuit(result) - - if result is None and self.property_set['layout']: + elif result is None: result_circuit = circuit.copy() + + if self.property_set['layout']: result_circuit._layout = self.property_set['layout'] return result_circuit diff --git a/qiskit/transpiler/layout.py b/qiskit/transpiler/layout.py index a1236da35628..c64bf73e1240 100644 --- a/qiskit/transpiler/layout.py +++ b/qiskit/transpiler/layout.py @@ -29,6 +29,7 @@ class Layout(): def __init__(self, input_dict=None): """construct a Layout from a bijective dictionary, mapping virtual qubits to physical qubits""" + self._regs = [] self._p2v = {} self._v2p = {} if input_dict is not None: @@ -101,6 +102,9 @@ def __getitem__(self, item): return self._v2p[item] raise KeyError('The item %s does not exist in the Layout' % (item,)) + def __contains__(self, item): + return item in self._p2v or item in self._v2p + def __setitem__(self, key, value): virtual, physical = Layout.order_based_on_type(key, value) self._set_type_checked_item(virtual, physical) @@ -138,6 +142,7 @@ def copy(self): """Returns a copy of a Layout instance.""" layout_copy = type(self)() + layout_copy._regs = self._regs.copy() layout_copy._p2v = self._p2v.copy() layout_copy._v2p = self._v2p.copy() @@ -166,16 +171,18 @@ def add_register(self, reg): Args: reg (Register): A (qu)bit Register. For example, QuantumRegister(3, 'qr'). """ + self._regs.append(reg) for bit in reg: - self.add(bit) + if bit not in self: + self.add(bit) def get_registers(self): """ Returns the registers in the layout [QuantumRegister(2, 'qr0'), QuantumRegister(3, 'qr1')] Returns: - List: A list of Register in the layout + Set: A set of Registers in the layout """ - return {bit.register for bit in self.get_virtual_bits()} + return set(self._regs) def get_virtual_bits(self): """ @@ -302,13 +309,14 @@ def from_intlist(int_list, *qregs): for idx in range(qreg.size): out[qreg[idx]] = int_list[main_idx] main_idx += 1 + out.add_register(qreg) if main_idx != len(int_list): for int_item in int_list[main_idx:]: out[int_item] = None return out @staticmethod - def from_qubit_list(qubit_list): + def from_qubit_list(qubit_list, *qregs): """ Populates a Layout from a list containing virtual qubits, Qubit or None. @@ -316,6 +324,8 @@ def from_qubit_list(qubit_list): Args: qubit_list (list): e.g.: [qr[0], None, qr[2], qr[3]] + *qregs (QuantumRegisters): The quantum registers to apply + the layout to. Returns: Layout: the corresponding Layout object Raises: @@ -331,4 +341,6 @@ def from_qubit_list(qubit_list): out[virtual] = physical else: raise LayoutError("The list should contain elements of the Bits or NoneTypes") + for qreg in qregs: + out.add_register(qreg) return out diff --git a/qiskit/transpiler/passes/layout/apply_layout.py b/qiskit/transpiler/passes/layout/apply_layout.py index f510880a310e..f89f3709f14b 100644 --- a/qiskit/transpiler/passes/layout/apply_layout.py +++ b/qiskit/transpiler/passes/layout/apply_layout.py @@ -47,6 +47,9 @@ def run(self, dag): raise TranspilerError( "The 'layout' must be full (with ancilla).") + for qreg in dag.qregs.values(): + self.property_set["layout"].add_register(qreg) + q = QuantumRegister(len(layout), 'q') new_dag = DAGCircuit() diff --git a/qiskit/transpiler/passes/layout/csp_layout.py b/qiskit/transpiler/passes/layout/csp_layout.py index d4416276659b..001d1edb752c 100644 --- a/qiskit/transpiler/passes/layout/csp_layout.py +++ b/qiskit/transpiler/passes/layout/csp_layout.py @@ -144,5 +144,7 @@ def constraint(control, target): else: stop_reason = 'solution found' self.property_set['layout'] = Layout({v: qubits[k] for k, v in solution.items()}) + for reg in dag.qregs.values(): + self.property_set['layout'].add_register(reg) self.property_set['CSPLayout_stop_reason'] = stop_reason diff --git a/qiskit/transpiler/passes/layout/dense_layout.py b/qiskit/transpiler/passes/layout/dense_layout.py index d8d5f6f8fa9e..9dea91f356e6 100644 --- a/qiskit/transpiler/passes/layout/dense_layout.py +++ b/qiskit/transpiler/passes/layout/dense_layout.py @@ -111,6 +111,7 @@ def run(self, dag): for i in range(qreg.size): layout[qreg[i]] = int(best_sub[map_iter]) map_iter += 1 + layout.add_register(qreg) self.property_set['layout'] = layout def _best_subset(self, num_qubits): diff --git a/qiskit/transpiler/passes/layout/enlarge_with_ancilla.py b/qiskit/transpiler/passes/layout/enlarge_with_ancilla.py index 1644d6cdde40..7e2f03fa1a95 100644 --- a/qiskit/transpiler/passes/layout/enlarge_with_ancilla.py +++ b/qiskit/transpiler/passes/layout/enlarge_with_ancilla.py @@ -41,8 +41,10 @@ def run(self, dag): if layout is None: raise TranspilerError('EnlargeWithAncilla requires property_set["layout"]') - new_qreg = self.property_set['layout_ancilla_register'] - if new_qreg: - dag.add_qreg(new_qreg) + new_qregs = {reg for reg in layout.get_registers() + if reg not in dag.qregs.values()} + + for qreg in new_qregs: + dag.add_qreg(qreg) return dag diff --git a/qiskit/transpiler/passes/layout/full_ancilla_allocation.py b/qiskit/transpiler/passes/layout/full_ancilla_allocation.py index af7ec3c1aa3f..afdd5167a925 100644 --- a/qiskit/transpiler/passes/layout/full_ancilla_allocation.py +++ b/qiskit/transpiler/passes/layout/full_ancilla_allocation.py @@ -87,10 +87,9 @@ def run(self, dag): else: qreg = QuantumRegister(len(idle_physical_qubits), name=self.ancilla_name) - self.property_set['layout_ancilla_register'] = qreg for idx, idle_q in enumerate(idle_physical_qubits): self.property_set['layout'][idle_q] = qreg[idx] - + self.property_set['layout'].add_register(qreg) return dag @staticmethod diff --git a/qiskit/transpiler/passes/layout/noise_adaptive_layout.py b/qiskit/transpiler/passes/layout/noise_adaptive_layout.py index cd9b6a7cf393..8278eb0906ce 100644 --- a/qiskit/transpiler/passes/layout/noise_adaptive_layout.py +++ b/qiskit/transpiler/passes/layout/noise_adaptive_layout.py @@ -275,4 +275,6 @@ def run(self, dag): pid = self._qarg_to_id(q) hwid = self.prog2hw[pid] layout[q] = hwid + for qreg in dag.qregs.values(): + layout.add_register(qreg) self.property_set['layout'] = layout diff --git a/qiskit/transpiler/passes/layout/sabre_layout.py b/qiskit/transpiler/passes/layout/sabre_layout.py index ef7e29c9292a..3e03f025e95a 100644 --- a/qiskit/transpiler/passes/layout/sabre_layout.py +++ b/qiskit/transpiler/passes/layout/sabre_layout.py @@ -113,6 +113,9 @@ def run(self, dag): logger.info('new initial layout') logger.info(initial_layout) + for qreg in dag.qregs.values(): + initial_layout.add_register(qreg) + self.property_set['layout'] = initial_layout def _layout_and_route_passmanager(self, initial_layout): diff --git a/qiskit/transpiler/passes/layout/trivial_layout.py b/qiskit/transpiler/passes/layout/trivial_layout.py index b9c50d22d9b6..c874802dafb4 100644 --- a/qiskit/transpiler/passes/layout/trivial_layout.py +++ b/qiskit/transpiler/passes/layout/trivial_layout.py @@ -52,4 +52,5 @@ def run(self, dag): """ if dag.num_qubits() > self.coupling_map.size(): raise TranspilerError('Number of qubits greater than device.') - self.property_set['layout'] = Layout.generate_trivial_layout(*dag.qubits) + self.property_set['layout'] = Layout.generate_trivial_layout( + *(dag.qubits + list(dag.qregs.values()))) diff --git a/qiskit/visualization/circuit_visualization.py b/qiskit/visualization/circuit_visualization.py index facfdfc00692..e953a7b2c566 100644 --- a/qiskit/visualization/circuit_visualization.py +++ b/qiskit/visualization/circuit_visualization.py @@ -278,19 +278,21 @@ def _text_circuit_drawer(circuit, filename=None, reverse_bits=False, Returns: TextDrawing: An instance that, when printed, draws the circuit in ascii art. """ - qregs, cregs, ops = utils._get_layered_instructions(circuit, - reverse_bits=reverse_bits, - justify=justify, - idle_wires=idle_wires) + qubits, clbits, ops = utils._get_layered_instructions(circuit, + reverse_bits=reverse_bits, + justify=justify, + idle_wires=idle_wires) if with_layout: layout = circuit._layout else: layout = None global_phase = circuit.global_phase if hasattr(circuit, 'global_phase') else None - text_drawing = _text.TextDrawing(qregs, cregs, ops, layout=layout, initial_state=initial_state, + text_drawing = _text.TextDrawing(qubits, clbits, ops, layout=layout, + initial_state=initial_state, cregbundle=cregbundle, global_phase=global_phase, - encoding=encoding) + encoding=encoding, + qregs=circuit.qregs, cregs=circuit.cregs) text_drawing.plotbarriers = plot_barriers text_drawing.line_length = fold text_drawing.vertical_compression = vertical_compression @@ -424,20 +426,21 @@ def _generate_latex_source(circuit, filename=None, Returns: str: Latex string appropriate for writing to file. """ - qregs, cregs, ops = utils._get_layered_instructions(circuit, - reverse_bits=reverse_bits, - justify=justify, idle_wires=idle_wires) + qubits, clbits, ops = utils._get_layered_instructions(circuit, + reverse_bits=reverse_bits, + justify=justify, idle_wires=idle_wires) if with_layout: layout = circuit._layout else: layout = None global_phase = circuit.global_phase if hasattr(circuit, 'global_phase') else None - qcimg = _latex.QCircuitImage(qregs, cregs, ops, scale, reverse_bits=reverse_bits, + qcimg = _latex.QCircuitImage(qubits, clbits, ops, scale, reverse_bits=reverse_bits, plot_barriers=plot_barriers, layout=layout, initial_state=initial_state, cregbundle=cregbundle, - global_phase=global_phase) + global_phase=global_phase, + qregs=circuit.qregs, cregs=circuit.cregs) latex = qcimg.latex() if filename: with open(filename, 'w') as latex_file: @@ -498,10 +501,10 @@ def _matplotlib_circuit_drawer(circuit, if the ``ax`` kwarg is not set. """ - qregs, cregs, ops = utils._get_layered_instructions(circuit, - reverse_bits=reverse_bits, - justify=justify, - idle_wires=idle_wires) + qubits, clbits, ops = utils._get_layered_instructions(circuit, + reverse_bits=reverse_bits, + justify=justify, + idle_wires=idle_wires) if with_layout: layout = circuit._layout else: @@ -511,8 +514,9 @@ def _matplotlib_circuit_drawer(circuit, fold = 25 global_phase = circuit.global_phase if hasattr(circuit, 'global_phase') else None - qcd = _matplotlib.MatplotlibDrawer(qregs, cregs, ops, scale=scale, style=style, + qcd = _matplotlib.MatplotlibDrawer(qubits, clbits, ops, scale=scale, style=style, plot_barriers=plot_barriers, layout=layout, fold=fold, ax=ax, initial_state=initial_state, - cregbundle=cregbundle, global_phase=global_phase) + cregbundle=cregbundle, global_phase=global_phase, + qregs=circuit.qregs, cregs=circuit.cregs) return qcd.draw(filename) diff --git a/qiskit/visualization/latex.py b/qiskit/visualization/latex.py index e322182a054e..b1daa9206e4f 100644 --- a/qiskit/visualization/latex.py +++ b/qiskit/visualization/latex.py @@ -39,7 +39,7 @@ class QCircuitImage: def __init__(self, qubits, clbits, ops, scale, reverse_bits=False, plot_barriers=True, layout=None, initial_state=False, - cregbundle=False, global_phase=None): + cregbundle=False, global_phase=None, qregs=None, cregs=None): """QCircuitImage initializer. Args: @@ -47,7 +47,7 @@ def __init__(self, qubits, clbits, ops, scale, reverse_bits=False, clbits (list[Clbit]): list of clbits ops (list[list[DAGNode]]): list of circuit instructions, grouped by layer scale (float): image scaling - reverse_bits: when True, reverse the bit ordering of the registers + reverse_bits (bool): when True, reverse the bit ordering of the registers plot_barriers (bool): Enable/disable drawing barriers in the output circuit. Defaults to True. layout (Layout or None): If present, the layout information will be @@ -55,6 +55,8 @@ def __init__(self, qubits, clbits, ops, scale, reverse_bits=False, initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `False`. cregbundle (bool): Optional. If set True bundle classical registers. Default: `False`. global_phase (float): Optional, the global phase for the circuit. + qregs (list): List qregs present in the circuit. + cregs (list): List of cregs present in the circuit. Raises: ImportError: If pylatexenc is not installed """ @@ -70,8 +72,9 @@ def __init__(self, qubits, clbits, ops, scale, reverse_bits=False, # Map of cregs to sizes self.cregs = {} - # List of qregs and cregs in order of appearance in code and image - self.ordered_regs = [] + # List of qubits and cbits in order of appearance in code and image + # May also include ClassicalRegisters if cregbundle=True + self.ordered_bits = [] # Map from registers to the list they appear in the image self.img_regs = {} @@ -107,10 +110,19 @@ def __init__(self, qubits, clbits, ops, scale, reverse_bits=False, ################################# self.qubit_list = qubits - self.ordered_regs = qubits + clbits + self.ordered_bits = qubits + clbits self.cregs, self.cregs_bits = self._get_register_specs(clbits) + + self.bit_locations = { + bit: {'register': register, 'index': index} + for register in cregs + qregs + for index, bit in enumerate(register)} + for index, bit in list(enumerate(qubits)) + list(enumerate(clbits)): + if bit not in self.bit_locations: + self.bit_locations[bit] = {'register': None, 'index': index} + self.img_regs = {bit: ind for ind, bit in - enumerate(self.ordered_regs)} + enumerate(self.ordered_bits)} if cregbundle: self.img_width = len(qubits) + len(self.cregs) else: @@ -182,38 +194,52 @@ def _initialize_latex_array(self): else: self.wire_separation = 1.0 self._latex = [ - ["\\cw" if isinstance(self.ordered_regs[j], Clbit) + ["\\cw" if isinstance(self.ordered_bits[j], Clbit) else "\\qw" for _ in range(self.img_depth + 1)] for j in range(self.img_width)] self._latex.append([" "] * (self.img_depth + 1)) if self.cregbundle: offset = 0 for i in range(self.img_width): - if isinstance(self.ordered_regs[i], Clbit): + if isinstance(self.ordered_bits[i], Clbit): if self.cregbundle: + reg = self.bit_locations[self.ordered_bits[i + offset]]['register'] self._latex[i][0] = \ - "\\lstick{" + self.ordered_regs[i + offset].register.name + ":" - clbitsize = self.cregs[self.ordered_regs[i + offset].register] + "\\lstick{" + reg.name + ":" + clbitsize = self.cregs[reg] self._latex[i][1] = "\\lstick{/_{_{" + str(clbitsize) + "}}} \\cw" offset += clbitsize - 1 else: - self._latex[i][0] = "\\lstick{" + self.ordered_regs[i].register.name + \ - "_{" + str(self.ordered_regs[i].index) + "}:" + self._latex[i][0] = ( + "\\lstick{" + + self.bit_locations[self.ordered_bits[i]]['register'].name + + "_{" + str(self.bit_locations[self.ordered_bits[i]]['index']) + "}:" + ) if self.initial_state: self._latex[i][0] += "0" self._latex[i][0] += "}" else: if self.layout is None: label = "\\lstick{{ {{{}}}_{{{}}} : ".format( - self.ordered_regs[i].register.name, self.ordered_regs[i].index) + self.bit_locations[self.ordered_bits[i]]['register'].name, + self.bit_locations[self.ordered_bits[i]]['index']) else: - if self.layout[self.ordered_regs[i].index]: - label = "\\lstick{{ {{{}}}_{{{}}}\\mapsto{{{}}} : ".format( - self.layout[self.ordered_regs[i].index].register.name, - self.layout[self.ordered_regs[i].index].index, - self.ordered_regs[i].index) + bit_location = self.bit_locations[self.ordered_bits[i]] + if bit_location and self.layout[bit_location['index']]: + virt_bit = self.layout[bit_location['index']] + try: + virt_reg = next(reg for reg in self.layout.get_registers() + if virt_bit in reg) + label = "\\lstick{{ {{{}}}_{{{}}}\\mapsto{{{}}} : ".format( + virt_reg.name, + virt_reg[:].index(virt_bit), + bit_location['index']) + except StopIteration: + label = "\\lstick{{ {{{}}} : ".format( + bit_location['index']) else: - label = "\\lstick{{ {{{}}} : ".format(self.ordered_regs[i].index) + label = "\\lstick{{ {{{}}} : ".format( + bit_location['index']) if self.initial_state: label += "\\ket{{0}}" label += " }" @@ -279,9 +305,9 @@ def _get_image_depth(self): sum_column_widths = sum(1 + v / 3 for v in max_column_widths) max_reg_name = 3 - for reg in self.ordered_regs: + for reg in self.ordered_bits: max_reg_name = max(max_reg_name, - len(reg.register.name)) + len(self.bit_locations[reg]['register'].name)) sum_column_widths += 5 + max_reg_name / 3 # could be a fraction so ceil diff --git a/qiskit/visualization/matplotlib.py b/qiskit/visualization/matplotlib.py index 9200efe2fc0c..23ce20143651 100644 --- a/qiskit/visualization/matplotlib.py +++ b/qiskit/visualization/matplotlib.py @@ -112,10 +112,10 @@ class MatplotlibDrawer: _mathmode_regex = re.compile(r"(? 1: + for ii, reg in enumerate(self._qubit): + register = self._bit_locations[reg]['register'] + index = self._bit_locations[reg]['index'] + + if len(self._qubit) > 1: if self._layout is None: - qreg_name = '${{{name}}}_{{{index}}}$'.format(name=reg.register.name, - index=reg.index) + qubit_name = '${{{name}}}_{{{index}}}$'.format(name=register.name, + index=index) else: - if self._layout[reg.index]: - qreg_name = '${{{name}}}_{{{index}}} \\mapsto {{{physical}}}$'.format( - name=self._layout[reg.index].register.name, - index=self._layout[reg.index].index, physical=reg.index) + if self._layout[index]: + virt_bit = self._layout[index] + try: + virt_reg = next(reg for reg in self._layout.get_registers() + if virt_bit in reg) + qubit_name = '${{{name}}}_{{{index}}} \\mapsto {{{physical}}}$'.format( + name=virt_reg.name, + index=virt_reg[:].index(virt_bit), + physical=index) + + except StopIteration: + qubit_name = '${{{name}}} \\mapsto {{{physical}}}$'.format( + name=virt_bit, + physical=index) else: - qreg_name = '${{{physical}}}$'.format(physical=reg.index) + qubit_name = '${{{physical}}}$'.format(physical=index) else: - qreg_name = '{name}'.format(name=reg.register.name) - qreg_name = _fix_double_script(qreg_name) + initial_qbit - text_width = self._get_text_width(qreg_name, fs) * 1.15 + qubit_name = '{name}'.format(name=register.name) + qubit_name = _fix_double_script(qubit_name) + initial_qbit + text_width = self._get_text_width(qubit_name, fs) * 1.15 if text_width > longest_reg_name_width: longest_reg_name_width = text_width pos = -ii - self._qreg_dict[ii] = { - 'y': pos, 'reg_name': qreg_name, 'index': reg.index, 'group': reg.register} + self._qubit_dict[ii] = { + 'y': pos, 'reg_name': qubit_name, 'index': index, 'group': register} self._n_lines += 1 # classical register - if self._creg: - n_creg = self._creg.copy() - n_creg.pop(0) + if self._clbit: + n_clbit = self._clbit.copy() + n_clbit.pop(0) idx = 0 - y_off = -len(self._qreg) - for ii, (reg, nreg) in enumerate(itertools.zip_longest(self._creg, n_creg)): + y_off = -len(self._qubit) + for ii, (reg, nreg) in enumerate(itertools.zip_longest(self._clbit, n_clbit)): pos = y_off - idx + register = self._bit_locations[reg]['register'] + index = self._bit_locations[reg]['index'] + if self._cregbundle: - creg_name = '{}'.format(reg.register.name) - creg_name = _fix_double_script(creg_name) + initial_cbit - text_width = self._get_text_width(reg.register.name, fs) * 1.15 + clbit_name = '{}'.format(register.name) + clbit_name = _fix_double_script(clbit_name) + initial_cbit + text_width = self._get_text_width(register.name, fs) * 1.15 if text_width > longest_reg_name_width: longest_reg_name_width = text_width - self._creg_dict[ii] = {'y': pos, 'reg_name': creg_name, 'index': reg.index, - 'group': reg.register} - if not (not nreg or reg.register != nreg.register): + self._clbit_dict[ii] = {'y': pos, 'reg_name': clbit_name, 'index': index, + 'group': register} + if not (not nreg or register != self._bit_locations[nreg]['register']): continue else: - creg_name = '${}_{{{}}}$'.format(reg.register.name, reg.index) - creg_name = _fix_double_script(creg_name) + initial_cbit - text_width = self._get_text_width(reg.register.name, fs) * 1.15 + clbit_name = '${}_{{{}}}$'.format(register.name, index) + clbit_name = _fix_double_script(clbit_name) + initial_cbit + text_width = self._get_text_width(register.name, fs) * 1.15 if text_width > longest_reg_name_width: longest_reg_name_width = text_width - self._creg_dict[ii] = {'y': pos, 'reg_name': creg_name, 'index': reg.index, - 'group': reg.register} + self._clbit_dict[ii] = {'y': pos, 'reg_name': clbit_name, 'index': index, + 'group': register} self._n_lines += 1 idx += 1 @@ -717,33 +741,33 @@ def _fix_double_script(reg_name): def _draw_regs_sub(self, n_fold, feedline_l=False, feedline_r=False): # quantum register fs = self._style['fs'] - for qreg in self._qreg_dict.values(): - qreg_name = qreg['reg_name'] - y = qreg['y'] - n_fold * (self._n_lines + 1) - self._ax.text(self._x_offset - 0.2, y, qreg_name, ha='right', va='center', + for qubit in self._qubit_dict.values(): + qubit_name = qubit['reg_name'] + y = qubit['y'] - n_fold * (self._n_lines + 1) + self._ax.text(self._x_offset - 0.2, y, qubit_name, ha='right', va='center', fontsize=1.25 * fs, color=self._style['tc'], clip_on=True, zorder=PORDER_TEXT) self._line([self._x_offset, y], [self._xmax, y], zorder=PORDER_REGLINE) # classical register - this_creg_dict = {} - for creg in self._creg_dict.values(): - creg_name = creg['reg_name'] - y = creg['y'] - n_fold * (self._n_lines + 1) - if y not in this_creg_dict.keys(): - this_creg_dict[y] = {'val': 1, 'reg_name': creg_name} + this_clbit_dict = {} + for clbit in self._clbit_dict.values(): + clbit_name = clbit['reg_name'] + y = clbit['y'] - n_fold * (self._n_lines + 1) + if y not in this_clbit_dict.keys(): + this_clbit_dict[y] = {'val': 1, 'reg_name': clbit_name} else: - this_creg_dict[y]['val'] += 1 - for y, this_creg in this_creg_dict.items(): + this_clbit_dict[y]['val'] += 1 + for y, this_clbit in this_clbit_dict.items(): # cregbundle - if this_creg['val'] > 1: + if this_clbit['val'] > 1: self._ax.plot([self._x_offset + 0.2, self._x_offset + 0.3], [y - 0.1, y + 0.1], color=self._style['cc'], zorder=PORDER_LINE) - self._ax.text(self._x_offset + 0.1, y + 0.1, str(this_creg['val']), ha='left', + self._ax.text(self._x_offset + 0.1, y + 0.1, str(this_clbit['val']), ha='left', va='bottom', fontsize=0.8 * fs, color=self._style['tc'], clip_on=True, zorder=PORDER_TEXT) - self._ax.text(self._x_offset - 0.2, y, this_creg['reg_name'], ha='right', va='center', + self._ax.text(self._x_offset - 0.2, y, this_clbit['reg_name'], ha='right', va='center', fontsize=1.25 * fs, color=self._style['tc'], clip_on=True, zorder=PORDER_TEXT) self._line([self._x_offset, y], [self._xmax, y], lc=self._style['cc'], @@ -772,13 +796,13 @@ def _draw_ops(self, verbose=False): # generate coordinate manager # q_anchors = {} - for key, qreg in self._qreg_dict.items(): + for key, qubit in self._qubit_dict.items(): q_anchors[key] = Anchor(reg_num=self._n_lines, - yind=qreg['y'], fold=self._fold) + yind=qubit['y'], fold=self._fold) c_anchors = {} - for key, creg in self._creg_dict.items(): + for key, clbit in self._clbit_dict.items(): c_anchors[key] = Anchor(reg_num=self._n_lines, - yind=creg['y'], fold=self._fold) + yind=clbit['y'], fold=self._fold) # # draw the ops # @@ -850,21 +874,21 @@ def _draw_ops(self, verbose=False): gate_text, ctrl_text = self._get_gate_ctrl_text(op) fc, ec, gt, tc, sc, lc = self._get_colors(op) - # get qreg index + # get qubit 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): + for index, reg in self._qubit_dict.items(): + if (reg['group'] == self._bit_locations[qarg]['register'] and + reg['index'] == self._bit_locations[qarg]['index']): q_idxs.append(index) break - # get creg index + # get clbit 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): + for index, reg in self._clbit_dict.items(): + if (reg['group'] == self._bit_locations[carg]['register'] and + reg['index'] == self._bit_locations[carg]['index']): c_idxs.append(index) break @@ -875,15 +899,15 @@ def _draw_ops(self, verbose=False): for ii in q_idxs: q_anchors[ii].set_index(this_anc, layer_width) - # qreg coordinate + # qubit coordinate q_xy = [q_anchors[ii].plot_coord(this_anc, layer_width, self._x_offset) for ii in q_idxs] - # creg coordinate + # clbit 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]) + # bottom and top point of qubit + qubit_b = min(q_xy, key=lambda xy: xy[1]) + qubit_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 @@ -901,10 +925,10 @@ def _draw_ops(self, verbose=False): # 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] + ii in self._clbit_dict] mask = 0 - for index, cbit in enumerate(self._creg): - if cbit.register == op.condition[0]: + for index, cbit in enumerate(self._clbit): + if self._bit_locations[cbit]['register'] == op.condition[0]: mask |= (1 << index) val = op.condition[1] # cbit list to consider @@ -925,24 +949,24 @@ def _draw_ops(self, verbose=False): self._conditional(xy, istrue=False) xy_plot.append(xy) v_ind += 1 - creg_b = sorted(xy_plot, key=lambda xy: xy[1])[0] - xpos, ypos = creg_b + clbit_b = sorted(xy_plot, key=lambda xy: xy[1])[0] + xpos, ypos = clbit_b self._ax.text(xpos, ypos - 0.3 * HIG, hex(val), ha='center', va='top', fontsize=sfs, color=self._style['tc'], clip_on=True, zorder=PORDER_TEXT) - self._line(qreg_t, creg_b, lc=self._style['cc'], + self._line(qubit_t, clbit_b, lc=self._style['cc'], ls=self._style['cline']) # # draw special gates # if op.name == 'measure': - vv = self._creg_dict[c_idxs[0]]['index'] + vv = self._clbit_dict[c_idxs[0]]['index'] self._measure(q_xy[0], c_xy[0], vv, fc=fc, ec=ec, gt=gt, sc=sc) elif op.op._directive: _barriers = {'coord': [], 'group': []} for index, qbit in enumerate(q_idxs): - q_group = self._qreg_dict[qbit]['group'] + q_group = self._qubit_dict[qbit]['group'] if q_group not in _barriers['group']: _barriers['group'].append(q_group) _barriers['coord'].append(q_xy[index]) @@ -978,7 +1002,7 @@ def _draw_ops(self, verbose=False): self._set_ctrl_bits(op.op.ctrl_state, num_ctrl_qubits, q_xy, ec=ec, tc=tc, text=ctrl_text, qargs=op.qargs) self._ctrl_qubit(q_xy[1], fc=ec, ec=ec, tc=tc) - self._line(qreg_b, qreg_t, lc=lc, zorder=PORDER_LINE + 1) + self._line(qubit_b, qubit_t, lc=lc, zorder=PORDER_LINE + 1) # cu1, cp, rzz, and controlled rzz gates (sidetext gates) elif op.name == 'rzz' or base_name in ['u1', 'p', 'rzz']: @@ -995,15 +1019,15 @@ def _draw_ops(self, verbose=False): stext = 'P' else: stext = 'ZZ' - self._sidetext(qreg_b, tc=tc, + self._sidetext(qubit_b, tc=tc, text='{}'.format(stext) + ' ' + '({})'.format(param)) - self._line(qreg_b, qreg_t, lc=lc) + self._line(qubit_b, qubit_t, lc=lc) # swap gate elif op.name == 'swap': self._swap(q_xy[0], color=lc) self._swap(q_xy[1], color=lc) - self._line(qreg_b, qreg_t, lc=lc) + self._line(qubit_b, qubit_t, lc=lc) # cswap gate elif op.name != 'swap' and base_name == 'swap': @@ -1012,7 +1036,7 @@ def _draw_ops(self, verbose=False): q_xy, ec=ec, tc=tc, text=ctrl_text, qargs=op.qargs) self._swap(q_xy[num_ctrl_qubits], color=lc) self._swap(q_xy[num_ctrl_qubits + 1], color=lc) - self._line(qreg_b, qreg_t, lc=lc) + self._line(qubit_b, qubit_t, lc=lc) # all other controlled gates elif isinstance(op.op, ControlledGate): @@ -1020,7 +1044,7 @@ def _draw_ops(self, verbose=False): num_qargs = len(q_xy) - num_ctrl_qubits self._set_ctrl_bits(op.op.ctrl_state, num_ctrl_qubits, q_xy, ec=ec, tc=tc, text=ctrl_text, qargs=op.qargs) - self._line(qreg_b, qreg_t, lc=lc) + self._line(qubit_b, qubit_t, lc=lc) if num_qargs == 1 and base_name == 'x': tgt_color = self._style['dispcol']['target'] tgt = tgt_color if isinstance(tgt_color, str) else tgt_color[0] @@ -1047,7 +1071,7 @@ def _draw_ops(self, verbose=False): # # adjust window size and draw horizontal lines # - anchors = [q_anchors[ii].get_index() for ii in self._qreg_dict] + anchors = [q_anchors[ii].get_index() for ii in self._qubit_dict] max_anc = max(anchors) if anchors else 0 n_fold = max(0, max_anc - 1) // self._fold if self._fold > 0 else 0 diff --git a/qiskit/visualization/text.py b/qiskit/visualization/text.py index 4fe621509b45..0ea396d6ee79 100644 --- a/qiskit/visualization/text.py +++ b/qiskit/visualization/text.py @@ -527,9 +527,11 @@ def fillup_layer(names): class TextDrawing(): """ The text drawing""" - def __init__(self, qregs, cregs, instructions, plotbarriers=True, + def __init__(self, qubits, clbits, instructions, plotbarriers=True, line_length=None, vertical_compression='high', layout=None, initial_state=True, - cregbundle=False, global_phase=None, encoding=None): + cregbundle=False, global_phase=None, encoding=None, qregs=None, cregs=None): + self.qubits = qubits + self.clbits = clbits self.qregs = qregs self.cregs = cregs self.instructions = instructions @@ -542,6 +544,7 @@ def __init__(self, qregs, cregs, instructions, plotbarriers=True, if vertical_compression not in ['high', 'medium', 'low']: raise ValueError("Vertical compression can only be 'high', 'medium', or 'low'") self.vertical_compression = vertical_compression + if encoding: self.encoding = encoding else: @@ -550,6 +553,14 @@ def __init__(self, qregs, cregs, instructions, plotbarriers=True, else: self.encoding = 'utf8' + self.bit_locations = { + bit: {'register': register, 'index': index} + for register in cregs + qregs + for index, bit in enumerate(register)} + for index, bit in list(enumerate(qubits)) + list(enumerate(clbits)): + if bit not in self.bit_locations: + self.bit_locations[bit] = {'register': None, 'index': index} + def __str__(self): return self.single_string() @@ -608,7 +619,7 @@ def lines(self, line_length=None): else: line_length, _ = get_terminal_size() - noqubits = len(self.qregs) + noqubits = len(self.qubits) try: layers = self.build_layers() @@ -682,35 +693,53 @@ def wire_names(self, with_initial_state=False): qubit_labels = [] if self.layout is None: - for bit in self.qregs: + for bit in self.qubits: label = '{name}_{index}: ' + initial_qubit_value - qubit_labels.append(label.format(name=bit.register.name, - index=bit.index, - physical='')) + if self.bit_locations[bit]['register'] is not None: + qubit_labels.append(label.format(name=self.bit_locations[bit]['register'].name, + index=self.bit_locations[bit]['index'], + physical='')) + else: + qubit_labels.append(label.format(name='', + index=self.bit_locations[bit]['index'], + physical='')) + else: - for bit in self.qregs: - if self.layout[bit.index]: - label = '{name}_{index} -> {physical} ' + initial_qubit_value - qubit_labels.append(label.format(name=self.layout[bit.index].register.name, - index=self.layout[bit.index].index, - physical=bit.index)) + for bit in self.qubits: + bit_index = self.bit_locations[bit]['index'] + if self.layout[bit_index]: + try: + layout_reg = next(reg for reg in self.layout.get_registers() + if self.layout[bit_index] in reg) + label = '{name}_{index} -> {physical} ' + initial_qubit_value + qubit_labels.append( + label.format(name=layout_reg.name, + index=layout_reg[:].index(self.layout[bit_index]), + physical=bit_index)) + except StopIteration: + label = '{name} -> {physical} ' + initial_qubit_value + qubit_labels.append(label.format(name='', + physical=bit_index)) else: - qubit_labels.append('%s ' % bit.index + initial_qubit_value) + qubit_labels.append('%s ' % bit_index + initial_qubit_value) clbit_labels = [] previous_creg = None - for bit in self.cregs: - if self.cregbundle: - if previous_creg and previous_creg == bit.register: + for bit in self.clbits: + register = self.bit_locations[bit]['register'] + index = self.bit_locations[bit]['index'] + if self.cregbundle and register is not None: + if previous_creg and previous_creg == register: continue - previous_creg = bit.register + previous_creg = register label = '{name}: {initial_value}{size}/' - clbit_labels.append(label.format(name=bit.register.name, + clbit_labels.append(label.format(name=register.name, initial_value=initial_clbit_value, - size=bit.register.size)) + size=register.size)) else: label = '{name}_{index}: ' + initial_clbit_value - clbit_labels.append(label.format(name=bit.register.name, index=bit.index)) + clbit_labels.append(label.format(name=register.name if register is not None else '', + index=index)) return qubit_labels + clbit_labels def should_compress(self, top_line, bot_line): @@ -920,12 +949,12 @@ def controlled_wires(instruction, layer): top_box = list() bot_box = list() - qubit_index = sorted([i for i, x in enumerate(layer.qregs) if x in args_qubits]) + qubit_index = sorted([i for i, x in enumerate(layer.qubits) if x in args_qubits]) for ctrl_qubit in zip(ctrl_qubits, ctrl_state): - if min(qubit_index) > layer.qregs.index(ctrl_qubit[0]): + if min(qubit_index) > layer.qubits.index(ctrl_qubit[0]): top_box.append(ctrl_qubit) - elif max(qubit_index) < layer.qregs.index(ctrl_qubit[0]): + elif max(qubit_index) < layer.qubits.index(ctrl_qubit[0]): bot_box.append(ctrl_qubit) else: in_box.append(ctrl_qubit) @@ -970,7 +999,7 @@ def _instruction_to_gate(self, instruction, layer): # add in a gate that operates over multiple qubits def add_connected_gate(instruction, gates, layer, current_cons): for i, gate in enumerate(gates): - actual_index = self.qregs.index(instruction.qargs[i]) + actual_index = self.qubits.index(instruction.qargs[i]) if actual_index not in [i for i, j in current_cons]: layer.set_qubit(instruction.qargs[i], gate) current_cons.append((actual_index, gate)) @@ -994,7 +1023,8 @@ def add_connected_gate(instruction, gates, layer, current_cons): gate = MeasureFrom() layer.set_qubit(instruction.qargs[0], gate) if self.cregbundle: - layer.set_clbit(instruction.cargs[0], MeasureTo(str(instruction.cargs[0].index))) + layer.set_clbit(instruction.cargs[0], + MeasureTo(str(self.bit_locations[instruction.cargs[0]]['index']))) else: layer.set_clbit(instruction.cargs[0], MeasureTo()) @@ -1004,7 +1034,7 @@ def add_connected_gate(instruction, gates, layer, current_cons): return layer, current_cons, connection_label for qubit in instruction.qargs: - if qubit in self.qregs: + if qubit in self.qubits: layer.set_qubit(qubit, Barrier()) elif isinstance(instruction.op, SwapGate): # swap @@ -1104,7 +1134,7 @@ def build_layers(self): layers = [InputWire.fillup_layer(wire_names)] for instruction_layer in self.instructions: - layer = Layer(self.qregs, self.cregs, self.cregbundle) + layer = Layer(self.qubits, self.clbits, self.cregbundle, self.cregs) for instruction in instruction_layer: layer, current_connections, connection_label = \ @@ -1120,21 +1150,32 @@ def build_layers(self): class Layer: """ A layer is the "column" of the circuit. """ - def __init__(self, qregs, cregs, cregbundle=False): - self.qregs = qregs + def __init__(self, qubits, clbits, cregbundle=False, cregs=None): + cregs = [] if cregs is None else cregs + + self.qubits = qubits + + self._clbit_locations = { + bit: {'register': register, 'index': index} + for register in cregs + for index, bit in enumerate(register)} + for index, bit in enumerate(clbits): + if bit not in self._clbit_locations: + self._clbit_locations[bit] = {'register': None, 'index': index} + if cregbundle: - self.cregs = [] + self.clbits = [] previous_creg = None - for bit in cregs: - if previous_creg and previous_creg == bit.register: + for bit in clbits: + if previous_creg and previous_creg == self._clbit_locations[bit]['register']: continue - previous_creg = bit.register - self.cregs.append(bit.register) + previous_creg = self._clbit_locations[bit]['register'] + self.clbits.append(previous_creg) else: - self.cregs = cregs - self.qubit_layer = [None] * len(qregs) + self.clbits = clbits + self.qubit_layer = [None] * len(qubits) self.connections = [] - self.clbit_layer = [None] * len(cregs) + self.clbit_layer = [None] * len(clbits) self.cregbundle = cregbundle @property @@ -1150,50 +1191,50 @@ def set_qubit(self, qubit, element): """Sets the qubit to the element. Args: - qubit (qbit): Element of self.qregs. + qubit (qbit): Element of self.qubits. element (DrawElement): Element to set in the qubit """ - self.qubit_layer[self.qregs.index(qubit)] = element + self.qubit_layer[self.qubits.index(qubit)] = element def set_clbit(self, clbit, element): """Sets the clbit to the element. Args: - clbit (cbit): Element of self.cregs. + clbit (cbit): Element of self.clbits. element (DrawElement): Element to set in the clbit """ if self.cregbundle: - self.clbit_layer[self.cregs.index(clbit.register)] = element + self.clbit_layer[self.clbits.index(self._clbit_locations[clbit]['register'])] = element else: - self.clbit_layer[self.cregs.index(clbit)] = element + self.clbit_layer[self.clbits.index(clbit)] = element def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None, bot_connect=None, conditional=False, controlled_edge=None): if qubits is not None and clbits is not None: qubits = list(qubits) clbits = list(clbits) - cbit_index = sorted([i for i, x in enumerate(self.cregs) if x in clbits]) - qbit_index = sorted([i for i, x in enumerate(self.qregs) if x in qubits]) + cbit_index = sorted([i for i, x in enumerate(self.clbits) if x in clbits]) + qbit_index = sorted([i for i, x in enumerate(self.qubits) if x in qubits]) # Further below, indices are used as wire labels. Here, get the length of # the longest label, and pad all labels with spaces to this length. wire_label_len = max(len(str(len(qubits) - 1)), len(str(len(clbits) - 1))) qargs = [str(qubits.index(qbit)).ljust(wire_label_len, ' ') - for qbit in self.qregs if qbit in qubits] + for qbit in self.qubits if qbit in qubits] cargs = [str(clbits.index(cbit)).ljust(wire_label_len, ' ') - for cbit in self.cregs if cbit in clbits] + for cbit in self.clbits if cbit in clbits] - box_height = len(self.qregs) - min(qbit_index) + max(cbit_index) + 1 + box_height = len(self.qubits) - min(qbit_index) + max(cbit_index) + 1 self.set_qubit(qubits.pop(0), BoxOnQuWireTop(label, wire_label=qargs.pop(0))) order = 0 - for order, bit_i in enumerate(range(min(qbit_index) + 1, len(self.qregs))): + for order, bit_i in enumerate(range(min(qbit_index) + 1, len(self.qubits))): if bit_i in qbit_index: named_bit = qubits.pop(0) wire_label = qargs.pop(0) else: - named_bit = self.qregs[bit_i] + named_bit = self.qubits[bit_i] wire_label = ' ' * wire_label_len self.set_qubit(named_bit, BoxOnQuWireMid(label, box_height, order, wire_label=wire_label)) @@ -1202,7 +1243,7 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None, named_bit = clbits.pop(0) wire_label = cargs.pop(0) else: - named_bit = self.cregs[bit_i] + named_bit = self.clbits[bit_i] wire_label = ' ' * wire_label_len self.set_clbit(named_bit, BoxOnClWireMid(label, box_height, order, wire_label=wire_label)) @@ -1211,9 +1252,9 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None, return cbit_index if qubits is None and clbits is not None: bits = list(clbits) - bit_index = sorted([i for i, x in enumerate(self.cregs) if x in bits]) + bit_index = sorted([i for i, x in enumerate(self.clbits) if x in bits]) wire_label_len = len(str(len(bits) - 1)) - bits.sort(key=self.cregs.index) + bits.sort(key=self.clbits.index) qargs = [''] * len(bits) set_bit = self.set_clbit OnWire = BoxOnClWire @@ -1222,11 +1263,11 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None, OnWireBot = BoxOnClWireBot elif clbits is None and qubits is not None: bits = list(qubits) - bit_index = sorted([i for i, x in enumerate(self.qregs) if x in bits]) + bit_index = sorted([i for i, x in enumerate(self.qubits) if x in bits]) wire_label_len = len(str(len(bits) - 1)) qargs = [str(bits.index(qbit)).ljust(wire_label_len, ' ') - for qbit in self.qregs if qbit in bits] - bits.sort(key=self.qregs.index) + for qbit in self.qubits if qbit in bits] + bits.sort(key=self.qubits.index) set_bit = self.set_qubit OnWire = BoxOnQuWire OnWireTop = BoxOnQuWireTop @@ -1237,7 +1278,7 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None, control_index = {} if controlled_edge: - for index, qubit in enumerate(self.qregs): + for index, qubit in enumerate(self.qubits): for qubit_in_edge, value in controlled_edge: if qubit == qubit_in_edge: control_index[index] = '■' if value == '1' else 'o' @@ -1251,7 +1292,7 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None, named_bit = bits.pop(0) wire_label = qargs.pop(0) else: - named_bit = (self.qregs + self.cregs)[bit_i] + named_bit = (self.qubits + self.clbits)[bit_i] wire_label = ' ' * wire_label_len control_label = control_index.get(bit_i) @@ -1272,7 +1313,8 @@ def set_cl_multibox(self, creg, label, top_connect='┴'): if self.cregbundle: self.set_clbit(creg[0], BoxOnClWire(label=label, top_connect=top_connect)) else: - clbit = [bit for bit in self.cregs if bit.register == creg] + clbit = [bit for bit in self.clbits + if self._clbit_locations[bit]['register'] == creg] self._set_multibox(label, clbits=clbit, top_connect=top_connect) def set_qu_multibox(self, bits, label, top_connect=None, bot_connect=None, diff --git a/qiskit/visualization/utils.py b/qiskit/visualization/utils.py index e1e4446b467d..aaf782274f70 100644 --- a/qiskit/visualization/utils.py +++ b/qiskit/visualization/utils.py @@ -78,8 +78,8 @@ def _trim(image): def _get_layered_instructions(circuit, reverse_bits=False, justify=None, idle_wires=True): """ - Given a circuit, return a tuple (qregs, cregs, ops) where - qregs and cregs are the quantum and classical registers + Given a circuit, return a tuple (qubits, clbits, ops) where + qubits and clbits are the quantum and classical registers in order (based on reverse_bits) and ops is a list of DAG nodes whose type is "operation". @@ -102,8 +102,8 @@ def _get_layered_instructions(circuit, reverse_bits=False, dag = circuit_to_dag(circuit) ops = [] - qregs = dag.qubits - cregs = dag.clbits + qubits = dag.qubits + clbits = dag.clbits # Create a mapping of each register to the max layer number for all measure ops # with that register as the target. Then when a node with condition is seen, @@ -117,22 +117,22 @@ def _get_layered_instructions(circuit, reverse_bits=False, ops = _LayerSpooler(dag, justify, measure_map) if reverse_bits: - qregs.reverse() - cregs.reverse() + qubits.reverse() + clbits.reverse() # Optionally remove all idle wires and instructions that are on them and # on them only. if not idle_wires: for wire in dag.idle_wires(ignore=['barrier', 'delay']): - if wire in qregs: - qregs.remove(wire) - if wire in cregs: - cregs.remove(wire) + if wire in qubits: + qubits.remove(wire) + if wire in clbits: + clbits.remove(wire) - ops = [[op for op in layer if any(q in qregs for q in op.qargs)] + ops = [[op for op in layer if any(q in qubits for q in op.qargs)] for layer in ops] - return qregs, cregs, ops + return qubits, clbits, ops def _sorted_nodes(dag_layer): @@ -145,14 +145,14 @@ def _sorted_nodes(dag_layer): return dag_instructions -def _get_gate_span(qregs, instruction): +def _get_gate_span(qubits, instruction): """Get the list of qubits drawing this gate would cover qiskit-terra #2802 """ - min_index = len(qregs) + min_index = len(qubits) max_index = 0 for qreg in instruction.qargs: - index = qregs.index(qreg) + index = qubits.index(qreg) if index < min_index: min_index = index @@ -160,20 +160,20 @@ def _get_gate_span(qregs, instruction): max_index = index if instruction.cargs: - return qregs[min_index:] + return qubits[min_index:] if instruction.condition: - return qregs[min_index:] + return qubits[min_index:] - return qregs[min_index:max_index + 1] + return qubits[min_index:max_index + 1] -def _any_crossover(qregs, node, nodes): +def _any_crossover(qubits, node, nodes): """Return True .IFF. 'node' crosses over any in 'nodes',""" - gate_span = _get_gate_span(qregs, node) + gate_span = _get_gate_span(qubits, node) all_indices = [] for check_node in nodes: if check_node != node: - all_indices += _get_gate_span(qregs, check_node) + all_indices += _get_gate_span(qubits, check_node) return any(i in gate_span for i in all_indices) @@ -184,7 +184,7 @@ def __init__(self, dag, justification, measure_map): """Create spool""" super().__init__() self.dag = dag - self.qregs = dag.qubits + self.qubits = dag.qubits self.justification = justification self.measure_map = measure_map @@ -218,7 +218,7 @@ def is_found_in(self, node, nodes): def insertable(self, node, nodes): """True .IFF. we can add 'node' to layer 'nodes'""" - return not _any_crossover(self.qregs, node, nodes) + return not _any_crossover(self.qubits, node, nodes) def slide_from_left(self, node, index): """Insert node into first layer where there is no conflict going l > r""" diff --git a/test/python/transpiler/test_enlarge_with_ancilla_pass.py b/test/python/transpiler/test_enlarge_with_ancilla_pass.py index b254d4c4bf64..22c334f6d7d2 100644 --- a/test/python/transpiler/test_enlarge_with_ancilla_pass.py +++ b/test/python/transpiler/test_enlarge_with_ancilla_pass.py @@ -50,10 +50,10 @@ def test_with_extension(self): layout = Layout({0: self.qr3[0], 1: ancilla[0], 2: self.qr3[1], 3: ancilla[1], 4: self.qr3[2]}) + layout.add_register(ancilla) pass_ = EnlargeWithAncilla() pass_.property_set['layout'] = layout - pass_.property_set['layout_ancilla_register'] = ancilla after = pass_.run(self.dag) qregs = list(after.qregs.values()) diff --git a/test/python/transpiler/test_full_ancilla_allocation.py b/test/python/transpiler/test_full_ancilla_allocation.py index 539a5a56f80d..54dab131c26b 100644 --- a/test/python/transpiler/test_full_ancilla_allocation.py +++ b/test/python/transpiler/test_full_ancilla_allocation.py @@ -133,19 +133,26 @@ def test_name_collision(self): initial_layout[0] = qr_ancilla[0] initial_layout[1] = qr_ancilla[1] initial_layout[2] = qr_ancilla[2] + initial_layout.add_register(qr_ancilla) pass_ = FullAncillaAllocation(self.cmap5) pass_.property_set['layout'] = initial_layout pass_.run(dag) after_layout = pass_.property_set['layout'] - after_ancilla_register = pass_.property_set['layout_ancilla_register'] - self.assertTrue(all(qubit in qr_ancilla or qubit in after_ancilla_register - for qubit in after_layout.get_virtual_bits())) + layout_qregs = after_layout.get_registers() + self.assertEqual(len(layout_qregs), 2) + self.assertIn(qr_ancilla, layout_qregs) + + layout_qregs.remove(qr_ancilla) + after_ancilla_register = layout_qregs.pop() self.assertEqual(len(after_ancilla_register), 2) self.assertRegex(after_ancilla_register.name, r'^ancilla\d+$') + self.assertTrue(all(qubit in qr_ancilla or qubit in after_ancilla_register + for qubit in after_layout.get_virtual_bits())) + def test_bad_layout(self): """Layout referes to a register that do not exist in the circuit """ diff --git a/test/python/transpiler/test_layout.py b/test/python/transpiler/test_layout.py index 76b7ce4fc35f..830737078a65 100644 --- a/test/python/transpiler/test_layout.py +++ b/test/python/transpiler/test_layout.py @@ -151,6 +151,8 @@ def test_layout_add_register(self): self.assertEqual(layout[qr0[0]], 0) self.assertEqual(layout[qr0[1]], 1) self.assertEqual(layout[qr1[0]], 2) + self.assertIn(qr0, layout.get_registers()) + self.assertIn(qr1, layout.get_registers()) def test_physical_keyerror(self): """When asking for an unexistant physical qubit, KeyError""" @@ -406,6 +408,17 @@ def test_layout_from_tuplelist(self): self.assertDictEqual(layout._p2v, expected._p2v) self.assertDictEqual(layout._v2p, expected._v2p) + def test_layout_contains(self): + """Verify Layouts support __contains__.""" + qr = QuantumRegister(2, 'qr') + layout = Layout() + layout.add(qr[0], 0) + + self.assertIn(qr[0], layout) + self.assertIn(0, layout) + self.assertNotIn(qr[1], layout) + self.assertNotIn(1, layout) + if __name__ == '__main__': unittest.main() diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py index cd52bbc02b5d..b72261061162 100644 --- a/test/python/visualization/test_circuit_text_drawer.py +++ b/test/python/visualization/test_circuit_text_drawer.py @@ -29,6 +29,7 @@ from qiskit.extensions import UnitaryGate, HamiltonianGate from qiskit.circuit.library import HGate, U2Gate, XGate, CZGate, ZGate, YGate, U1Gate, \ SwapGate, RZZGate, CU3Gate, CU1Gate, CPhaseGate +from qiskit.transpiler.passes import ApplyLayout class TestTextDrawerElement(QiskitTestCase): @@ -2903,20 +2904,23 @@ def test_mixed_layout(self): """ With a mixed layout. """ expected = '\n'.join([" ┌───┐", " v_0 -> 0 |0>┤ H ├", - " ├───┤", - "ancilla_1 -> 1 |0>┤ H ├", - " ├───┤", - "ancilla_0 -> 2 |0>┤ H ├", - " ├───┤", + " └───┘", + "ancilla_1 -> 1 |0>─────", + " ", + "ancilla_0 -> 2 |0>─────", + " ┌───┐", " v_1 -> 3 |0>┤ H ├", " └───┘"]) - pqr = QuantumRegister(4, 'v') qr = QuantumRegister(2, 'v') ancilla = QuantumRegister(2, 'ancilla') - circuit = QuantumCircuit(pqr) - circuit._layout = Layout({qr[0]: 0, ancilla[1]: 1, ancilla[0]: 2, qr[1]: 3}) - circuit.h(pqr) - self.assertEqual(str(_text_circuit_drawer(circuit)), expected) + circuit = QuantumCircuit(qr, ancilla) + circuit.h(qr) + + pass_ = ApplyLayout() + pass_.property_set['layout'] = Layout({qr[0]: 0, ancilla[1]: 1, ancilla[0]: 2, qr[1]: 3}) + circuit_with_layout = pass_(circuit) + + self.assertEqual(str(_text_circuit_drawer(circuit_with_layout)), expected) def test_partial_layout(self): """ With a partial layout. @@ -2936,6 +2940,8 @@ def test_partial_layout(self): circuit.h(0) circuit.h(3) circuit._layout = Layout({0: qr[0], 1: None, 2: None, 3: qr[1]}) + circuit._layout.add_register(qr) + self.assertEqual(str(_text_circuit_drawer(circuit)), expected) def test_with_classical_regs(self): @@ -2953,15 +2959,19 @@ def test_with_classical_regs(self): " ║ ", " cr_1: 0 ════╩═", " "]) - pqr = QuantumRegister(4, 'q') qr1 = QuantumRegister(2, 'qr1') - cr = ClassicalRegister(2, 'cr') qr2 = QuantumRegister(2, 'qr2') - circuit = QuantumCircuit(pqr, cr) - circuit._layout = Layout({qr1[0]: 0, qr1[1]: 1, qr2[0]: 2, qr2[1]: 3}) - circuit.measure(pqr[2], cr[0]) - circuit.measure(pqr[3], cr[1]) - self.assertEqual(str(_text_circuit_drawer(circuit)), expected) + cr = ClassicalRegister(2, 'cr') + + circuit = QuantumCircuit(qr1, qr2, cr) + circuit.measure(qr2[0], cr[0]) + circuit.measure(qr2[1], cr[1]) + + pass_ = ApplyLayout() + pass_.property_set['layout'] = Layout({qr1[0]: 0, qr1[1]: 1, qr2[0]: 2, qr2[1]: 3}) + circuit_with_layout = pass_(circuit) + + self.assertEqual(str(_text_circuit_drawer(circuit_with_layout)), expected) def test_with_layout_but_disable(self): """ With parameter without_layout=False """