diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2341372b5fb6..a8de4d43f271 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -40,6 +40,11 @@ Removed - The ``qiskit.qiskiterror`` module has been removed. Please use ``qiskit.exceptions`` instead. (#2399) +Changed +------- +- Qubits and classical bits are not represented as a tuples anymore, but as + instances of ``Qubit`` and ``Clbit`` respectively. + `0.8.0`_ - 2019-05-02 ===================== diff --git a/qiskit/assembler/assemble_circuits.py b/qiskit/assembler/assemble_circuits.py index d7fe8d147c42..1a1ad8d9ec19 100644 --- a/qiskit/assembler/assemble_circuits.py +++ b/qiskit/assembler/assemble_circuits.py @@ -87,11 +87,11 @@ def assemble_circuits(circuits, run_config, qobj_id, qobj_header): qargs = op_context[1] cargs = op_context[2] if qargs: - qubit_indices = [qubit_labels.index([qubit[0].name, qubit[1]]) + qubit_indices = [qubit_labels.index([qubit.register.name, qubit.index]) for qubit in qargs] instruction.qubits = qubit_indices if cargs: - clbit_indices = [clbit_labels.index([clbit[0].name, clbit[1]]) + clbit_indices = [clbit_labels.index([clbit.register.name, clbit.index]) for clbit in cargs] instruction.memory = clbit_indices # If the experiment has conditional instructions, assume every diff --git a/qiskit/circuit/__init__.py b/qiskit/circuit/__init__.py index 992d93d96fc5..0557d8736b09 100644 --- a/qiskit/circuit/__init__.py +++ b/qiskit/circuit/__init__.py @@ -14,8 +14,8 @@ """Module for Circuits.""" from .quantumcircuit import QuantumCircuit -from .classicalregister import ClassicalRegister -from .quantumregister import QuantumRegister +from .classicalregister import ClassicalRegister, Clbit +from .quantumregister import QuantumRegister, Qubit from .gate import Gate from .instruction import Instruction from .instructionset import InstructionSet diff --git a/qiskit/circuit/bit.py b/qiskit/circuit/bit.py new file mode 100644 index 000000000000..528229a98ff8 --- /dev/null +++ b/qiskit/circuit/bit.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# This code is part of Qiskit. +# +# (C) Copyright IBM 2019. +# +# This code is licensed under the Apache License, Version 2.0. You may +# obtain a copy of this license in the LICENSE.txt file in the root directory +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. +# +# Any modifications or derivative works of this code must retain this +# copyright notice, and modified files need to carry a notice indicating +# that they have been altered from the originals. + +""" +Quantum bit and Classical bit objects. +""" +from warnings import warn +from qiskit.exceptions import QiskitError + + +class Bit: + """Implement a generic bit.""" + + def __init__(self, register, index): + """Create a new generic bit. + """ + try: + index = int(index) + except Exception: + raise QiskitError("index needs to be castable to an int: type %s was provided" % + type(index)) + + if index < 0: + index += register.size + + if index >= register.size: + raise QiskitError("index must be under the size of the register: %s was provided" % + index) + + self.register = register + self.index = index + + def __repr__(self): + """Return the official string representing the bit.""" + return "%s(%s, %s)" % (self.__class__.__name__, self.register, self.index) + + def __getitem__(self, item): + warn('Accessing a bit register by bit[0] or its index by bit[1] is deprecated. ' + 'Go for bit.register and bit.index.', DeprecationWarning) + if item == 0: + return self.register + elif item == 1: + return self.index + else: + raise IndexError + + def __hash__(self): + return hash((self.register, self.index)) + + def __eq__(self, other): + if isinstance(other, tuple): + return other[1] == self.index and other[0] == self.register + return other.index == self.index and other.register == self.register diff --git a/qiskit/circuit/classicalregister.py b/qiskit/circuit/classicalregister.py index b8dbc97c17a3..6ef52e898bc0 100644 --- a/qiskit/circuit/classicalregister.py +++ b/qiskit/circuit/classicalregister.py @@ -17,7 +17,20 @@ """ import itertools +from qiskit.exceptions import QiskitError from .register import Register +from .bit import Bit + + +class Clbit(Bit): + """Implement a classical bit.""" + + def __init__(self, register, index): + if isinstance(register, ClassicalRegister): + super().__init__(register, index) + else: + raise QiskitError('Clbit needs a ClassicalRegister and %s was provided' % + type(register).__name__) class ClassicalRegister(Register): @@ -27,6 +40,7 @@ class ClassicalRegister(Register): instances_counter = itertools.count() # Prefix to use for auto naming. prefix = 'c' + bit_type = Clbit def qasm(self): """Return OPENQASM string for this register.""" diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py index baa4f0d79722..9e66fe045c8a 100644 --- a/qiskit/circuit/quantumcircuit.py +++ b/qiskit/circuit/quantumcircuit.py @@ -18,17 +18,19 @@ import itertools import sys import multiprocessing as mp +from warnings import warn from qiskit.circuit.instruction import Instruction from qiskit.qasm.qasm import Qasm from qiskit.exceptions import QiskitError from qiskit.circuit.parameter import Parameter -from .quantumregister import QuantumRegister -from .classicalregister import ClassicalRegister +from .quantumregister import QuantumRegister, Qubit +from .classicalregister import ClassicalRegister, Clbit from .parametertable import ParameterTable from .parametervector import ParameterVector from .instructionset import InstructionSet from .register import Register +from .bit import Bit def _is_bit(obj): @@ -36,6 +38,8 @@ def _is_bit(obj): # If there is a bit type this could be replaced by isinstance. if isinstance(obj, tuple) and len(obj) == 2: if isinstance(obj[0], Register) and isinstance(obj[1], int) and obj[1] < len(obj[0]): + warn('Referring to a bit as a tuple is being deprecated. ' + 'Instead go of (qr, 0), use qr[0].', DeprecationWarning) return True return False @@ -265,35 +269,43 @@ def cast(value, _type): @staticmethod def _bit_argument_conversion(bit_representation, in_array): + ret = None try: if _is_bit(bit_representation): + # circuit.h((qr, 0)) -> circuit.h([qr[0]]) + ret = [bit_representation[0][bit_representation[1]]] + elif isinstance(bit_representation, Bit): # circuit.h(qr[0]) -> circuit.h([qr[0]]) - return [bit_representation] + ret = [bit_representation] elif isinstance(bit_representation, Register): # circuit.h(qr) -> circuit.h([qr[0], qr[1]]) - return bit_representation[:] + ret = bit_representation[:] elif isinstance(QuantumCircuit.cast(bit_representation, int), int): # circuit.h(0) -> circuit.h([qr[0]]) - return [in_array[bit_representation]] + ret = [in_array[bit_representation]] elif isinstance(bit_representation, slice): # circuit.h(slice(0,2)) -> circuit.h([qr[0], qr[1]]) - return in_array[bit_representation] + ret = in_array[bit_representation] elif isinstance(bit_representation, list) and \ all(_is_bit(bit) for bit in bit_representation): + ret = [bit[0][bit[1]] for bit in bit_representation] + elif isinstance(bit_representation, list) and \ + all(isinstance(bit, Bit) for bit in bit_representation): # circuit.h([qr[0], qr[1]]) -> circuit.h([qr[0], qr[1]]) - return bit_representation + ret = bit_representation elif isinstance(QuantumCircuit.cast(bit_representation, list), (range, list)): # circuit.h([0, 1]) -> circuit.h([qr[0], qr[1]]) # circuit.h(range(0,2)) -> circuit.h([qr[0], qr[1]]) - return [in_array[index] for index in bit_representation] + ret = [in_array[index] for index in bit_representation] else: raise QiskitError('Not able to expand a %s (%s)' % (bit_representation, type(bit_representation))) except IndexError: raise QiskitError('Index out of range.') except TypeError: - raise QiskitError('Type error handeling %s (%s)' % (bit_representation, - type(bit_representation))) + raise QiskitError('Type error handling %s (%s)' % (bit_representation, + type(bit_representation))) + return ret def qbit_argument_conversion(self, qubit_representation): """ @@ -429,25 +441,17 @@ def _check_dups(self, qubits): def _check_qargs(self, qargs): """Raise exception if a qarg is not in this circuit or bad format.""" - if not all(isinstance(i, tuple) and - isinstance(i[0], QuantumRegister) and - isinstance(i[1], int) for i in qargs): - raise QiskitError("qarg not (QuantumRegister, int) tuple") - if not all(self.has_register(i[0]) for i in qargs): + if not all(isinstance(i, Qubit) for i in qargs): + raise QiskitError("qarg is not a Qubit") + if not all(self.has_register(i.register) for i in qargs): raise QiskitError("register not in this circuit") - for qubit in qargs: - qubit[0].check_range(qubit[1]) def _check_cargs(self, cargs): """Raise exception if clbit is not in this circuit or bad format.""" - if not all(isinstance(i, tuple) and - isinstance(i[0], ClassicalRegister) and - isinstance(i[1], int) for i in cargs): - raise QiskitError("carg not (ClassicalRegister, int) tuple") - if not all(self.has_register(i[0]) for i in cargs): + if not all(isinstance(i, Clbit) for i in cargs): + raise QiskitError("carg is not a Clbit") + if not all(self.has_register(i.register) for i in cargs): raise QiskitError("register not in this circuit") - for clbit in cargs: - clbit[0].check_range(clbit[1]) def to_instruction(self, parameter_map=None): """Create an Instruction out of this circuit. @@ -502,11 +506,11 @@ def qasm(self): qubit = qargs[0] clbit = cargs[0] string_temp += "%s %s[%d] -> %s[%d];\n" % (instruction.qasm(), - qubit[0].name, qubit[1], - clbit[0].name, clbit[1]) + qubit.register.name, qubit.index, + clbit.register.name, clbit.index) else: string_temp += "%s %s;\n" % (instruction.qasm(), - ",".join(["%s[%d]" % (j[0].name, j[1]) + ",".join(["%s[%d]" % (j.register.name, j.index) for j in qargs + cargs])) return string_temp @@ -627,7 +631,7 @@ def depth(self): for ind, reg in enumerate(qargs + cargs): # Add to the stacks of the qubits and # cbits used in the gate. - reg_ints.append(reg_map[reg[0].name] + reg[1]) + reg_ints.append(reg_map[reg.register.name] + reg.index) levels.append(op_stack[reg_ints[ind]] + 1) if instr.control: # Controls operate over all bits in the @@ -719,7 +723,7 @@ def num_connected_components(self, unitary_only=False): break for item in args: - reg_int = reg_map[item[0].name] + item[1] + reg_int = reg_map[item.register.name] + item.index for k in range(num_sub_graphs): if reg_int in sub_graphs[k]: if k not in graphs_touched: diff --git a/qiskit/circuit/quantumregister.py b/qiskit/circuit/quantumregister.py index 587e56882c66..ff603c202bab 100644 --- a/qiskit/circuit/quantumregister.py +++ b/qiskit/circuit/quantumregister.py @@ -17,7 +17,20 @@ """ import itertools +from qiskit.exceptions import QiskitError from .register import Register +from .bit import Bit + + +class Qubit(Bit): + """Implement a quantum bit.""" + + def __init__(self, register, index): + if isinstance(register, QuantumRegister): + super().__init__(register, index) + else: + raise QiskitError('Qubit needs a QuantumRegister and %s was provided' % + type(register).__name__) class QuantumRegister(Register): @@ -26,6 +39,7 @@ class QuantumRegister(Register): instances_counter = itertools.count() # Prefix to use for auto naming. prefix = 'q' + bit_type = Qubit def qasm(self): """Return OPENQASM string for this register.""" diff --git a/qiskit/circuit/register.py b/qiskit/circuit/register.py index e5b47681e35e..56545819752e 100644 --- a/qiskit/circuit/register.py +++ b/qiskit/circuit/register.py @@ -12,13 +12,15 @@ # copyright notice, and modified files need to carry a notice indicating # that they have been altered from the originals. +# pylint: disable=not-callable + """ Base register reference object. """ import re import itertools -from qiskit.exceptions import QiskitError, QiskitIndexError +from qiskit.exceptions import QiskitError class Register: @@ -28,6 +30,7 @@ class Register: instances_counter = itertools.count() # Prefix to use for auto naming. prefix = 'reg' + bit_type = None def __init__(self, size, name=None): """Create a new generic register. @@ -61,59 +64,41 @@ def __init__(self, size, name=None): def __repr__(self): """Return the official string representing the register.""" - return "%s(%d, '%s')" % (self.__class__.__qualname__, - self.size, self.name) + return "%s(%d, '%s')" % (self.__class__.__qualname__, self.size, self.name) def __len__(self): """Return register size""" return self.size - def check_range(self, j): - """Check that j is a valid index into self.""" - if isinstance(j, int): - if j < 0 or j >= self.size: - raise QiskitIndexError("register index out of range") - if isinstance(j, slice): - if j.start < 0 or j.stop >= self.size or (j.step is not None and - j.step <= 0): - raise QiskitIndexError("register index slice out of range") - def __getitem__(self, key): """ Arg: - key (int|slice|list): index of the bit/qubit to be retrieved. + bit_type (Qubit or Clbit): a constructor type return element/s. + key (int or slice or list): index of the clbit to be retrieved. Returns: - tuple[Register, int]: a tuple in the form `(self, key)` if key is int. - If key is a slice, return a `list((self,key))`. + Qubit or Clbit or list(Qubit) or list(Clbit): a instances Qubit or Clbit if key is int. + If key is a slice, return a list of them. Raises: QiskitError: if the `key` is not an integer. - QiskitIndexError: if the `key` is not in the range - `(0, self.size)`. + QiskitIndexError: if the `key` is not in the range `(0, self.size)`. """ if not isinstance(key, (int, slice, list)): raise QiskitError("expected integer or slice index into register") - if isinstance(key, int) and key < 0: - key = self.size + key - self.check_range(key) if isinstance(key, slice): - return [(self, ind) for ind in range(*key.indices(len(self)))] + return [self.bit_type(self, ind) for ind in range(*key.indices(len(self)))] elif isinstance(key, list): # list of qubit indices if max(key) < len(self): - return [(self, ind) for ind in key] + return [self.bit_type(self, ind) for ind in key] else: raise QiskitError('register index out of range') else: - return self, key + return self.bit_type(self, key) def __iter__(self): - """ - Returns: - iterator: an iterator over the bits/qubits of the register, in the - form `tuple (Register, int)`. - """ - return zip([self] * self.size, range(self.size)) + for bit in range(self.size): + yield self[bit] def __eq__(self, other): """Two Registers are the same if they are of the same type diff --git a/qiskit/compiler/transpile.py b/qiskit/compiler/transpile.py index 8494d105a5b7..0a6baf570689 100644 --- a/qiskit/compiler/transpile.py +++ b/qiskit/compiler/transpile.py @@ -20,6 +20,7 @@ from qiskit.transpiler.transpile_config import TranspileConfig from qiskit.transpiler.transpile_circuit import transpile_circuit from qiskit.pulse import Schedule +from qiskit.circuit.quantumregister import Qubit def transpile(circuits, @@ -269,8 +270,8 @@ def _layout_from_raw(initial_layout, circuit): if isinstance(initial_layout, list): if all(isinstance(elem, int) for elem in initial_layout): initial_layout = Layout.from_intlist(initial_layout, *circuit.qregs) - elif all(elem is None or isinstance(elem, tuple) for elem in initial_layout): - initial_layout = Layout.from_tuplelist(initial_layout) + elif all(elem is None or isinstance(elem, Qubit) for elem in initial_layout): + initial_layout = Layout.from_qubit_list(initial_layout) elif isinstance(initial_layout, dict): initial_layout = Layout(initial_layout) return initial_layout diff --git a/qiskit/converters/ast_to_dag.py b/qiskit/converters/ast_to_dag.py index 318ff980eb7a..96eb1f727562 100644 --- a/qiskit/converters/ast_to_dag.py +++ b/qiskit/converters/ast_to_dag.py @@ -126,6 +126,7 @@ def _process_bit_id(self, node): Return a list of tuples (Register,index). """ reg = None + if node.name in self.dag.qregs: reg = self.dag.qregs[node.name] elif node.name in self.dag.cregs: @@ -137,12 +138,12 @@ def _process_bit_id(self, node): if node.type == "indexed_id": # An indexed bit or qubit - return [(reg, node.index)] + return [reg[node.index]] elif node.type == "id": # A qubit or qreg or creg if not self.bit_stack[-1]: # Global scope - return [(reg, j) for j in range(reg.size)] + return [bit for bit in reg] else: # local scope if node.name in self.bit_stack[-1]: @@ -345,7 +346,7 @@ def _create_dag_op(self, name, params, qargs): Args: name (str): operation name to apply to the dag. params (list): op parameters - qargs (list(QuantumRegister, int)): qubits to attach to + qargs (list(Qubit)): qubits to attach to Raises: QiskitError: if encountering a non-basis opaque gate diff --git a/qiskit/converters/circuit_to_dag.py b/qiskit/converters/circuit_to_dag.py index 3bfb0f0813f4..c652591c401a 100644 --- a/qiskit/converters/circuit_to_dag.py +++ b/qiskit/converters/circuit_to_dag.py @@ -34,13 +34,6 @@ def circuit_to_dag(circuit): dagcircuit.add_creg(register) for instruction, qargs, cargs in circuit.data: - # Get arguments for classical control (if any) - if instruction.control is None: - control = None - else: - control = (instruction.control[0], instruction.control[1]) - - dagcircuit.apply_operation_back(instruction.copy(), - qargs, cargs, control) + dagcircuit.apply_operation_back(instruction.copy(), qargs, cargs, instruction.control) return dagcircuit diff --git a/qiskit/converters/circuit_to_instruction.py b/qiskit/converters/circuit_to_instruction.py index 7d3fabac9049..c0d427e9f34a 100644 --- a/qiskit/converters/circuit_to_instruction.py +++ b/qiskit/converters/circuit_to_instruction.py @@ -16,7 +16,7 @@ from qiskit.exceptions import QiskitError from qiskit.circuit.instruction import Instruction -from qiskit.circuit.quantumregister import QuantumRegister +from qiskit.circuit.quantumregister import QuantumRegister, Qubit from qiskit.circuit.classicalregister import ClassicalRegister @@ -63,12 +63,12 @@ def find_bit_position(bit): """find the index of a given bit (Register, int) within a flat ordered list of bits of the circuit """ - if isinstance(bit[0], QuantumRegister): + if isinstance(bit, Qubit): ordered_regs = circuit.qregs else: ordered_regs = circuit.cregs - reg_index = ordered_regs.index(bit[0]) - return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit[1] + reg_index = ordered_regs.index(bit.register) + return sum([reg.size for reg in ordered_regs[:reg_index]]) + bit.index target = circuit.copy() target._substitute_parameters(parameter_dict) @@ -82,8 +82,8 @@ def find_bit_position(bit): definition = list(map(lambda x: (x[0], - list(map(lambda y: (q, find_bit_position(y)), x[1])), - list(map(lambda y: (c, find_bit_position(y)), x[2]))), definition)) + list(map(lambda y: q[find_bit_position(y)], x[1])), + list(map(lambda y: c[find_bit_position(y)], x[2]))), definition)) instruction.definition = definition return instruction diff --git a/qiskit/converters/dag_to_circuit.py b/qiskit/converters/dag_to_circuit.py index d84f910a3983..9850f48e1f99 100644 --- a/qiskit/converters/dag_to_circuit.py +++ b/qiskit/converters/dag_to_circuit.py @@ -44,19 +44,14 @@ def dag_to_circuit(dag): for node in dag.topological_op_nodes(): qubits = [] for qubit in node.qargs: - qubits.append(qregs[qubit[0].name][qubit[1]]) + qubits.append(qregs[qubit.register.name][qubit.index]) clbits = [] for clbit in node.cargs: - clbits.append(cregs[clbit[0].name][clbit[1]]) + clbits.append(cregs[clbit.register.name][clbit.index]) # Get arguments for classical control (if any) - if node.condition is None: - control = None - else: - control = (node.condition[0], node.condition[1]) - inst = node.op.copy() - inst.control = control + inst.control = node.condition circuit.append(inst, qubits, clbits) return circuit diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index f2d944f56b7b..7761cecba5bf 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -29,8 +29,8 @@ import warnings import networkx as nx -from qiskit.circuit.quantumregister import QuantumRegister -from qiskit.circuit.classicalregister import ClassicalRegister +from qiskit.circuit.quantumregister import QuantumRegister, Qubit +from qiskit.circuit.classicalregister import ClassicalRegister, Clbit from qiskit.circuit.gate import Gate from .exceptions import DAGCircuitError from .dagnode import DAGNode @@ -109,8 +109,8 @@ def get_qubits(self): return self.qubits() def qubits(self): - """Return a list of qubits as (QuantumRegister, index) pairs.""" - return [(v, i) for k, v in self.qregs.items() for i in range(v.size)] + """Return a list of qubits (as a list of Qubit instances).""" + return [qubit for qreg in self.qregs.values() for qubit in qreg] def get_bits(self): """Deprecated. Use clbits().""" @@ -119,8 +119,8 @@ def get_bits(self): return self.clbits() def clbits(self): - """Return a list of bits as (ClassicalRegister, index) pairs.""" - return [(v, i) for k, v in self.cregs.items() for i in range(v.size)] + """Return a list of classical bits (as a list of Clbit instances).""" + return [clbit for creg in self.cregs.values() for clbit in creg] @property def node_counter(self): @@ -192,7 +192,7 @@ def add_qreg(self, qreg): raise DAGCircuitError("duplicate register %s" % qreg.name) self.qregs[qreg.name] = qreg for j in range(qreg.size): - self._add_wire((qreg, j)) + self._add_wire(qreg[j]) def add_creg(self, creg): """Add all wires in a classical register.""" @@ -202,7 +202,7 @@ def add_creg(self, creg): raise DAGCircuitError("duplicate register %s" % creg.name) self.cregs[creg.name] = creg for j in range(creg.size): - self._add_wire((creg, j)) + self._add_wire(creg[j]) def _add_wire(self, wire): """Add a qubit or bit to the circuit. @@ -222,7 +222,7 @@ def _add_wire(self, wire): self._max_node_id += 1 output_map_wire = self._max_node_id - wire_name = "%s[%s]" % (wire[0].name, wire[1]) + wire_name = "%s[%s]" % (wire.register.name, wire.index) inp_node = DAGNode(data_dict={'type': 'in', 'name': wire_name, 'wire': wire}, nid=input_map_wire) @@ -241,7 +241,7 @@ def _add_wire(self, wire): outp_node) self._multi_graph.adj[inp_node][outp_node][0]["name"] \ - = "%s[%s]" % (wire[0].name, wire[1]) + = "%s[%s]" % (wire.register.name, wire.index) self._multi_graph.adj[inp_node][outp_node][0]["wire"] \ = wire else: @@ -286,12 +286,9 @@ def _bits_in_condition(self, cond): cond (tuple or None): optional condition (ClassicalRegister, int) Returns: - list[(ClassicalRegister, idx)]: list of bits + list[Clbit]: list of classical bits """ - all_bits = [] - if cond is not None: - all_bits.extend([(cond[0], j) for j in range(self.cregs[cond[0].name].size)]) - return all_bits + return [] if cond is None else [cbit for cbit in cond[0]] def _add_op_node(self, op, qargs, cargs, condition=None): """Add a new operation node to the graph and assign properties. @@ -322,8 +319,8 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): Args: op (Instruction): the operation associated with the DAG node - qargs (list[tuple]): qubits that op will be applied to - cargs (list[tuple]): cbits that op will be applied to + qargs (list[Qubit]): qubits that op will be applied to + cargs (list[Clbit]): cbits that op will be applied to condition (tuple or None): optional condition (ClassicalRegister, int) Returns: @@ -356,10 +353,10 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): raise DAGCircuitError("output node has multiple in-edges") self._multi_graph.add_edge(ie[0], self._id_to_node[self._max_node_id], - name="%s[%s]" % (q[0].name, q[1]), wire=q) + name="%s[%s]" % (q.register.name, q.index), wire=q) self._multi_graph.remove_edge(ie[0], self.output_map[q]) self._multi_graph.add_edge(self._id_to_node[self._max_node_id], self.output_map[q], - name="%s[%s]" % (q[0].name, q[1]), wire=q) + name="%s[%s]" % (q.register.name, q.index), wire=q) return self._id_to_node[self._max_node_id] @@ -394,10 +391,10 @@ def apply_operation_front(self, op, qargs, cargs, condition=None): if len(ie) != 1: raise DAGCircuitError("input node has multiple out-edges") self._multi_graph.add_edge(self._id_to_node[self._max_node_id], ie[0], - name="%s[%s]" % (q[0].name, q[1]), wire=q) + name="%s[%s]" % (q.register.name, q.index), wire=q) self._multi_graph.remove_edge(self.input_map[q], ie[0]) self._multi_graph.add_edge(self.input_map[q], self._id_to_node[self._max_node_id], - name="%s[%s]" % (q[0].name, q[1]), wire=q) + name="%s[%s]" % (q.register.name, q.index), wire=q) return self._id_to_node[self._max_node_id] @@ -429,8 +426,8 @@ def _check_edgemap_registers(self, edge_map, keyregs, valregs, valreg=True): for v in keyregs.values(): reg_frag_chk[v] = {j: False for j in range(len(v))} for k in edge_map.keys(): - if k[0].name in keyregs: - reg_frag_chk[k[0]][k[1]] = True + if k.register.name in keyregs: + reg_frag_chk[k.register][k.index] = True for k, v in reg_frag_chk.items(): s = set(v.values()) if len(s) == 2: @@ -445,11 +442,11 @@ def _check_edgemap_registers(self, edge_map, keyregs, valregs, valreg=True): # If mapping to a register not in valregs, add it. # (k,0) exists in edge_map because edge_map doesn't # fragment k - if not edge_map[(k, 0)][0].name in valregs: - size = max(map(lambda x: x[1], - filter(lambda x: x[0] == edge_map[(k, 0)][0], + if not edge_map[(k, 0)].register.name in valregs: + size = max(map(lambda x: x.index, + filter(lambda x: x.register == edge_map[(k, 0)].register, edge_map.values()))) - qreg = QuantumRegister(size + 1, edge_map[(k, 0)][0].name) + qreg = QuantumRegister(size + 1, edge_map[(k, 0)].register.name) add_regs.add(qreg) return add_regs @@ -469,8 +466,8 @@ def _check_wiremap_validity(self, wire_map, keymap, valmap): DAGCircuitError: if wire_map not valid """ for k, v in wire_map.items(): - kname = "%s[%d]" % (k[0].name, k[1]) - vname = "%s[%d]" % (v[0].name, v[1]) + kname = "%s[%d]" % (k.register.name, k.index) + vname = "%s[%d]" % (v.register.name, v.index) if k not in keymap: raise DAGCircuitError("invalid wire mapping key %s" % kname) if v not in valmap: @@ -495,7 +492,7 @@ def _map_condition(self, wire_map, condition): # fragmented by the wire_map (this must have been checked # elsewhere) bit0 = (condition[0], 0) - new_condition = (wire_map.get(bit0, bit0)[0], condition[1]) + new_condition = (wire_map.get(bit0, bit0).register, condition[1]) return new_condition def extend_back(self, dag, edge_map=None): @@ -831,8 +828,8 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): replay_node.cargs, condition=condition) if wires is None: - qwires = [w for w in input_dag.wires if isinstance(w[0], QuantumRegister)] - cwires = [w for w in input_dag.wires if isinstance(w[0], ClassicalRegister)] + qwires = [w for w in input_dag.wires if isinstance(w, Qubit)] + cwires = [w for w in input_dag.wires if isinstance(w, Clbit)] wires = qwires + cwires self._check_wires_list(wires, node) @@ -891,7 +888,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): for q in itertools.chain(*al): self._multi_graph.add_edge(full_pred_map[q], self._id_to_node[self._max_node_id], - name="%s[%s]" % (q[0].name, q[1]), + name="%s[%s]" % (q.register.name, q.index), wire=q) full_pred_map[q] = self._id_to_node[self._max_node_id] @@ -900,7 +897,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): for w in full_pred_map: self._multi_graph.add_edge(full_pred_map[w], full_succ_map[w], - name="%s[%s]" % (w[0].name, w[1]), + name="%s[%s]" % (w.register.name, w.index), wire=w) o_pred = list(self._multi_graph.predecessors(self.output_map[w])) if len(o_pred) > 1: @@ -1101,8 +1098,7 @@ def quantum_predecessors(self, node): predecessors = [] for predecessor in self.predecessors(node): - if isinstance(self._multi_graph.get_edge_data(predecessor, node, key=0)['wire'][0], - QuantumRegister): + if isinstance(self._multi_graph.get_edge_data(predecessor, node, key=0)['wire'], Qubit): predecessors.append(predecessor) return predecessors @@ -1151,8 +1147,7 @@ def quantum_successors(self, node): successors = [] for successor in self.successors(node): if isinstance(self._multi_graph.get_edge_data( - node, successor, key=0)['wire'][0], - QuantumRegister): + node, successor, key=0)['wire'], Qubit): successors.append(successor) return successors @@ -1178,7 +1173,7 @@ def remove_op_node(self, node): for w in pred_map.keys(): self._multi_graph.add_edge(pred_map[w], succ_map[w], - name="%s[%s]" % (w[0].name, w[1]), wire=w) + name="%s[%s]" % (w.register.name, w.index), wire=w) def remove_ancestors_of(self, node): """Remove all of the ancestor operation nodes of node.""" @@ -1298,7 +1293,7 @@ def add_nodes_from(layer, nodes): for op_node in op_nodes: args = self._bits_in_condition(op_node.condition) \ + op_node.cargs + op_node.qargs - arg_ids = (self.input_map[(arg[0], arg[1])] for arg in args) + arg_ids = (self.input_map[(arg.register, arg.index)] for arg in args) for arg_id in arg_ids: wires[arg_id], wires[op_node] = op_node, wires[arg_id] diff --git a/qiskit/extensions/simulator/snapshot.py b/qiskit/extensions/simulator/snapshot.py index 33a66fc6f988..8fd8b112769b 100644 --- a/qiskit/extensions/simulator/snapshot.py +++ b/qiskit/extensions/simulator/snapshot.py @@ -19,7 +19,7 @@ from qiskit import QuantumCircuit from qiskit.circuit import CompositeGate -from qiskit import QuantumRegister +from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit import Instruction from qiskit.extensions.exceptions import ExtensionError @@ -134,7 +134,7 @@ def snapshot(self, for tuple_element in tuples: if isinstance(tuple_element, QuantumRegister): for j in range(tuple_element.size): - qubits.append((tuple_element, j)) + qubits.append(tuple_element[j]) else: qubits.append(tuple_element) return self.append( diff --git a/qiskit/extensions/standard/barrier.py b/qiskit/extensions/standard/barrier.py index ec764f6199bd..f940192391c5 100644 --- a/qiskit/extensions/standard/barrier.py +++ b/qiskit/extensions/standard/barrier.py @@ -17,7 +17,7 @@ """ from qiskit.circuit import QuantumCircuit from qiskit.circuit import CompositeGate -from qiskit.circuit import QuantumRegister +from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit import Instruction @@ -46,11 +46,11 @@ def barrier(self, *qargs): if not qargs: # None for qreg in self.qregs: for j in range(qreg.size): - qubits.append((qreg, j)) + qubits.append(qreg[j]) for qarg in qargs: if isinstance(qarg, QuantumRegister): - qubits.extend([(qarg, j) for j in range(qarg.size)]) + qubits.extend([qarg[j] for j in range(qarg.size)]) elif isinstance(qarg, list): qubits.extend(qarg) elif isinstance(qarg, range): diff --git a/qiskit/quantum_info/operators/channel/superop.py b/qiskit/quantum_info/operators/channel/superop.py index 305905dab183..eca1fa770704 100644 --- a/qiskit/quantum_info/operators/channel/superop.py +++ b/qiskit/quantum_info/operators/channel/superop.py @@ -474,7 +474,7 @@ def _append_instruction(self, obj, qargs=None): 'Cannot apply instruction with classical registers: {}' .format(instr.name)) # Get the integer position of the flat register - new_qargs = [tup[1] for tup in qregs] + new_qargs = [tup.index for tup in qregs] self._append_instruction(instr, qargs=new_qargs) else: raise QiskitError('Input is not an instruction.') diff --git a/qiskit/quantum_info/operators/operator.py b/qiskit/quantum_info/operators/operator.py index 7ae4741a0dbe..5e5654b987a1 100644 --- a/qiskit/quantum_info/operators/operator.py +++ b/qiskit/quantum_info/operators/operator.py @@ -462,7 +462,7 @@ def _append_instruction(self, obj, qargs=None): 'Cannot apply instruction with classical registers: {}'.format( instr.name)) # Get the integer position of the flat register - new_qargs = [tup[1] for tup in qregs] + new_qargs = [tup.index for tup in qregs] self._append_instruction(instr, qargs=new_qargs) else: raise QiskitError('Input is not an instruction.') diff --git a/qiskit/transpiler/layout.py b/qiskit/transpiler/layout.py index 44effad54c96..49a1625004fa 100644 --- a/qiskit/transpiler/layout.py +++ b/qiskit/transpiler/layout.py @@ -19,8 +19,9 @@ Virtual (qu)bits are tuples, e.g. `(QuantumRegister(3, 'qr'), 2)` or simply `qr[2]`. Physical (qu)bits are integers. """ +from warnings import warn -from qiskit.circuit.register import Register +from qiskit.circuit.quantumregister import Qubit from qiskit.transpiler.exceptions import LayoutError @@ -72,6 +73,8 @@ def from_dict(self, input_dict): 2: qr[2]} """ for key, value in input_dict.items(): + key = Layout._cast_tuple_to_bit(key) + value = Layout._cast_tuple_to_bit(value) virtual, physical = Layout.order_based_on_type(key, value) self._p2v[physical] = virtual if virtual is None: @@ -81,24 +84,27 @@ def from_dict(self, input_dict): @staticmethod def order_based_on_type(value1, value2): """decides which one is physical/virtual based on the type. Returns (virtual, physical)""" - if isinstance(value1, int) and Layout.is_virtual(value2): + if isinstance(value1, int) and isinstance(value2, (Qubit, type(None))): physical = value1 virtual = value2 - elif isinstance(value2, int) and Layout.is_virtual(value1): + elif isinstance(value2, int) and isinstance(value1, (Qubit, type(None))): physical = value2 virtual = value1 else: - raise LayoutError('The map (%s -> %s) has to be a ((Register, integer) -> integer)' + raise LayoutError('The map (%s -> %s) has to be a (Bit -> integer)' ' or the other way around.' % (type(value1), type(value2))) return virtual, physical @staticmethod - def is_virtual(value): - """Checks if value has the format of a virtual qubit """ - return value is None or isinstance(value, tuple) and len(value) == 2 and isinstance( - value[0], Register) and isinstance(value[1], int) + def _cast_tuple_to_bit(value): + if isinstance(value, tuple): + warn('Querying layout with a tuple (i.e. layout[(qr, 0)]) is deprecated. ' + 'Go for layout[qr[0]].', DeprecationWarning) + value = value[0][value[1]] + return value def __getitem__(self, item): + item = Layout._cast_tuple_to_bit(item) if item in self._p2v: return self._p2v[item] if item in self._v2p: @@ -106,6 +112,8 @@ def __getitem__(self, item): raise KeyError('The item %s does not exist in the Layout' % (item,)) def __setitem__(self, key, value): + key = Layout._cast_tuple_to_bit(key) + value = Layout._cast_tuple_to_bit(value) virtual, physical = Layout.order_based_on_type(key, value) self._set_type_checked_item(virtual, physical) @@ -123,14 +131,12 @@ def __delitem__(self, key): if isinstance(key, int): del self._p2v[key] del self._v2p[self._p2v[key]] - elif isinstance(key, tuple) and \ - len(key) == 2 and \ - isinstance(key[0], Register) and isinstance(key[1], int): + elif isinstance(key, Qubit): del self._v2p[key] del self._p2v[self._v2p[key]] else: raise LayoutError('The key to remove should be of the form' - ' (Register, integer) or integer) and %s was provided' % (type(key),)) + ' Qubit or integer) and %s was provided' % (type(key),)) def __len__(self): return len(self._p2v) @@ -175,7 +181,7 @@ def get_registers(self): Returns: List: A list of Register in the layout """ - return {reg for reg, _ in self.get_virtual_bits()} + return {bit.register for bit in self.get_virtual_bits()} def get_virtual_bits(self): """ @@ -276,7 +282,7 @@ def from_intlist(int_list, *qregs): main_idx = 0 for qreg in qregs: for idx in range(qreg.size): - out[(qreg, idx)] = int_list[main_idx] + out[qreg[idx]] = int_list[main_idx] main_idx += 1 if main_idx != len(int_list): for int_item in int_list[main_idx:]: @@ -288,24 +294,46 @@ def from_tuplelist(tuple_list): """ Populates a Layout from a list containing virtual qubits---(QuantumRegister, int) tuples---, or None. - Args: tuple_list (list): - e.g.: [qr[0], None, qr[2], qr[3]] + e.g.: [(qr,0), None, (qr,2), (qr,3)] Returns: Layout: the corresponding Layout object Raises: LayoutError: If the elements are not (Register, integer) or None """ + warn('Creating a layout with a list of tuples (eg. [(qr,0), None, (qr,2), (qr,3)]) ' + 'is deprecated. Go for [qr[0], None, qr[2], qr[3]].', DeprecationWarning) + new_list = [] + for tuple_ in tuple_list: + if tuple_ is None: + new_list.append(None) + else: + new_list.append(tuple_[0][tuple_[1]]) + return Layout.from_qubit_list(new_list) + + @staticmethod + def from_qubit_list(qubit_list): + """ + Populates a Layout from a list containing virtual + qubits, Qubit or None. + + Args: + qubit_list (list): + e.g.: [qr[0], None, qr[2], qr[3]] + Returns: + Layout: the corresponding Layout object + Raises: + LayoutError: If the elements are not Qubit or None + """ out = Layout() - for physical, virtual in enumerate(tuple_list): + for physical, virtual in enumerate(qubit_list): if virtual is None: continue - elif Layout.is_virtual(virtual): + elif isinstance(virtual, Qubit): if virtual in out._v2p: raise LayoutError('Duplicate values not permitted; Layout is bijective.') out[virtual] = physical else: - raise LayoutError("The list should contain elements of the form" - " (Register, integer) or None") + raise LayoutError("The list should contain elements of the Bits or NoneTypes") return out diff --git a/qiskit/transpiler/passes/collect_2q_blocks.py b/qiskit/transpiler/passes/collect_2q_blocks.py index 6bb25cea9708..03245737a556 100644 --- a/qiskit/transpiler/passes/collect_2q_blocks.py +++ b/qiskit/transpiler/passes/collect_2q_blocks.py @@ -56,7 +56,7 @@ def run(self, dag): group = [] # Explore predecessors and successors of cx gates if nd.name == "cx" and nd.condition is None and not nodes_seen[nd]: - these_qubits = sorted(nd.qargs) + these_qubits = set(nd.qargs) # Explore predecessors of the "cx" node pred = list(dag.predecessors(nd)) explore = True @@ -66,7 +66,7 @@ def run(self, dag): if len(pred) == 1 and not nodes_seen[pred[0]]: pnd = pred[0] if pnd.name in good_names: - if (pnd.name == "cx" and sorted(pnd.qargs) == these_qubits) or \ + if (pnd.name == "cx" and set(pnd.qargs) == these_qubits) or \ pnd.name != "cx": group.append(pnd) nodes_seen[pnd] = True @@ -82,9 +82,9 @@ def run(self, dag): # We need to avoid accidentally adding a cx on these_qubits # since these must have a dependency through the other predecessor # in this case - if pred[0].name == "cx" and sorted(pred[0].qargs) == these_qubits: + if pred[0].name == "cx" and set(pred[0].qargs) == these_qubits: sorted_pred = [pred[1]] - elif pred[1].name == "cx" and sorted(pred[1].qargs) == these_qubits: + elif pred[1].name == "cx" and set(pred[1].qargs) == these_qubits: sorted_pred = [pred[0]] else: sorted_pred = pred @@ -103,7 +103,7 @@ def run(self, dag): pred_next.extend(dag.predecessors(pnd)) # If cx, check qubits else: - pred_qubits = sorted(pnd.qargs) + pred_qubits = set(pnd.qargs) if pred_qubits == these_qubits: # add if on same qubits if not nodes_seen[pnd]: @@ -124,7 +124,7 @@ def run(self, dag): group.append(nd) nodes_seen[nd] = True # Reset these_qubits - these_qubits = sorted(nd.qargs) + these_qubits = set(nd.qargs) # Explore successors of the "cx" node succ = list(dag.successors(nd)) explore = True @@ -134,7 +134,7 @@ def run(self, dag): if len(succ) == 1 and not nodes_seen[succ[0]]: snd = succ[0] if snd.name in good_names: - if (snd.name == "cx" and sorted(snd.qargs) == these_qubits) or \ + if (snd.name == "cx" and set(snd.qargs) == these_qubits) or \ snd.name != "cx": group.append(snd) nodes_seen[snd] = True @@ -150,9 +150,9 @@ def run(self, dag): # We need to avoid accidentally adding a cx on these_qubits # since these must have a dependency through the other successor # in this case - if succ[0].name == "cx" and sorted(succ[0].qargs) == these_qubits: + if succ[0].name == "cx" and set(succ[0].qargs) == these_qubits: sorted_succ = [succ[1]] - elif succ[1].name == "cx" and sorted(succ[1].qargs) == these_qubits: + elif succ[1].name == "cx" and set(succ[1].qargs) == these_qubits: sorted_succ = [succ[0]] else: sorted_succ = succ @@ -172,7 +172,7 @@ def run(self, dag): succ_next.extend(dag.successors(snd)) else: # If cx, check qubits - succ_qubits = sorted(snd.qargs) + succ_qubits = set(snd.qargs) if succ_qubits == these_qubits: # add if on same qubits if not nodes_seen[snd]: diff --git a/qiskit/transpiler/passes/commutation_analysis.py b/qiskit/transpiler/passes/commutation_analysis.py index c0f86564bac0..98f90d7c4bb5 100644 --- a/qiskit/transpiler/passes/commutation_analysis.py +++ b/qiskit/transpiler/passes/commutation_analysis.py @@ -52,18 +52,17 @@ def run(self, dag): # Build a dictionary to keep track of the gates on each qubit for wire in dag.wires: - wire_name = "{0}[{1}]".format(str(wire[0].name), str(wire[1])) + wire_name = "{0}[{1}]".format(str(wire.register.name), str(wire.index)) self.property_set['commutation_set'][wire_name] = [] # Add edges to the dictionary for each qubit for node in dag.topological_op_nodes(): for (_, _, edge_data) in dag.edges(node): - edge_name = edge_data['name'] self.property_set['commutation_set'][(node, edge_name)] = -1 for wire in dag.wires: - wire_name = "{0}[{1}]".format(str(wire[0].name), str(wire[1])) + wire_name = "{0}[{1}]".format(str(wire.register.name), str(wire.index)) for current_gate in dag.nodes_on_wire(wire): @@ -148,7 +147,7 @@ def _gate_master_def(name, params=None): dtype=np.complex) if name == 'u3': - return 1./np.sqrt(2) * np.array( + return 1. / np.sqrt(2) * np.array( [[np.cos(float(params[0]) / 2.), -np.exp(1j * float(params[2])) * np.sin(float(params[0]) / 2.)], [np.exp(1j * float(params[1])) * np.sin(float(params[0]) / 2.), @@ -168,9 +167,8 @@ def _gate_master_def(name, params=None): def _calc_product(node1, node2): - wire_num = len(set(node1.qargs + node2.qargs)) - wires = sorted(list(map(lambda x: "{0}[{1}]".format(str(x[0].name), str(x[1])), + wires = sorted(list(map(lambda x: "{0}[{1}]".format(str(x.register.name), str(x.index)), list(set(node1.qargs + node2.qargs))))) final_unitary = np.identity(2 ** wire_num, dtype=np.complex) @@ -182,8 +180,9 @@ def _calc_product(node1, node2): qstate_list_ext = [np.identity(2)] * wire_num - node_ctrl = "{0}[{1}]".format(str(node.qargs[0][0].name), str(node.qargs[0][1])) - node_tgt = "{0}[{1}]".format(str(node.qargs[1][0].name), str(node.qargs[1][1])) + node_ctrl = "{0}[{1}]".format(str(node.qargs[0].register.name), + str(node.qargs[0].index)) + node_tgt = "{0}[{1}]".format(str(node.qargs[1].register.name), str(node.qargs[1].index)) ctrl = wires.index(node_ctrl) tgt = wires.index(node_tgt) @@ -202,8 +201,8 @@ def _calc_product(node1, node2): else: mat = _gate_master_def(name=node.name, params=node.op.params) - node_num = "{0}[{1}]".format(str(node.qargs[0][0].name), - str(node.qargs[0][1])) + node_num = "{0}[{1}]".format(str(node.qargs[0].register.name), + str(node.qargs[0].index)) qstate_list[wires.index(node_num)] = mat rt_list = [qstate_list] diff --git a/qiskit/transpiler/passes/commutative_cancellation.py b/qiskit/transpiler/passes/commutative_cancellation.py index af54d2448ce6..b5a01eb00be5 100644 --- a/qiskit/transpiler/passes/commutative_cancellation.py +++ b/qiskit/transpiler/passes/commutative_cancellation.py @@ -56,7 +56,7 @@ def run(self, dag): cancellation_sets = defaultdict(lambda: []) for wire in dag.wires: - wire_name = "{0}[{1}]".format(str(wire[0].name), str(wire[1])) + wire_name = "{0}[{1}]".format(str(wire.register.name), str(wire.index)) wire_commutation_set = self.property_set['commutation_set'][wire_name] for com_set_idx, com_set in enumerate(wire_commutation_set): @@ -69,8 +69,8 @@ def run(self, dag): if num_qargs == 1 and node.name in ['u1', 'rz', 't', 's']: cancellation_sets[('z_rotation', wire_name, com_set_idx)].append(node) elif num_qargs == 2 and node.qargs[0] == wire: - second_op_name = "{0}[{1}]".format(str(node.qargs[1][0].name), - str(node.qargs[1][1])) + second_op_name = "{0}[{1}]".format(str(node.qargs[1].register.name), + str(node.qargs[1].index)) q2_key = (node.name, wire_name, second_op_name, self.property_set['commutation_set'][(node, second_op_name)]) cancellation_sets[q2_key].append(node) @@ -104,9 +104,9 @@ def run(self, dag): # Replace the data of the first node in the run new_op = U1Gate(total_angle) - new_qarg = (QuantumRegister(1, 'q'), 0) + new_qarg = QuantumRegister(1, 'q')[0] new_dag = DAGCircuit() - new_dag.add_qreg(new_qarg[0]) + new_dag.add_qreg(new_qarg.register) new_dag.apply_operation_back(new_op, [new_qarg]) dag.substitute_node_with_dag(run[0], new_dag) diff --git a/qiskit/transpiler/passes/consolidate_blocks.py b/qiskit/transpiler/passes/consolidate_blocks.py index 709c67037320..3cdd49d03535 100644 --- a/qiskit/transpiler/passes/consolidate_blocks.py +++ b/qiskit/transpiler/passes/consolidate_blocks.py @@ -19,7 +19,7 @@ The blocks are collected by a previous pass, such as Collect2qBlocks. """ -from qiskit.circuit import QuantumRegister, QuantumCircuit +from qiskit.circuit import QuantumRegister, QuantumCircuit, Qubit from qiskit.dagcircuit import DAGCircuit from qiskit.quantum_info.operators import Operator from qiskit.extensions import UnitaryGate @@ -47,10 +47,10 @@ def run(self, dag): # compute ordered indices for the global circuit wires global_index_map = {} for wire in dag.wires: - if not isinstance(wire[0], QuantumRegister): + if not isinstance(wire, Qubit): continue global_qregs = list(dag.qregs.values()) - global_index_map[wire] = global_qregs.index(wire[0]) + wire[1] + global_index_map[wire] = global_qregs.index(wire.register) + wire.index blocks = self.property_set['block_list'] nodes_seen = set() diff --git a/qiskit/transpiler/passes/decompose.py b/qiskit/transpiler/passes/decompose.py index 8689a319663a..05960c05bdf6 100644 --- a/qiskit/transpiler/passes/decompose.py +++ b/qiskit/transpiler/passes/decompose.py @@ -49,9 +49,9 @@ def run(self, dag): # hacky way to build a dag on the same register as the rule is defined # TODO: need anonymous rules to address wires by index decomposition = DAGCircuit() - decomposition.add_qreg(rule[0][1][0][0]) + decomposition.add_qreg(rule[0][1][0].register) if rule[0][2]: - decomposition.add_creg(rule[0][2][0][0]) + decomposition.add_creg(rule[0][2][0].register) for inst in rule: decomposition.apply_operation_back(*inst) dag.substitute_node_with_dag(node, decomposition) diff --git a/qiskit/transpiler/passes/mapping/cx_direction.py b/qiskit/transpiler/passes/mapping/cx_direction.py index 1afa5835b838..14bfaad1bcfe 100644 --- a/qiskit/transpiler/passes/mapping/cx_direction.py +++ b/qiskit/transpiler/passes/mapping/cx_direction.py @@ -84,10 +84,10 @@ def run(self, dag): # A flip needs to be done # Create the involved registers - if control[0] not in subdag.qregs.values(): - subdag.add_qreg(control[0]) - if target[0] not in subdag.qregs.values(): - subdag.add_qreg(target[0]) + if control.register not in subdag.qregs.values(): + subdag.add_qreg(control.register) + if target.register not in subdag.qregs.values(): + subdag.add_qreg(target.register) # Add H gates around subdag.apply_operation_back(U2Gate(0, pi), [target], []) diff --git a/qiskit/transpiler/passes/mapping/cython/stochastic_swap/utils.pyx b/qiskit/transpiler/passes/mapping/cython/stochastic_swap/utils.pyx index 3f394c621881..7af3dea02d31 100644 --- a/qiskit/transpiler/passes/mapping/cython/stochastic_swap/utils.pyx +++ b/qiskit/transpiler/passes/mapping/cython/stochastic_swap/utils.pyx @@ -21,7 +21,7 @@ from libc.stdlib cimport calloc, free from libcpp.vector cimport vector from qiskit.transpiler.layout import Layout - +from qiskit.circuit import Qubit cdef class EdgeCollection: """ A simple contain that contains a C++ vector @@ -46,6 +46,7 @@ cdef class EdgeCollection: int: Size of the edge collection. """ return self._edges.size() + @cython.boundscheck(False) def edges(self): """ Returns the vector of edges as a NumPy arrau. @@ -147,8 +148,7 @@ cdef class NLayout: """ Converts numeric layout back to Qiskit Layout object. Args: - qregs (OrderedDict): An ordered dict of (QuantumRegister, int) - tuples. + qregs (OrderedDict): An ordered dict of Qubit instances. Returns: Layout: The corresponding Qiskit Layout object. @@ -158,7 +158,7 @@ cdef class NLayout: cdef size_t idx for qreg in qregs.values(): for idx in range(qreg.size): - out[(qreg, idx)] = self.logic_to_phys[main_idx] + out[qreg[idx]] = self.logic_to_phys[main_idx] main_idx += 1 return out @@ -169,8 +169,7 @@ cpdef NLayout nlayout_from_layout(object layout, object qregs, Args: layout (Layout): A Qiskit Layout instance. - qregs (OrderedDict): An ordered dict of (QuantumRegister, int) - tuples. + qregs (OrderedDict): An ordered dict of Qubit instances. physical_qubits (int): Number of physical qubits. Returns: NLayout: The corresponding numerical layout. @@ -188,8 +187,8 @@ cpdef NLayout nlayout_from_layout(object layout, object qregs, cdef object key, val cdef dict merged_dict = {**layout._p2v, **layout._v2p} for key, val in merged_dict.items(): - if isinstance(key, tuple): - out.logic_to_phys[reg_idx[regint[key[0]]]+key[1]] = val + if isinstance(key, Qubit): + out.logic_to_phys[reg_idx[regint[key.register]]+key.index] = val else: - out.phys_to_logic[key] = reg_idx[regint[val[0]]]+val[1] + out.phys_to_logic[key] = reg_idx[regint[val.register]]+val.index return out diff --git a/qiskit/transpiler/passes/mapping/dense_layout.py b/qiskit/transpiler/passes/mapping/dense_layout.py index 7a4119d7620c..8a2710e7b4c8 100644 --- a/qiskit/transpiler/passes/mapping/dense_layout.py +++ b/qiskit/transpiler/passes/mapping/dense_layout.py @@ -15,7 +15,7 @@ """A pass for choosing a Layout of a circuit onto a Coupling graph. This pass associates a physical qubit (int) to each virtual qubit -of the circuit (tuple(QuantumRegister, int)). +of the circuit (Qubit). Note: even though a 'layout' is not strictly a property of the DAG, in the transpiler architecture it is best passed around between passes by @@ -68,7 +68,7 @@ def run(self, dag): map_iter = 0 for qreg in dag.qregs.values(): for i in range(qreg.size): - layout[(qreg, i)] = int(best_sub[map_iter]) + layout[qreg[i]] = int(best_sub[map_iter]) map_iter += 1 self.property_set['layout'] = layout diff --git a/qiskit/transpiler/passes/mapping/enlarge_with_ancilla.py b/qiskit/transpiler/passes/mapping/enlarge_with_ancilla.py index f09848b95077..f904cdfc710f 100644 --- a/qiskit/transpiler/passes/mapping/enlarge_with_ancilla.py +++ b/qiskit/transpiler/passes/mapping/enlarge_with_ancilla.py @@ -53,7 +53,7 @@ def run(self, dag): " \"layout\" parameter to run") layout_virtual_qubits = self.layout.get_virtual_bits().keys() - new_qregs = {virtual_qubit[0] for virtual_qubit in layout_virtual_qubits + new_qregs = {virtual_qubit.register for virtual_qubit in layout_virtual_qubits if virtual_qubit not in dag.wires} for qreg in new_qregs: diff --git a/qiskit/transpiler/passes/mapping/legacy_swap.py b/qiskit/transpiler/passes/mapping/legacy_swap.py index ff142d9596fd..38776c3e628f 100644 --- a/qiskit/transpiler/passes/mapping/legacy_swap.py +++ b/qiskit/transpiler/passes/mapping/legacy_swap.py @@ -86,11 +86,11 @@ def run(self, dag): # to an expected dict{(reg,idx): (reg,idx)} virtual_qubits = self.initial_layout.get_virtual_bits() - self.initial_layout = {(v[0].name, v[1]): ('q', self.initial_layout[v]) for v in - virtual_qubits} + self.initial_layout = {(v.register.name, v.index): ('q', self.initial_layout[v]) for v + in virtual_qubits} device_register = QuantumRegister(self.coupling_map.size(), 'q') - initial_layout = {(dag.qregs[k[0]], k[1]): (device_register, v[1]) + initial_layout = {dag.qregs[k[0]][k[1]]: device_register[v[1]] for k, v in self.initial_layout.items()} # Check the input layout circ_qubits = dag.qubits() @@ -107,7 +107,7 @@ def run(self, dag): "CouplingGraph" % (v[0].name, v[1])) else: # Supply a default layout - qubit_subset = [(QuantumRegister(self.coupling_map.size(), 'q'), wire) for wire in + qubit_subset = [QuantumRegister(self.coupling_map.size(), 'q')[wire] for wire in self.coupling_map.physical_qubits] qubit_subset = qubit_subset[0:dag.width()] initial_layout = {a: b for a, b in zip(dag.qubits(), qubit_subset)} @@ -129,10 +129,10 @@ def run(self, dag): identity_wire_map = {} q = QuantumRegister(self.coupling_map.size(), 'q') for j in range(self.coupling_map.size()): - identity_wire_map[(q, j)] = (q, j) + identity_wire_map[q[j]] = q[j] for creg in dag.cregs.values(): for j in range(creg.size): - identity_wire_map[(creg, j)] = (creg, j) + identity_wire_map[creg[j]] = creg[j] first_layer = True # True until first layer is output @@ -244,7 +244,8 @@ def layer_permutation(self, layer_partition, layout, qubit_subset): gates.append(tuple(layer)) # Can we already apply the gates? - dist = sum([self.coupling_map.distance(layout[g[0]][1], layout[g[1]][1]) for g in gates]) + dist = sum( + [self.coupling_map.distance(layout[g[0]].index, layout[g[1]].index) for g in gates]) if dist == len(gates): circ = DAGCircuit() circ.add_qreg(QuantumRegister(self.coupling_map.size(), "q")) @@ -283,7 +284,7 @@ def layer_permutation(self, layer_partition, layout, qubit_subset): circ.add_qreg(QR) # Identity wire-map for composing the circuits - identity_wire_map = {(QR, j): (QR, j) for j in range(n)} + identity_wire_map = {QR[j]: QR[j] for j in range(n)} while d < 2 * n + 1: # Set of available qubits @@ -297,7 +298,7 @@ def layer_permutation(self, layer_partition, layout, qubit_subset): progress_made = False # Loop over edges of coupling graph for e in self.coupling_map.get_edges(): - e = [(QR, edge) for edge in e] + e = [QR[edge] for edge in e] # Are the qubits available? if e[0] in qubit_set and e[1] in qubit_set: # Try this edge to reduce the cost @@ -326,15 +327,15 @@ def layer_permutation(self, layer_partition, layout, qubit_subset): rev_trial_layout = rev_opt_layout circ.apply_operation_back( SwapGate(), - [(opt_edge[0][0], opt_edge[0][1]), (opt_edge[1][0], opt_edge[1][1])], + [opt_edge[0], opt_edge[1]], []) else: break # We have either run out of qubits or failed to improve # Compute the coupling graph distance_qubits - dist = sum([self.coupling_map.distance(trial_layout[g[0]][1], - trial_layout[g[1]][1]) for g in gates]) + dist = sum([self.coupling_map.distance(trial_layout[g[0]].index, + trial_layout[g[1]].index) for g in gates]) # If all gates can be applied now, we are finished # Otherwise we need to consider a deeper swap circuit if dist == len(gates): @@ -345,8 +346,8 @@ def layer_permutation(self, layer_partition, layout, qubit_subset): d += 1 # Either we have succeeded at some depth d < dmax or failed - dist = sum([self.coupling_map.distance(trial_layout[g[0]][1], - trial_layout[g[1]][1]) for g in gates]) + dist = sum([self.coupling_map.distance(trial_layout[g[0]].index, + trial_layout[g[1]].index) for g in gates]) if dist == len(gates): if d < best_d: best_circ = trial_circ @@ -376,7 +377,7 @@ def swap_mapper_layer_update(self, i, first_layer, best_layout, best_d, QR = QuantumRegister(self.coupling_map.size(), 'q') dagcircuit_output.add_qreg(QR) # Identity wire-map for composing the circuits - identity_wire_map = {(QR, j): (QR, j) for j in range(self.coupling_map.size())} + identity_wire_map = {QR[j]: QR[j] for j in range(self.coupling_map.size())} # If this is the first layer with multi-qubit gates, # output all layers up to this point and ignore any diff --git a/qiskit/transpiler/passes/mapping/lookahead_swap.py b/qiskit/transpiler/passes/mapping/lookahead_swap.py index 8e1f001ea400..105a8f0222fa 100644 --- a/qiskit/transpiler/passes/mapping/lookahead_swap.py +++ b/qiskit/transpiler/passes/mapping/lookahead_swap.py @@ -286,7 +286,7 @@ def _transform_gate_for_layout(gate, layout): # Workaround until #1816, apply mapped to qargs to both DAGNode and op device_qreg = QuantumRegister(len(layout.get_physical_bits()), 'q') - mapped_qargs = [(device_qreg, layout[a]) for a in mapped_op_node.qargs] + mapped_qargs = [device_qreg[layout[a]] for a in mapped_op_node.qargs] mapped_op_node.qargs = mapped_op_node.op.qargs = mapped_qargs mapped_op_node.pop('name') @@ -298,7 +298,7 @@ def _swap_ops_from_edge(edge, layout): """Generate list of ops to implement a SWAP gate along a coupling edge.""" device_qreg = QuantumRegister(len(layout.get_physical_bits()), 'q') - qreg_edge = [(device_qreg, i) for i in edge] + qreg_edge = [device_qreg[i] for i in edge] # TODO shouldn't be making other nodes not by the DAG!! return [ diff --git a/qiskit/transpiler/passes/mapping/noise_adaptive_layout.py b/qiskit/transpiler/passes/mapping/noise_adaptive_layout.py index a7a06a9fa6ce..511103472459 100644 --- a/qiskit/transpiler/passes/mapping/noise_adaptive_layout.py +++ b/qiskit/transpiler/passes/mapping/noise_adaptive_layout.py @@ -15,7 +15,7 @@ """A pass for choosing a Layout of a circuit onto a Backend This pass associates a physical qubit (int) to each virtual qubit -of the circuit (tuple(QuantumRegister, int)), using calibration data. +of the circuit (Qubit), using calibration data. The pass implements the qubit mapping method from: Noise-Adaptive Compiler Mappings for Noisy Intermediate-Scale Quantum Computers @@ -135,7 +135,7 @@ def _qarg_to_id(self, qubit): """ Converts qarg with name and value to an integer id """ - return self.qarg_to_id[qubit[0].name + str(qubit[1])] + return self.qarg_to_id[qubit.register.name + str(qubit.index)] def _create_program_graph(self, dag): """ @@ -146,7 +146,7 @@ def _create_program_graph(self, dag): """ idx = 0 for q in dag.qubits(): - self.qarg_to_id[q[0].name + str(q[1])] = idx + self.qarg_to_id[q.register.name + str(q.index)] = idx idx += 1 for gate in dag.twoQ_gates(): qid1 = self._qarg_to_id(gate.qargs[0]) @@ -248,5 +248,5 @@ def run(self, dag): for q in dag.qubits(): pid = self._qarg_to_id(q) hwid = self.prog2hw[pid] - layout[(q[0], q[1])] = hwid + layout[q] = hwid self.property_set['layout'] = layout diff --git a/qiskit/transpiler/passes/mapping/set_layout.py b/qiskit/transpiler/passes/mapping/set_layout.py index 96fdf6e70f06..27c272e8baf0 100644 --- a/qiskit/transpiler/passes/mapping/set_layout.py +++ b/qiskit/transpiler/passes/mapping/set_layout.py @@ -16,7 +16,7 @@ Sets property_set['layout'] to layout. This pass associates a physical qubit (int) to each virtual qubit -of the circuit (tuple(QuantumRegister, int)) in increasing order. +of the circuit (Qubit) in increasing order. """ from qiskit.transpiler.basepasses import AnalysisPass diff --git a/qiskit/transpiler/passes/mapping/stochastic_swap.py b/qiskit/transpiler/passes/mapping/stochastic_swap.py index 8777891ac15e..03b74390375b 100644 --- a/qiskit/transpiler/passes/mapping/stochastic_swap.py +++ b/qiskit/transpiler/passes/mapping/stochastic_swap.py @@ -184,9 +184,9 @@ def _layer_update(self, i, first_layer, best_layout, best_depth, logger.debug("layer_update: layout = %s", pformat(layout)) logger.debug("layer_update: self.initial_layout = %s", pformat(self.initial_layout)) dagcircuit_output = DAGCircuit() - for register in layout.get_virtual_bits().keys(): - if register[0] not in dagcircuit_output.qregs.values(): - dagcircuit_output.add_qreg(register[0]) + for qubit in layout.get_virtual_bits().keys(): + if qubit.register not in dagcircuit_output.qregs.values(): + dagcircuit_output.add_qreg(qubit.register) # If this is the first layer with multi-qubit gates, # output all layers up to this point and ignore any @@ -443,8 +443,8 @@ def _layer_permutation(layer_partition, initial_layout, layout, qubit_subset, logger.debug("layer_permutation: nothing to do") circ = DAGCircuit() for register in layout.get_virtual_bits().keys(): - if register[0] not in circ.qregs.values(): - circ.add_qreg(register[0]) + if register.register not in circ.qregs.values(): + circ.add_qreg(register.register) return True, circ, 0, layout, (not bool(gates)) # Begin loop over trials of randomized algorithm @@ -463,14 +463,14 @@ def _layer_permutation(layer_partition, initial_layout, layout, qubit_subset, int_layout = nlayout_from_layout(layout, qregs, coupling.size()) trial_circuit = DAGCircuit() # SWAP circuit for this trial - for register in layout.get_virtual_bits().keys(): - if register[0] not in trial_circuit.qregs.values(): - trial_circuit.add_qreg(register[0]) + for qubit in layout.get_virtual_bits().keys(): + if qubit.register not in trial_circuit.qregs.values(): + trial_circuit.add_qreg(qubit.register) slice_circuit = DAGCircuit() # circuit for this swap slice - for register in layout.get_virtual_bits().keys(): - if register[0] not in slice_circuit.qregs.values(): - slice_circuit.add_qreg(register[0]) + for qubit in layout.get_virtual_bits().keys(): + if qubit.register not in slice_circuit.qregs.values(): + slice_circuit.add_qreg(qubit.register) edges = np.asarray(coupling.get_edges(), dtype=np.int32).ravel() cdist = coupling._dist_matrix for trial in range(trials): @@ -515,13 +515,11 @@ def _layer_permutation(layer_partition, initial_layout, layout, qubit_subset, def regtuple_to_numeric(items, qregs): - """Takes (QuantumRegister, int) tuples and converts - them into an integer array. + """Takes Qubit instances and converts them into an integer array. Args: - items (list): List of tuples of (QuantumRegister, int) - to convert. - qregs (dict): List of )QuantumRegister, int) tuples. + items (list): List of Qubit instances to convert. + qregs (dict): List of Qubit instances. Returns: ndarray: Array of integers. @@ -533,7 +531,7 @@ def regtuple_to_numeric(items, qregs): regint[qreg] = ind out = np.zeros(len(items), dtype=np.int32) for idx, val in enumerate(items): - out[idx] = reg_idx[regint[val[0]]]+val[1] + out[idx] = reg_idx[regint[val.register]]+val.index return out @@ -541,9 +539,8 @@ def gates_to_idx(gates, qregs): """Converts gate tuples into a nested list of integers. Args: - gates (list): List of (QuantumRegister, int) pairs - representing gates. - qregs (dict): List of )QuantumRegister, int) tuples. + gates (list): List of Qubit instances representing gates. + qregs (dict): List of Qubit instances. Returns: list: Nested list of integers for gates. @@ -555,6 +552,6 @@ def gates_to_idx(gates, qregs): regint[qreg] = ind out = np.zeros(2*len(gates), dtype=np.int32) for idx, gate in enumerate(gates): - out[2*idx] = reg_idx[regint[gate[0][0]]]+gate[0][1] - out[2*idx+1] = reg_idx[regint[gate[1][0]]]+gate[1][1] + out[2*idx] = reg_idx[regint[gate[0].register]]+gate[0].index + out[2*idx+1] = reg_idx[regint[gate[1].register]]+gate[1].index return out diff --git a/qiskit/transpiler/passes/mapping/trivial_layout.py b/qiskit/transpiler/passes/mapping/trivial_layout.py index ed1187c5e19d..c17f0409059f 100644 --- a/qiskit/transpiler/passes/mapping/trivial_layout.py +++ b/qiskit/transpiler/passes/mapping/trivial_layout.py @@ -16,7 +16,7 @@ round-robin order. This pass associates a physical qubit (int) to each virtual qubit -of the circuit (tuple(QuantumRegister, int)) in increasing order. +of the circuit (Qubit) in increasing order. """ from qiskit.transpiler.layout import Layout diff --git a/qiskit/transpiler/passes/optimize_1q_gates.py b/qiskit/transpiler/passes/optimize_1q_gates.py index 59b7090e5ac0..08c1551a502b 100644 --- a/qiskit/transpiler/passes/optimize_1q_gates.py +++ b/qiskit/transpiler/passes/optimize_1q_gates.py @@ -168,7 +168,7 @@ def run(self, dag): # Replace the the first node in the run with a dummy DAG which contains a dummy # qubit. The name is irrelevant, because substitute_node_with_dag will take care of # putting it in the right place. - run_qarg = (QuantumRegister(1, 'q'), 0) + run_qarg = QuantumRegister(1, 'q')[0] new_op = Gate(name="", num_qubits=1, params=[]) if right_name == "u1": new_op = U1Gate(right_parameters[2]) @@ -179,7 +179,7 @@ def run(self, dag): if right_name != 'nop': new_dag = DAGCircuit() - new_dag.add_qreg(run_qarg[0]) + new_dag.add_qreg(run_qarg.register) new_dag.apply_operation_back(new_op, [run_qarg], []) dag.substitute_node_with_dag(run[0], new_dag) diff --git a/qiskit/transpiler/passes/unroll_3q_or_more.py b/qiskit/transpiler/passes/unroll_3q_or_more.py index 3c99fd600050..0aeae0c3eb6c 100644 --- a/qiskit/transpiler/passes/unroll_3q_or_more.py +++ b/qiskit/transpiler/passes/unroll_3q_or_more.py @@ -46,7 +46,7 @@ def run(self, dag): # hacky way to build a dag on the same register as the rule is defined # TODO: need anonymous rules to address wires by index decomposition = DAGCircuit() - decomposition.add_qreg(rule[0][1][0][0]) + decomposition.add_qreg(rule[0][1][0].register) for inst in rule: decomposition.apply_operation_back(*inst) decomposition = self.run(decomposition) # recursively unroll diff --git a/qiskit/transpiler/passes/unroller.py b/qiskit/transpiler/passes/unroller.py index 707f6dd68cd3..0199c2dc7245 100644 --- a/qiskit/transpiler/passes/unroller.py +++ b/qiskit/transpiler/passes/unroller.py @@ -75,7 +75,7 @@ def run(self, dag): # hacky way to build a dag on the same register as the rule is defined # TODO: need anonymous rules to address wires by index decomposition = DAGCircuit() - decomposition.add_qreg(rule[0][1][0][0]) + decomposition.add_qreg(rule[0][1][0].register) for inst in rule: decomposition.apply_operation_back(*inst) diff --git a/qiskit/visualization/latex.py b/qiskit/visualization/latex.py index 8a6147c1e36c..399b56f49c82 100644 --- a/qiskit/visualization/latex.py +++ b/qiskit/visualization/latex.py @@ -360,8 +360,8 @@ def _build_latex_array(self, aliases=None): 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])] + pos_1 = self.img_regs[(qarglist[0].register, + qarglist[0].index)] if op.condition: mask = self._get_mask(op.condition[0]) @@ -410,8 +410,7 @@ def _build_latex_array(self, aliases=None): self._latex[pos_1][column] = "\\gate{R_z(%s)}" % ( op.op.params[0]) else: - self._latex[pos_1][column] = ( - "\\gate{%s}" % utf8tolatex(nm)) + self._latex[pos_1][column] = ("\\gate{%s}" % utf8tolatex(nm)) gap = pos_2 - pos_1 for i in range(self.cregs[if_reg]): @@ -470,12 +469,11 @@ def _build_latex_array(self, aliases=None): "\\push{\\rule{.6em}{0em}\\ket{0}\\" "rule{.2em}{0em}} \\qw") else: - self._latex[pos_1][column] = ( - "\\gate{%s}" % utf8tolatex(nm)) + self._latex[pos_1][column] = ("\\gate{%s}" % utf8tolatex(nm)) elif len(qarglist) == 2: - pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] - pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])] + pos_1 = self.img_regs[(qarglist[0].register, qarglist[0].index)] + pos_2 = self.img_regs[(qarglist[1].register, qarglist[1].index)] if op.condition: pos_3 = self.img_regs[(if_reg, 0)] @@ -576,31 +574,30 @@ def _build_latex_array(self, aliases=None): elif nm == "cu3": self._latex[pos_1][column] = "\\ctrl{" + str( pos_2 - pos_1) + "}" - self._latex[pos_2][column] = ("\\gate{U_3(%s,%s,%s)}" % ( - op.op.params[0], - op.op.params[1], - op.op.params[2])) + self._latex[pos_2][column] = ("\\gate{U_3(%s,%s,%s)}" % + (op.op.params[0], + op.op.params[1], + op.op.params[2])) else: start_pos = min([pos_1, pos_2]) stop_pos = max([pos_1, pos_2]) if stop_pos - start_pos >= 2: delta = stop_pos - start_pos - self._latex[start_pos][column] = ( - "\\multigate{%s}{%s}" % ( - delta, utf8tolatex(nm))) + self._latex[start_pos][column] = ("\\multigate{%s}{%s}" + % (delta, utf8tolatex(nm))) for i_pos in range(start_pos + 1, stop_pos + 1): - self._latex[i_pos][column] = ( - "\\ghost{%s}" % utf8tolatex(nm)) + self._latex[i_pos][column] = ("\\ghost{%s}" + % utf8tolatex(nm)) else: - self._latex[start_pos][column] = ( - "\\multigate{1}{%s}" % utf8tolatex(nm)) - self._latex[stop_pos][column] = ( - "\\ghost{%s}" % utf8tolatex(nm)) + self._latex[start_pos][column] = ("\\multigate{1}{%s}" + % utf8tolatex(nm)) + self._latex[stop_pos][column] = ("\\ghost{%s}" % + utf8tolatex(nm)) elif len(qarglist) == 3: - pos_1 = self.img_regs[(qarglist[0][0], qarglist[0][1])] - pos_2 = self.img_regs[(qarglist[1][0], qarglist[1][1])] - pos_3 = self.img_regs[(qarglist[2][0], qarglist[2][1])] + pos_1 = self.img_regs[(qarglist[0].register, qarglist[0].index)] + pos_2 = self.img_regs[(qarglist[1].register, qarglist[1].index)] + pos_3 = self.img_regs[(qarglist[2].register, qarglist[2].index)] if op.condition: pos_4 = self.img_regs[(if_reg, 0)] @@ -677,19 +674,18 @@ def _build_latex_array(self, aliases=None): stop_pos = max([pos_1, pos_2, pos_3]) if stop_pos - start_pos >= 3: delta = stop_pos - start_pos - self._latex[start_pos][column] = ( - "\\multigate{%s}{%s}" % ( - delta, utf8tolatex(nm))) + self._latex[start_pos][column] = ("\\multigate{%s}{%s}" % + (delta, utf8tolatex(nm))) for i_pos in range(start_pos + 1, stop_pos + 1): - self._latex[i_pos][column] = ( - "\\ghost{%s}" % utf8tolatex(nm)) + self._latex[i_pos][column] = ("\\ghost{%s}" % + utf8tolatex(nm)) else: - self._latex[pos_1][column] = ( - "\\multigate{2}{%s}" % utf8tolatex(nm)) - self._latex[pos_2][column] = ( - "\\ghost{%s}" % utf8tolatex(nm)) - self._latex[pos_3][column] = ( - "\\ghost{%s}" % utf8tolatex(nm)) + self._latex[pos_1][column] = ("\\multigate{2}{%s}" % + utf8tolatex(nm)) + self._latex[pos_2][column] = ("\\ghost{%s}" % + utf8tolatex(nm)) + self._latex[pos_3][column] = ("\\ghost{%s}" % + utf8tolatex(nm)) elif len(qarglist) > 3: nbits = len(qarglist) @@ -701,12 +697,10 @@ def _build_latex_array(self, aliases=None): pos_start = min(pos_array) pos_stop = max(pos_array) delta = pos_stop - pos_start - self._latex[pos_start][column] = ( - "\\multigate{%s}{%s}" % ( - nbits - 1, utf8tolatex(nm))) + self._latex[pos_start][column] = ("\\multigate{%s}{%s}" % + (nbits - 1, utf8tolatex(nm))) for pos in range(pos_start + 1, pos_stop + 1): - self._latex[pos][column] = ( - "\\ghost{%s}" % utf8tolatex(nm)) + self._latex[pos][column] = ("\\ghost{%s}" % utf8tolatex(nm)) elif op.name == "measure": if (len(op.cargs) != 1 @@ -718,8 +712,10 @@ def _build_latex_array(self, aliases=None): raise exceptions.VisualizationError( "If controlled measures currently not supported.") - qname, qindex = op.qargs[0] - cname, cindex = op.cargs[0] + qname = op.qargs[0].register + qindex = op.qargs[0].index + cname = op.cargs[0].register + cindex = op.cargs[0].index if aliases: newq = aliases[(qname, qindex)] qname = newq[0] diff --git a/qiskit/visualization/text.py b/qiskit/visualization/text.py index a250debc349e..94cc9c56fdd0 100644 --- a/qiskit/visualization/text.py +++ b/qiskit/visualization/text.py @@ -618,7 +618,7 @@ def draw_wires(wires, vertically_compressed=True): @staticmethod def label_for_conditional(instruction): """ Creates the label for a conditional instruction.""" - return "%s %s" % ('=', instruction.condition[1]) + return "= %s" % instruction.condition[1] @staticmethod def params_for_label(instruction): diff --git a/test/python/circuit/test_circuit_registers.py b/test/python/circuit/test_circuit_registers.py index 2ff7b4d1535c..99582d7c91fa 100644 --- a/test/python/circuit/test_circuit_registers.py +++ b/test/python/circuit/test_circuit_registers.py @@ -23,7 +23,7 @@ import qiskit.extensions.simulator from qiskit import BasicAer -from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit +from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit, Qubit, Clbit from qiskit import execute from qiskit import QiskitError from qiskit.quantum_info import state_fidelity @@ -68,13 +68,30 @@ def test_qarg_numpy_int_size(self): self.assertEqual(qr1.size, 10) self.assertEqual(type(qr1), QuantumRegister) + def test_numpy_array_of_registers(self): + """Test numpy array of Registers . + See https://github.com/Qiskit/qiskit-terra/issues/1898 + """ + qrs = [QuantumRegister(2, name='q%s' % i) for i in range(5)] + qreg_array = np.array([], dtype=object, ndmin=1) + qreg_array = np.append(qreg_array, qrs) + + expected = [qrs[0][0], qrs[0][1], + qrs[1][0], qrs[1][1], + qrs[2][0], qrs[2][1], + qrs[3][0], qrs[3][1], + qrs[4][0], qrs[4][1]] + + self.assertEqual(len(qreg_array), 10) + self.assertEqual(qreg_array.tolist(), expected) + def test_negative_index(self): """Test indexing from the back """ qr1 = QuantumRegister(10, "q") cr1 = ClassicalRegister(10, "c") - self.assertEqual(qr1[-1], (qr1, 9)) - self.assertEqual(qr1[-3:-1], [(qr1, 7), (qr1, 8)]) + self.assertEqual(qr1[-1], qr1[9]) + self.assertEqual(qr1[-3:-1], [qr1[7], qr1[8]]) self.assertEqual(len(cr1[0:-2]), 8) def test_reg_equal(self): @@ -155,7 +172,7 @@ def test_apply_gate_to_slice(self): qc = QuantumCircuit(qr, cr) qc.h(qr[0:9:2]) for i, index in enumerate(range(*sli.indices(sli.stop))): - self.assertEqual(qc.data[i][1][0][1], index) + self.assertEqual(qc.data[i][1][0].index, index) def test_apply_barrier_to_slice(self): """test applying barrier to register slice""" @@ -169,8 +186,8 @@ def test_apply_barrier_to_slice(self): self.assertEqual(len(qc.data), 1) self.assertEqual(qc.data[0][0].name, 'barrier') self.assertEqual(len(qc.data[0][1]), n_qubits) - for i, (_, idx) in enumerate(qc.data[0][1]): - self.assertEqual(idx, i) + for i, bit in enumerate(qc.data[0][1]): + self.assertEqual(bit.index, i) # test slice n_qubits = 2 qc = QuantumCircuit(qr, cr) @@ -180,7 +197,7 @@ def test_apply_barrier_to_slice(self): self.assertEqual(qc.data[0][0].name, 'barrier') self.assertEqual(len(qc.data[0][1]), n_qubits) for i in range(n_qubits): - self.assertEqual(qc.data[0][1][i][1], i) + self.assertEqual(qc.data[0][1][i].index, i) def test_apply_ccx_to_slice(self): """test applying ccx to register slice""" @@ -195,9 +212,9 @@ def test_apply_ccx_to_slice(self): for i, ictl, (gate, qargs, _) in zip(range(len(qc.data)), range(0, 10, 2), qc.data): self.assertEqual(gate.name, 'ccx') self.assertEqual(len(qargs), 3) - self.assertIn(qargs[0][1], [ictl, ictl + 1]) - self.assertIn(qargs[1][1], [ictl, ictl + 1]) - self.assertEqual(qargs[2][1], i) + self.assertIn(qargs[0].index, [ictl, ictl + 1]) + self.assertIn(qargs[1].index, [ictl, ictl + 1]) + self.assertEqual(qargs[2].index, i) # test decrementing slice qc = QuantumCircuit(qcontrol, qtarget) qc.ccx(qcontrol[2:0:-1], qcontrol[4:6], qtarget[0:2]) @@ -206,18 +223,18 @@ def test_apply_ccx_to_slice(self): range(4, 6), range(0, 2)): self.assertEqual(gate.name, 'ccx') self.assertEqual(len(qargs), 3) - self.assertEqual(qargs[0][1], ictl1) - self.assertEqual(qargs[1][1], ictl2) - self.assertEqual(qargs[2][1], itgt) + self.assertEqual(qargs[0].index, ictl1) + self.assertEqual(qargs[1].index, ictl2) + self.assertEqual(qargs[2].index, itgt) # test register expansion in ccx qc = QuantumCircuit(qcontrol, qcontrol2, qtarget2) qc.ccx(qcontrol, qcontrol2, qtarget2) for i, (gate, qargs, _) in enumerate(qc.data): self.assertEqual(gate.name, 'ccx') self.assertEqual(len(qargs), 3) - self.assertEqual(qargs[0][1], i) - self.assertEqual(qargs[1][1], i) - self.assertEqual(qargs[2][1], i) + self.assertEqual(qargs[0].index, i) + self.assertEqual(qargs[1].index, i) + self.assertEqual(qargs[2].index, i) def test_cswap_on_slice(self): """test applying cswap to register slice""" @@ -256,16 +273,16 @@ def test_apply_ch_to_slice(self): for (gate, qargs, _), ictrl, itgt in zip(qc.data, range(0, 2), range(2, 4)): self.assertEqual(gate.name, 'ch') self.assertEqual(len(qargs), 2) - self.assertEqual(qargs[0][1], ictrl) - self.assertEqual(qargs[1][1], itgt) + self.assertEqual(qargs[0].index, ictrl) + self.assertEqual(qargs[1].index, itgt) # test single qubit args qc = QuantumCircuit(qr, cr) qc.ch(qr[0], qr[1]) self.assertEqual(len(qc.data), 1) op, qargs, _ = qc.data[0] self.assertEqual(op.name, 'ch') - self.assertEqual(qargs[0][1], 0) - self.assertEqual(qargs[1][1], 1) + self.assertEqual(qargs[0].index, 0) + self.assertEqual(qargs[1].index, 1) def test_measure_slice(self): """test measure slice""" @@ -278,8 +295,8 @@ def test_measure_slice(self): self.assertEqual(gate.name, 'measure') self.assertEqual(len(qargs), 1) self.assertEqual(len(cargs), 1) - self.assertEqual(qargs[0][1], ictrl) - self.assertEqual(cargs[0][1], itgt) + self.assertEqual(qargs[0].index, ictrl) + self.assertEqual(cargs[0].index, itgt) # test single element slice qc = QuantumCircuit(qr, cr) qc.measure(qr[0:1], cr[2:3]) @@ -287,8 +304,8 @@ def test_measure_slice(self): self.assertEqual(gate.name, 'measure') self.assertEqual(len(qargs), 1) self.assertEqual(len(cargs), 1) - self.assertEqual(qargs[0][1], ictrl) - self.assertEqual(cargs[0][1], itgt) + self.assertEqual(qargs[0].index, ictrl) + self.assertEqual(cargs[0].index, itgt) # test tuple qc = QuantumCircuit(qr, cr) qc.measure(qr[0], cr[2]) @@ -297,10 +314,10 @@ def test_measure_slice(self): self.assertEqual(op.name, 'measure') self.assertEqual(len(qargs), 1) self.assertEqual(len(cargs), 1) - self.assertTrue(isinstance(qargs[0], tuple)) - self.assertTrue(isinstance(cargs[0], tuple)) - self.assertEqual(qargs[0][1], 0) - self.assertEqual(cargs[0][1], 2) + self.assertTrue(isinstance(qargs[0], Qubit)) + self.assertTrue(isinstance(cargs[0], Clbit)) + self.assertEqual(qargs[0].index, 0) + self.assertEqual(cargs[0].index, 2) # test full register qc = QuantumCircuit(qr, cr) qc.measure(qr, cr) @@ -308,8 +325,8 @@ def test_measure_slice(self): self.assertEqual(gate.name, 'measure') self.assertEqual(len(qargs), 1) self.assertEqual(len(cargs), 1) - self.assertEqual(qargs[0][1], ictrl) - self.assertEqual(cargs[0][1], itgt) + self.assertEqual(qargs[0].index, ictrl) + self.assertEqual(cargs[0].index, itgt) # test mix slice full register qc = QuantumCircuit(qr, cr2) qc.measure(qr[::2], cr2) @@ -317,8 +334,8 @@ def test_measure_slice(self): self.assertEqual(gate.name, 'measure') self.assertEqual(len(qargs), 1) self.assertEqual(len(cargs), 1) - self.assertEqual(qargs[0][1], ictrl) - self.assertEqual(cargs[0][1], itgt) + self.assertEqual(qargs[0].index, ictrl) + self.assertEqual(cargs[0].index, itgt) def test_measure_slice_raises(self): """test raising exception for strange measures""" @@ -341,12 +358,49 @@ def test_list_indexing(self): for (gate, qargs, _), index in zip(qc.data, ind): self.assertEqual(gate.name, 'h') self.assertEqual(len(qargs), 1) - self.assertEqual(qargs[0][1], index) + self.assertEqual(qargs[0].index, index) qc = QuantumCircuit(qr, cr) ind = [0, 1, 8, 9] qc.cx(qr[ind], qr[2:6]) for (gate, qargs, _), ind1, ind2 in zip(qc.data, ind, range(2, 6)): self.assertEqual(gate.name, 'cx') self.assertEqual(len(qargs), 2) - self.assertEqual(qargs[0][1], ind1) - self.assertEqual(qargs[1][1], ind2) + self.assertEqual(qargs[0].index, ind1) + self.assertEqual(qargs[1].index, ind2) + + +class TestCircuitBit(QiskitTestCase): + """QuantumCircuit Registers tests.""" + + def test_bit_getitem(self): + """ Deprecated Bit.__getitem__. + """ + qubit = QuantumRegister(1, "q")[0] + + with self.assertWarns(DeprecationWarning): + self.assertEqual(qubit[0], qubit.register) + self.assertEqual(qubit[1], qubit.index) + + def test_gate_with_tuples(self): + """ Deprecated gate parameters as tuples""" + qr = QuantumRegister(1) + qc = QuantumCircuit(qr) + + expected = QuantumCircuit(qr) + expected.h(qr[0]) + + with self.assertWarns(DeprecationWarning): + qc.h((qr, 0)) + self.assertEqual(qc, expected) + + def test_gate_with_tuple_list(self): + """ Deprecated gate parameters as tuple list""" + qr = QuantumRegister(2) + qc = QuantumCircuit(qr) + + expected = QuantumCircuit(qr) + expected.h([qr[0], qr[1]]) + + with self.assertWarns(DeprecationWarning): + qc.h([(qr, 0), (qr, 1)]) + self.assertEqual(qc, expected) diff --git a/test/python/circuit/test_extensions_standard.py b/test/python/circuit/test_extensions_standard.py index 72bf849d8503..612f84dc81d6 100644 --- a/test/python/circuit/test_extensions_standard.py +++ b/test/python/circuit/test_extensions_standard.py @@ -49,7 +49,6 @@ def test_barrier_invalid(self): qc = self.circuit self.assertRaises(QiskitError, qc.barrier, self.cr[0]) self.assertRaises(QiskitError, qc.barrier, self.cr) - self.assertRaises(QiskitError, qc.barrier, (self.qr, -3)) self.assertRaises(QiskitError, qc.barrier, (self.qr, 'a')) self.assertRaises(QiskitError, qc.barrier, .0) @@ -85,7 +84,6 @@ def test_ccx_invalid(self): self.assertRaises(QiskitError, qc.ccx, self.cr[0], self.cr[1], self.cr[2]) self.assertRaises(QiskitError, qc.ccx, self.qr[0], self.qr[0], self.qr[2]) self.assertRaises(QiskitError, qc.ccx, 0.0, self.qr[0], self.qr[2]) - self.assertRaises(QiskitError, qc.ccx, (self.qr, -3), self.qr[1], self.qr[2]) self.assertRaises(QiskitError, qc.ccx, self.cr, self.qr, self.qr) self.assertRaises(QiskitError, qc.ccx, 'a', self.qr[1], self.qr[2]) @@ -934,7 +932,6 @@ def test_x_invalid(self): qc = self.circuit self.assertRaises(QiskitError, qc.x, self.cr[0]) self.assertRaises(QiskitError, qc.x, self.cr) - self.assertRaises(QiskitError, qc.x, (self.qr, -3)) self.assertRaises(QiskitError, qc.x, (self.qr, 'a')) self.assertRaises(QiskitError, qc.x, 0.0) @@ -968,7 +965,6 @@ def test_y_invalid(self): qc = self.circuit self.assertRaises(QiskitError, qc.y, self.cr[0]) self.assertRaises(QiskitError, qc.y, self.cr) - self.assertRaises(QiskitError, qc.y, (self.qr, -3)) self.assertRaises(QiskitError, qc.y, (self.qr, 'a')) self.assertRaises(QiskitError, qc.y, 0.0) diff --git a/test/python/circuit/test_unitary.py b/test/python/circuit/test_unitary.py index 56c5d7e17fab..324311d76eba 100644 --- a/test/python/circuit/test_unitary.py +++ b/test/python/circuit/test_unitary.py @@ -94,9 +94,8 @@ def test_1q_unitary(self): dnode = dag_nodes[0] self.assertIsInstance(dnode.op, UnitaryGate) for qubit in dnode.qargs: - self.assertTrue(qubit[1] in [0, 1]) - self.assertTrue(numpy.allclose(dnode.op.to_matrix(), - matrix)) + self.assertTrue(qubit.index in [0, 1]) + self.assertTrue(numpy.allclose(dnode.op.to_matrix(), matrix)) def test_2q_unitary(self): """test 2 qubit unitary matrix""" @@ -123,7 +122,7 @@ def test_2q_unitary(self): dnode = nodes[0] self.assertIsInstance(dnode.op, UnitaryGate) for qubit in dnode.qargs: - self.assertTrue(qubit[1] in [0, 1]) + self.assertTrue(qubit.index in [0, 1]) self.assertTrue(numpy.allclose(dnode.op.to_matrix(), matrix)) qc3 = dag_to_circuit(dag) @@ -148,7 +147,7 @@ def test_3q_unitary(self): dnode = nodes[0] self.assertIsInstance(dnode.op, UnitaryGate) for qubit in dnode.qargs: - self.assertTrue(qubit[1] in [0, 1, 3]) + self.assertTrue(qubit.index in [0, 1, 3]) self.assertTrue(numpy.allclose(dnode.op.to_matrix(), matrix)) diff --git a/test/python/compiler/test_compiler.py b/test/python/compiler/test_compiler.py index 642c40a5b410..604cbb3dbe8e 100644 --- a/test/python/compiler/test_compiler.py +++ b/test/python/compiler/test_compiler.py @@ -177,7 +177,7 @@ def test_compile_single_qubit(self): qr = QuantumRegister(1, 'qr') circuit = QuantumCircuit(qr) circuit.h(qr[0]) - layout = {(qr, 0): 12} + layout = {qr[0]: 12} cmap = [[1, 0], [1, 2], [2, 3], [4, 3], [4, 10], [5, 4], [5, 6], [5, 9], [6, 8], [7, 8], [9, 8], [9, 10], [11, 3], [11, 10], [11, 12], [12, 2], [13, 1], [13, 12]] @@ -219,7 +219,7 @@ def test_compile_with_initial_layout(self): qc = QuantumCircuit(qr, cr) qc.cx(qr[2], qr[1]) qc.cx(qr[2], qr[0]) - initial_layout = {0: (qr, 1), 2: (qr, 0), 15: (qr, 2)} + initial_layout = {0: qr[1], 2: qr[0], 15: qr[2]} backend = FakeRueschlikon() qc_b = transpile(qc, backend, seed_transpiler=42, initial_layout=initial_layout) qobj = assemble(qc_b) diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 3b14bb6fc523..0c15f8fe7454 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -116,7 +116,7 @@ def test_transpile_non_adjacent_layout(self): for gate, qargs, _ in new_circuit.data: if isinstance(gate, CnotGate): - self.assertIn([x[1] for x in qargs], coupling_map) + self.assertIn([x.index for x in qargs], coupling_map) def test_transpile_qft_grid(self): """Transpile pipeline can handle 8-qubit QFT on 14-qubit grid. @@ -136,7 +136,7 @@ def test_transpile_qft_grid(self): for gate, qargs, _ in new_circuit.data: if isinstance(gate, CnotGate): - self.assertIn([x[1] for x in qargs], coupling_map) + self.assertIn([x.index for x in qargs], coupling_map) def test_already_mapped_1(self): """Circuit not remapped if matches topology. @@ -163,7 +163,7 @@ def test_already_mapped_1(self): new_qc = transpile(qc, coupling_map=coupling_map, basis_gates=basis_gates) cx_qubits = [qargs for (gate, qargs, _) in new_qc.data if gate.name == "cx"] - cx_qubits_physical = [[ctrl[1], tgt[1]] for [ctrl, tgt] in cx_qubits] + cx_qubits_physical = [[ctrl.index, tgt.index] for [ctrl, tgt] in cx_qubits] self.assertEqual(sorted(cx_qubits_physical), [[3, 4], [3, 14], [5, 4], [9, 8], [12, 11], [13, 4]]) @@ -204,7 +204,7 @@ def test_already_mapped_via_layout(self): basis_gates=basis_gates, initial_layout=initial_layout) cx_qubits = [qargs for (gate, qargs, _) in new_qc.data if gate.name == "cx"] - cx_qubits_physical = [[ctrl[1], tgt[1]] for [ctrl, tgt] in cx_qubits] + cx_qubits_physical = [[ctrl.index, tgt.index] for [ctrl, tgt] in cx_qubits] self.assertEqual(sorted(cx_qubits_physical), [[9, 4], [9, 4]]) @@ -341,7 +341,7 @@ def test_transpiler_layout_from_intlist(self): initial_layout=layout) mapped_qubits = [] for _, qargs, _ in new_circ.data: - mapped_qubits.append(qargs[0][1]) + mapped_qubits.append(qargs[0].index) self.assertEqual(mapped_qubits, [4, 6, 10]) @@ -392,9 +392,9 @@ def test_wrong_initial_layout(self): qc.cx(qubit_reg[0], qubit_reg[1]) qc.measure(qubit_reg, clbit_reg) - bad_initial_layout = [(QuantumRegister(3, 'q'), 0), - (QuantumRegister(3, 'q'), 1), - (QuantumRegister(3, 'q'), 2)] + bad_initial_layout = [QuantumRegister(3, 'q')[0], + QuantumRegister(3, 'q')[1], + QuantumRegister(3, 'q')[2]] self.assertRaises(KeyError, transpile, qc, backend, initial_layout=bad_initial_layout) diff --git a/test/python/pickles/TestsBasicSwap_a_cx_to_map.pickle b/test/python/pickles/TestsBasicSwap_a_cx_to_map.pickle index aa3d1a3a02d8..7a7bd7bbb6fd 100644 Binary files a/test/python/pickles/TestsBasicSwap_a_cx_to_map.pickle and b/test/python/pickles/TestsBasicSwap_a_cx_to_map.pickle differ diff --git a/test/python/pickles/TestsBasicSwap_handle_measurement.pickle b/test/python/pickles/TestsBasicSwap_handle_measurement.pickle index 2cafb04bbe9d..b9d978082ba3 100644 Binary files a/test/python/pickles/TestsBasicSwap_handle_measurement.pickle and b/test/python/pickles/TestsBasicSwap_handle_measurement.pickle differ diff --git a/test/python/pickles/TestsBasicSwap_initial_layout.pickle b/test/python/pickles/TestsBasicSwap_initial_layout.pickle index abd62a271c71..7bbe177290aa 100644 Binary files a/test/python/pickles/TestsBasicSwap_initial_layout.pickle and b/test/python/pickles/TestsBasicSwap_initial_layout.pickle differ diff --git a/test/python/pickles/TestsLegacySwap_a_cx_to_map.pickle b/test/python/pickles/TestsLegacySwap_a_cx_to_map.pickle index adba96478e08..99ef11c2322b 100644 Binary files a/test/python/pickles/TestsLegacySwap_a_cx_to_map.pickle and b/test/python/pickles/TestsLegacySwap_a_cx_to_map.pickle differ diff --git a/test/python/pickles/TestsLegacySwap_handle_measurement.pickle b/test/python/pickles/TestsLegacySwap_handle_measurement.pickle index ea40c0a05384..fcb5740641aa 100644 Binary files a/test/python/pickles/TestsLegacySwap_handle_measurement.pickle and b/test/python/pickles/TestsLegacySwap_handle_measurement.pickle differ diff --git a/test/python/pickles/TestsLegacySwap_initial_layout.pickle b/test/python/pickles/TestsLegacySwap_initial_layout.pickle index 3ad56bfe765a..84163ae31d93 100644 Binary files a/test/python/pickles/TestsLegacySwap_initial_layout.pickle and b/test/python/pickles/TestsLegacySwap_initial_layout.pickle differ diff --git a/test/python/pickles/TestsLookaheadSwap_a_cx_to_map.pickle b/test/python/pickles/TestsLookaheadSwap_a_cx_to_map.pickle index 663bfe64677b..1ebc382daa0c 100644 Binary files a/test/python/pickles/TestsLookaheadSwap_a_cx_to_map.pickle and b/test/python/pickles/TestsLookaheadSwap_a_cx_to_map.pickle differ diff --git a/test/python/pickles/TestsLookaheadSwap_handle_measurement.pickle b/test/python/pickles/TestsLookaheadSwap_handle_measurement.pickle index 691deb63c8cf..720776744c40 100644 Binary files a/test/python/pickles/TestsLookaheadSwap_handle_measurement.pickle and b/test/python/pickles/TestsLookaheadSwap_handle_measurement.pickle differ diff --git a/test/python/pickles/TestsLookaheadSwap_initial_layout.pickle b/test/python/pickles/TestsLookaheadSwap_initial_layout.pickle index 3da94d5d57ef..2025bc0af0c2 100644 Binary files a/test/python/pickles/TestsLookaheadSwap_initial_layout.pickle and b/test/python/pickles/TestsLookaheadSwap_initial_layout.pickle differ diff --git a/test/python/pickles/TestsStochasticSwap_a_cx_to_map.pickle b/test/python/pickles/TestsStochasticSwap_a_cx_to_map.pickle index adba96478e08..99ef11c2322b 100644 Binary files a/test/python/pickles/TestsStochasticSwap_a_cx_to_map.pickle and b/test/python/pickles/TestsStochasticSwap_a_cx_to_map.pickle differ diff --git a/test/python/pickles/TestsStochasticSwap_handle_measurement.pickle b/test/python/pickles/TestsStochasticSwap_handle_measurement.pickle index 38c52e777109..112ef16a8226 100644 Binary files a/test/python/pickles/TestsStochasticSwap_handle_measurement.pickle and b/test/python/pickles/TestsStochasticSwap_handle_measurement.pickle differ diff --git a/test/python/pickles/TestsStochasticSwap_initial_layout.pickle b/test/python/pickles/TestsStochasticSwap_initial_layout.pickle index abd62a271c71..7bbe177290aa 100644 Binary files a/test/python/pickles/TestsStochasticSwap_initial_layout.pickle and b/test/python/pickles/TestsStochasticSwap_initial_layout.pickle differ diff --git a/test/python/test_dagcircuit.py b/test/python/test_dagcircuit.py index 3f575f1829d5..f3c5a059f2bd 100644 --- a/test/python/test_dagcircuit.py +++ b/test/python/test_dagcircuit.py @@ -301,9 +301,8 @@ def test_dag_nodes_on_wire(self): self.assertEqual([7, 8], [i._node_id for i in self.dag.nodes_on_wire(cbit)]) self.assertEqual([], [i._node_id for i in self.dag.nodes_on_wire(cbit, only_ops=True)]) - (reg, _) = qbit with self.assertRaises(DAGCircuitError): - next(self.dag.nodes_on_wire((reg, 7))) + next(self.dag.nodes_on_wire((qbit.register, 7))) def test_dag_nodes_on_wire_multiple_successors(self): """ diff --git a/test/python/transpiler/test_full_ancilla_allocation.py b/test/python/transpiler/test_full_ancilla_allocation.py index 525e9b66d063..734c7f79a403 100644 --- a/test/python/transpiler/test_full_ancilla_allocation.py +++ b/test/python/transpiler/test_full_ancilla_allocation.py @@ -139,7 +139,7 @@ def test_name_collision(self): pass_.run(dag) after_layout = pass_.property_set['layout'] - qregs = set(v[0] for v in after_layout.get_virtual_bits().keys()) + qregs = set(v.register for v in after_layout.get_virtual_bits().keys()) self.assertEqual(2, len(qregs)) self.assertIn(qr_ancilla, qregs) qregs.remove(qr_ancilla) diff --git a/test/python/transpiler/test_layout.py b/test/python/transpiler/test_layout.py index de96d363fb15..4b1c0f0a3589 100644 --- a/test/python/transpiler/test_layout.py +++ b/test/python/transpiler/test_layout.py @@ -17,7 +17,7 @@ import copy import unittest -from qiskit import QuantumRegister +from qiskit.circuit import QuantumRegister, Qubit from qiskit.transpiler.layout import Layout from qiskit.transpiler.exceptions import LayoutError from qiskit.test import QiskitTestCase @@ -26,6 +26,385 @@ class LayoutTest(QiskitTestCase): """Test the methods in the layout object.""" + def setUp(self): + self.qr = QuantumRegister(3, 'qr') + + def test_default_layout(self): + """Static method generate_trivial_layout creates a Layout""" + qr0 = QuantumRegister(3, 'q0') + qr1 = QuantumRegister(2, 'qr1') + layout = Layout.generate_trivial_layout(qr0, qr1) + + self.assertEqual(layout[(qr0, 0)], 0) + self.assertEqual(layout[(qr0, 1)], 1) + self.assertEqual(layout[(qr0, 2)], 2) + self.assertEqual(layout[(qr1, 0)], 3) + self.assertEqual(layout[(qr1, 1)], 4) + + def test_layout_from_dict(self): + """Constructor from a dict""" + layout = Layout({self.qr[0]: 0, + self.qr[1]: 1, + self.qr[2]: 2}) + + self.assertEqual(layout[self.qr[0]], 0) + self.assertEqual(layout[self.qr[1]], 1) + self.assertEqual(layout[self.qr[2]], 2) + self.assertEqual(layout[0], self.qr[0]) + self.assertEqual(layout[1], self.qr[1]) + self.assertEqual(layout[2], self.qr[2]) + + def test_layout_from_dict_hole(self): + """Constructor from a dict with a hole""" + qr0 = QuantumRegister(2) + qr1 = QuantumRegister(2) + + layout = Layout({qr0[0]: 0, + qr1[0]: 1, + qr1[1]: 3, + qr0[1]: 4}) + + self.assertEqual(layout[qr0[0]], 0) + self.assertEqual(layout[qr1[0]], 1) + with self.assertRaises(KeyError): + _ = layout[None] + self.assertEqual(layout[qr1[1]], 3) + self.assertEqual(layout[qr0[1]], 4) + + self.assertEqual(layout[0], qr0[0]) + self.assertEqual(layout[1], qr1[0]) + self.assertEqual(layout[3], qr1[1]) + self.assertEqual(layout[4], qr0[1]) + + def test_layout_set(self): + """Setter""" + layout = Layout() + layout[self.qr[0]] = 0 + self.assertEqual(layout[self.qr[0]], 0) + self.assertEqual(layout[0], self.qr[0]) + + def test_layout_avoid_dangling_physical(self): + """ No dangling pointers for physical qubits.""" + layout = Layout({self.qr[0]: 0}) + self.assertEqual(layout[0], self.qr[0]) + layout[self.qr[0]] = 1 + with self.assertRaises(KeyError): + _ = layout[0] + + def test_layout_avoid_dangling_virtual(self): + """ No dangling pointers for virtual qubits.""" + layout = Layout({self.qr[0]: 0}) + self.assertEqual(layout[0], (self.qr, 0)) + layout[0] = self.qr[1] + with self.assertRaises(KeyError): + _ = layout[self.qr[0]] + + def test_layout_len(self): + """Length of the layout is the amount of physical bits""" + layout = Layout() + self.assertEqual(len(layout), 0) + layout.add(self.qr[2]) + self.assertEqual(len(layout), 1) + layout.add(self.qr[1], 3) + self.assertEqual(len(layout), 2) + + def test_layout_len_with_idle(self): + """Length of the layout is the amount of physical bits""" + layout = Layout() + self.assertEqual(len(layout), 0) + layout.add(self.qr[2]) + self.assertEqual(len(layout), 1) + layout.add(self.qr[1], 3) + self.assertEqual(len(layout), 2) + + def test_layout_get_bits(self): + """Get the map from the (qu)bits view""" + layout_dict = {self.qr[0]: 0, + self.qr[1]: 1, + self.qr[2]: 2} + layout = Layout(layout_dict) + self.assertDictEqual(layout_dict, layout.get_virtual_bits()) + + def test_layout_get_physical_bits(self): + """Get the map from the physical bits view""" + layout = Layout({self.qr[0]: 0, self.qr[1]: 1, self.qr[2]: 2}) + self.assertDictEqual(layout.get_physical_bits(), {0: self.qr[0], + 1: self.qr[1], + 2: self.qr[2]}) + + def test_layout_add(self): + """add() method""" + layout = Layout() + layout[self.qr[0]] = 0 + layout.add(self.qr[1]) + + self.assertEqual(layout[self.qr[1]], 1) + + def test_layout_add_register(self): + """add_register() method""" + layout = Layout() + layout.add_register(QuantumRegister(2, 'q0')) + layout.add_register(QuantumRegister(1, 'qr1')) + + self.assertEqual(layout[(QuantumRegister(2, 'q0'), 0)], 0) + self.assertEqual(layout[(QuantumRegister(2, 'q0'), 1)], 1) + self.assertEqual(layout[(QuantumRegister(1, 'qr1'), 0)], 2) + + def test_physical_keyerror(self): + """When asking for an unexistant physical qubit, KeyError""" + layout = Layout() + layout[self.qr[0]] = 1 + + with self.assertRaises(KeyError): + _ = layout[0] + + def test_virtual_keyerror(self): + """When asking for an unexistant virtual qubit, KeyError""" + layout = Layout() + layout[self.qr[0]] = 1 + + with self.assertRaises(KeyError): + _ = layout[(self.qr, 1)] + + def test_layout_swap(self): + """swap() method""" + layout = Layout() + layout.add(self.qr[0]) + layout.add(self.qr[1]) + layout.swap(0, 1) + self.assertDictEqual(layout.get_virtual_bits(), {(self.qr, 0): 1, (self.qr, 1): 0}) + + def test_layout_swap_error(self): + """swap() method error""" + layout = Layout() + layout.add(self.qr[0]) + layout.add(self.qr[1]) + with self.assertRaises(LayoutError): + layout.swap(0, (self.qr, 0)) + + def test_layout_combine(self): + """combine_into_edge_map() method""" + layout = Layout() + layout.add(self.qr[0]) + layout.add(self.qr[1]) + another_layout = Layout() + another_layout.add(self.qr[1]) + another_layout.add(self.qr[0]) + + edge_map = layout.combine_into_edge_map(another_layout) + self.assertDictEqual(edge_map, {(self.qr, 0): (self.qr, 1), (self.qr, 1): (self.qr, 0)}) + + def test_layout_combine_bigger(self): + """combine_into_edge_map() method with another_layout is bigger""" + layout = Layout() + layout.add(self.qr[0]) + layout.add(self.qr[1]) + another_layout = Layout() + another_layout.add(self.qr[1]) + another_layout.add(self.qr[0]) + another_layout.add(self.qr[2]) + + edge_map = layout.combine_into_edge_map(another_layout) + self.assertDictEqual(edge_map, {(self.qr, 0): (self.qr, 1), (self.qr, 1): (self.qr, 0)}) + + def test_set_virtual_without_physical(self): + """When adding a virtual without care in which physical is going""" + layout = Layout() + layout.add(self.qr[1], 2) + layout.add(self.qr[0]) + + self.assertDictEqual(layout.get_virtual_bits(), {(self.qr, 0): 1, (self.qr, 1): 2}) + + def test_layout_combine_smaller(self): + """combine_into_edge_map() method with another_layout is smaller and raises an Error""" + layout = Layout() + layout.add(self.qr[0]) + layout.add(self.qr[1]) + layout.add(self.qr[2]) + another_layout = Layout() + another_layout.add(self.qr[1]) + another_layout.add(self.qr[0]) + + with self.assertRaises(LayoutError): + _ = layout.combine_into_edge_map(another_layout) + + def test_copy(self): + """Test copy methods return equivalent layouts.""" + layout = Layout() + layout.add(self.qr[0]) + layout.add(self.qr[1]) + + layout_dict_copy = layout.copy() + self.assertTrue(isinstance(layout_dict_copy, Layout)) + self.assertDictEqual(layout.get_physical_bits(), layout_dict_copy.get_physical_bits()) + self.assertDictEqual(layout.get_virtual_bits(), layout_dict_copy.get_virtual_bits()) + + layout_copy_copy = copy.copy(layout) + self.assertTrue(isinstance(layout_copy_copy, Layout)) + self.assertDictEqual(layout.get_physical_bits(), layout_dict_copy.get_physical_bits()) + self.assertDictEqual(layout.get_virtual_bits(), layout_dict_copy.get_virtual_bits()) + + layout_copy_deepcopy = copy.deepcopy(layout) + self.assertTrue(isinstance(layout_copy_deepcopy, Layout)) + self.assertDictEqual(layout.get_physical_bits(), layout_dict_copy.get_physical_bits()) + self.assertDictEqual(layout.get_virtual_bits(), layout_dict_copy.get_virtual_bits()) + + def test_layout_error_str_key(self): + """Layout does not work with strings""" + layout = Layout() + + with self.assertRaises(LayoutError): + layout['a_string'] = 3 + + with self.assertRaises(LayoutError): + layout[2] = 'a_string' + + def test_layout_error_when_same_type(self): + """Layout does not work when key and value are the same type""" + layout = Layout() + + with self.assertRaises(LayoutError): + layout[(self.qr, 0)] = (self.qr, 1) + + with self.assertRaises(LayoutError): + layout[0] = 1 + + def test_layout_repr(self): + """Layout repr reproduces layout""" + qr = QuantumRegister(5, 'qr') + layout = Layout({qr[0]: 2, + qr[1]: 4, + qr[2]: 3, + qr[3]: 0, + qr[4]: 1, + }) + + repr_layout = eval(layout.__repr__(), {'Qubit': Qubit, # pylint: disable=eval-used + 'QuantumRegister': QuantumRegister, + 'Layout': Layout}) + self.assertDictEqual(layout._p2v, repr_layout._p2v) + self.assertDictEqual(layout._v2p, repr_layout._v2p) + + def test_layout_repr_with_holes(self): + """A non-bijective Layout repr reproduces layout""" + qr = QuantumRegister(5, 'qr') + layout = Layout({qr[0]: 0, qr[1]: 3, qr[2]: 4, qr[3]: 5, qr[4]: 6}) + + repr_layout = eval(layout.__repr__(), {'Qubit': Qubit, # pylint: disable=eval-used + 'QuantumRegister': QuantumRegister, + 'Layout': Layout}) + self.assertDictEqual(layout._p2v, repr_layout._p2v) + self.assertDictEqual(layout._v2p, repr_layout._v2p) + + def test_layout_from_intlist(self): + """Create a layout from a list of integers. + virtual physical + q1_0 -> 4 + q2_0 -> 5 + q2_1 -> 6 + q3_0 -> 8 + q3_1 -> 9 + q3_2 -> 10 + """ + qr1 = QuantumRegister(1, 'qr1') + qr2 = QuantumRegister(2, 'qr2') + qr3 = QuantumRegister(3, 'qr3') + intlist_layout = [4, 5, 6, 8, 9, 10] + layout = Layout.from_intlist(intlist_layout, qr1, qr2, qr3) + + expected = Layout({4: qr1[0], + 5: qr2[0], + 6: qr2[1], + 8: qr3[0], + 9: qr3[1], + 10: qr3[2] + }) + self.assertDictEqual(layout._p2v, expected._p2v) + self.assertDictEqual(layout._v2p, expected._v2p) + + def test_layout_from_intlist_short(self): + """If the intlist is longer that your quantum register, map them to None. + virtual physical + q1_0 -> 4 + q2_0 -> 5 + q2_1 -> 6 + None -> 8 + None -> 9 + None -> 10 + """ + qr1 = QuantumRegister(1, 'qr1') + qr2 = QuantumRegister(2, 'qr2') + + intlist_layout = [4, 5, 6, 8, 9, 10] + layout = Layout.from_intlist(intlist_layout, qr1, qr2) + + expected = Layout({4: qr1[0], + 5: qr2[0], + 6: qr2[1], + 8: None, + 9: None, + 10: None + }) + self.assertDictEqual(layout._p2v, expected._p2v) + self.assertDictEqual(layout._v2p, expected._v2p) + + def test_layout_from_intlist_long(self): + """If the intlist is shorter that your quantum register, fail. + virtual physical + q1_0 -> 4 + q2_0 -> 5 + q2_1 -> 6 + q3_0 -> 8 + q3_1 -> ? + q3_2 -> ? + """ + qr1 = QuantumRegister(1, 'qr1') + qr2 = QuantumRegister(2, 'qr2') + qr3 = QuantumRegister(3, 'qr3') + intlist_layout = [4, 5, 6, 8] + + with self.assertRaises(LayoutError): + _ = Layout.from_intlist(intlist_layout, qr1, qr2, qr3) + + def test_layout_from_intlist_duplicated(self): + """If the intlist contains duplicated ints, fail. + virtual physical + q1_0 -> 4 + q2_0 -> 6 -- This is + q2_1 -> 6 -- not allowed + """ + qr1 = QuantumRegister(1, 'qr1') + qr2 = QuantumRegister(2, 'qr2') + intlist_layout = [4, 6, 6] + + with self.assertRaises(LayoutError): + _ = Layout.from_intlist(intlist_layout, qr1, qr2) + + def test_layout_from_tuplelist(self): + """Create a Layout from list of tuples + virtual physical + q1_0 -> 3 + q2_0 -> 5 + q2_1 -> 7 + """ + qr1 = QuantumRegister(1, 'qr1') + qr2 = QuantumRegister(2, 'qr2') + tuplelist_layout = [None, None, None, qr1[0], None, qr2[0], None, qr2[1]] + + layout = Layout.from_qubit_list(tuplelist_layout) + + expected = Layout({3: qr1[0], + 5: qr2[0], + 7: qr2[1], + }) + self.assertDictEqual(layout._p2v, expected._p2v) + self.assertDictEqual(layout._v2p, expected._v2p) + + +class LayoutDeprecatedTest(QiskitTestCase): + """Test layout object with tuples, to be deprecated. + (to be removed when _cast_tuple_to_bit gets removed)""" + def setUp(self): self.qr = QuantumRegister(3, 'qr') @@ -97,7 +476,7 @@ def test_layout_avoid_dangling_virtual(self): self.assertEqual(layout[0], (self.qr, 0)) layout[0] = (self.qr, 1) with self.assertRaises(KeyError): - print(layout[(self.qr, 0)]) + _ = layout[(self.qr, 0)] def test_layout_len(self): """Length of the layout is the amount of physical bits"""