From d41727e15b61913a475663a1a3cd50b9fe3f00d0 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sat, 5 Jun 2021 13:29:18 -0700 Subject: [PATCH 01/37] First dagcircuit dagnode changes --- qiskit/converters/dag_to_circuit.py | 2 +- qiskit/dagcircuit/dagcircuit.py | 129 ++++++++--------- qiskit/dagcircuit/dagnode.py | 212 +++++++++++++++++----------- 3 files changed, 199 insertions(+), 144 deletions(-) diff --git a/qiskit/converters/dag_to_circuit.py b/qiskit/converters/dag_to_circuit.py index ffd232dd899b..6fdbcbd6fe9b 100644 --- a/qiskit/converters/dag_to_circuit.py +++ b/qiskit/converters/dag_to_circuit.py @@ -60,7 +60,7 @@ def dag_to_circuit(dag): for node in dag.topological_op_nodes(): # Get arguments for classical control (if any) - inst = node.op.copy() + inst = node.copy() circuit._append(inst, node.qargs, node.cargs) circuit.duration = dag.duration diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 1da0ea71e052..6dd9dfba6d52 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -35,7 +35,7 @@ from qiskit.circuit.gate import Gate from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.dagcircuit.exceptions import DAGCircuitError -from qiskit.dagcircuit.dagnode import DAGNode +from qiskit.dagcircuit.dagnode import DAGNode, OpNode, InNode, OutNode from qiskit.exceptions import MissingOptionalLibraryError @@ -136,17 +136,17 @@ def from_networkx(cls, graph): ) from ex dag = DAGCircuit() for node in nx.topological_sort(graph): - if node.type == "out": + if isinstance(node, OutNode): continue - if node.type == "in": + if isinstance(node, InNode): if isinstance(node.wire, Qubit): dag.add_qubits([node.wire]) elif isinstance(node.wire, Clbit): dag.add_clbits([node.wire]) else: raise DAGCircuitError("unknown node wire type: {}".format(node.wire)) - elif node.type == "op": - dag.apply_operation_back(node.op.copy(), node.qargs, node.cargs) + elif isinstance(node, OpNode): + dag.apply_operation_back(node.copy(), node.qargs, node.cargs) return dag @property @@ -227,7 +227,7 @@ def has_calibration_for(self, node): return False qubits = tuple(self.qubits.index(qubit) for qubit in node.qargs) params = [] - for p in node.op.params: + for p in node.params: if isinstance(p, ParameterExpression) and not p.parameters: params.append(float(p)) else: @@ -306,8 +306,8 @@ def _add_wire(self, wire): if wire not in self._wires: self._wires.add(wire) - inp_node = DAGNode(type="in", wire=wire) - outp_node = DAGNode(type="out", wire=wire) + inp_node = InNode(wire=wire) + outp_node = OutNode(wire=wire) input_map_id, output_map_id = self._multi_graph.add_nodes_from([inp_node, outp_node]) inp_node._node_id = input_map_id outp_node._node_id = output_map_id @@ -374,7 +374,7 @@ def _bits_in_condition(self, cond): else: raise CircuitError("Condition must be used with ClassicalRegister or Clbit.") - def _add_op_node(self, op, qargs, cargs): + def _add_op_node(self, name, qargs, cargs): """Add a new operation node to the graph and assign properties. Args: @@ -385,7 +385,8 @@ def _add_op_node(self, op, qargs, cargs): int: The integer node index for the new op node on the DAG """ # Add a new operation node to the graph - new_node = DAGNode(type="op", op=op, qargs=qargs, cargs=cargs) + #new_node = DAGNode(qargs=qargs, cargs=cargs) + new_node = OpNode(name=name, qargs=qargs, cargs=cargs) node_index = self._multi_graph.add_node(new_node) new_node._node_id = node_index return node_index @@ -439,7 +440,7 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): self._check_bits(qargs, self.output_map) self._check_bits(all_cbits, self.output_map) - node_index = self._add_op_node(op, qargs, cargs) + node_index = self._add_op_node(op.name, qargs, cargs) # Add new in-edges from predecessors of the output nodes to the # operation node while deleting the old in-edges of the output nodes @@ -478,7 +479,7 @@ def apply_operation_front(self, op, qargs, cargs, condition=None): self._check_condition(op.name, op.condition) self._check_bits(qargs, self.input_map) self._check_bits(all_cbits, self.input_map) - node_index = self._add_op_node(op, qargs, cargs) + node_index = self._add_op_node(op.name, qargs, cargs) # Add new out-edges to successors of the input nodes from the # operation node while deleting the old out-edges of the input nodes @@ -746,7 +747,7 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i dag._calibrations[gate].update(cals) for nd in other.topological_nodes(): - if nd.type == "in": + if isinstance(nd, InNode): # if in edge_map, get new name, else use existing name m_wire = edge_map.get(nd.wire, nd.wire) # the mapped wire should already exist @@ -759,15 +760,15 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i "inconsistent wire type for %s[%d] in other" % (nd.register.name, nd.wire.index) ) - elif nd.type == "out": + elif isinstance(nd, OutNode): # ignore output nodes pass - elif nd.type == "op": - condition = dag._map_condition(edge_map, nd.op.condition, dag.cregs.values()) + elif isinstance(nd, OpNode): + condition = dag._map_condition(edge_map, nd.condition, dag.cregs.values()) dag._check_condition(nd.name, condition) m_qargs = list(map(lambda x: edge_map.get(x, x), nd.qargs)) m_cargs = list(map(lambda x: edge_map.get(x, x), nd.cargs)) - op = nd.op.copy() + op = nd.copy() op.condition = condition dag.apply_operation_back(op, m_qargs, m_cargs) else: @@ -873,8 +874,8 @@ def _check_wires_list(self, wires, node): raise DAGCircuitError("duplicate wires") wire_tot = len(node.qargs) + len(node.cargs) - if node.op.condition is not None: - wire_tot += node.op.condition[0].size + if node.condition is not None: + wire_tot += node.condition[0].size if len(wires) != wire_tot: raise DAGCircuitError("expected %d wires, got %d" % (wire_tot, len(wires))) @@ -997,7 +998,7 @@ def topological_op_nodes(self): Returns: generator(DAGNode): op node in topological order """ - return (nd for nd in self.topological_nodes() if nd.type == "op") + return (nd for nd in self.topological_nodes() if isinstance(nd, OpNode)) def substitute_node_with_dag(self, node, input_dag, wires=None): """Replace one node with dag. @@ -1013,7 +1014,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): DAGCircuitError: if met with unexpected predecessor/successors """ in_dag = input_dag - condition = None if node.type != "op" else node.op.condition + condition = None if not isinstance(node, OpNode) else node.condition # the dag must be amended if used in a # conditional context. delete the op nodes and replay @@ -1023,13 +1024,13 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): in_dag.add_creg(condition[0]) to_replay = [] for sorted_node in in_dag.topological_nodes(): - if sorted_node.type == "op": - sorted_node.op.condition = condition + if isinstance(sorted_node, OpNode): + sorted_node.condition = condition to_replay.append(sorted_node) for input_node in in_dag.op_nodes(): in_dag.remove_op_node(input_node) for replay_node in to_replay: - in_dag.apply_operation_back(replay_node.op, replay_node.qargs, replay_node.cargs) + in_dag.apply_operation_back(replay_node, replay_node.qargs, replay_node.cargs) if in_dag.global_phase: self.global_phase += in_dag.global_phase @@ -1053,8 +1054,8 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): # Constructing and checking the validity of the wire_map. # If a gate is conditioned, we expect the replacement subcircuit # to depend on those condition bits as well. - if node.type != "op": - raise DAGCircuitError('expected node type "op", got %s' % node.type) + if not isinstance(node, OpNode): + raise DAGCircuitError('expected node OpNode, got %s' % node) condition_bit_list = self._bits_in_condition(condition) @@ -1085,10 +1086,10 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): # Iterate over nodes of input_circuit for sorted_node in in_dag.topological_op_nodes(): # Insert a new node - condition = self._map_condition(wire_map, sorted_node.op.condition, self.cregs.values()) + condition = self._map_condition(wire_map, sorted_node.condition, self.cregs.values()) m_qargs = list(map(lambda x: wire_map.get(x, x), sorted_node.qargs)) m_cargs = list(map(lambda x: wire_map.get(x, x), sorted_node.cargs)) - node_index = self._add_op_node(sorted_node.op, m_qargs, m_cargs) + node_index = self._add_op_node(sorted_node.name, m_qargs, m_cargs) # Add edges from predecessor nodes to new node # and update predecessor nodes that change @@ -1136,29 +1137,29 @@ def substitute_node(self, node, op, inplace=False): location of target node. """ - if node.type != "op": - raise DAGCircuitError('Only DAGNodes of type "op" can be replaced.') + if not isinstance(node, OpNode): + raise DAGCircuitError('Only OpNodes can be replaced.') - if node.op.num_qubits != op.num_qubits or node.op.num_clbits != op.num_clbits: + if node.num_qubits != op.num_qubits or node.num_clbits != op.num_clbits: raise DAGCircuitError( "Cannot replace node of width ({} qubits, {} clbits) with " "instruction of mismatched width ({} qubits, {} clbits).".format( - node.op.num_qubits, node.op.num_clbits, op.num_qubits, op.num_clbits + node.num_qubits, node.num_clbits, op.num_qubits, op.num_clbits ) ) if inplace: - save_condition = node.op.condition - node.op = op + save_condition = node.condition + node = op node.name = op.name - node.op.condition = save_condition + node.condition = save_condition return node new_node = copy.copy(node) - save_condition = new_node.op.condition - new_node.op = op + save_condition = new_node.condition + new_node = op new_node.name = op.name - new_node.op.condition = save_condition + new_node.condition = save_condition self._multi_graph[node._node_id] = new_node return new_node @@ -1219,10 +1220,10 @@ def op_nodes(self, op=None, include_directives=True): """ nodes = [] for node in self._multi_graph.nodes(): - if node.type == "op": - if not include_directives and node.op._directive: + if isinstance(node, OpNode): + if not include_directives and node._directive: continue - if op is None or isinstance(node.op, op): + if op is None or isinstance(node, OpNode): nodes.append(node) return nodes @@ -1234,7 +1235,7 @@ def gate_nodes(self): """ nodes = [] for node in self.op_nodes(): - if isinstance(node.op, Gate): + if isinstance(node, Gate): nodes.append(node) return nodes @@ -1242,7 +1243,7 @@ def named_nodes(self, *names): """Get the set of "op" nodes with the given name.""" named_nodes = [] for node in self._multi_graph.nodes(): - if node.type == "op" and node.op.name in names: + if isinstance(node, OpNode) and node.name in names: named_nodes.append(node) return named_nodes @@ -1346,10 +1347,10 @@ def remove_op_node(self, node): Add edges from predecessors to successors. """ - if node.type != "op": + if isinstance(node, OpNode): raise DAGCircuitError( - 'The method remove_op_node only works on op node types. An "%s" ' - "node type was wrongly provided." % node.type + 'The method remove_op_node only works on OpNodes. A "%s" ' + "node type was wrongly provided." % node ) self._multi_graph.remove_node_retain_edges( @@ -1363,14 +1364,14 @@ def remove_ancestors_of(self, node): # multi_graph.remove_nodes_from; same for related functions ... for anc_node in anc: - if anc_node.type == "op": + if isinstance(anc_node, OpNode): self.remove_op_node(anc_node) def remove_descendants_of(self, node): """Remove all of the descendant operation nodes of node.""" desc = rx.descendants(self._multi_graph, node) for desc_node in desc: - if desc_node.type == "op": + if isinstance(desc_node, OpNode): self.remove_op_node(desc_node) def remove_nonancestors_of(self, node): @@ -1378,7 +1379,7 @@ def remove_nonancestors_of(self, node): anc = rx.ancestors(self._multi_graph, node) comp = list(set(self._multi_graph.nodes()) - set(anc)) for n in comp: - if n.type == "op": + if isinstance(n, OpNode): self.remove_op_node(n) def remove_nondescendants_of(self, node): @@ -1386,7 +1387,7 @@ def remove_nondescendants_of(self, node): dec = rx.descendants(self._multi_graph, node) comp = list(set(self._multi_graph.nodes()) - set(dec)) for n in comp: - if n.type == "op": + if isinstance(n, OpNode): self.remove_op_node(n) def front_layer(self): @@ -1397,7 +1398,7 @@ def front_layer(self): except StopIteration: return [] - op_nodes = [node for node in next(graph_layers) if node.type == "op"] + op_nodes = [node for node in next(graph_layers) if isinstance(node, OpNode)] return op_nodes @@ -1428,7 +1429,7 @@ def layers(self): for graph_layer in graph_layers: # Get the op nodes from the layer, removing any input and output nodes. - op_nodes = [node for node in graph_layer if node.type == "op"] + op_nodes = [node for node in graph_layer if isinstance(node, OpNode)] # Sort to make sure they are in the order they were added to the original DAG # It has to be done by node_id as graph_layer is just a list of nodes @@ -1446,11 +1447,11 @@ def layers(self): for node in op_nodes: # this creates new DAGNodes in the new_layer - new_layer.apply_operation_back(node.op, node.qargs, node.cargs) + new_layer.apply_operation_back(node, node.qargs, node.cargs) # The quantum registers that have an operation in this layer. support_list = [ - op_node.qargs for op_node in new_layer.op_nodes() if not op_node.op._directive + op_node.qargs for op_node in new_layer.op_nodes() if not op_node._directive ] yield {"graph": new_layer, "partition": support_list} @@ -1467,16 +1468,16 @@ def serial_layers(self): # Save the support of the operation we add to the layer support_list = [] # Operation data - op = copy.copy(next_node.op) + op = copy.copy(next_node) qa = copy.copy(next_node.qargs) ca = copy.copy(next_node.cargs) - co = copy.copy(next_node.op.condition) + co = copy.copy(next_node.condition) _ = self._bits_in_condition(co) # Add node to new_layer new_layer.apply_operation_back(op, qa, ca) # Add operation to partition - if not next_node.op._directive: + if not next_node._directive: support_list.append(list(qa)) l_dict = {"graph": new_layer, "partition": support_list} yield l_dict @@ -1500,7 +1501,7 @@ def collect_runs(self, namelist): """ def filter_fn(node): - return node.type == "op" and node.name in namelist and node.op.condition is None + return isinstance(node, OpNode) and node.name in namelist and node.condition is None group_list = rx.collect_runs(self._multi_graph, filter_fn) return set(tuple(x) for x in group_list) @@ -1510,13 +1511,13 @@ def collect_1q_runs(self): def filter_fn(node): return ( - node.type == "op" + isinstance(node, OpNode) and len(node.qargs) == 1 and len(node.cargs) == 0 - and node.op.condition is None - and not node.op.is_parameterized() - and isinstance(node.op, Gate) - and hasattr(node.op, "__array__") + and node.condition is None + and not node.is_parameterized() + and isinstance(node, Gate) + and hasattr(node, "__array__") ) return rx.collect_runs(self._multi_graph, filter_fn) @@ -1544,7 +1545,7 @@ def nodes_on_wire(self, wire, only_ops=False): while more_nodes: more_nodes = False # allow user to just get ops on the wire - not the input/output nodes - if current_node.type == "op" or not only_ops: + if isinstance(node, OpNode) or not only_ops: yield current_node try: diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 6934da6a3db3..94805ef1e3ec 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -17,6 +17,7 @@ import warnings from qiskit.exceptions import QiskitError +from qiskit.circuit import Instruction class DAGNode: @@ -26,76 +27,58 @@ class DAGNode: be supplied to functions that take a node. """ - __slots__ = ["type", "_op", "_qargs", "cargs", "_wire", "sort_key", "_node_id"] + __slots__ = ["type", "_qargs", "cargs", "sort_key", "_node_id"] - def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=None, nid=-1): + def __init__(self, qargs=None, cargs=None, nid=-1): """Create a node""" - self.type = type - self._op = op - if name is not None: - warnings.warn( - "The DAGNode 'name' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date. " - "You can use 'DAGNode.op.name' if the DAGNode is of type 'op'.", - DeprecationWarning, - 2, - ) self._qargs = qargs if qargs is not None else [] self.cargs = cargs if cargs is not None else [] - self._wire = wire - self._node_id = nid self.sort_key = str(self._qargs) + self._node_id = nid @property - def op(self): - """Returns the Instruction object corresponding to the op for the node, else None""" - if not self.type or self.type != "op": - raise QiskitError("The node %s is not an op node" % (str(self))) - return self._op + def qargs(self): + """ + Returns list of Qubit, else an empty list. + """ + return self._qargs - @op.setter - def op(self, data): - self._op = data + @qargs.setter + def qargs(self, new_qargs): + """Sets the qargs to be the given list of qargs.""" + self._qargs = new_qargs + self.sort_key = str(new_qargs) - @property - def name(self): - """Returns the Instruction name corresponding to the op for this node""" - if self.type and self.type == "op": - return self._op.name - return None + def __lt__(self, other): + return self._node_id < other._node_id - @name.setter - def name(self, name): - if self.type and self.type == "op": - self._op.name = name + def __gt__(self, other): + return self._node_id > other._node_id - @property - def condition(self): - """Returns the condition of the node.op""" - if not self.type or self.type != "op": - raise QiskitError("The node %s is not an op node" % (str(self))) - warnings.warn( - "The DAGNode 'condition' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date. " - "You can use 'DAGNode.op.condition' if the DAGNode is of type 'op'.", - DeprecationWarning, - 2, - ) - return self._op.condition - - @condition.setter - def condition(self, new_condition): - """Sets the node.condition which sets the node.op.condition.""" - if not self.type or self.type != "op": - raise QiskitError("The node %s is not an op node" % (str(self))) - warnings.warn( - "The DAGNode 'condition' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date. " - "You can use 'DAGNode.op.condition' if the DAGNode is of type 'op'.", - DeprecationWarning, - 2, - ) - self._op.condition = new_condition + def __str__(self): + # TODO is this used anywhere other than in DAG drawing? + # needs to be unique as it is what pydot uses to distinguish nodes + return str(id(self)) + + +class OpNode(DAGNode, Instruction): + """Object to represent the information at a node in the DAGCircuit. + + It is used as the return value from `*_nodes()` functions and can + be supplied to functions that take a node. + """ + + __slots__ = ["name", "_qargs", "cargs", "sort_key", "_node_id"] + + def __init__(self, name=None, qargs=None, cargs=None, nid=-1): + """Create a node""" + self.name = name + self._qargs = qargs if qargs is not None else [] + self.cargs = cargs if cargs is not None else [] + self._node_id = nid + self.sort_key = str(self._qargs) + DAGNode.__init__(self, qargs=self._qargs, cargs=self.cargs, nid=nid) + Instruction.__init__(self, name, len(self._qargs), len(self.cargs), []) @property def qargs(self): @@ -110,19 +93,6 @@ def qargs(self, new_qargs): self._qargs = new_qargs self.sort_key = str(new_qargs) - @property - def wire(self): - """ - Returns the Bit object, else None. - """ - if self.type not in ["in", "out"]: - raise QiskitError("The node %s is not an input/output node" % str(self)) - return self._wire - - @wire.setter - def wire(self, data): - self._wire = data - def __lt__(self, other): return self._node_id < other._node_id @@ -174,15 +144,99 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): return set(node1_qargs) == set(node2_qargs) if node1.type == node2.type: - if node1._op == node2._op: - if node1.name == node2.name: - if node1_qargs == node2_qargs: - if node1_cargs == node2_cargs: - if node1.type == "op": - if node1._op.condition != node2._op.condition: - return False + if node1.name == node2.name: + if node1_qargs == node2_qargs: + if node1_cargs == node2_cargs: + if node1.condition == node2.condition: if bit_indices1.get(node1._wire, None) == bit_indices2.get( node2._wire, None ): return True return False + + +class InNode(DAGNode): + """Object to represent the information at a node in the DAGCircuit. + + It is used as the return value from `*_nodes()` functions and can + be supplied to functions that take a node. + """ + + __slots__ = ["wire", "_qargs", "cargs", "sort_key", "_node_id"] + + def __init__(self, wire=None, qargs=None, cargs=None, nid=-1): + """Create a node""" + self.wire = wire + self._qargs = qargs if qargs is not None else [] + self.cargs = cargs if cargs is not None else [] + self._node_id = nid + self.sort_key = str(self._qargs) + super().__init__(qargs=self._qargs, cargs=self.cargs, nid=nid) + + @property + def qargs(self): + """ + Returns list of Qubit, else an empty list. + """ + return self._qargs + + @qargs.setter + def qargs(self, new_qargs): + """Sets the qargs to be the given list of qargs.""" + self._qargs = new_qargs + self.sort_key = str(new_qargs) + + def __lt__(self, other): + return self._node_id < other._node_id + + def __gt__(self, other): + return self._node_id > other._node_id + + def __str__(self): + # TODO is this used anywhere other than in DAG drawing? + # needs to be unique as it is what pydot uses to distinguish nodes + return str(id(self)) + + +class OutNode(DAGNode): + """Object to represent the information at a node in the DAGCircuit. + + It is used as the return value from `*_nodes()` functions and can + be supplied to functions that take a node. + """ + + __slots__ = ["wire", "_qargs", "cargs", "sort_key", "_node_id"] + + def __init__(self, wire=None, qargs=None, cargs=None, nid=-1): + """Create a node""" + self.wire = wire + self._qargs = qargs if qargs is not None else [] + self.cargs = cargs if cargs is not None else [] + self._node_id = nid + self.sort_key = str(self._qargs) + super().__init__(qargs=self._qargs, cargs=self.cargs, nid=nid) + + @property + def qargs(self): + """ + Returns list of Qubit, else an empty list. + """ + return self._qargs + + @qargs.setter + def qargs(self, new_qargs): + """Sets the qargs to be the given list of qargs.""" + self._qargs = new_qargs + self.sort_key = str(new_qargs) + + def __lt__(self, other): + return self._node_id < other._node_id + + def __gt__(self, other): + return self._node_id > other._node_id + + def __str__(self): + # TODO is this used anywhere other than in DAG drawing? + # needs to be unique as it is what pydot uses to distinguish nodes + return str(id(self)) + From 35b6e30adfe20b3109311ee6a915d0feb00d6a1d Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sat, 5 Jun 2021 14:42:28 -0700 Subject: [PATCH 02/37] Stage 2 OpNode, etc --- qiskit/dagcircuit/dagcircuit.py | 15 +-- qiskit/dagcircuit/dagnode.py | 158 ++++++++------------------------ 2 files changed, 48 insertions(+), 125 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 6dd9dfba6d52..1d0dfc45a421 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -104,6 +104,7 @@ def to_networkx(self): ) from ex G = nx.MultiDiGraph() for node in self._multi_graph.nodes(): + print(type(node)) G.add_node(node) for node_id in rx.topological_sort(self._multi_graph): for source_id, dest_id, edge in self._multi_graph.in_edges(node_id): @@ -374,7 +375,7 @@ def _bits_in_condition(self, cond): else: raise CircuitError("Condition must be used with ClassicalRegister or Clbit.") - def _add_op_node(self, name, qargs, cargs): + def _add_op_node(self, op, qargs, cargs): """Add a new operation node to the graph and assign properties. Args: @@ -386,7 +387,7 @@ def _add_op_node(self, name, qargs, cargs): """ # Add a new operation node to the graph #new_node = DAGNode(qargs=qargs, cargs=cargs) - new_node = OpNode(name=name, qargs=qargs, cargs=cargs) + new_node = OpNode(op=op, qargs=qargs, cargs=cargs) node_index = self._multi_graph.add_node(new_node) new_node._node_id = node_index return node_index @@ -440,7 +441,7 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): self._check_bits(qargs, self.output_map) self._check_bits(all_cbits, self.output_map) - node_index = self._add_op_node(op.name, qargs, cargs) + node_index = self._add_op_node(op, qargs, cargs) # Add new in-edges from predecessors of the output nodes to the # operation node while deleting the old in-edges of the output nodes @@ -479,7 +480,7 @@ def apply_operation_front(self, op, qargs, cargs, condition=None): self._check_condition(op.name, op.condition) self._check_bits(qargs, self.input_map) self._check_bits(all_cbits, self.input_map) - node_index = self._add_op_node(op.name, qargs, cargs) + node_index = self._add_op_node(op, qargs, cargs) # Add new out-edges to successors of the input nodes from the # operation node while deleting the old out-edges of the input nodes @@ -1089,7 +1090,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): condition = self._map_condition(wire_map, sorted_node.condition, self.cregs.values()) m_qargs = list(map(lambda x: wire_map.get(x, x), sorted_node.qargs)) m_cargs = list(map(lambda x: wire_map.get(x, x), sorted_node.cargs)) - node_index = self._add_op_node(sorted_node.name, m_qargs, m_cargs) + node_index = self._add_op_node(sorted_node, m_qargs, m_cargs) # Add edges from predecessor nodes to new node # and update predecessor nodes that change @@ -1347,7 +1348,7 @@ def remove_op_node(self, node): Add edges from predecessors to successors. """ - if isinstance(node, OpNode): + if not isinstance(node, OpNode): raise DAGCircuitError( 'The method remove_op_node only works on OpNodes. A "%s" ' "node type was wrongly provided." % node @@ -1545,7 +1546,7 @@ def nodes_on_wire(self, wire, only_ops=False): while more_nodes: more_nodes = False # allow user to just get ops on the wire - not the input/output nodes - if isinstance(node, OpNode) or not only_ops: + if isinstance(current_node, OpNode) or not only_ops: yield current_node try: diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 94805ef1e3ec..87f3608d42d2 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -60,50 +60,6 @@ def __str__(self): # needs to be unique as it is what pydot uses to distinguish nodes return str(id(self)) - -class OpNode(DAGNode, Instruction): - """Object to represent the information at a node in the DAGCircuit. - - It is used as the return value from `*_nodes()` functions and can - be supplied to functions that take a node. - """ - - __slots__ = ["name", "_qargs", "cargs", "sort_key", "_node_id"] - - def __init__(self, name=None, qargs=None, cargs=None, nid=-1): - """Create a node""" - self.name = name - self._qargs = qargs if qargs is not None else [] - self.cargs = cargs if cargs is not None else [] - self._node_id = nid - self.sort_key = str(self._qargs) - DAGNode.__init__(self, qargs=self._qargs, cargs=self.cargs, nid=nid) - Instruction.__init__(self, name, len(self._qargs), len(self.cargs), []) - - @property - def qargs(self): - """ - Returns list of Qubit, else an empty list. - """ - return self._qargs - - @qargs.setter - def qargs(self, new_qargs): - """Sets the qargs to be the given list of qargs.""" - self._qargs = new_qargs - self.sort_key = str(new_qargs) - - def __lt__(self, other): - return self._node_id < other._node_id - - def __gt__(self, other): - return self._node_id > other._node_id - - def __str__(self): - # TODO is this used anywhere other than in DAG drawing? - # needs to be unique as it is what pydot uses to distinguish nodes - return str(id(self)) - @staticmethod def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): """ @@ -139,63 +95,58 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs] node2_cargs = [bit_indices2[carg] for carg in node2.cargs] - # For barriers, qarg order is not significant so compare as sets - if "barrier" == node1.name == node2.name: - return set(node1_qargs) == set(node2_qargs) - - if node1.type == node2.type: - if node1.name == node2.name: - if node1_qargs == node2_qargs: - if node1_cargs == node2_cargs: - if node1.condition == node2.condition: - if bit_indices1.get(node1._wire, None) == bit_indices2.get( - node2._wire, None - ): + if isinstance(node1, OpNode) and isinstance(node2, OpNode): + # For barriers, qarg order is not significant so compare as sets + if "barrier" == node1.name == node2.name: + return set(node1_qargs) == set(node2_qargs) + + if type(node1) == type(node2): + if node1.name == node2.name: + if node1_qargs == node2_qargs: + if node1_cargs == node2_cargs: + if node1.condition == node2.condition: return True - return False + elif ((isinstance(node1, InNode) and isinstance(node2, InNode)) + or (isinstance(node1, OutNode) and isinstance(node2, OutNode))): + if node1_qargs == node2_qargs: + if node1_cargs == node2_cargs: + if bit_indices1.get(node1.wire, None) == bit_indices2.get( + node2.wire, None + ): + return True + else: + return False -class InNode(DAGNode): + +class OpNode(DAGNode, Instruction): """Object to represent the information at a node in the DAGCircuit. It is used as the return value from `*_nodes()` functions and can be supplied to functions that take a node. """ - __slots__ = ["wire", "_qargs", "cargs", "sort_key", "_node_id"] + __slots__ = ["op"] - def __init__(self, wire=None, qargs=None, cargs=None, nid=-1): + def __init__(self, op, qargs=None, cargs=None): """Create a node""" - self.wire = wire - self._qargs = qargs if qargs is not None else [] - self.cargs = cargs if cargs is not None else [] - self._node_id = nid - self.sort_key = str(self._qargs) - super().__init__(qargs=self._qargs, cargs=self.cargs, nid=nid) - - @property - def qargs(self): - """ - Returns list of Qubit, else an empty list. - """ - return self._qargs + self.op = op + DAGNode.__init__(self, qargs, cargs) + Instruction.__init__(self, op.name, num_qubits=len(qargs), num_clbits=len(cargs), params=op.params) - @qargs.setter - def qargs(self, new_qargs): - """Sets the qargs to be the given list of qargs.""" - self._qargs = new_qargs - self.sort_key = str(new_qargs) +class InNode(DAGNode): + """Object to represent the information at a node in the DAGCircuit. - def __lt__(self, other): - return self._node_id < other._node_id + It is used as the return value from `*_nodes()` functions and can + be supplied to functions that take a node. + """ - def __gt__(self, other): - return self._node_id > other._node_id + __slots__ = ["wire"] - def __str__(self): - # TODO is this used anywhere other than in DAG drawing? - # needs to be unique as it is what pydot uses to distinguish nodes - return str(id(self)) + def __init__(self, wire, qargs=None, cargs=None): + """Create a node""" + self.wire = wire + super().__init__(qargs, cargs) class OutNode(DAGNode): @@ -205,38 +156,9 @@ class OutNode(DAGNode): be supplied to functions that take a node. """ - __slots__ = ["wire", "_qargs", "cargs", "sort_key", "_node_id"] + __slots__ = ["wire"] - def __init__(self, wire=None, qargs=None, cargs=None, nid=-1): + def __init__(self, wire, qargs=None, cargs=None): """Create a node""" self.wire = wire - self._qargs = qargs if qargs is not None else [] - self.cargs = cargs if cargs is not None else [] - self._node_id = nid - self.sort_key = str(self._qargs) - super().__init__(qargs=self._qargs, cargs=self.cargs, nid=nid) - - @property - def qargs(self): - """ - Returns list of Qubit, else an empty list. - """ - return self._qargs - - @qargs.setter - def qargs(self, new_qargs): - """Sets the qargs to be the given list of qargs.""" - self._qargs = new_qargs - self.sort_key = str(new_qargs) - - def __lt__(self, other): - return self._node_id < other._node_id - - def __gt__(self, other): - return self._node_id > other._node_id - - def __str__(self): - # TODO is this used anywhere other than in DAG drawing? - # needs to be unique as it is what pydot uses to distinguish nodes - return str(id(self)) - + super().__init__(qargs, cargs) From fc8bf1cb8e8391cd71d17166bef4dd21f87d0b1d Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sat, 5 Jun 2021 20:26:17 -0700 Subject: [PATCH 03/37] Update node ops and node types --- qiskit/dagcircuit/__init__.py | 2 +- qiskit/dagcircuit/dagcircuit.py | 13 +++- qiskit/dagcircuit/dagnode.py | 12 ++-- test/python/dagcircuit/test_dagcircuit.py | 78 +++++++++++++---------- 4 files changed, 64 insertions(+), 41 deletions(-) diff --git a/qiskit/dagcircuit/__init__.py b/qiskit/dagcircuit/__init__.py index fe2f8c4e0d27..54c209a9fc9e 100644 --- a/qiskit/dagcircuit/__init__.py +++ b/qiskit/dagcircuit/__init__.py @@ -37,7 +37,7 @@ DAGCircuitError """ from .dagcircuit import DAGCircuit -from .dagnode import DAGNode +from .dagnode import DAGNode, OpNode, InNode, OutNode from .dagdepnode import DAGDepNode from .exceptions import DAGCircuitError from .dagdependency import DAGDependency diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 1d0dfc45a421..a2a1739f63ba 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -104,7 +104,6 @@ def to_networkx(self): ) from ex G = nx.MultiDiGraph() for node in self._multi_graph.nodes(): - print(type(node)) G.add_node(node) for node_id in rx.topological_sort(self._multi_graph): for source_id, dest_id, edge in self._multi_graph.in_edges(node_id): @@ -808,7 +807,9 @@ def idle_wires(self, ignore=None): ignore = [] for wire in self._wires: nodes = [ - node for node in self.nodes_on_wire(wire, only_ops=False) if node.name not in ignore + node for node in self.nodes_on_wire(wire, only_ops=False) if ( + isinstance(node, OpNode) and node.name not in ignore + ) ] if len(nodes) == 2: yield wire @@ -1302,6 +1303,14 @@ def successors(self, node): def predecessors(self, node): """Returns iterator of the predecessors of a node as DAGNodes.""" + print("IN PREDIC ") + print(type(node), node._node_id) + print(self._multi_graph.predecessors(node._node_id)) + x = self._multi_graph.predecessors(node._node_id) + for z in x: + print("z", z) + print(set(x)) + return iter(self._multi_graph.predecessors(node._node_id)) def quantum_predecessors(self, node): diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 87f3608d42d2..e6820cc54b40 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -17,7 +17,7 @@ import warnings from qiskit.exceptions import QiskitError -from qiskit.circuit import Instruction +from qiskit.circuit import Instruction, Gate class DAGNode: @@ -119,20 +119,20 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): -class OpNode(DAGNode, Instruction): +class OpNode(DAGNode, Gate, Instruction): """Object to represent the information at a node in the DAGCircuit. It is used as the return value from `*_nodes()` functions and can be supplied to functions that take a node. """ - __slots__ = ["op"] - def __init__(self, op, qargs=None, cargs=None): """Create a node""" - self.op = op DAGNode.__init__(self, qargs, cargs) - Instruction.__init__(self, op.name, num_qubits=len(qargs), num_clbits=len(cargs), params=op.params) + if isinstance(op, Gate): + Gate.__init__(self, op.name, num_qubits=len(qargs), params=op.params) + else: + Instruction.__init__(self, op.name, num_qubits=len(qargs), num_clbits=len(cargs), params=op.params) class InNode(DAGNode): """Object to represent the information at a node in the DAGCircuit. diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 53d2f36be831..0a6333b972ff 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -18,7 +18,7 @@ import retworkx as rx -from qiskit.dagcircuit import DAGCircuit +from qiskit.dagcircuit import DAGCircuit, OpNode, InNode, OutNode from qiskit.circuit import QuantumRegister from qiskit.circuit import ClassicalRegister, Clbit from qiskit.circuit import QuantumCircuit, Qubit @@ -56,19 +56,19 @@ def raise_if_dagcircuit_invalid(dag): # Every node should be of type in, out, or op. # All input/output nodes should be present in input_map/output_map. for node in dag._multi_graph.nodes(): - if node.type == "in": + if isinstance(node, InNode): assert node is dag.input_map[node.wire] - elif node.type == "out": + elif isinstance(node, OutNode): assert node is dag.output_map[node.wire] - elif node.type == "op": + elif isinstance(node, OpNode): continue else: - raise DAGCircuitError("Found node of unexpected type: {}".format(node.type)) + raise DAGCircuitError("Found node of unexpected type: {}".format(node)) # Shape of node.op should match shape of node. for node in dag.op_nodes(): - assert len(node.qargs) == node.op.num_qubits - assert len(node.cargs) == node.op.num_clbits + assert len(node.qargs) == node.num_qubits + assert len(node.cargs) == node.num_clbits # Every edge should be labled with a known wire. edges_outside_wires = [ @@ -87,8 +87,8 @@ def raise_if_dagcircuit_invalid(dag): assert in_node.wire == wire assert out_node.wire == wire - assert in_node.type == "in" - assert out_node.type == "out" + assert isinstance(in_node, InNode) + assert isinstance(out_node, OutNode) # Every wire should be propagated by exactly one edge between nodes. for wire in dag.wires: @@ -114,7 +114,7 @@ def raise_if_dagcircuit_invalid(dag): in_wires = {data for src, dest, data in in_edges} out_wires = {data for src, dest, data in out_edges} - node_cond_bits = set(node.op.condition[0][:] if node.op.condition is not None else []) + node_cond_bits = set(node.condition[0][:] if node.condition is not None else []) node_qubits = set(node.qargs) node_clbits = set(node.cargs) @@ -300,7 +300,7 @@ def test_apply_operation_back_conditional(self): self.assertEqual(h_node.qargs, [self.qubit2]) self.assertEqual(h_node.cargs, []) - self.assertEqual(h_node.op.condition, h_gate.condition) + self.assertEqual(h_node.condition, h_gate.condition) self.assertEqual( sorted(self.dag._multi_graph.in_edges(h_node._node_id)), @@ -341,7 +341,7 @@ def test_apply_operation_back_conditional_measure(self): self.assertEqual(meas_node.qargs, [self.qubit0]) self.assertEqual(meas_node.cargs, [self.clbit0]) - self.assertEqual(meas_node.op.condition, meas_gate.condition) + self.assertEqual(meas_node.condition, meas_gate.condition) self.assertEqual( sorted(self.dag._multi_graph.in_edges(meas_node._node_id)), @@ -387,7 +387,7 @@ def test_apply_operation_back_conditional_measure_to_self(self): self.assertEqual(meas_node.qargs, [self.qubit1]) self.assertEqual(meas_node.cargs, [self.clbit1]) - self.assertEqual(meas_node.op.condition, meas_gate.condition) + self.assertEqual(meas_node.condition, meas_gate.condition) self.assertEqual( sorted(self.dag._multi_graph.in_edges(meas_node._node_id)), @@ -449,7 +449,7 @@ def test_front_layer(self): op_nodes = self.dag.front_layer() self.assertEqual(len(op_nodes), 1) - self.assertIsInstance(op_nodes[0].op, HGate) + self.assertIsInstance(op_nodes[0], HGate) def test_get_op_nodes_all(self): """The method dag.op_nodes() returns all op nodes""" @@ -461,7 +461,7 @@ def test_get_op_nodes_all(self): self.assertEqual(len(op_nodes), 3) for node in op_nodes: - self.assertIsInstance(node.op, Instruction) + self.assertIsInstance(node, Instruction) def test_get_op_nodes_particular(self): """The method dag.gates_nodes(op=AGate) returns all the AGate nodes""" @@ -477,8 +477,8 @@ def test_get_op_nodes_particular(self): op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() - self.assertIsInstance(op_node_1.op, HGate) - self.assertIsInstance(op_node_2.op, HGate) + self.assertIsInstance(op_node_1, HGate) + self.assertIsInstance(op_node_2, HGate) def test_quantum_successors(self): """The method dag.quantum_successors() returns successors connected by quantum edges""" @@ -500,7 +500,7 @@ def test_quantum_successors(self): with self.assertRaises(StopIteration): next(successor_measure) - self.assertIsInstance(cnot_node.op, CXGate) + self.assertIsInstance(cnot_node, CXGate) successor_cnot = self.dag.quantum_successors(cnot_node) # Ordering between Reset and out[q1] is indeterminant. @@ -511,8 +511,8 @@ def test_quantum_successors(self): next(successor_cnot) self.assertTrue( - (successor1.type == "out" and isinstance(successor2.op, Reset)) - or (successor2.type == "out" and isinstance(successor1.op, Reset)) + (isinstance(successor1, OutNode) and isinstance(successor2, Reset)) + or (isinstanc(successor2, OutNode) and isinstance(successor1, Reset)) ) def test_quantum_predecessors(self): @@ -535,7 +535,7 @@ def test_quantum_predecessors(self): with self.assertRaises(StopIteration): next(predecessor_measure) - self.assertIsInstance(cnot_node.op, CXGate) + self.assertIsInstance(cnot_node, CXGate) predecessor_cnot = self.dag.quantum_predecessors(cnot_node) # Ordering between Reset and in[q1] is indeterminant. @@ -546,8 +546,8 @@ def test_quantum_predecessors(self): next(predecessor_cnot) self.assertTrue( - (predecessor1.type == "in" and isinstance(predecessor2.op, Reset)) - or (predecessor2.type == "in" and isinstance(predecessor1.op, Reset)) + (isinstance(predecessor1, InNode) and isinstance(predecessor2, Reset)) + or (isinstance(predecessor2, InNode) and isinstance(predecessor1, Reset)) ) def test_get_gates_nodes(self): @@ -562,8 +562,8 @@ def test_get_gates_nodes(self): op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() - self.assertIsInstance(op_node_1.op, Gate) - self.assertIsInstance(op_node_2.op, Gate) + self.assertIsInstance(op_node_1, Gate) + self.assertIsInstance(op_node_2, Gate) def test_two_q_gates(self): """The method dag.two_qubit_ops() returns all 2Q gate operation nodes""" @@ -576,7 +576,7 @@ def test_two_q_gates(self): self.assertEqual(len(op_nodes), 1) op_node = op_nodes.pop() - self.assertIsInstance(op_node.op, Gate) + self.assertIsInstance(op_node, Gate) self.assertEqual(len(op_node.qargs), 2) def test_get_named_nodes(self): @@ -630,7 +630,7 @@ def test_topological_nodes(self): (cr[1], []), ] self.assertEqual( - [(i.name if i.type == "op" else i.wire, i.qargs) for i in named_nodes], expected + [(i.name if isinstance(i, OpNode) else i.wire, i.qargs) for i in named_nodes], expected ) def test_topological_op_nodes(self): @@ -927,7 +927,7 @@ def test_layers_basic(self): self.assertEqual(5, len(layers)) name_layers = [ - [node.op.name for node in layer["graph"].nodes() if node.type == "op"] + [node.name for node in layer["graph"].nodes() if isinstance(node, OpNode)] for layer in layers ] @@ -951,7 +951,7 @@ def test_layers_maintains_order(self): dag1.apply_operation_back(IGate(), [qr[0]], []) comp = [ - (nd.type, nd.name if nd.type == "op" else nd.wire, nd._node_id) + (nd, nd.name if isinstance(nd, OpNode) else nd.wire, nd._node_id) for nd in dag1.topological_nodes() ] self.assertEqual(comp, truth) @@ -1219,7 +1219,7 @@ def test_substituting_node_preserves_args_condition(self, inplace): self.assertEqual(replacement_node.name, "cz") self.assertEqual(replacement_node.qargs, [qr[1], qr[0]]) self.assertEqual(replacement_node.cargs, []) - self.assertEqual(replacement_node.op.condition, (cr, 1)) + self.assertEqual(replacement_node.condition, (cr, 1)) self.assertEqual(replacement_node is node_to_be_replaced, inplace) @@ -1232,14 +1232,28 @@ def test_substituting_node_preserves_parents_children(self, inplace): qc.rz(0.1, 2) qc.cx(1, 2) qc.cx(0, 1) + #print(qc) dag = circuit_to_dag(qc) + print(dag) node_to_be_replaced = dag.named_nodes("rz")[0] + print(node_to_be_replaced) + print(type(node_to_be_replaced)) + x = dag.predecessors(node_to_be_replaced) + for z in x: + print(z) + print(next(x)) + y = set(x) + print(y) + print("HERe 1") predecessors = set(dag.predecessors(node_to_be_replaced)) + print("HERE") successors = set(dag.successors(node_to_be_replaced)) ancestors = dag.ancestors(node_to_be_replaced) descendants = dag.descendants(node_to_be_replaced) + print("\n", predecessors, successors, ancestors, descendants) replacement_node = dag.substitute_node(node_to_be_replaced, U1Gate(0.1), inplace=inplace) + print(replacement_node) raise_if_dagcircuit_invalid(dag) self.assertEqual(set(dag.predecessors(replacement_node)), predecessors) @@ -1380,7 +1394,7 @@ def test_creg_conditional(self): self.circuit.h(self.qreg[0]).c_if(self.creg, 1) self.dag = circuit_to_dag(self.circuit) gate_node = self.dag.gate_nodes()[0] - self.assertEqual(gate_node.op, HGate()) + self.assertEqual(gate_node, HGate()) self.assertEqual(gate_node.qargs, [self.qreg[0]]) self.assertEqual(gate_node.cargs, []) self.assertEqual(gate_node.condition, (self.creg, 1)) @@ -1412,7 +1426,7 @@ def test_clbit_conditional(self): self.circuit.h(self.qreg[0]).c_if(self.creg[0], 1) self.dag = circuit_to_dag(self.circuit) gate_node = self.dag.gate_nodes()[0] - self.assertEqual(gate_node.op, HGate()) + self.assertEqual(gate_node, HGate()) self.assertEqual(gate_node.qargs, [self.qreg[0]]) self.assertEqual(gate_node.cargs, []) self.assertEqual(gate_node.condition, (self.creg[0], 1)) From 9d588624173452f74087cd1ae3aead26838a7824 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sun, 6 Jun 2021 13:45:56 -0700 Subject: [PATCH 04/37] More predecessor testing --- qiskit/dagcircuit/dagcircuit.py | 8 ++++---- qiskit/dagcircuit/dagnode.py | 16 +++++++++++++++- test/python/dagcircuit/test_dagcircuit.py | 23 +++++++++++++++-------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index a2a1739f63ba..83f215dfb9f9 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -1299,7 +1299,7 @@ def longest_path(self): def successors(self, node): """Returns iterator of the successors of a node as DAGNodes.""" - return iter(self._multi_graph.successors(node._node_id)) + return self._multi_graph.successors(node._node_id) def predecessors(self, node): """Returns iterator of the predecessors of a node as DAGNodes.""" @@ -1309,9 +1309,9 @@ def predecessors(self, node): x = self._multi_graph.predecessors(node._node_id) for z in x: print("z", z) - print(set(x)) - - return iter(self._multi_graph.predecessors(node._node_id)) + #print(set(x)) + print(self._multi_graph.nodes()) + return self._multi_graph.predecessors(node._node_id) def quantum_predecessors(self, node): """Returns iterator of the predecessors of a node that are diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index e6820cc54b40..7613e3c479b7 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -27,7 +27,7 @@ class DAGNode: be supplied to functions that take a node. """ - __slots__ = ["type", "_qargs", "cargs", "sort_key", "_node_id"] + __slots__ = ["_qargs", "cargs", "sort_key", "_node_id"] def __init__(self, qargs=None, cargs=None, nid=-1): """Create a node""" @@ -134,6 +134,20 @@ def __init__(self, op, qargs=None, cargs=None): else: Instruction.__init__(self, op.name, num_qubits=len(qargs), num_clbits=len(cargs), params=op.params) + def __lt__(self, other): + return self._node_id < other._node_id + + def __gt__(self, other): + return self._node_id > other._node_id + + def __str__(self): + # TODO is this used anywhere other than in DAG drawing? + # needs to be unique as it is what pydot uses to distinguish nodes + return str(id(self)) + + def __eq__(self, other): + return DAGNode.semantic_eq(self, other) + class InNode(DAGNode): """Object to represent the information at a node in the DAGCircuit. diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 0a6333b972ff..5b3f23587452 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -1238,16 +1238,23 @@ def test_substituting_node_preserves_parents_children(self, inplace): node_to_be_replaced = dag.named_nodes("rz")[0] print(node_to_be_replaced) print(type(node_to_be_replaced)) - x = dag.predecessors(node_to_be_replaced) + """x = dag.predecessors(node_to_be_replaced) for z in x: print(z) - print(next(x)) - y = set(x) - print(y) + #print(next(x)) + #y = set(x) + #print(y)""" print("HERe 1") - predecessors = set(dag.predecessors(node_to_be_replaced)) + predecessors = dag.predecessors(node_to_be_replaced) + if len(predecessors) == 1: + predecessors = (predecessors[0],) + print(predecessors) + #print(next(predecessors)) + print(predecessors[0].name, predecessors[0].qargs, predecessors[0].cargs) + print('Here 2') + predecessors = set(predecessors) print("HERE") - successors = set(dag.successors(node_to_be_replaced)) + successors = frozenset(tuple(dag.successors(node_to_be_replaced))) ancestors = dag.ancestors(node_to_be_replaced) descendants = dag.descendants(node_to_be_replaced) @@ -1256,8 +1263,8 @@ def test_substituting_node_preserves_parents_children(self, inplace): print(replacement_node) raise_if_dagcircuit_invalid(dag) - self.assertEqual(set(dag.predecessors(replacement_node)), predecessors) - self.assertEqual(set(dag.successors(replacement_node)), successors) + self.assertEqual(frozenset(tuple(dag.predecessors(replacement_node)), predecessors)) + self.assertEqual(frozenset(tuple(dag.successors(replacement_node)), successors)) self.assertEqual(dag.ancestors(replacement_node), ancestors) self.assertEqual(dag.descendants(replacement_node), descendants) From 8661860b83fb4660f54834148e9d30e077da983a Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Mon, 7 Jun 2021 06:48:59 -0700 Subject: [PATCH 05/37] Further testing --- qiskit/dagcircuit/dagcircuit.py | 14 +++++++++++--- qiskit/dagcircuit/dagnode.py | 17 ++++------------- test/python/dagcircuit/test_dagcircuit.py | 12 ++++++++++-- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 83f215dfb9f9..daa884bc8eaa 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -439,6 +439,7 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): self._check_condition(op.name, op.condition) self._check_bits(qargs, self.output_map) self._check_bits(all_cbits, self.output_map) + print("\n\n\n\n\n9999999999999999999", qargs, cargs) node_index = self._add_op_node(op, qargs, cargs) @@ -450,6 +451,7 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): self._multi_graph.insert_node_on_in_edges_multiple( node_index, [self.output_map[q]._node_id for q in itertools.chain(*al)] ) + print("******************", self._multi_graph[node_index].name) return self._multi_graph[node_index] def apply_operation_front(self, op, qargs, cargs, condition=None): @@ -875,6 +877,8 @@ def _check_wires_list(self, wires, node): if len(set(wires)) != len(wires): raise DAGCircuitError("duplicate wires") + print("\n\n\n\n%%%%%%%%%%%%%%%%%%%%%", node.qargs, node.cargs) + print(len(wires)) wire_tot = len(node.qargs) + len(node.cargs) if node.condition is not None: wire_tot += node.condition[0].size @@ -1037,8 +1041,11 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): if in_dag.global_phase: self.global_phase += in_dag.global_phase + print('\n\n&&&&&&&&&&&&&&&&', wires) if wires is None: wires = in_dag.wires + print(wires) + print(node.qargs) self._check_wires_list(wires, node) @@ -1091,6 +1098,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): condition = self._map_condition(wire_map, sorted_node.condition, self.cregs.values()) m_qargs = list(map(lambda x: wire_map.get(x, x), sorted_node.qargs)) m_cargs = list(map(lambda x: wire_map.get(x, x), sorted_node.cargs)) + print("\n\n\n111111111111111111111111111111111111", m_qargs) node_index = self._add_op_node(sorted_node, m_qargs, m_cargs) # Add edges from predecessor nodes to new node @@ -1152,14 +1160,14 @@ def substitute_node(self, node, op, inplace=False): if inplace: save_condition = node.condition - node = op + node = OpNode(op, node.qargs, node.cargs) node.name = op.name node.condition = save_condition return node new_node = copy.copy(node) save_condition = new_node.condition - new_node = op + new_node = OpNode(op) new_node.name = op.name new_node.condition = save_condition self._multi_graph[node._node_id] = new_node @@ -1311,7 +1319,7 @@ def predecessors(self, node): print("z", z) #print(set(x)) print(self._multi_graph.nodes()) - return self._multi_graph.predecessors(node._node_id) + return iter(self._multi_graph.predecessors(node._node_id)) def quantum_predecessors(self, node): """Returns iterator of the predecessors of a node that are diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 7613e3c479b7..94f5628c797e 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -133,20 +133,11 @@ def __init__(self, op, qargs=None, cargs=None): Gate.__init__(self, op.name, num_qubits=len(qargs), params=op.params) else: Instruction.__init__(self, op.name, num_qubits=len(qargs), num_clbits=len(cargs), params=op.params) + self._hash = hash((type(self), op.name)) + print(self.qargs, qargs) - def __lt__(self, other): - return self._node_id < other._node_id - - def __gt__(self, other): - return self._node_id > other._node_id - - def __str__(self): - # TODO is this used anywhere other than in DAG drawing? - # needs to be unique as it is what pydot uses to distinguish nodes - return str(id(self)) - - def __eq__(self, other): - return DAGNode.semantic_eq(self, other) + def __hash__(self): + return self._hash class InNode(DAGNode): """Object to represent the information at a node in the DAGCircuit. diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 5b3f23587452..2e5cf67dcc8f 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -1116,16 +1116,20 @@ def setUp(self): self.clbit0 = creg[0] self.clbit1 = creg[1] self.condition = (creg, 3) - self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) + cx_node = self.dag.op_nodes(op=CXGate).pop() + print("\n\n\00000000000000000000000000000000000000000000000000000000000000000000000000", cx_node.qargs) self.dag.apply_operation_back(XGate(), [self.qubit1], []) def test_substitute_circuit_one_middle(self): """The method substitute_node_with_dag() replaces a in-the-middle node with a DAG.""" cx_node = self.dag.op_nodes(op=CXGate).pop() + print("\n\n\n888888888888888888888888888888888888888888888888888888888888", cx_node.qargs) + print("\n\n\n3333333333333333333333", cx_node.qargs, cx_node.cargs) flipped_cx_circuit = DAGCircuit() + print("\n\n\n888888888888888888888888888888888888888888888888888888888888", cx_node.qargs) v = QuantumRegister(2, "v") flipped_cx_circuit.add_qreg(v) flipped_cx_circuit.apply_operation_back(HGate(), [v[0]], []) @@ -1133,8 +1137,10 @@ def test_substitute_circuit_one_middle(self): flipped_cx_circuit.apply_operation_back(CXGate(), [v[1], v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[1]], []) + print("\n\n\n888888888888888888888888888888888888888888888888888888888888", cx_node.qargs) self.dag.substitute_node_with_dag(cx_node, flipped_cx_circuit, wires=[v[0], v[1]]) + print("\n\n\n77777777777777777777777777777777777777777777777777777777777", cx_node.qargs) self.assertEqual(self.dag.count_ops()["h"], 5) @@ -1252,7 +1258,9 @@ def test_substituting_node_preserves_parents_children(self, inplace): #print(next(predecessors)) print(predecessors[0].name, predecessors[0].qargs, predecessors[0].cargs) print('Here 2') - predecessors = set(predecessors) + z = set() + print("Here 3") + predecessors = z.update(predecessors) print("HERE") successors = frozenset(tuple(dag.successors(node_to_be_replaced))) ancestors = dag.ancestors(node_to_be_replaced) From 69ae5248c94ed88961d05c55dfdf4624926c3f8c Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 10 Jun 2021 20:51:27 -0700 Subject: [PATCH 06/37] Put op in OpNode and further testing of dagcircuit --- qiskit/converters/dag_to_circuit.py | 2 +- qiskit/dagcircuit/dagcircuit.py | 125 ++++++++++++---------- qiskit/dagcircuit/dagnode.py | 17 +-- test/python/dagcircuit/test_dagcircuit.py | 104 +++++++++--------- 4 files changed, 129 insertions(+), 119 deletions(-) diff --git a/qiskit/converters/dag_to_circuit.py b/qiskit/converters/dag_to_circuit.py index 6fdbcbd6fe9b..ffd232dd899b 100644 --- a/qiskit/converters/dag_to_circuit.py +++ b/qiskit/converters/dag_to_circuit.py @@ -60,7 +60,7 @@ def dag_to_circuit(dag): for node in dag.topological_op_nodes(): # Get arguments for classical control (if any) - inst = node.copy() + inst = node.op.copy() circuit._append(inst, node.qargs, node.cargs) circuit.duration = dag.duration diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index daa884bc8eaa..4959d666c261 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -146,7 +146,7 @@ def from_networkx(cls, graph): else: raise DAGCircuitError("unknown node wire type: {}".format(node.wire)) elif isinstance(node, OpNode): - dag.apply_operation_back(node.copy(), node.qargs, node.cargs) + dag.apply_operation_back(node.op.copy(), node.qargs, node.cargs) return dag @property @@ -223,17 +223,17 @@ def has_calibration_for(self, node): """Return True if the dag has a calibration defined for the node operation. In this case, the operation does not need to be translated to the device basis. """ - if not self.calibrations or node.name not in self.calibrations: + if not self.calibrations or node.op.name not in self.calibrations: return False qubits = tuple(self.qubits.index(qubit) for qubit in node.qargs) params = [] - for p in node.params: + for p in node.op.params: if isinstance(p, ParameterExpression) and not p.parameters: params.append(float(p)) else: params.append(p) params = tuple(params) - return (qubits, params) in self.calibrations[node.name] + return (qubits, params) in self.calibrations[node.op.name] def remove_all_ops_named(self, opname): """Remove all operation nodes with the given name.""" @@ -439,7 +439,7 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): self._check_condition(op.name, op.condition) self._check_bits(qargs, self.output_map) self._check_bits(all_cbits, self.output_map) - print("\n\n\n\n\n9999999999999999999", qargs, cargs) + print("\n\n\n apply back 9999999999999999999", qargs, cargs) node_index = self._add_op_node(op, qargs, cargs) @@ -448,10 +448,11 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): # and adding new edges from the operation node to each output node al = [qargs, all_cbits] + print('ALLLL: ', al) self._multi_graph.insert_node_on_in_edges_multiple( node_index, [self.output_map[q]._node_id for q in itertools.chain(*al)] ) - print("******************", self._multi_graph[node_index].name) + #print("apply back multi graph name ******************", self._multi_graph[node_index].name, self._multi_graph[node_index].qargs) return self._multi_graph[node_index] def apply_operation_front(self, op, qargs, cargs, condition=None): @@ -766,11 +767,11 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i # ignore output nodes pass elif isinstance(nd, OpNode): - condition = dag._map_condition(edge_map, nd.condition, dag.cregs.values()) - dag._check_condition(nd.name, condition) + condition = dag._map_condition(edge_map, nd.op.condition, dag.cregs.values()) + dag._check_condition(nd.op.name, condition) m_qargs = list(map(lambda x: edge_map.get(x, x), nd.qargs)) m_cargs = list(map(lambda x: edge_map.get(x, x), nd.cargs)) - op = nd.copy() + op = nd.op.copy() op.condition = condition dag.apply_operation_back(op, m_qargs, m_cargs) else: @@ -810,7 +811,7 @@ def idle_wires(self, ignore=None): for wire in self._wires: nodes = [ node for node in self.nodes_on_wire(wire, only_ops=False) if ( - isinstance(node, OpNode) and node.name not in ignore + isinstance(node, OpNode) and node.op.name not in ignore ) ] if len(nodes) == 2: @@ -877,11 +878,11 @@ def _check_wires_list(self, wires, node): if len(set(wires)) != len(wires): raise DAGCircuitError("duplicate wires") - print("\n\n\n\n%%%%%%%%%%%%%%%%%%%%%", node.qargs, node.cargs) - print(len(wires)) + print("\n\n\ncheck wires %%%%%%%%%%%%%%%%%%%%%", node.qargs, node.cargs) + print('LEN', len(wires)) wire_tot = len(node.qargs) + len(node.cargs) - if node.condition is not None: - wire_tot += node.condition[0].size + if node.op.condition is not None: + wire_tot += node.op.condition[0].size if len(wires) != wire_tot: raise DAGCircuitError("expected %d wires, got %d" % (wire_tot, len(wires))) @@ -1020,7 +1021,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): DAGCircuitError: if met with unexpected predecessor/successors """ in_dag = input_dag - condition = None if not isinstance(node, OpNode) else node.condition + condition = None if not isinstance(node, OpNode) else node.op.condition # the dag must be amended if used in a # conditional context. delete the op nodes and replay @@ -1031,21 +1032,21 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): to_replay = [] for sorted_node in in_dag.topological_nodes(): if isinstance(sorted_node, OpNode): - sorted_node.condition = condition + sorted_node.op.condition = condition to_replay.append(sorted_node) for input_node in in_dag.op_nodes(): in_dag.remove_op_node(input_node) for replay_node in to_replay: - in_dag.apply_operation_back(replay_node, replay_node.qargs, replay_node.cargs) + in_dag.apply_operation_back(replay_node.op, replay_node.qargs, replay_node.cargs) if in_dag.global_phase: self.global_phase += in_dag.global_phase - print('\n\n&&&&&&&&&&&&&&&&', wires) + print('\n\n\nsub wires &&&&&&&&&&&&&&&&', wires) if wires is None: wires = in_dag.wires - print(wires) - print(node.qargs) + print('wires2', wires) + print('qargs', node.qargs) self._check_wires_list(wires, node) @@ -1095,11 +1096,11 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): # Iterate over nodes of input_circuit for sorted_node in in_dag.topological_op_nodes(): # Insert a new node - condition = self._map_condition(wire_map, sorted_node.condition, self.cregs.values()) + condition = self._map_condition(wire_map, sorted_node.op.condition, self.cregs.values()) m_qargs = list(map(lambda x: wire_map.get(x, x), sorted_node.qargs)) m_cargs = list(map(lambda x: wire_map.get(x, x), sorted_node.cargs)) - print("\n\n\n111111111111111111111111111111111111", m_qargs) - node_index = self._add_op_node(sorted_node, m_qargs, m_cargs) + print("\n\n\nsub node qargs 111111111111111111111111111111111111", m_qargs) + node_index = self._add_op_node(sorted_node.op, m_qargs, m_cargs) # Add edges from predecessor nodes to new node # and update predecessor nodes that change @@ -1150,26 +1151,26 @@ def substitute_node(self, node, op, inplace=False): if not isinstance(node, OpNode): raise DAGCircuitError('Only OpNodes can be replaced.') - if node.num_qubits != op.num_qubits or node.num_clbits != op.num_clbits: + if node.op.num_qubits != op.num_qubits or node.op.num_clbits != op.num_clbits: raise DAGCircuitError( "Cannot replace node of width ({} qubits, {} clbits) with " "instruction of mismatched width ({} qubits, {} clbits).".format( - node.num_qubits, node.num_clbits, op.num_qubits, op.num_clbits + node.op.num_qubits, node.op.num_clbits, op.num_qubits, op.num_clbits ) ) if inplace: - save_condition = node.condition + save_condition = node.op.condition node = OpNode(op, node.qargs, node.cargs) - node.name = op.name - node.condition = save_condition + node.op.name = op.name + node.op.condition = save_condition return node new_node = copy.copy(node) - save_condition = new_node.condition + save_condition = new_node.op.condition new_node = OpNode(op) - new_node.name = op.name - new_node.condition = save_condition + new_node.op.name = op.name + new_node.op.condition = save_condition self._multi_graph[node._node_id] = new_node return new_node @@ -1231,9 +1232,12 @@ def op_nodes(self, op=None, include_directives=True): nodes = [] for node in self._multi_graph.nodes(): if isinstance(node, OpNode): - if not include_directives and node._directive: + if not include_directives and node.op._directive: continue - if op is None or isinstance(node, OpNode): + #if op is not None: + # print("\n\nTTTTTTTTTTTTTTTTType", type(node), op, op.name) + # print("ZZZZZZZZZ", node.op.name, op.name) + if op is None or isinstance(node.op, op): nodes.append(node) return nodes @@ -1245,7 +1249,7 @@ def gate_nodes(self): """ nodes = [] for node in self.op_nodes(): - if isinstance(node, Gate): + if isinstance(node.op, Gate): nodes.append(node) return nodes @@ -1253,7 +1257,7 @@ def named_nodes(self, *names): """Get the set of "op" nodes with the given name.""" named_nodes = [] for node in self._multi_graph.nodes(): - if isinstance(node, OpNode) and node.name in names: + if isinstance(node, OpNode) and node.op.name in names: named_nodes.append(node) return named_nodes @@ -1311,14 +1315,14 @@ def successors(self, node): def predecessors(self, node): """Returns iterator of the predecessors of a node as DAGNodes.""" - print("IN PREDIC ") - print(type(node), node._node_id) - print(self._multi_graph.predecessors(node._node_id)) - x = self._multi_graph.predecessors(node._node_id) - for z in x: - print("z", z) + print("\n\nIN PREDIC ") + #print(type(node), node._node_id) + #print(self._multi_graph.predecessors(node._node_id)) + #x = self._multi_graph.predecessors(node._node_id) + #for z in x: + # print("z", z) #print(set(x)) - print(self._multi_graph.nodes()) + #print(self._multi_graph.nodes()) return iter(self._multi_graph.predecessors(node._node_id)) def quantum_predecessors(self, node): @@ -1465,11 +1469,11 @@ def layers(self): for node in op_nodes: # this creates new DAGNodes in the new_layer - new_layer.apply_operation_back(node, node.qargs, node.cargs) + new_layer.apply_operation_back(node.op, node.qargs, node.cargs) # The quantum registers that have an operation in this layer. support_list = [ - op_node.qargs for op_node in new_layer.op_nodes() if not op_node._directive + op_node.qargs for op_node in new_layer.op_nodes() if not op_node.op._directive ] yield {"graph": new_layer, "partition": support_list} @@ -1489,13 +1493,13 @@ def serial_layers(self): op = copy.copy(next_node) qa = copy.copy(next_node.qargs) ca = copy.copy(next_node.cargs) - co = copy.copy(next_node.condition) + co = copy.copy(next_node.op.condition) _ = self._bits_in_condition(co) # Add node to new_layer - new_layer.apply_operation_back(op, qa, ca) + new_layer.apply_operation_back(op.op, qa, ca) # Add operation to partition - if not next_node._directive: + if not next_node.op._directive: support_list.append(list(qa)) l_dict = {"graph": new_layer, "partition": support_list} yield l_dict @@ -1519,7 +1523,7 @@ def collect_runs(self, namelist): """ def filter_fn(node): - return isinstance(node, OpNode) and node.name in namelist and node.condition is None + return isinstance(node, OpNode) and node.op.name in namelist and node.op.condition is None group_list = rx.collect_runs(self._multi_graph, filter_fn) return set(tuple(x) for x in group_list) @@ -1532,10 +1536,10 @@ def filter_fn(node): isinstance(node, OpNode) and len(node.qargs) == 1 and len(node.cargs) == 0 - and node.condition is None - and not node.is_parameterized() - and isinstance(node, Gate) - and hasattr(node, "__array__") + and node.op.condition is None + and not node.op.is_parameterized() + and isinstance(node.op, Gate) + and hasattr(node.op, "__array__") ) return rx.collect_runs(self._multi_graph, filter_fn) @@ -1581,11 +1585,14 @@ def count_ops(self): """ op_dict = {} for node in self.topological_op_nodes(): - name = node.name - if name not in op_dict: - op_dict[name] = 1 - else: - op_dict[name] += 1 + print("\n\n\n\n\n\n\nTYPE NODE", type(node)) + if isinstance(node, OpNode): + print(type(node.op)) + name = node.op.name + if name not in op_dict: + op_dict[name] = 1 + else: + op_dict[name] += 1 return op_dict def count_ops_longest_path(self): @@ -1596,8 +1603,8 @@ def count_ops_longest_path(self): op_dict = {} path = self.longest_path() path = path[1:-1] # remove qubits at beginning and end of path - for node in path: - name = node.name + for op in path: + name = op.name if name not in op_dict: op_dict[name] = 1 else: diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 94f5628c797e..a643c19284f5 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -97,14 +97,14 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if isinstance(node1, OpNode) and isinstance(node2, OpNode): # For barriers, qarg order is not significant so compare as sets - if "barrier" == node1.name == node2.name: + if "barrier" == node1.op.name == node2.op.name: return set(node1_qargs) == set(node2_qargs) if type(node1) == type(node2): - if node1.name == node2.name: + if node1.op.name == node2.op.name: if node1_qargs == node2_qargs: if node1_cargs == node2_cargs: - if node1.condition == node2.condition: + if node1.op.condition == node2.op.condition: return True elif ((isinstance(node1, InNode) and isinstance(node2, InNode)) or (isinstance(node1, OutNode) and isinstance(node2, OutNode))): @@ -119,7 +119,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): -class OpNode(DAGNode, Gate, Instruction): +class OpNode(DAGNode): """Object to represent the information at a node in the DAGCircuit. It is used as the return value from `*_nodes()` functions and can @@ -129,15 +129,16 @@ class OpNode(DAGNode, Gate, Instruction): def __init__(self, op, qargs=None, cargs=None): """Create a node""" DAGNode.__init__(self, qargs, cargs) - if isinstance(op, Gate): + self.op = op + """if isinstance(op, Gate): Gate.__init__(self, op.name, num_qubits=len(qargs), params=op.params) else: Instruction.__init__(self, op.name, num_qubits=len(qargs), num_clbits=len(cargs), params=op.params) self._hash = hash((type(self), op.name)) - print(self.qargs, qargs) + print('OpNode INIT: self qarqs and qargs', self.qargs, qargs)""" - def __hash__(self): - return self._hash + #def __hash__(self): + # return self._hash class InNode(DAGNode): """Object to represent the information at a node in the DAGCircuit. diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 2e5cf67dcc8f..466531f88f1c 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -67,8 +67,8 @@ def raise_if_dagcircuit_invalid(dag): # Shape of node.op should match shape of node. for node in dag.op_nodes(): - assert len(node.qargs) == node.num_qubits - assert len(node.cargs) == node.num_clbits + assert len(node.qargs) == node.op.num_qubits + assert len(node.cargs) == node.op.num_clbits # Every edge should be labled with a known wire. edges_outside_wires = [ @@ -114,7 +114,7 @@ def raise_if_dagcircuit_invalid(dag): in_wires = {data for src, dest, data in in_edges} out_wires = {data for src, dest, data in out_edges} - node_cond_bits = set(node.condition[0][:] if node.condition is not None else []) + node_cond_bits = set(node.op.condition[0][:] if node.op.condition is not None else []) node_qubits = set(node.qargs) node_clbits = set(node.cargs) @@ -300,7 +300,7 @@ def test_apply_operation_back_conditional(self): self.assertEqual(h_node.qargs, [self.qubit2]) self.assertEqual(h_node.cargs, []) - self.assertEqual(h_node.condition, h_gate.condition) + self.assertEqual(h_node.op.condition, h_gate.condition) self.assertEqual( sorted(self.dag._multi_graph.in_edges(h_node._node_id)), @@ -341,7 +341,7 @@ def test_apply_operation_back_conditional_measure(self): self.assertEqual(meas_node.qargs, [self.qubit0]) self.assertEqual(meas_node.cargs, [self.clbit0]) - self.assertEqual(meas_node.condition, meas_gate.condition) + self.assertEqual(meas_node.op.condition, meas_gate.condition) self.assertEqual( sorted(self.dag._multi_graph.in_edges(meas_node._node_id)), @@ -387,7 +387,7 @@ def test_apply_operation_back_conditional_measure_to_self(self): self.assertEqual(meas_node.qargs, [self.qubit1]) self.assertEqual(meas_node.cargs, [self.clbit1]) - self.assertEqual(meas_node.condition, meas_gate.condition) + self.assertEqual(meas_node.op.condition, meas_gate.condition) self.assertEqual( sorted(self.dag._multi_graph.in_edges(meas_node._node_id)), @@ -500,7 +500,7 @@ def test_quantum_successors(self): with self.assertRaises(StopIteration): next(successor_measure) - self.assertIsInstance(cnot_node, CXGate) + self.assertIsInstance(cnot_node.op, CXGate) successor_cnot = self.dag.quantum_successors(cnot_node) # Ordering between Reset and out[q1] is indeterminant. @@ -512,7 +512,7 @@ def test_quantum_successors(self): self.assertTrue( (isinstance(successor1, OutNode) and isinstance(successor2, Reset)) - or (isinstanc(successor2, OutNode) and isinstance(successor1, Reset)) + or (isinstance(successor2, OutNode) and isinstance(successor1, Reset)) ) def test_quantum_predecessors(self): @@ -535,7 +535,7 @@ def test_quantum_predecessors(self): with self.assertRaises(StopIteration): next(predecessor_measure) - self.assertIsInstance(cnot_node, CXGate) + self.assertIsInstance(cnot_node.op, CXGate) predecessor_cnot = self.dag.quantum_predecessors(cnot_node) # Ordering between Reset and in[q1] is indeterminant. @@ -630,7 +630,7 @@ def test_topological_nodes(self): (cr[1], []), ] self.assertEqual( - [(i.name if isinstance(i, OpNode) else i.wire, i.qargs) for i in named_nodes], expected + [(i.op.name if isinstance(i, OpNode) else i.wire, i.qargs) for i in named_nodes], expected ) def test_topological_op_nodes(self): @@ -650,7 +650,7 @@ def test_topological_op_nodes(self): ("cx", [self.qubit0, self.qubit2]), ("h", [self.qubit2]), ] - self.assertEqual(expected, [(i.name, i.qargs) for i in named_nodes]) + self.assertEqual(expected, [(i.op.name, i.qargs) for i in named_nodes]) def test_dag_nodes_on_wire(self): """Test that listing the gates on a qubit/classical bit gets the correct gates""" @@ -687,7 +687,7 @@ def test_dag_nodes_on_wire_multiple_successors(self): self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) nodes = self.dag.nodes_on_wire(self.dag.qubits[1], only_ops=True) - node_names = [nd.name for nd in nodes] + node_names = [nd.op.name for nd in nodes] self.assertEqual(node_names, ["cx", "h", "cx"]) @@ -718,7 +718,7 @@ def test_remove_op_node_longer(self): ("cx", [self.qubit0, self.qubit2]), ("h", [self.qubit2]), ] - self.assertEqual(expected, [(i.name, i.qargs) for i in self.dag.topological_op_nodes()]) + self.assertEqual(expected, [(i.op.name, i.qargs) for i in self.dag.topological_op_nodes()]) def test_remove_non_op_node(self): """Try to remove a non-op node with remove_op_node method.""" @@ -738,19 +738,19 @@ def test_dag_collect_runs(self): collected_runs = self.dag.collect_runs(["u1", "cx", "h"]) self.assertEqual(len(collected_runs), 3) for run in collected_runs: - if run[0].name == "cx": + if run[0].op.name == "cx": self.assertEqual(len(run), 2) - self.assertEqual(["cx"] * 2, [x.name for x in run]) + self.assertEqual(["cx"] * 2, [x.op.name for x in run]) self.assertEqual( [[self.qubit2, self.qubit1], [self.qubit1, self.qubit2]], [x.qargs for x in run] ) - elif run[0].name == "h": + elif run[0].op.name == "h": self.assertEqual(len(run), 1) - self.assertEqual(["h"], [x.name for x in run]) + self.assertEqual(["h"], [x.op.name for x in run]) self.assertEqual([[self.qubit2]], [x.qargs for x in run]) - elif run[0].name == "u1": + elif run[0].op.name == "u1": self.assertEqual(len(run), 3) - self.assertEqual(["u1"] * 3, [x.name for x in run]) + self.assertEqual(["u1"] * 3, [x.op.name for x in run]) self.assertEqual( [[self.qubit0], [self.qubit0], [self.qubit0]], [x.qargs for x in run] ) @@ -768,7 +768,7 @@ def test_dag_collect_runs_start_with_conditional(self): self.assertEqual(len(collected_runs), 1) run = collected_runs.pop() self.assertEqual(len(run), 2) - self.assertEqual(["h", "h"], [x.name for x in run]) + self.assertEqual(["h", "h"], [x.op.name for x in run]) self.assertEqual([[self.qubit0], [self.qubit0]], [x.qargs for x in run]) def test_dag_collect_runs_conditional_in_middle(self): @@ -783,7 +783,7 @@ def test_dag_collect_runs_conditional_in_middle(self): self.assertEqual(len(collected_runs), 2) for run in collected_runs: self.assertEqual(len(run), 1) - self.assertEqual(["h"], [x.name for x in run]) + self.assertEqual(["h"], [x.op.name for x in run]) self.assertEqual([[self.qubit0]], [x.qargs for x in run]) def test_dag_collect_1q_runs(self): @@ -799,13 +799,13 @@ def test_dag_collect_1q_runs(self): collected_runs = self.dag.collect_1q_runs() self.assertEqual(len(collected_runs), 2) for run in collected_runs: - if run[0].name == "h": + if run[0].op.name == "h": self.assertEqual(len(run), 1) - self.assertEqual(["h"], [x.name for x in run]) + self.assertEqual(["h"], [x.op.name for x in run]) self.assertEqual([[self.qubit2]], [x.qargs for x in run]) - elif run[0].name == "u1": + elif run[0].op.name == "u1": self.assertEqual(len(run), 3) - self.assertEqual(["u1"] * 3, [x.name for x in run]) + self.assertEqual(["u1"] * 3, [x.op.name for x in run]) self.assertEqual( [[self.qubit0], [self.qubit0], [self.qubit0]], [x.qargs for x in run] ) @@ -825,7 +825,7 @@ def test_dag_collect_1q_runs_start_with_conditional(self): self.assertEqual(len(collected_runs), 1) run = collected_runs.pop() self.assertEqual(len(run), 2) - self.assertEqual(["h", "h"], [x.name for x in run]) + self.assertEqual(["h", "h"], [x.op.name for x in run]) self.assertEqual([[self.qubit0], [self.qubit0]], [x.qargs for x in run]) def test_dag_collect_1q_runs_conditional_in_middle(self): @@ -842,7 +842,7 @@ def test_dag_collect_1q_runs_conditional_in_middle(self): self.assertEqual(len(collected_runs), 2) for run in collected_runs: self.assertEqual(len(run), 1) - self.assertEqual(["h"], [x.name for x in run]) + self.assertEqual(["h"], [x.op.name for x in run]) self.assertEqual([[self.qubit0]], [x.qargs for x in run]) def test_dag_collect_1q_runs_with_parameterized_gate(self): @@ -857,10 +857,10 @@ def test_dag_collect_1q_runs_with_parameterized_gate(self): self.dag.apply_operation_back(XGate(), [self.qubit0]) collected_runs = self.dag.collect_1q_runs() self.assertEqual(len(collected_runs), 2) - run_gates = [[x.name for x in run] for run in collected_runs] + run_gates = [[x.op.name for x in run] for run in collected_runs] self.assertIn(["h", "h"], run_gates) self.assertIn(["x", "x"], run_gates) - self.assertNotIn("u1", [x.name for run in collected_runs for x in run]) + self.assertNotIn("u1", [x.op.name for run in collected_runs for x in run]) def test_dag_collect_1q_runs_with_cx_in_middle(self): """Test collect_1q_runs_with a cx in the middle of the run.""" @@ -880,21 +880,21 @@ def test_dag_collect_1q_runs_with_cx_in_middle(self): collected_runs = self.dag.collect_1q_runs() self.assertEqual(len(collected_runs), 4) for run in collected_runs: - if run[0].name == "h": + if run[0].op.name == "h": self.assertEqual(len(run), 3) - self.assertEqual(["h", "h", "u1"], [x.name for x in run]) + self.assertEqual(["h", "h", "u1"], [x.op.name for x in run]) self.assertEqual([[self.qubit0]] * 3, [x.qargs for x in run]) - elif run[0].name == "u1": + elif run[0].op.name == "u1": self.assertEqual(len(run), 3) - self.assertEqual(["u1", "u1", "h"], [x.name for x in run]) + self.assertEqual(["u1", "u1", "h"], [x.op.name for x in run]) self.assertEqual([[self.qubit1]] * 3, [x.qargs for x in run]) - elif run[0].name == "x": + elif run[0].op.name == "x": self.assertEqual(len(run), 2) - self.assertEqual(["x", "x"], [x.name for x in run]) + self.assertEqual(["x", "x"], [x.op.name for x in run]) self.assertEqual([[self.qubit1]] * 2, [x.qargs for x in run]) - elif run[0].name == "y": + elif run[0].op.name == "y": self.assertEqual(len(run), 2) - self.assertEqual(["y", "y"], [x.name for x in run]) + self.assertEqual(["y", "y"], [x.op.name for x in run]) self.assertEqual([[self.qubit0]] * 2, [x.qargs for x in run]) else: self.fail("Unknown run encountered") @@ -927,7 +927,7 @@ def test_layers_basic(self): self.assertEqual(5, len(layers)) name_layers = [ - [node.name for node in layer["graph"].nodes() if isinstance(node, OpNode)] + [node.op.name for node in layer["graph"].nodes() if isinstance(node, OpNode)] for layer in layers ] @@ -951,7 +951,7 @@ def test_layers_maintains_order(self): dag1.apply_operation_back(IGate(), [qr[0]], []) comp = [ - (nd, nd.name if isinstance(nd, OpNode) else nd.wire, nd._node_id) + (nd, nd.op.name if isinstance(nd, OpNode) else nd.wire, nd._node_id) for nd in dag1.topological_nodes() ] self.assertEqual(comp, truth) @@ -1118,18 +1118,20 @@ def setUp(self): self.condition = (creg, 3) self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) - cx_node = self.dag.op_nodes(op=CXGate).pop() - print("\n\n\00000000000000000000000000000000000000000000000000000000000000000000000000", cx_node.qargs) + #cx_node = self.dag.op_nodes(op=CXGate).pop() + #print("\n\n\00000000000000000000000000000000000000000000000000000000000000000000000000", cx_node.qargs) self.dag.apply_operation_back(XGate(), [self.qubit1], []) def test_substitute_circuit_one_middle(self): """The method substitute_node_with_dag() replaces a in-the-middle node with a DAG.""" + for x in self.dag.op_nodes(): + print("XXXXXXXXXXXX", x.op.name, x.qargs) cx_node = self.dag.op_nodes(op=CXGate).pop() - print("\n\n\n888888888888888888888888888888888888888888888888888888888888", cx_node.qargs) + print("\n\n\neeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", cx_node.qargs) print("\n\n\n3333333333333333333333", cx_node.qargs, cx_node.cargs) flipped_cx_circuit = DAGCircuit() - print("\n\n\n888888888888888888888888888888888888888888888888888888888888", cx_node.qargs) + print("\n\n\nfffffffffffffffffffffffffffffffffffffffffffffffff", cx_node.qargs) v = QuantumRegister(2, "v") flipped_cx_circuit.add_qreg(v) flipped_cx_circuit.apply_operation_back(HGate(), [v[0]], []) @@ -1137,7 +1139,7 @@ def test_substitute_circuit_one_middle(self): flipped_cx_circuit.apply_operation_back(CXGate(), [v[1], v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[1]], []) - print("\n\n\n888888888888888888888888888888888888888888888888888888888888", cx_node.qargs) + print("\n\n\nggggggggggggggggggggggggggggggggggggggggggggggggg", cx_node.qargs) self.dag.substitute_node_with_dag(cx_node, flipped_cx_circuit, wires=[v[0], v[1]]) print("\n\n\n77777777777777777777777777777777777777777777777777777777777", cx_node.qargs) @@ -1153,7 +1155,7 @@ def test_substitute_circuit_one_back(self): pass def test_raise_if_substituting_dag_modifies_its_conditional(self): - """Verify that we raise if the input dag modifies any of the bits in node.condition.""" + """Verify that we raise if the input dag modifies any of the bits in node.op.condition.""" # Our unroller's rely on substitute_node_with_dag carrying the condition # from the node over to the input dag, which it does by making every @@ -1222,10 +1224,10 @@ def test_substituting_node_preserves_args_condition(self, inplace): replacement_node = dag.substitute_node(node_to_be_replaced, CZGate(), inplace=inplace) raise_if_dagcircuit_invalid(dag) - self.assertEqual(replacement_node.name, "cz") + self.assertEqual(replacement_node.op.name, "cz") self.assertEqual(replacement_node.qargs, [qr[1], qr[0]]) self.assertEqual(replacement_node.cargs, []) - self.assertEqual(replacement_node.condition, (cr, 1)) + self.assertEqual(replacement_node.op.condition, (cr, 1)) self.assertEqual(replacement_node is node_to_be_replaced, inplace) @@ -1409,10 +1411,10 @@ def test_creg_conditional(self): self.circuit.h(self.qreg[0]).c_if(self.creg, 1) self.dag = circuit_to_dag(self.circuit) gate_node = self.dag.gate_nodes()[0] - self.assertEqual(gate_node, HGate()) + self.assertEqual(gate_node.op, HGate()) self.assertEqual(gate_node.qargs, [self.qreg[0]]) self.assertEqual(gate_node.cargs, []) - self.assertEqual(gate_node.condition, (self.creg, 1)) + self.assertEqual(gate_node.op.condition, (self.creg, 1)) self.assertEqual( sorted(self.dag._multi_graph.in_edges(gate_node._node_id)), sorted( @@ -1441,10 +1443,10 @@ def test_clbit_conditional(self): self.circuit.h(self.qreg[0]).c_if(self.creg[0], 1) self.dag = circuit_to_dag(self.circuit) gate_node = self.dag.gate_nodes()[0] - self.assertEqual(gate_node, HGate()) + self.assertEqual(gate_node.op, HGate()) self.assertEqual(gate_node.qargs, [self.qreg[0]]) self.assertEqual(gate_node.cargs, []) - self.assertEqual(gate_node.condition, (self.creg[0], 1)) + self.assertEqual(gate_node.op.condition, (self.creg[0], 1)) self.assertEqual( sorted(self.dag._multi_graph.in_edges(gate_node._node_id)), sorted( From be6738edc3ec15cd2deb31a62696ed47dcf9c44a Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 11 Jun 2021 10:36:55 -0700 Subject: [PATCH 07/37] Passing dagcircuit tests --- qiskit/dagcircuit/dagcircuit.py | 30 +--------- qiskit/dagcircuit/dagnode.py | 14 +---- test/python/dagcircuit/test_dagcircuit.py | 68 ++++++----------------- 3 files changed, 24 insertions(+), 88 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 4959d666c261..2e337d3592b3 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -439,7 +439,6 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): self._check_condition(op.name, op.condition) self._check_bits(qargs, self.output_map) self._check_bits(all_cbits, self.output_map) - print("\n\n\n apply back 9999999999999999999", qargs, cargs) node_index = self._add_op_node(op, qargs, cargs) @@ -448,11 +447,9 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): # and adding new edges from the operation node to each output node al = [qargs, all_cbits] - print('ALLLL: ', al) self._multi_graph.insert_node_on_in_edges_multiple( node_index, [self.output_map[q]._node_id for q in itertools.chain(*al)] ) - #print("apply back multi graph name ******************", self._multi_graph[node_index].name, self._multi_graph[node_index].qargs) return self._multi_graph[node_index] def apply_operation_front(self, op, qargs, cargs, condition=None): @@ -811,7 +808,7 @@ def idle_wires(self, ignore=None): for wire in self._wires: nodes = [ node for node in self.nodes_on_wire(wire, only_ops=False) if ( - isinstance(node, OpNode) and node.op.name not in ignore + not isinstance(node, OpNode) or node.op.name not in ignore ) ] if len(nodes) == 2: @@ -878,8 +875,6 @@ def _check_wires_list(self, wires, node): if len(set(wires)) != len(wires): raise DAGCircuitError("duplicate wires") - print("\n\n\ncheck wires %%%%%%%%%%%%%%%%%%%%%", node.qargs, node.cargs) - print('LEN', len(wires)) wire_tot = len(node.qargs) + len(node.cargs) if node.op.condition is not None: wire_tot += node.op.condition[0].size @@ -1042,11 +1037,8 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): if in_dag.global_phase: self.global_phase += in_dag.global_phase - print('\n\n\nsub wires &&&&&&&&&&&&&&&&', wires) if wires is None: wires = in_dag.wires - print('wires2', wires) - print('qargs', node.qargs) self._check_wires_list(wires, node) @@ -1099,7 +1091,6 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): condition = self._map_condition(wire_map, sorted_node.op.condition, self.cregs.values()) m_qargs = list(map(lambda x: wire_map.get(x, x), sorted_node.qargs)) m_cargs = list(map(lambda x: wire_map.get(x, x), sorted_node.cargs)) - print("\n\n\nsub node qargs 111111111111111111111111111111111111", m_qargs) node_index = self._add_op_node(sorted_node.op, m_qargs, m_cargs) # Add edges from predecessor nodes to new node @@ -1161,15 +1152,13 @@ def substitute_node(self, node, op, inplace=False): if inplace: save_condition = node.op.condition - node = OpNode(op, node.qargs, node.cargs) - node.op.name = op.name + node.op = op node.op.condition = save_condition return node new_node = copy.copy(node) save_condition = new_node.op.condition - new_node = OpNode(op) - new_node.op.name = op.name + new_node.op = op new_node.op.condition = save_condition self._multi_graph[node._node_id] = new_node return new_node @@ -1234,9 +1223,6 @@ def op_nodes(self, op=None, include_directives=True): if isinstance(node, OpNode): if not include_directives and node.op._directive: continue - #if op is not None: - # print("\n\nTTTTTTTTTTTTTTTTType", type(node), op, op.name) - # print("ZZZZZZZZZ", node.op.name, op.name) if op is None or isinstance(node.op, op): nodes.append(node) return nodes @@ -1315,14 +1301,6 @@ def successors(self, node): def predecessors(self, node): """Returns iterator of the predecessors of a node as DAGNodes.""" - print("\n\nIN PREDIC ") - #print(type(node), node._node_id) - #print(self._multi_graph.predecessors(node._node_id)) - #x = self._multi_graph.predecessors(node._node_id) - #for z in x: - # print("z", z) - #print(set(x)) - #print(self._multi_graph.nodes()) return iter(self._multi_graph.predecessors(node._node_id)) def quantum_predecessors(self, node): @@ -1585,9 +1563,7 @@ def count_ops(self): """ op_dict = {} for node in self.topological_op_nodes(): - print("\n\n\n\n\n\n\nTYPE NODE", type(node)) if isinstance(node, OpNode): - print(type(node.op)) name = node.op.name if name not in op_dict: op_dict[name] = 1 diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index a643c19284f5..ddb5bc3a1ec2 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -100,7 +100,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if "barrier" == node1.op.name == node2.op.name: return set(node1_qargs) == set(node2_qargs) - if type(node1) == type(node2): + if type(node1.op) == type(node2.op): if node1.op.name == node2.op.name: if node1_qargs == node2_qargs: if node1_cargs == node2_cargs: @@ -118,7 +118,6 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): return False - class OpNode(DAGNode): """Object to represent the information at a node in the DAGCircuit. @@ -126,19 +125,12 @@ class OpNode(DAGNode): be supplied to functions that take a node. """ + __slots__ = ["op"] def __init__(self, op, qargs=None, cargs=None): """Create a node""" - DAGNode.__init__(self, qargs, cargs) self.op = op - """if isinstance(op, Gate): - Gate.__init__(self, op.name, num_qubits=len(qargs), params=op.params) - else: - Instruction.__init__(self, op.name, num_qubits=len(qargs), num_clbits=len(cargs), params=op.params) - self._hash = hash((type(self), op.name)) - print('OpNode INIT: self qarqs and qargs', self.qargs, qargs)""" + super().__init__(qargs, cargs) - #def __hash__(self): - # return self._hash class InNode(DAGNode): """Object to represent the information at a node in the DAGCircuit. diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 466531f88f1c..f0dc3f7e8f5d 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -34,6 +34,7 @@ from qiskit.circuit.library.standard_gates.x import XGate from qiskit.circuit.library.standard_gates.y import YGate from qiskit.circuit.library.standard_gates.u1 import U1Gate +from qiskit.circuit.library.standard_gates.i import IGate from qiskit.circuit.barrier import Barrier from qiskit.dagcircuit.exceptions import DAGCircuitError from qiskit.converters import circuit_to_dag @@ -449,7 +450,7 @@ def test_front_layer(self): op_nodes = self.dag.front_layer() self.assertEqual(len(op_nodes), 1) - self.assertIsInstance(op_nodes[0], HGate) + self.assertIsInstance(op_nodes[0].op, HGate) def test_get_op_nodes_all(self): """The method dag.op_nodes() returns all op nodes""" @@ -461,7 +462,7 @@ def test_get_op_nodes_all(self): self.assertEqual(len(op_nodes), 3) for node in op_nodes: - self.assertIsInstance(node, Instruction) + self.assertIsInstance(node.op, Instruction) def test_get_op_nodes_particular(self): """The method dag.gates_nodes(op=AGate) returns all the AGate nodes""" @@ -477,8 +478,8 @@ def test_get_op_nodes_particular(self): op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() - self.assertIsInstance(op_node_1, HGate) - self.assertIsInstance(op_node_2, HGate) + self.assertIsInstance(op_node_1.op, HGate) + self.assertIsInstance(op_node_2.op, HGate) def test_quantum_successors(self): """The method dag.quantum_successors() returns successors connected by quantum edges""" @@ -511,8 +512,8 @@ def test_quantum_successors(self): next(successor_cnot) self.assertTrue( - (isinstance(successor1, OutNode) and isinstance(successor2, Reset)) - or (isinstance(successor2, OutNode) and isinstance(successor1, Reset)) + (isinstance(successor1, OutNode) and isinstance(successor2.op, Reset)) + or (isinstance(successor2, OutNode) and isinstance(successor1.op, Reset)) ) def test_quantum_predecessors(self): @@ -546,8 +547,8 @@ def test_quantum_predecessors(self): next(predecessor_cnot) self.assertTrue( - (isinstance(predecessor1, InNode) and isinstance(predecessor2, Reset)) - or (isinstance(predecessor2, InNode) and isinstance(predecessor1, Reset)) + (isinstance(predecessor1, InNode) and isinstance(predecessor2.op, Reset)) + or (isinstance(predecessor2, InNode) and isinstance(predecessor1.op, Reset)) ) def test_get_gates_nodes(self): @@ -562,8 +563,8 @@ def test_get_gates_nodes(self): op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() - self.assertIsInstance(op_node_1, Gate) - self.assertIsInstance(op_node_2, Gate) + self.assertIsInstance(op_node_1.op, Gate) + self.assertIsInstance(op_node_2.op, Gate) def test_two_q_gates(self): """The method dag.two_qubit_ops() returns all 2Q gate operation nodes""" @@ -576,7 +577,7 @@ def test_two_q_gates(self): self.assertEqual(len(op_nodes), 1) op_node = op_nodes.pop() - self.assertIsInstance(op_node, Gate) + self.assertIsInstance(op_node.op, Gate) self.assertEqual(len(op_node.qargs), 2) def test_get_named_nodes(self): @@ -939,7 +940,7 @@ def test_layers_maintains_order(self): qr = QuantumRegister(1, "q0") # the order the nodes should be in - truth = [("in", qr[0], 0), ("op", "x", 2), ("op", "id", 3), ("out", qr[0], 1)] + truth = [(InNode, qr[0], 0), (OpNode, "x", 2), (OpNode, "id", 3), (OutNode, qr[0], 1)] # this only occurred sometimes so has to be run more than once # (10 times seemed to always be enough for this bug to show at least once) @@ -951,7 +952,7 @@ def test_layers_maintains_order(self): dag1.apply_operation_back(IGate(), [qr[0]], []) comp = [ - (nd, nd.op.name if isinstance(nd, OpNode) else nd.wire, nd._node_id) + (type(nd), nd.op.name if isinstance(nd, OpNode) else nd.wire, nd._node_id) for nd in dag1.topological_nodes() ] self.assertEqual(comp, truth) @@ -1118,20 +1119,13 @@ def setUp(self): self.condition = (creg, 3) self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CXGate(), [self.qubit0, self.qubit1], []) - #cx_node = self.dag.op_nodes(op=CXGate).pop() - #print("\n\n\00000000000000000000000000000000000000000000000000000000000000000000000000", cx_node.qargs) self.dag.apply_operation_back(XGate(), [self.qubit1], []) def test_substitute_circuit_one_middle(self): """The method substitute_node_with_dag() replaces a in-the-middle node with a DAG.""" - for x in self.dag.op_nodes(): - print("XXXXXXXXXXXX", x.op.name, x.qargs) cx_node = self.dag.op_nodes(op=CXGate).pop() - print("\n\n\neeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", cx_node.qargs) - print("\n\n\n3333333333333333333333", cx_node.qargs, cx_node.cargs) flipped_cx_circuit = DAGCircuit() - print("\n\n\nfffffffffffffffffffffffffffffffffffffffffffffffff", cx_node.qargs) v = QuantumRegister(2, "v") flipped_cx_circuit.add_qreg(v) flipped_cx_circuit.apply_operation_back(HGate(), [v[0]], []) @@ -1139,10 +1133,8 @@ def test_substitute_circuit_one_middle(self): flipped_cx_circuit.apply_operation_back(CXGate(), [v[1], v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[0]], []) flipped_cx_circuit.apply_operation_back(HGate(), [v[1]], []) - print("\n\n\nggggggggggggggggggggggggggggggggggggggggggggggggg", cx_node.qargs) self.dag.substitute_node_with_dag(cx_node, flipped_cx_circuit, wires=[v[0], v[1]]) - print("\n\n\n77777777777777777777777777777777777777777777777777777777777", cx_node.qargs) self.assertEqual(self.dag.count_ops()["h"], 5) @@ -1240,44 +1232,20 @@ def test_substituting_node_preserves_parents_children(self, inplace): qc.rz(0.1, 2) qc.cx(1, 2) qc.cx(0, 1) - #print(qc) dag = circuit_to_dag(qc) - print(dag) node_to_be_replaced = dag.named_nodes("rz")[0] - print(node_to_be_replaced) - print(type(node_to_be_replaced)) - """x = dag.predecessors(node_to_be_replaced) - for z in x: - print(z) - #print(next(x)) - #y = set(x) - #print(y)""" - print("HERe 1") - predecessors = dag.predecessors(node_to_be_replaced) - if len(predecessors) == 1: - predecessors = (predecessors[0],) - print(predecessors) - #print(next(predecessors)) - print(predecessors[0].name, predecessors[0].qargs, predecessors[0].cargs) - print('Here 2') - z = set() - print("Here 3") - predecessors = z.update(predecessors) - print("HERE") - successors = frozenset(tuple(dag.successors(node_to_be_replaced))) + predecessors = set(dag.predecessors(node_to_be_replaced)) + successors = set(dag.successors(node_to_be_replaced)) ancestors = dag.ancestors(node_to_be_replaced) descendants = dag.descendants(node_to_be_replaced) - print("\n", predecessors, successors, ancestors, descendants) replacement_node = dag.substitute_node(node_to_be_replaced, U1Gate(0.1), inplace=inplace) - print(replacement_node) raise_if_dagcircuit_invalid(dag) - self.assertEqual(frozenset(tuple(dag.predecessors(replacement_node)), predecessors)) - self.assertEqual(frozenset(tuple(dag.successors(replacement_node)), successors)) + self.assertEqual(set(dag.predecessors(replacement_node)), predecessors) + self.assertEqual(set(dag.successors(replacement_node)), successors) self.assertEqual(dag.ancestors(replacement_node), ancestors) self.assertEqual(dag.descendants(replacement_node), descendants) - self.assertEqual(replacement_node is node_to_be_replaced, inplace) From 30a02db9eed2c9e5d21fd7e1502e3bf6981ef160 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 11 Jun 2021 10:46:40 -0700 Subject: [PATCH 08/37] Final dagcircuit cleanup --- qiskit/dagcircuit/dagcircuit.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index e0fa65d19406..ddb459b809a8 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -385,7 +385,6 @@ def _add_op_node(self, op, qargs, cargs): int: The integer node index for the new op node on the DAG """ # Add a new operation node to the graph - #new_node = DAGNode(qargs=qargs, cargs=cargs) new_node = OpNode(op=op, qargs=qargs, cargs=cargs) node_index = self._multi_graph.add_node(new_node) new_node._node_id = node_index @@ -1297,7 +1296,7 @@ def longest_path(self): def successors(self, node): """Returns iterator of the successors of a node as DAGNodes.""" - return self._multi_graph.successors(node._node_id) + return iter(self._multi_graph.successors(node._node_id)) def predecessors(self, node): """Returns iterator of the predecessors of a node as DAGNodes.""" @@ -1581,8 +1580,8 @@ def count_ops_longest_path(self): op_dict = {} path = self.longest_path() path = path[1:-1] # remove qubits at beginning and end of path - for op in path: - name = op.name + for node in path: + name = node.op.name if name not in op_dict: op_dict[name] = 1 else: From 318c0b50763bc52aae5f737a244c20d8bf79181b Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 11 Jun 2021 16:44:20 -0700 Subject: [PATCH 09/37] Transpiler mods for node.type --- qiskit/dagcircuit/dagcircuit.py | 2 +- qiskit/dagcircuit/dagnode.py | 8 +++ .../transpiler/passes/layout/apply_layout.py | 4 +- .../passes/optimization/collect_2q_blocks.py | 53 ++++++++++--------- .../optimization/commutation_analysis.py | 3 +- .../optimization/commutative_cancellation.py | 4 +- .../passes/optimization/consolidate_blocks.py | 7 +-- .../crosstalk_adaptive_schedule.py | 3 +- .../optimize_swap_before_measure.py | 8 +-- .../remove_diagonal_gates_before_measure.py | 7 +-- .../remove_reset_in_zero_state.py | 3 +- .../template_matching/backward_match.py | 5 +- .../template_matching/forward_match.py | 5 +- .../passes/routing/lookahead_swap.py | 8 +-- .../transpiler/passes/routing/sabre_swap.py | 25 ++++++--- .../passes/scheduling/calibration_creators.py | 4 +- .../barrier_before_final_measurements.py | 4 +- .../passes/utils/remove_final_measurements.py | 3 +- qiskit/visualization/dag_visualization.py | 7 +-- qiskit/visualization/matplotlib.py | 5 +- test/python/compiler/test_transpiler.py | 3 +- 21 files changed, 101 insertions(+), 70 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index ddb459b809a8..49c6380b0a16 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -771,7 +771,7 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i op.condition = condition dag.apply_operation_back(op, m_qargs, m_cargs) else: - raise DAGCircuitError("bad node type %s" % nd.type) + raise DAGCircuitError("bad node type %s" % nd) if not inplace: return dag diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index ddb5bc3a1ec2..36b4014f1e31 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -131,6 +131,14 @@ def __init__(self, op, qargs=None, cargs=None): self.op = op super().__init__(qargs, cargs) + @property + def name(self): + return self.op.name + + @name.setter + def name(self, new_name): + self.op.name = new_name + class InNode(DAGNode): """Object to represent the information at a node in the DAGCircuit. diff --git a/qiskit/transpiler/passes/layout/apply_layout.py b/qiskit/transpiler/passes/layout/apply_layout.py index 794b933cf28f..36be3bd4d3c1 100644 --- a/qiskit/transpiler/passes/layout/apply_layout.py +++ b/qiskit/transpiler/passes/layout/apply_layout.py @@ -13,7 +13,7 @@ """Transform a circuit with virtual qubits into a circuit with physical qubits.""" from qiskit.circuit import QuantumRegister -from qiskit.dagcircuit import DAGCircuit +from qiskit.dagcircuit import DAGCircuit, OpNode from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError @@ -59,7 +59,7 @@ def run(self, dag): for creg in dag.cregs.values(): new_dag.add_creg(creg) for node in dag.topological_op_nodes(): - if node.type == "op": + if isinstance(node, OpNode): qargs = [q[layout[qarg]] for qarg in node.qargs] new_dag.apply_operation_back(node.op, qargs, node.cargs) new_dag._global_phase = dag._global_phase diff --git a/qiskit/transpiler/passes/optimization/collect_2q_blocks.py b/qiskit/transpiler/passes/optimization/collect_2q_blocks.py index 226ec0bf19b7..c1359859d9ec 100644 --- a/qiskit/transpiler/passes/optimization/collect_2q_blocks.py +++ b/qiskit/transpiler/passes/optimization/collect_2q_blocks.py @@ -15,6 +15,7 @@ from collections import defaultdict from qiskit.circuit import Gate +from qiskit.dagcircuit import OpNode from qiskit.transpiler.basepasses import AnalysisPass @@ -57,12 +58,12 @@ def run(self, dag): group = [] # Explore predecessors and successors of 2q gates if ( # pylint: disable=too-many-boolean-expressions - nd.type == "op" - and isinstance(nd._op, Gate) + isinstance(nd, OpNode) + and isinstance(nd.op, Gate) and len(nd._qargs) == 2 and not nodes_seen[nd] - and nd._op.condition is None - and not nd._op.is_parameterized() + and nd.op.condition is None + and not nd.op.is_parameterized() ): these_qubits = set(nd._qargs) # Explore predecessors of the 2q node @@ -74,11 +75,11 @@ def run(self, dag): if len(pred) == 1 and not nodes_seen[pred[0]]: pnd = pred[0] if ( - pnd.type == "op" - and isinstance(pnd._op, Gate) + isinstance(pnd, OpNode) + and isinstance(pnd.op, Gate) and len(pnd._qargs) <= 2 - and pnd._op.condition is None - and not pnd._op.is_parameterized() + and pnd.op.condition is None + and not pnd.op.is_parameterized() ): if (len(pnd._qargs) == 2 and set(pnd._qargs) == these_qubits) or len( pnd._qargs @@ -112,18 +113,18 @@ def run(self, dag): # Examine each predecessor for pnd in sorted_pred: if ( - pnd.type != "op" - or not isinstance(pnd._op, Gate) + not isinstance(pnd, OpNode) + or not isinstance(pnd.op, Gate) or len(pnd._qargs) > 2 - or pnd._op.condition is not None - or pnd._op.is_parameterized() + or pnd.op.condition is not None + or pnd.op.is_parameterized() ): # remove any qubits that are interrupted by a gate # e.g. a measure in the middle of the circuit these_qubits = list(set(these_qubits) - set(pnd._qargs)) continue # If a predecessor is a single qubit gate, add it - if len(pnd._qargs) == 1 and not pnd._op.is_parameterized(): + if len(pnd._qargs) == 1 and not pnd.op.is_parameterized(): if not nodes_seen[pnd]: group.append(pnd) nodes_seen[pnd] = True @@ -133,8 +134,8 @@ def run(self, dag): pred_qubits = set(pnd._qargs) if ( pred_qubits == these_qubits - and pnd._op.condition is None - and not pnd._op.is_parameterized() + and pnd.op.condition is None + and not pnd.op.is_parameterized() ): # add if on same qubits if not nodes_seen[pnd]: @@ -164,11 +165,11 @@ def run(self, dag): if len(succ) == 1 and not nodes_seen[succ[0]]: snd = succ[0] if ( - snd.type == "op" - and isinstance(snd._op, Gate) + isinstance(snd, OpNode) + and isinstance(snd.op, Gate) and len(snd._qargs) <= 2 - and snd._op.condition is None - and not snd._op.is_parameterized() + and snd.op.condition is None + and not snd.op.is_parameterized() ): if (len(snd._qargs) == 2 and set(snd._qargs) == these_qubits) or len( snd._qargs @@ -202,11 +203,11 @@ def run(self, dag): # Examine each successor for snd in sorted_succ: if ( - snd.type != "op" - or not isinstance(snd._op, Gate) + not isinstance(snd, OpNode) + or not isinstance(snd.op, Gate) or len(snd._qargs) > 2 - or snd._op.condition is not None - or snd._op.is_parameterized() + or snd.op.condition is not None + or snd.op.is_parameterized() ): # remove qubits from consideration if interrupted # by a gate e.g. a measure in the middle of the circuit @@ -216,7 +217,7 @@ def run(self, dag): # If a successor is a single qubit gate, add it # NB as we have eliminated all gates with names not in # good_names, this check guarantees they are single qubit - if len(snd._qargs) == 1 and not snd._op.is_parameterized(): + if len(snd._qargs) == 1 and not snd.op.is_parameterized(): if not nodes_seen[snd]: group.append(snd) nodes_seen[snd] = True @@ -226,8 +227,8 @@ def run(self, dag): succ_qubits = set(snd._qargs) if ( succ_qubits == these_qubits - and snd._op.condition is None - and not snd._op.is_parameterized() + and snd.op.condition is None + and not snd.op.is_parameterized() ): # add if on same qubits if not nodes_seen[snd]: diff --git a/qiskit/transpiler/passes/optimization/commutation_analysis.py b/qiskit/transpiler/passes/optimization/commutation_analysis.py index 2f8b0daee4b2..3c0d067627f6 100644 --- a/qiskit/transpiler/passes/optimization/commutation_analysis.py +++ b/qiskit/transpiler/passes/optimization/commutation_analysis.py @@ -17,6 +17,7 @@ from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.basepasses import AnalysisPass from qiskit.quantum_info.operators import Operator +from qiskit.dagcircuit import OpNode _CUTOFF_PRECISION = 1e-10 @@ -88,7 +89,7 @@ def run(self, dag): def _commute(node1, node2, cache): - if node1.type != "op" or node2.type != "op": + if not isinstance(node1, OpNode) or not isinstance(node2, OpNode): return False for nd in [node1, node2]: diff --git a/qiskit/transpiler/passes/optimization/commutative_cancellation.py b/qiskit/transpiler/passes/optimization/commutative_cancellation.py index 1b0b6b7f2c3a..c568ee98068c 100644 --- a/qiskit/transpiler/passes/optimization/commutative_cancellation.py +++ b/qiskit/transpiler/passes/optimization/commutative_cancellation.py @@ -19,7 +19,7 @@ from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.passes.optimization.commutation_analysis import CommutationAnalysis -from qiskit.dagcircuit import DAGCircuit +from qiskit.dagcircuit import DAGCircuit, InNode, OutNode from qiskit.circuit.library.standard_gates.u1 import U1Gate from qiskit.circuit.library.standard_gates.rx import RXGate from qiskit.circuit.library.standard_gates.p import PhaseGate @@ -97,7 +97,7 @@ def run(self, dag): wire_commutation_set = self.property_set["commutation_set"][wire] for com_set_idx, com_set in enumerate(wire_commutation_set): - if com_set[0].type in ["in", "out"]: + if isinstance(com_set[0], (InNode, OutNode)): continue for node in com_set: num_qargs = len(node.qargs) diff --git a/qiskit/transpiler/passes/optimization/consolidate_blocks.py b/qiskit/transpiler/passes/optimization/consolidate_blocks.py index 9722a1dfc06d..63ae9dbb0c84 100644 --- a/qiskit/transpiler/passes/optimization/consolidate_blocks.py +++ b/qiskit/transpiler/passes/optimization/consolidate_blocks.py @@ -16,6 +16,7 @@ from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit, Gate +from qiskit.dagcircuit import OpNode from qiskit.quantum_info.operators import Operator from qiskit.quantum_info.synthesis import TwoQubitBasisDecomposer from qiskit.extensions import UnitaryGate @@ -83,7 +84,7 @@ def run(self, dag): for node in dag.topological_op_nodes(): if node not in all_block_nodes: # need to add this node to find out where in the list it goes - preds = [nd for nd in dag.predecessors(node) if nd.type == "op"] + preds = [nd for nd in dag.predecessors(node) if isinstance(nd, OpNode)] block_count = 0 while preds: @@ -112,7 +113,7 @@ def run(self, dag): if len(block) == 1 and block[0].name != basis_gate_name: # pylint: disable=too-many-boolean-expressions if ( - block[0].type == "op" + isinstance(block[0], OpNode) and self.basis_gates and block[0].name not in self.basis_gates and len(block[0].cargs) == 0 @@ -133,7 +134,7 @@ def run(self, dag): block_cargs = set() for nd in block: block_qargs |= set(nd.qargs) - if nd.type == "op" and nd.op.condition: + if isinstance(nd, OpNode) and nd.op.condition: block_cargs |= set(nd.op.condition[0]) # convert block to a sub-circuit, then simulate unitary and add q = QuantumRegister(len(block_qargs)) diff --git a/qiskit/transpiler/passes/optimization/crosstalk_adaptive_schedule.py b/qiskit/transpiler/passes/optimization/crosstalk_adaptive_schedule.py index be22224ed68b..32395ab02f96 100644 --- a/qiskit/transpiler/passes/optimization/crosstalk_adaptive_schedule.py +++ b/qiskit/transpiler/passes/optimization/crosstalk_adaptive_schedule.py @@ -43,6 +43,7 @@ from qiskit.circuit.library.standard_gates import U1Gate, U2Gate, U3Gate, CXGate from qiskit.circuit import Measure from qiskit.circuit.barrier import Barrier +from qiskit.dagcircuit import OpNode from qiskit.transpiler.exceptions import TranspilerError NUM_PREC = 10 @@ -340,7 +341,7 @@ def scheduling_constraints(self): """ for gate in self.gate_start_time: for dep_gate in self.dag.successors(gate): - if not dep_gate.type == "op": + if not isinstance(dep_gate, OpNode): continue if isinstance(dep_gate.op, Measure): continue diff --git a/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py b/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py index de1646f5a318..855536404135 100644 --- a/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +++ b/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py @@ -16,7 +16,7 @@ from qiskit.circuit import Measure from qiskit.circuit.library.standard_gates import SwapGate from qiskit.transpiler.basepasses import TransformationPass -from qiskit.dagcircuit import DAGCircuit +from qiskit.dagcircuit import DAGCircuit, OpNode, OutNode class OptimizeSwapBeforeMeasure(TransformationPass): @@ -42,8 +42,8 @@ def run(self, dag): final_successor = [] for successor in dag.successors(swap): final_successor.append( - successor.type == "out" - or (successor.type == "op" and isinstance(successor.op, Measure)) + isinstance(successor, OutNode) + or (isinstance(successor, OpNode) and isinstance(successor.op, Measure)) ) if all(final_successor): # the node swap needs to be removed and, if a measure follows, needs to be adapted @@ -54,7 +54,7 @@ def run(self, dag): for creg in dag.cregs.values(): measure_layer.add_creg(creg) for successor in list(dag.successors(swap)): - if successor.type == "op" and successor.op.name == "measure": + if isinstance(successor, OpNode) and successor.op.name == "measure": # replace measure node with a new one, where qargs is set with the "other" # swap qarg. dag.remove_op_node(successor) diff --git a/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py b/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py index 7717a7269500..0787f28cd2e4 100644 --- a/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py +++ b/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py @@ -26,6 +26,7 @@ CU1Gate, RZZGate, ) +from qiskit.dagcircuit import OpNode from qiskit.transpiler.basepasses import TransformationPass @@ -52,12 +53,12 @@ def run(self, dag): for measure in dag.op_nodes(Measure): predecessor = next(dag.quantum_predecessors(measure)) - if predecessor.type == "op" and isinstance(predecessor.op, diagonal_1q_gates): + if isinstance(predecessor, OpNode) and isinstance(predecessor.op, diagonal_1q_gates): nodes_to_remove.add(predecessor) - if predecessor.type == "op" and isinstance(predecessor.op, diagonal_2q_gates): + if isinstance(predecessor, OpNode) and isinstance(predecessor.op, diagonal_2q_gates): successors = dag.quantum_successors(predecessor) - if all(s.type == "op" and isinstance(s.op, Measure) for s in successors): + if all(isinstance(s, OpNode) and isinstance(s.op, Measure) for s in successors): nodes_to_remove.add(predecessor) for node_to_remove in nodes_to_remove: diff --git a/qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py b/qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py index dc0390906895..6c1e19d78771 100644 --- a/qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py +++ b/qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py @@ -13,6 +13,7 @@ """Remove reset gate when the qubit is in zero state.""" from qiskit.circuit import Reset +from qiskit.dagcircuit import InNode from qiskit.transpiler.basepasses import TransformationPass @@ -31,6 +32,6 @@ def run(self, dag): resets = dag.op_nodes(Reset) for reset in resets: predecessor = next(dag.predecessors(reset)) - if predecessor.type == "in": + if isinstance(predecessor, InNode): dag.remove_op_node(reset) return dag diff --git a/qiskit/transpiler/passes/optimization/template_matching/backward_match.py b/qiskit/transpiler/passes/optimization/template_matching/backward_match.py index 7285c6e6e61d..fb0e5423e84d 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/backward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/backward_match.py @@ -27,6 +27,7 @@ import heapq from qiskit.circuit.controlledgate import ControlledGate +from qiskit.dagcircuit import OpNode class Match: @@ -303,9 +304,9 @@ def _is_same_c_conf(self, node_circuit, node_template, carg_circuit): bool: True if possible, False otherwise. """ if ( - node_circuit.type == "op" + isinstance(node_circuit, OpNode) and node_circuit.op.condition - and node_template.type == "op" + and isinstance(node_template, OpNode) and node_template.op.condition ): if set(carg_circuit) != set(node_template.cindices): diff --git a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py index 83de15f30b5f..d895acdf0a08 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py @@ -25,6 +25,7 @@ """ from qiskit.circuit.controlledgate import ControlledGate +from qiskit.dagcircuit import OpNode class ForwardMatch: @@ -312,9 +313,9 @@ def _is_same_c_conf(self, node_circuit, node_template): bool: True if possible, False otherwise. """ if ( - node_circuit.type == "op" + isinstance(node_circuit, OpNode) and node_circuit.op.condition - and node_template.type == "op" + and isinstance(node_template, OpNode) and node_template.op.conditon ): if set(self.carg_indices) != set(node_template.cindices): diff --git a/qiskit/transpiler/passes/routing/lookahead_swap.py b/qiskit/transpiler/passes/routing/lookahead_swap.py index df8ccb9c67d2..6d6e360fbaad 100644 --- a/qiskit/transpiler/passes/routing/lookahead_swap.py +++ b/qiskit/transpiler/passes/routing/lookahead_swap.py @@ -20,7 +20,7 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.layout import Layout -from qiskit.dagcircuit import DAGNode +from qiskit.dagcircuit import DAGNode, OpNode logger = logging.getLogger(__name__) @@ -266,7 +266,7 @@ def _map_free_gates(layout, gates, coupling_map): # Gates without a partition (barrier, snapshot, save, load, noise) may # still have associated qubits. Look for them in the qargs. if not gate["partition"]: - qubits = [n for n in gate["graph"].nodes() if n.type == "op"][0].qargs + qubits = [n for n in gate["graph"].nodes() if isinstance(n, OpNode)][0].qargs if not qubits: continue @@ -321,7 +321,7 @@ def _score_step(step): def _transform_gate_for_layout(gate, layout): """Return op implementing a virtual gate on given layout.""" - mapped_op_node = deepcopy([n for n in gate["graph"].nodes() if n.type == "op"][0]) + mapped_op_node = deepcopy([n for n in gate["graph"].nodes() if isinstance(n, OpNode)][0]) device_qreg = QuantumRegister(len(layout.get_physical_bits()), "q") mapped_qargs = [device_qreg[layout[a]] for a in mapped_op_node.qargs] @@ -336,4 +336,4 @@ def _swap_ops_from_edge(edge, layout): qreg_edge = [device_qreg[i] for i in edge] # TODO shouldn't be making other nodes not by the DAG!! - return [DAGNode(op=SwapGate(), qargs=qreg_edge, cargs=[], type="op")] + return [OpNode(op=SwapGate(), qargs=qreg_edge, cargs=[])] diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index 7bfb5125f517..f1f81e02ea48 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -21,7 +21,7 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.layout import Layout -from qiskit.dagcircuit import DAGNode +from qiskit.dagcircuit import DAGNode, OpNode, OutNode logger = logging.getLogger(__name__) @@ -166,12 +166,19 @@ def run(self, dag): # Start algorithm from the front layer and iterate until all gates done. num_search_steps = 0 front_layer = dag.front_layer() + for x in front_layer: + #if isinstance(x, OutNode): + print('\n\n\n\nFront Layer', type(x), type(front_layer)) self.applied_gates = set() while front_layer: execute_gate_list = [] # Remove as many immediately applicable gates as possible for node in front_layer: + if isinstance(node, OutNode): + print('\n\n\n\n\nNode in front', node) + front_layer.remove(node) + continue if len(node.qargs) == 2: v0, v1 = node.qargs if self.coupling_map.graph.has_edge(current_layout[v0], current_layout[v1]): @@ -181,12 +188,16 @@ def run(self, dag): if execute_gate_list: for node in execute_gate_list: + if isinstance(node, OutNode): + print('\n\n\n\n\nOut Node', node) new_node = _transform_gate_for_layout(node, current_layout, canonical_register) + if isinstance(new_node, OutNode): + print('\n\n\n\n\nOut Node 2', new_node) mapped_dag.apply_operation_back(new_node.op, new_node.qargs, new_node.cargs) front_layer.remove(node) self.applied_gates.add(node) for successor in dag.quantum_successors(node): - if successor.type != "op": + if isinstance(successor, OpNode): continue if self._is_resolved(successor, dag): front_layer.append(successor) @@ -195,8 +206,8 @@ def run(self, dag): self._reset_qubits_decay() # Diagnostics - logger.debug("free! %s", [(n.name, n.qargs) for n in execute_gate_list]) - logger.debug("front_layer: %s", [(n.name, n.qargs) for n in front_layer]) + logger.debug("free! %s", [(n.name if isinstance(n, OpNode) else None, n.qargs) for n in execute_gate_list]) + logger.debug("front_layer: %s", [(n.name if isinstance(n, OpNode) else None, n.qargs) for n in front_layer]) continue @@ -217,7 +228,7 @@ def run(self, dag): best_swaps = [k for k, v in swap_scores.items() if v == min_score] best_swaps.sort(key=lambda x: (self._bit_indices[x[0]], self._bit_indices[x[1]])) best_swap = rng.choice(best_swaps) - swap_node = DAGNode(op=SwapGate(), qargs=best_swap, type="op") + swap_node = OpNode(op=SwapGate(), qargs=best_swap) swap_node = _transform_gate_for_layout(swap_node, current_layout, canonical_register) mapped_dag.apply_operation_back(swap_node.op, swap_node.qargs) current_layout.swap(*best_swap) @@ -249,7 +260,7 @@ def _reset_qubits_decay(self): def _is_resolved(self, node, dag): """Return True if all of a node's predecessors in dag are applied.""" predecessors = dag.quantum_predecessors(node) - predecessors = filter(lambda x: x.type == "op", predecessors) + predecessors = filter(lambda x: isinstance(x, OpNode), predecessors) return all(n in self.applied_gates for n in predecessors) def _obtain_extended_set(self, dag, front_layer): @@ -267,7 +278,7 @@ def _obtain_extended_set(self, dag, front_layer): try: _, successors = next(node_successor_generator) successors = list( - filter(lambda x: x.type == "op" and len(x.qargs) == 2, successors) + filter(lambda x: isinstance(x, OpNode) and len(x.qargs) == 2, successors) ) except StopIteration: node_lookahead_exhausted[i] = True diff --git a/qiskit/transpiler/passes/scheduling/calibration_creators.py b/qiskit/transpiler/passes/scheduling/calibration_creators.py index 255e742123d4..8e0cf52235c8 100644 --- a/qiskit/transpiler/passes/scheduling/calibration_creators.py +++ b/qiskit/transpiler/passes/scheduling/calibration_creators.py @@ -29,7 +29,7 @@ from qiskit.pulse.instructions.instruction import Instruction from qiskit.exceptions import QiskitError from qiskit.providers import basebackend -from qiskit.dagcircuit import DAGNode +from qiskit.dagcircuit import DAGNode, OpNode from qiskit.circuit.library.standard_gates import RZXGate from qiskit.transpiler.basepasses import TransformationPass @@ -57,7 +57,7 @@ def run(self, dag): bit_indices = {bit: index for index, bit in enumerate(dag.qubits)} for node in dag.nodes(): - if node.type == "op": + if isinstance(node, OpNode): if self.supported(node.op): params = node.op.params qubits = [bit_indices[qarg] for qarg in node.qargs] diff --git a/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py b/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py index 122fdf0cfc75..6a85bc59ff40 100644 --- a/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +++ b/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py @@ -15,7 +15,7 @@ from qiskit.circuit.barrier import Barrier from qiskit.transpiler.basepasses import TransformationPass -from qiskit.dagcircuit import DAGCircuit +from qiskit.dagcircuit import DAGCircuit, OpNode from .merge_adjacent_barriers import MergeAdjacentBarriers @@ -38,7 +38,7 @@ def run(self, dag): for _, child_successors in dag.bfs_successors(candidate_node): if any( - suc.type == "op" and suc.name not in final_op_types for suc in child_successors + isinstance(suc, OpNode) and suc.name not in final_op_types for suc in child_successors ): is_final_op = False break diff --git a/qiskit/transpiler/passes/utils/remove_final_measurements.py b/qiskit/transpiler/passes/utils/remove_final_measurements.py index 5e61a42cd91a..c40ea770b062 100644 --- a/qiskit/transpiler/passes/utils/remove_final_measurements.py +++ b/qiskit/transpiler/passes/utils/remove_final_measurements.py @@ -13,6 +13,7 @@ """Remove final measurements and barriers at the end of a circuit.""" from qiskit.transpiler.basepasses import TransformationPass +from qiskit.dagcircuit import OpNode class RemoveFinalMeasurements(TransformationPass): @@ -44,7 +45,7 @@ def run(self, dag): for _, child_successors in dag.bfs_successors(candidate_node): if any( - suc.type == "op" and suc.name not in final_op_types for suc in child_successors + isinstance(suc, OpNode) and suc.name not in final_op_types for suc in child_successors ): is_final_op = False break diff --git a/qiskit/visualization/dag_visualization.py b/qiskit/visualization/dag_visualization.py index 2947dd4fafa3..4fb57d15e05e 100644 --- a/qiskit/visualization/dag_visualization.py +++ b/qiskit/visualization/dag_visualization.py @@ -20,6 +20,7 @@ import sys import tempfile +from qiskit.dagcircuit import OpNode, InNode, OutNode from qiskit.exceptions import MissingOptionalLibraryError from .exceptions import VisualizationError @@ -137,17 +138,17 @@ def node_attr_func(node): return {} if style == "color": n = {} - if node.type == "op": + if isinstance(node, OpNode): n["label"] = node.name n["color"] = "blue" n["style"] = "filled" n["fillcolor"] = "lightblue" - if node.type == "in": + if isinstance(node, InNode): n["label"] = bit_labels[node.wire] n["color"] = "black" n["style"] = "filled" n["fillcolor"] = "green" - if node.type == "out": + if isinstance(node, OutNode): n["label"] = bit_labels[node.wire] n["color"] = "black" n["style"] = "filled" diff --git a/qiskit/visualization/matplotlib.py b/qiskit/visualization/matplotlib.py index f08cb5cf85e4..dc1210d71dae 100644 --- a/qiskit/visualization/matplotlib.py +++ b/qiskit/visualization/matplotlib.py @@ -32,6 +32,7 @@ HAS_PYLATEX = False from qiskit.circuit import ControlledGate, Gate, Instruction +from qiskit.dagcircuit import OpNode from qiskit.exceptions import MissingOptionalLibraryError from qiskit.visualization.qcstyle import DefaultStyle, set_style from qiskit.circuit import Delay @@ -1333,7 +1334,7 @@ def _draw_ops(self, verbose=False): # load param if ( - op.type == "op" + isinstance(op, OpNode) and hasattr(op.op, "params") and len(op.op.params) > 0 and not any(isinstance(param, np.ndarray) for param in op.op.params) @@ -1343,7 +1344,7 @@ def _draw_ops(self, verbose=False): param = "" # conditional gate - if op.type == "op" and op.op.condition: + if isinstance(op, OpNode) and op.op.condition: c_xy = [ c_anchors[ii].plot_coord(this_anc, layer_width, self._x_offset) for ii in self._clbit_dict diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 681a9373f2ec..e76948ff3321 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -32,6 +32,7 @@ from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, pulse from qiskit.circuit import Parameter, Gate, Qubit, Clbit from qiskit.compiler import transpile +from qiskit.dagcircuit import OutNode from qiskit.converters import circuit_to_dag from qiskit.circuit.library import CXGate, U3Gate, U2Gate, U1Gate, RXGate, RYGate, RZGate from qiskit.test import QiskitTestCase @@ -678,7 +679,7 @@ def test_move_measurements(self): meas_nodes = out_dag.named_nodes("measure") for meas_node in meas_nodes: is_last_measure = all( - after_measure.type == "out" + isinstance(after_measure, OutNode) for after_measure in out_dag.quantum_successors(meas_node) ) self.assertTrue(is_last_measure) From 7d5558ae3201f1241930c66ae8cc6f82798e754f Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Fri, 11 Jun 2021 17:29:28 -0700 Subject: [PATCH 10/37] Final transpiler tests --- qiskit/transpiler/passes/routing/sabre_swap.py | 13 +------------ test/python/transpiler/test_consolidate_blocks.py | 3 ++- test/python/transpiler/test_faulty_backend.py | 3 ++- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index f1f81e02ea48..ca18145f117f 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -166,19 +166,12 @@ def run(self, dag): # Start algorithm from the front layer and iterate until all gates done. num_search_steps = 0 front_layer = dag.front_layer() - for x in front_layer: - #if isinstance(x, OutNode): - print('\n\n\n\nFront Layer', type(x), type(front_layer)) self.applied_gates = set() while front_layer: execute_gate_list = [] # Remove as many immediately applicable gates as possible for node in front_layer: - if isinstance(node, OutNode): - print('\n\n\n\n\nNode in front', node) - front_layer.remove(node) - continue if len(node.qargs) == 2: v0, v1 = node.qargs if self.coupling_map.graph.has_edge(current_layout[v0], current_layout[v1]): @@ -188,16 +181,12 @@ def run(self, dag): if execute_gate_list: for node in execute_gate_list: - if isinstance(node, OutNode): - print('\n\n\n\n\nOut Node', node) new_node = _transform_gate_for_layout(node, current_layout, canonical_register) - if isinstance(new_node, OutNode): - print('\n\n\n\n\nOut Node 2', new_node) mapped_dag.apply_operation_back(new_node.op, new_node.qargs, new_node.cargs) front_layer.remove(node) self.applied_gates.add(node) for successor in dag.quantum_successors(node): - if isinstance(successor, OpNode): + if not isinstance(successor, OpNode): continue if self._is_resolved(successor, dag): front_layer.append(successor) diff --git a/test/python/transpiler/test_consolidate_blocks.py b/test/python/transpiler/test_consolidate_blocks.py index 1fdfe3e48453..4ab243ac91f6 100644 --- a/test/python/transpiler/test_consolidate_blocks.py +++ b/test/python/transpiler/test_consolidate_blocks.py @@ -19,6 +19,7 @@ from qiskit.circuit import QuantumCircuit, QuantumRegister from qiskit.circuit.library import U2Gate +from qiskit.dagcircuit import OpNode from qiskit.extensions import UnitaryGate from qiskit.converters import circuit_to_dag from qiskit.transpiler.passes import ConsolidateBlocks @@ -94,7 +95,7 @@ def test_topological_order_preserved(self): pass_.property_set["block_list"] = [block_1, block_2] new_dag = pass_.run(dag) - new_topo_ops = [i for i in new_dag.topological_op_nodes() if i.type == "op"] + new_topo_ops = [i for i in new_dag.topological_op_nodes() if isinstance(i, OpNode)] self.assertEqual(len(new_topo_ops), 2) self.assertEqual(new_topo_ops[0].qargs, [qr[1], qr[2]]) self.assertEqual(new_topo_ops[1].qargs, [qr[0], qr[1]]) diff --git a/test/python/transpiler/test_faulty_backend.py b/test/python/transpiler/test_faulty_backend.py index 2e9a312684cd..f75ff63fcb94 100644 --- a/test/python/transpiler/test_faulty_backend.py +++ b/test/python/transpiler/test_faulty_backend.py @@ -19,6 +19,7 @@ from qiskit.test import QiskitTestCase from qiskit.converters import circuit_to_dag from qiskit.circuit.library import CXGate +from qiskit.dagcircuit import OpNode from qiskit.transpiler import TranspilerError from ..providers.faulty_backends import ( FakeOurenseFaultyQ1, @@ -223,7 +224,7 @@ def assertIdleQ1(self, circuit): physical_qubits = QuantumRegister(5, "q") nodes = circuit_to_dag(circuit).nodes_on_wire(physical_qubits[1]) for node in nodes: - if node.type == "op": + if isinstance(node, OpNode): raise AssertionError("Faulty Qubit Q1 not totally idle") @data(0, 1, 2, 3) From f8cbd6351e0b85c4ff9679670ecaaee7f1fc7076 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sat, 12 Jun 2021 16:11:44 -0700 Subject: [PATCH 11/37] Fix transpiler tests, change to DAGNodeP --- qiskit/dagcircuit/__init__.py | 3 +- qiskit/dagcircuit/dagcircuit.py | 27 ++- qiskit/dagcircuit/dagnode.py | 208 ++++++++++++++++-- .../passes/routing/lookahead_swap.py | 2 +- .../transpiler/passes/routing/sabre_swap.py | 15 +- .../passes/scheduling/calibration_creators.py | 6 +- .../barrier_before_final_measurements.py | 3 +- .../passes/utils/remove_final_measurements.py | 3 +- test/python/dagcircuit/test_dagcircuit.py | 2 + test/python/transpiler/test_hoare_opt.py | 10 +- 10 files changed, 232 insertions(+), 47 deletions(-) diff --git a/qiskit/dagcircuit/__init__.py b/qiskit/dagcircuit/__init__.py index 54c209a9fc9e..3e1615510e92 100644 --- a/qiskit/dagcircuit/__init__.py +++ b/qiskit/dagcircuit/__init__.py @@ -24,7 +24,6 @@ :toctree: ../stubs/ DAGCircuit - DAGNode DAGDepNode DAGDependency @@ -37,7 +36,7 @@ DAGCircuitError """ from .dagcircuit import DAGCircuit -from .dagnode import DAGNode, OpNode, InNode, OutNode +from .dagnode import OpNode, InNode, OutNode from .dagdepnode import DAGDepNode from .exceptions import DAGCircuitError from .dagdependency import DAGDependency diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 49c6380b0a16..e7b17266e370 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -35,7 +35,7 @@ from qiskit.circuit.gate import Gate from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.dagcircuit.exceptions import DAGCircuitError -from qiskit.dagcircuit.dagnode import DAGNode, OpNode, InNode, OutNode +from qiskit.dagcircuit.dagnode import DAGNodeP, OpNode, InNode, OutNode from qiskit.exceptions import MissingOptionalLibraryError @@ -806,9 +806,9 @@ def idle_wires(self, ignore=None): ignore = [] for wire in self._wires: nodes = [ - node for node in self.nodes_on_wire(wire, only_ops=False) if ( - not isinstance(node, OpNode) or node.op.name not in ignore - ) + node + for node in self.nodes_on_wire(wire, only_ops=False) + if (not isinstance(node, OpNode) or node.op.name not in ignore) ] if len(nodes) == 2: yield wire @@ -975,7 +975,7 @@ def __eq__(self, other): return False def node_eq(node_self, node_other): - return DAGNode.semantic_eq(node_self, node_other, self_bit_indices, other_bit_indices) + return DAGNodeP.semantic_eq(node_self, node_other, self_bit_indices, other_bit_indices) return rx.is_isomorphic_node_match(self._multi_graph, other._multi_graph, node_eq) @@ -988,7 +988,12 @@ def topological_nodes(self): """ def _key(x): - return x.sort_key + #print('\n\n\nkey: ', type(x)) + if isinstance(x, OpNode): + #print('sort_key: ', x.sort_key) + return x.sort_key + else: + return "" return iter(rx.lexicographical_topological_sort(self._multi_graph, key=_key)) @@ -1056,7 +1061,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): # If a gate is conditioned, we expect the replacement subcircuit # to depend on those condition bits as well. if not isinstance(node, OpNode): - raise DAGCircuitError('expected node OpNode, got %s' % node) + raise DAGCircuitError("expected node OpNode, got %s" % node) condition_bit_list = self._bits_in_condition(condition) @@ -1139,7 +1144,7 @@ def substitute_node(self, node, op, inplace=False): """ if not isinstance(node, OpNode): - raise DAGCircuitError('Only OpNodes can be replaced.') + raise DAGCircuitError("Only OpNodes can be replaced.") if node.op.num_qubits != op.num_qubits or node.op.num_clbits != op.num_clbits: raise DAGCircuitError( @@ -1199,7 +1204,7 @@ def edges(self, nodes=None): if nodes is None: nodes = self._multi_graph.nodes() - elif isinstance(nodes, DAGNode): + elif isinstance(nodes, (InNode, OutNode, OpNode)): nodes = [nodes] for node in nodes: raw_nodes = self._multi_graph.out_edges(node._node_id) @@ -1502,7 +1507,9 @@ def collect_runs(self, namelist): """ def filter_fn(node): - return isinstance(node, OpNode) and node.op.name in namelist and node.op.condition is None + return ( + isinstance(node, OpNode) and node.op.name in namelist and node.op.condition is None + ) group_list = rx.collect_runs(self._multi_graph, filter_fn) return set(tuple(x) for x in group_list) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 36b4014f1e31..165a20c09633 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -20,14 +20,14 @@ from qiskit.circuit import Instruction, Gate -class DAGNode: +class DAGNodeP: """Object to represent the information at a node in the DAGCircuit. It is used as the return value from `*_nodes()` functions and can be supplied to functions that take a node. """ - __slots__ = ["_qargs", "cargs", "sort_key", "_node_id"] + __slots__ = ["_node_id"] def __init__(self, qargs=None, cargs=None, nid=-1): """Create a node""" @@ -89,13 +89,13 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): bit_indices1 = {arg: arg for arg in node1.qargs + node1.cargs} bit_indices2 = {arg: arg for arg in node2.qargs + node2.cargs} - node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs] - node1_cargs = [bit_indices1[carg] for carg in node1.cargs] + if isinstance(node1, OpNode) and isinstance(node2, OpNode): + node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs] + node1_cargs = [bit_indices1[carg] for carg in node1.cargs] - node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs] - node2_cargs = [bit_indices2[carg] for carg in node2.cargs] + node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs] + node2_cargs = [bit_indices2[carg] for carg in node2.cargs] - if isinstance(node1, OpNode) and isinstance(node2, OpNode): # For barriers, qarg order is not significant so compare as sets if "barrier" == node1.op.name == node2.op.name: return set(node1_qargs) == set(node2_qargs) @@ -106,26 +106,24 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if node1_cargs == node2_cargs: if node1.op.condition == node2.op.condition: return True - elif ((isinstance(node1, InNode) and isinstance(node2, InNode)) - or (isinstance(node1, OutNode) and isinstance(node2, OutNode))): - if node1_qargs == node2_qargs: - if node1_cargs == node2_cargs: - if bit_indices1.get(node1.wire, None) == bit_indices2.get( - node2.wire, None - ): - return True + elif (isinstance(node1, InNode) and isinstance(node2, InNode)) or ( + isinstance(node1, OutNode) and isinstance(node2, OutNode) + ): + if bit_indices1.get(node1.wire, None) == bit_indices2.get(node2.wire, None): + return True else: return False -class OpNode(DAGNode): +class OpNode(DAGNodeP): """Object to represent the information at a node in the DAGCircuit. It is used as the return value from `*_nodes()` functions and can be supplied to functions that take a node. """ - __slots__ = ["op"] + __slots__ = ["op", "_qargs", "cargs"] + def __init__(self, op, qargs=None, cargs=None): """Create a node""" self.op = op @@ -140,31 +138,199 @@ def name(self, new_name): self.op.name = new_name -class InNode(DAGNode): +class InNode(DAGNodeP): """Object to represent the information at a node in the DAGCircuit. It is used as the return value from `*_nodes()` functions and can be supplied to functions that take a node. """ - __slots__ = ["wire"] + __slots__ = ["wire", "qargs", "cargs"] def __init__(self, wire, qargs=None, cargs=None): """Create a node""" self.wire = wire + #self.qargs = qargs if qargs is not None else [] super().__init__(qargs, cargs) -class OutNode(DAGNode): +class OutNode(DAGNodeP): """Object to represent the information at a node in the DAGCircuit. It is used as the return value from `*_nodes()` functions and can be supplied to functions that take a node. """ - __slots__ = ["wire"] + __slots__ = ["wire", "qargs", "cargs"] def __init__(self, wire, qargs=None, cargs=None): """Create a node""" self.wire = wire + #self.qargs = qargs if qargs is not None else [] super().__init__(qargs, cargs) + + +class DAGNode: + """Object to represent the information at a node in the DAGCircuit. + It is used as the return value from `*_nodes()` functions and can + be supplied to functions that take a node. + """ + + __slots__ = ["type", "_op", "_qargs", "cargs", "_wire", "sort_key", "_node_id"] + + def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=None, nid=-1): + """Create a node""" + self.type = type + self._op = op + if name is not None: + warnings.warn( + "The DAGNode 'name' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use 'DAGNode.op.name' if the DAGNode is of type 'op'.", + DeprecationWarning, + 2, + ) + self._qargs = qargs if qargs is not None else [] + self.cargs = cargs if cargs is not None else [] + self._wire = wire + self._node_id = nid + self.sort_key = str(self._qargs) + + @property + def op(self): + """Returns the Instruction object corresponding to the op for the node, else None""" + if not self.type or self.type != "op": + raise QiskitError("The node %s is not an op node" % (str(self))) + return self._op + + @op.setter + def op(self, data): + self._op = data + + @property + def name(self): + """Returns the Instruction name corresponding to the op for this node""" + if self.type and self.type == "op": + return self._op.name + return None + + @name.setter + def name(self, name): + if self.type and self.type == "op": + self._op.name = name + + @property + def condition(self): + """Returns the condition of the node.op""" + if not self.type or self.type != "op": + raise QiskitError("The node %s is not an op node" % (str(self))) + warnings.warn( + "The DAGNode 'condition' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use 'DAGNode.op.condition' if the DAGNode is of type 'op'.", + DeprecationWarning, + 2, + ) + return self._op.condition + + @condition.setter + def condition(self, new_condition): + """Sets the node.condition which sets the node.op.condition.""" + if not self.type or self.type != "op": + raise QiskitError("The node %s is not an op node" % (str(self))) + warnings.warn( + "The DAGNode 'condition' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use 'DAGNode.op.condition' if the DAGNode is of type 'op'.", + DeprecationWarning, + 2, + ) + self._op.condition = new_condition + + @property + def qargs(self): + """ + Returns list of Qubit, else an empty list. + """ + return self._qargs + + @qargs.setter + def qargs(self, new_qargs): + """Sets the qargs to be the given list of qargs.""" + self._qargs = new_qargs + self.sort_key = str(new_qargs) + + @property + def wire(self): + """ + Returns the Bit object, else None. + """ + if self.type not in ["in", "out"]: + raise QiskitError("The node %s is not an input/output node" % str(self)) + return self._wire + + @wire.setter + def wire(self, data): + self._wire = data + + def __lt__(self, other): + return self._node_id < other._node_id + + def __gt__(self, other): + return self._node_id > other._node_id + + def __str__(self): + # TODO is this used anywhere other than in DAG drawing? + # needs to be unique as it is what pydot uses to distinguish nodes + return str(id(self)) + + @staticmethod + def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): + """ + Check if DAG nodes are considered equivalent, e.g., as a node_match for nx.is_isomorphic. + Args: + node1 (DAGNode): A node to compare. + node2 (DAGNode): The other node to compare. + bit_indices1 (dict): Dictionary mapping Bit instances to their index + within the circuit containing node1 + bit_indices2 (dict): Dictionary mapping Bit instances to their index + within the circuit containing node2 + Return: + Bool: If node1 == node2 + """ + if bit_indices1 is None or bit_indices2 is None: + warnings.warn( + "DAGNode.semantic_eq now expects two bit-to-circuit index " + "mappings as arguments. To ease the transition, these will be " + "pre-populated based on the values found in Bit.index and " + "Bit.register. However, this behavior is deprecated and a future " + "release will require the mappings to be provided as arguments.", + DeprecationWarning, + ) + + bit_indices1 = {arg: arg for arg in node1.qargs + node1.cargs} + bit_indices2 = {arg: arg for arg in node2.qargs + node2.cargs} + + node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs] + node1_cargs = [bit_indices1[carg] for carg in node1.cargs] + + node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs] + node2_cargs = [bit_indices2[carg] for carg in node2.cargs] + + # For barriers, qarg order is not significant so compare as sets + if "barrier" == node1.name == node2.name: + return set(node1_qargs) == set(node2_qargs) + + if node1.type == node2.type: + if node1._op == node2._op: + if node1.name == node2.name: + if node1_qargs == node2_qargs: + if node1_cargs == node2_cargs: + if node1.type == "op": + if node1._op.condition != node2._op.condition: + return False + if bit_indices1.get(node1._wire, None) == bit_indices2.get( + node2._wire, None + ): + return True + return False diff --git a/qiskit/transpiler/passes/routing/lookahead_swap.py b/qiskit/transpiler/passes/routing/lookahead_swap.py index 6d6e360fbaad..2072a39d926b 100644 --- a/qiskit/transpiler/passes/routing/lookahead_swap.py +++ b/qiskit/transpiler/passes/routing/lookahead_swap.py @@ -20,7 +20,7 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.layout import Layout -from qiskit.dagcircuit import DAGNode, OpNode +from qiskit.dagcircuit import OpNode logger = logging.getLogger(__name__) diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index ca18145f117f..8999e24e02a2 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -21,7 +21,7 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.layout import Layout -from qiskit.dagcircuit import DAGNode, OpNode, OutNode +from qiskit.dagcircuit import OpNode, OutNode logger = logging.getLogger(__name__) @@ -195,8 +195,17 @@ def run(self, dag): self._reset_qubits_decay() # Diagnostics - logger.debug("free! %s", [(n.name if isinstance(n, OpNode) else None, n.qargs) for n in execute_gate_list]) - logger.debug("front_layer: %s", [(n.name if isinstance(n, OpNode) else None, n.qargs) for n in front_layer]) + logger.debug( + "free! %s", + [ + (n.name if isinstance(n, OpNode) else None, n.qargs) + for n in execute_gate_list + ], + ) + logger.debug( + "front_layer: %s", + [(n.name if isinstance(n, OpNode) else None, n.qargs) for n in front_layer], + ) continue diff --git a/qiskit/transpiler/passes/scheduling/calibration_creators.py b/qiskit/transpiler/passes/scheduling/calibration_creators.py index 8e0cf52235c8..e8119ec02f07 100644 --- a/qiskit/transpiler/passes/scheduling/calibration_creators.py +++ b/qiskit/transpiler/passes/scheduling/calibration_creators.py @@ -29,7 +29,7 @@ from qiskit.pulse.instructions.instruction import Instruction from qiskit.exceptions import QiskitError from qiskit.providers import basebackend -from qiskit.dagcircuit import DAGNode, OpNode +from qiskit.dagcircuit import OpNode from qiskit.circuit.library.standard_gates import RZXGate from qiskit.transpiler.basepasses import TransformationPass @@ -38,7 +38,7 @@ class CalibrationCreator(TransformationPass): """Abstract base class to inject calibrations into circuits.""" @abstractmethod - def supported(self, node_op: DAGNode) -> bool: + def supported(self, node_op: OpNode) -> bool: """Determine if a given name supports the calibration.""" @abstractmethod @@ -103,7 +103,7 @@ def __init__(self, backend: basebackend): self._config = backend.configuration() self._channel_map = backend.configuration().qubit_channel_mapping - def supported(self, node_op: DAGNode) -> bool: + def supported(self, node_op: OpNode) -> bool: """ Args: node_op: The node from the dag dep. diff --git a/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py b/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py index 6a85bc59ff40..b6dddcdd8bd1 100644 --- a/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +++ b/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py @@ -38,7 +38,8 @@ def run(self, dag): for _, child_successors in dag.bfs_successors(candidate_node): if any( - isinstance(suc, OpNode) and suc.name not in final_op_types for suc in child_successors + isinstance(suc, OpNode) and suc.name not in final_op_types + for suc in child_successors ): is_final_op = False break diff --git a/qiskit/transpiler/passes/utils/remove_final_measurements.py b/qiskit/transpiler/passes/utils/remove_final_measurements.py index c40ea770b062..fc7aa7dbc067 100644 --- a/qiskit/transpiler/passes/utils/remove_final_measurements.py +++ b/qiskit/transpiler/passes/utils/remove_final_measurements.py @@ -45,7 +45,8 @@ def run(self, dag): for _, child_successors in dag.bfs_successors(candidate_node): if any( - isinstance(suc, OpNode) and suc.name not in final_op_types for suc in child_successors + isinstance(suc, OpNode) and suc.name not in final_op_types + for suc in child_successors ): is_final_op = False break diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 48ed16aeda32..6370e9118560 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -640,6 +640,8 @@ def test_topological_nodes(self): named_nodes = self.dag.topological_nodes() + print([(i.op.name if isinstance(i, OpNode) else i.wire, i.qargs) for i in named_nodes]) + qr = self.dag.qregs["qr"] cr = self.dag.cregs["cr"] expected = [ diff --git a/test/python/transpiler/test_hoare_opt.py b/test/python/transpiler/test_hoare_opt.py index 9dc501a05e0f..5d3402788a61 100644 --- a/test/python/transpiler/test_hoare_opt.py +++ b/test/python/transpiler/test_hoare_opt.py @@ -20,7 +20,7 @@ from qiskit import QuantumCircuit from qiskit.test import QiskitTestCase from qiskit.circuit.library import XGate, RZGate, CSwapGate, SwapGate -from qiskit.dagcircuit import DAGNode +from qiskit.dagcircuit import OpNode from qiskit.quantum_info import Statevector @@ -297,16 +297,16 @@ def test_is_identity(self): """The is_identity function determines whether a pair of gates forms the identity, when ignoring control qubits. """ - seq = [DAGNode(type="op", op=XGate().control()), DAGNode(type="op", op=XGate().control(2))] + seq = [OpNode(op=XGate().control()), OpNode(op=XGate().control(2))] self.assertTrue(HoareOptimizer()._is_identity(seq)) seq = [ - DAGNode(type="op", op=RZGate(-pi / 2).control()), - DAGNode(type="op", op=RZGate(pi / 2).control(2)), + OpNode(op=RZGate(-pi / 2).control()), + OpNode(op=RZGate(pi / 2).control(2)), ] self.assertTrue(HoareOptimizer()._is_identity(seq)) - seq = [DAGNode(type="op", op=CSwapGate()), DAGNode(type="op", op=SwapGate())] + seq = [OpNode(op=CSwapGate()), OpNode(op=SwapGate())] self.assertTrue(HoareOptimizer()._is_identity(seq)) def test_multiple_pass(self): From 5d2843618525f474786527a1296c0dea763a1dbd Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sun, 13 Jun 2021 04:56:43 -0700 Subject: [PATCH 12/37] Fix minimal InNode and OutNode --- qiskit/dagcircuit/dagcircuit.py | 24 +++++--------- qiskit/dagcircuit/dagnode.py | 33 +++++++++---------- .../transpiler/passes/routing/sabre_swap.py | 2 +- test/python/dagcircuit/test_dagcircuit.py | 5 ++- 4 files changed, 28 insertions(+), 36 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index e7b17266e370..07a2f17969aa 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -771,7 +771,7 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i op.condition = condition dag.apply_operation_back(op, m_qargs, m_cargs) else: - raise DAGCircuitError("bad node type %s" % nd) + raise DAGCircuitError("bad node type %s" % type(nd)) if not inplace: return dag @@ -988,12 +988,7 @@ def topological_nodes(self): """ def _key(x): - #print('\n\n\nkey: ', type(x)) - if isinstance(x, OpNode): - #print('sort_key: ', x.sort_key) - return x.sort_key - else: - return "" + return x.sort_key return iter(rx.lexicographical_topological_sort(self._multi_graph, key=_key)) @@ -1061,7 +1056,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): # If a gate is conditioned, we expect the replacement subcircuit # to depend on those condition bits as well. if not isinstance(node, OpNode): - raise DAGCircuitError("expected node OpNode, got %s" % node) + raise DAGCircuitError("expected node OpNode, got %s" % type(node)) condition_bit_list = self._bits_in_condition(condition) @@ -1356,7 +1351,7 @@ def remove_op_node(self, node): if not isinstance(node, OpNode): raise DAGCircuitError( 'The method remove_op_node only works on OpNodes. A "%s" ' - "node type was wrongly provided." % node + "node type was wrongly provided." % type(node) ) self._multi_graph.remove_node_retain_edges( @@ -1571,12 +1566,11 @@ def count_ops(self): """ op_dict = {} for node in self.topological_op_nodes(): - if isinstance(node, OpNode): - name = node.op.name - if name not in op_dict: - op_dict[name] = 1 - else: - op_dict[name] += 1 + name = node.op.name + if name not in op_dict: + op_dict[name] = 1 + else: + op_dict[name] += 1 return op_dict def count_ops_longest_path(self): diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 165a20c09633..e5541f0ed1ca 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -17,7 +17,6 @@ import warnings from qiskit.exceptions import QiskitError -from qiskit.circuit import Instruction, Gate class DAGNodeP: @@ -27,7 +26,7 @@ class DAGNodeP: be supplied to functions that take a node. """ - __slots__ = ["_node_id"] + __slots__ = ["_qargs", "cargs", "sort_key", "_node_id"] def __init__(self, qargs=None, cargs=None, nid=-1): """Create a node""" @@ -100,12 +99,11 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if "barrier" == node1.op.name == node2.op.name: return set(node1_qargs) == set(node2_qargs) - if type(node1.op) == type(node2.op): - if node1.op.name == node2.op.name: - if node1_qargs == node2_qargs: - if node1_cargs == node2_cargs: - if node1.op.condition == node2.op.condition: - return True + if node1.op.name == node2.op.name: + if node1_qargs == node2_qargs: + if node1_cargs == node2_cargs: + if node1.op.condition == node2.op.condition: + return True elif (isinstance(node1, InNode) and isinstance(node2, InNode)) or ( isinstance(node1, OutNode) and isinstance(node2, OutNode) ): @@ -122,7 +120,7 @@ class OpNode(DAGNodeP): be supplied to functions that take a node. """ - __slots__ = ["op", "_qargs", "cargs"] + __slots__ = ["op"] def __init__(self, op, qargs=None, cargs=None): """Create a node""" @@ -131,10 +129,12 @@ def __init__(self, op, qargs=None, cargs=None): @property def name(self): + """Returns the Instruction name corresponding to the op for this node""" return self.op.name @name.setter def name(self, new_name): + """Sets the Instruction name corresponding to the op for this node""" self.op.name = new_name @@ -145,13 +145,12 @@ class InNode(DAGNodeP): be supplied to functions that take a node. """ - __slots__ = ["wire", "qargs", "cargs"] + __slots__ = ["wire"] - def __init__(self, wire, qargs=None, cargs=None): + def __init__(self, wire): """Create a node""" self.wire = wire - #self.qargs = qargs if qargs is not None else [] - super().__init__(qargs, cargs) + super().__init__() class OutNode(DAGNodeP): @@ -161,13 +160,12 @@ class OutNode(DAGNodeP): be supplied to functions that take a node. """ - __slots__ = ["wire", "qargs", "cargs"] + __slots__ = ["wire"] - def __init__(self, wire, qargs=None, cargs=None): + def __init__(self, wire): """Create a node""" self.wire = wire - #self.qargs = qargs if qargs is not None else [] - super().__init__(qargs, cargs) + super().__init__() class DAGNode: @@ -216,6 +214,7 @@ def name(self): @name.setter def name(self, name): + """Sets the Instruction name corresponding to the op for this node""" if self.type and self.type == "op": self._op.name = name diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index 8999e24e02a2..ea30eee80b72 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -21,7 +21,7 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.layout import Layout -from qiskit.dagcircuit import OpNode, OutNode +from qiskit.dagcircuit import OpNode logger = logging.getLogger(__name__) diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 6370e9118560..4b105ddbeffe 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -640,8 +640,6 @@ def test_topological_nodes(self): named_nodes = self.dag.topological_nodes() - print([(i.op.name if isinstance(i, OpNode) else i.wire, i.qargs) for i in named_nodes]) - qr = self.dag.qregs["qr"] cr = self.dag.cregs["cr"] expected = [ @@ -662,7 +660,8 @@ def test_topological_nodes(self): (cr[1], []), ] self.assertEqual( - [(i.op.name if isinstance(i, OpNode) else i.wire, i.qargs) for i in named_nodes], expected + [(i.op.name if isinstance(i, OpNode) else i.wire, i.qargs) for i in named_nodes], + expected, ) def test_topological_op_nodes(self): From 5853cde66b955ae1c5f280d30206f53854811db9 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sun, 13 Jun 2021 12:20:01 -0700 Subject: [PATCH 13/37] Doc changes --- qiskit/dagcircuit/dagcircuit.py | 61 ++++++++++--------- .../passes/analysis/dag_longest_path.py | 2 +- .../passes/optimization/hoare_opt.py | 6 +- .../template_matching/forward_match.py | 4 +- .../passes/utils/merge_adjacent_barriers.py | 4 +- qiskit/visualization/latex.py | 2 +- test/python/dagcircuit/test_dagcircuit.py | 2 +- 7 files changed, 41 insertions(+), 40 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 07a2f17969aa..743538f0ba95 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2021. # # 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 @@ -416,7 +416,7 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): cargs (list[Clbit]): cbits that op will be applied to condition (tuple or None): DEPRECATED optional condition (ClassicalRegister, int) Returns: - DAGNode: the current max node + OpNode or OutNode: the current max node Raises: DAGCircuitError: if a leaf node is connected to multiple outputs @@ -460,7 +460,7 @@ def apply_operation_front(self, op, qargs, cargs, condition=None): cargs (list[Clbit]): cbits that op will be applied to condition (tuple or None): DEPRECATED optional condition (ClassicalRegister, int) Returns: - DAGNode: the current max node + OpNode or OutNode: the current max node Raises: DAGCircuitError: if initial nodes connected to multiple out edges @@ -866,7 +866,7 @@ def _check_wires_list(self, wires, node): Args: wires (list[Bit]): gives an order for (qu)bits in the input circuit that is replacing the node. - node (DAGNode): a node in the dag + node (OpNode): a node in the dag Raises: DAGCircuitError: if check doesn't pass. @@ -885,7 +885,7 @@ def _make_pred_succ_maps(self, node): """Return predecessor and successor dictionaries. Args: - node (DAGNode): reference to multi_graph node + node (OpNode): reference to multi_graph node Returns: tuple(dict): tuple(predecessor_map, successor_map) @@ -984,7 +984,7 @@ def topological_nodes(self): Yield nodes in topological order. Returns: - generator(DAGNode): node in topological order + generator(OpNode, InNode, or OutNode): node in topological order """ def _key(x): @@ -997,7 +997,7 @@ def topological_op_nodes(self): Yield op nodes in topological order. Returns: - generator(DAGNode): op node in topological order + generator(OpNode): op node in topological order """ return (nd for nd in self.topological_nodes() if isinstance(nd, OpNode)) @@ -1005,7 +1005,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): """Replace one node with dag. Args: - node (DAGNode): node to substitute + node (OpNode): node to substitute input_dag (DAGCircuit): circuit that will substitute the node wires (list[Bit]): gives an order for (qu)bits in the input circuit. This order gets matched to the node wires @@ -1117,13 +1117,13 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): self._multi_graph.remove_edge(p[0], self.output_map[w]) def substitute_node(self, node, op, inplace=False): - """Replace a DAGNode with a single instruction. qargs, cargs and + """Replace an OpNode with a single instruction. qargs, cargs and conditions for the new instruction will be inferred from the node to be replaced. The new instruction will be checked to match the shape of the replaced instruction. Args: - node (DAGNode): Node to be replaced + node (OpNode): Node to be replaced op (qiskit.circuit.Instruction): The :class:`qiskit.circuit.Instruction` instance to be added to the DAG inplace (bool): Optional, default False. If True, existing DAG node @@ -1131,7 +1131,7 @@ def substitute_node(self, node, op, inplace=False): be used. Returns: - DAGNode: the new node containing the added instruction. + OpNode: the new node containing the added instruction. Raises: DAGCircuitError: If replacement instruction was incompatible with @@ -1188,9 +1188,9 @@ def edges(self, nodes=None): no nodes are specified all edges from the graph are returned. Args: - nodes(DAGNode|list(DAGNode): Either a list of nodes or a single - input node. If none is specified all edges are returned from - the graph. + nodes(OpNode, InNode, or OutNode|list(OpNodes, InNodes, or OutNodes): + Either a list of nodes or a single input node. If none is specified, + all edges are returned from the graph. Yield: edge: the edge in the same format as out_edges the tuple @@ -1215,7 +1215,7 @@ def op_nodes(self, op=None, include_directives=True): include_directives (bool): include `barrier`, `snapshot` etc. Returns: - list[DAGNode]: the list of node ids containing the given op. + list[OpNode]: the list of node ids containing the given op. """ nodes = [] for node in self._multi_graph.nodes(): @@ -1230,7 +1230,7 @@ def gate_nodes(self): """Get the list of gate nodes in the dag. Returns: - list[DAGNode]: the list of DAGNodes that represent gates. + list[OpNode]: the list of OpNodes that represent gates. """ nodes = [] for node in self.op_nodes(): @@ -1291,15 +1291,15 @@ def multi_qubit_ops(self): return ops def longest_path(self): - """Returns the longest path in the dag as a list of DAGNodes.""" + """Returns the longest path in the dag as a list of OpNodes, InNodes, and OutNodes.""" return [self._multi_graph[x] for x in rx.dag_longest_path(self._multi_graph)] def successors(self, node): - """Returns iterator of the successors of a node as DAGNodes.""" + """Returns iterator of the successors of a node as OpNodes and OutNodes.""" return iter(self._multi_graph.successors(node._node_id)) def predecessors(self, node): - """Returns iterator of the predecessors of a node as DAGNodes.""" + """Returns iterator of the predecessors of a node as OpNodes and InNodes.""" return iter(self._multi_graph.predecessors(node._node_id)) def is_successor(self, node, node_succ): @@ -1312,7 +1312,7 @@ def is_predecessor(self, node, node_pred): def quantum_predecessors(self, node): """Returns iterator of the predecessors of a node that are - connected by a quantum edge as DAGNodes.""" + connected by a quantum edge as OpNodes and InNodes.""" return iter( self._multi_graph.find_predecessors_by_edge( node._node_id, lambda edge_data: isinstance(edge_data, Qubit) @@ -1320,23 +1320,24 @@ def quantum_predecessors(self, node): ) def ancestors(self, node): - """Returns set of the ancestors of a node as DAGNodes.""" + """Returns set of the ancestors of a node as OpNodes and InNodes.""" return {self._multi_graph[x] for x in rx.ancestors(self._multi_graph, node._node_id)} def descendants(self, node): - """Returns set of the descendants of a node as DAGNodes.""" + """Returns set of the descendants of a node as OpNodes and OutNodes.""" return {self._multi_graph[x] for x in rx.descendants(self._multi_graph, node._node_id)} def bfs_successors(self, node): """ - Returns an iterator of tuples of (DAGNode, [DAGNodes]) where the DAGNode is the current node - and [DAGNode] is its successors in BFS order. + Returns an iterator of tuples of (OpNode, InNode, or OutNode, [OpNodes or OutNodes]) + where the OpNode, InNode, or OutNode is the current node and + [OpNodes and OutNodes] is its successors in BFS order. """ return iter(rx.bfs_successors(self._multi_graph, node._node_id)) def quantum_successors(self, node): """Returns iterator of the successors of a node that are - connected by a quantum edge as DAGNodes.""" + connected by a quantum edge as Opnodes and OutNodes.""" return iter( self._multi_graph.find_successors_by_edge( node._node_id, lambda edge_data: isinstance(edge_data, Qubit) @@ -1413,9 +1414,9 @@ def layers(self): greedy algorithm. Each returned layer is a dict containing {"graph": circuit graph, "partition": list of qubit lists}. - The returned layer contains new (but semantically equivalent) DAGNodes. - These are not the same as nodes of the original dag, but are equivalent - via DAGNode.semantic_eq(node1, node2). + The returned layer contains new (but semantically equivalent) OpNodes, InNodes, + and OutNodes. These are not the same as nodes of the original dag, but are equivalent + via DAGNodeP.semantic_eq(node1, node2). TODO: Gates that use the same cbits will end up in different layers as this is currently implemented. This may not be @@ -1447,7 +1448,7 @@ def layers(self): new_layer = self._copy_circuit_metadata() for node in op_nodes: - # this creates new DAGNodes in the new_layer + # this creates new OpNodes in the new_layer new_layer.apply_operation_back(node.op, node.qargs, node.cargs) # The quantum registers that have an operation in this layer. @@ -1534,7 +1535,7 @@ def nodes_on_wire(self, wire, only_ops=False): only_ops (bool): True if only the ops nodes are wanted; otherwise, all nodes are returned. Yield: - DAGNode: the successive ops on the given wire + OpNodes, InNodes, or OutNodes: the successive nodes on the given wire Raises: DAGCircuitError: if the given wire doesn't exist in the DAG diff --git a/qiskit/transpiler/passes/analysis/dag_longest_path.py b/qiskit/transpiler/passes/analysis/dag_longest_path.py index 90a2951682f1..366adca06a24 100644 --- a/qiskit/transpiler/passes/analysis/dag_longest_path.py +++ b/qiskit/transpiler/passes/analysis/dag_longest_path.py @@ -16,7 +16,7 @@ class DAGLongestPath(AnalysisPass): - """Return the longest path in a DAGcircuit as a list of DAGNodes.""" + """Return the longest path in a DAGcircuit as a list of OpNodes, InNodes, and OutNodes.""" def run(self, dag): """Run the DAGLongestPath pass on `dag`.""" diff --git a/qiskit/transpiler/passes/optimization/hoare_opt.py b/qiskit/transpiler/passes/optimization/hoare_opt.py index f23a9c3512b9..c4dabce1e474 100644 --- a/qiskit/transpiler/passes/optimization/hoare_opt.py +++ b/qiskit/transpiler/passes/optimization/hoare_opt.py @@ -175,7 +175,7 @@ def _target_successive_seq(self, qubit): Args: qubit (Qubit): qubit cache to inspect Returns: - list(list(DAGNode)): list of target successive gate sequences for + list(list(OpNodes and OutNodes)): list of target successive gate sequences for this qubit's cache """ seqs = [] @@ -205,7 +205,7 @@ def _is_identity(self, sequence): """determine whether the sequence of gates combines to the identity (consider sequences of length 2 for now) Args: - sequence (list(DAGNode)): gate sequence to inspect + sequence (list(OpNode)): gate sequence to inspect Returns: bool: if gate sequence combines to identity """ @@ -237,7 +237,7 @@ def _seq_as_one(self, sequence): all executed or none of them are executed, based on control qubits (consider sequences of length 2 for now) Args: - sequence (list(DAGNode)): gate sequence to inspect + sequence (list(OpNode)): gate sequence to inspect Returns: bool: if gate sequence is only executed completely or not at all """ diff --git a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py index d895acdf0a08..d7389b047d88 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py @@ -199,7 +199,7 @@ def _update_successor(self, node, successor_id): successor_id (int): successor id to remove. Returns: - DAGNode: DAGNode with updated attribute 'SuccessorToVisit'. + OpNode or OutNode: Node with updated attribute 'SuccessorToVisit'. """ node_update = node node_update.successorstovisit.pop(successor_id) @@ -209,7 +209,7 @@ def _get_successors_to_visit(self, node, list_id): """ Return the successor for a given node and id. Args: - node (DAGNode): current node. + node (OpNode or OutNode): current node. list_id (int): id in the list for the successor to get. Returns: diff --git a/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py b/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py index ecebf51e6ce0..0eca133740bc 100644 --- a/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +++ b/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py @@ -76,8 +76,8 @@ def run(self, dag): def _collect_potential_merges(dag, barriers): """Return the potential merges. - Returns a dict of DAGNode : Barrier objects, where the barrier needs to be - inserted where the corresponding DAGNode appears in the main DAG. + Returns a dict of OpNode: Barrier objects, where the barrier needs to be + inserted where the corresponding OpNode appears in the main DAG. """ # if only got 1 or 0 barriers then can't merge if len(barriers) < 2: diff --git a/qiskit/visualization/latex.py b/qiskit/visualization/latex.py index 7fb98d8bc8df..b697fced83d5 100644 --- a/qiskit/visualization/latex.py +++ b/qiskit/visualization/latex.py @@ -56,7 +56,7 @@ def __init__( Args: qubits (list[Qubit]): list of qubits clbits (list[Clbit]): list of clbits - ops (list[list[DAGNode]]): list of circuit instructions, grouped by layer + ops (list[list[OpNode]]): list of circuit instructions, grouped by layer scale (float): image scaling reverse_bits (bool): when True, reverse the bit ordering of the registers plot_barriers (bool): Enable/disable drawing barriers in the output diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 4b105ddbeffe..72fad3baef75 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -703,7 +703,7 @@ def test_dag_nodes_on_wire(self): def test_dag_nodes_on_wire_multiple_successors(self): """ - Test that if a DAGNode has multiple successors in the DAG along one wire, they are all + Test that if an OpNode has multiple successors in the DAG along one wire, they are all retrieved in order. This could be the case for a circuit such as q0_0: |0>──■─────────■── From 803eaf241e446f9ad95e22b47de0142527c4676f Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sun, 13 Jun 2021 15:18:13 -0700 Subject: [PATCH 14/37] More docs --- qiskit/dagcircuit/__init__.py | 5 +- qiskit/dagcircuit/dagcircuit.py | 26 +++++------ qiskit/dagcircuit/dagnode.py | 46 ++++++------------- .../passes/optimization/hoare_opt.py | 2 +- .../optimize_swap_before_measure.py | 2 +- test/python/dagcircuit/test_dagcircuit.py | 2 +- 6 files changed, 34 insertions(+), 49 deletions(-) diff --git a/qiskit/dagcircuit/__init__.py b/qiskit/dagcircuit/__init__.py index 3e1615510e92..470f6007c030 100644 --- a/qiskit/dagcircuit/__init__.py +++ b/qiskit/dagcircuit/__init__.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017. +# (C) Copyright IBM 2017, 2021. # # 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 @@ -24,6 +24,9 @@ :toctree: ../stubs/ DAGCircuit + OpNode + InNode + OutNode DAGDepNode DAGDependency diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 743538f0ba95..e7a8a4a61a99 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -1188,7 +1188,7 @@ def edges(self, nodes=None): no nodes are specified all edges from the graph are returned. Args: - nodes(OpNode, InNode, or OutNode|list(OpNodes, InNodes, or OutNodes): + nodes(OpNode, InNode, or OutNode|list(OpNode, InNode, or OutNode): Either a list of nodes or a single input node. If none is specified, all edges are returned from the graph. @@ -1199,7 +1199,7 @@ def edges(self, nodes=None): if nodes is None: nodes = self._multi_graph.nodes() - elif isinstance(nodes, (InNode, OutNode, OpNode)): + elif isinstance(nodes, (OpNode, InNode, OutNode)): nodes = [nodes] for node in nodes: raw_nodes = self._multi_graph.out_edges(node._node_id) @@ -1329,9 +1329,9 @@ def descendants(self, node): def bfs_successors(self, node): """ - Returns an iterator of tuples of (OpNode, InNode, or OutNode, [OpNodes or OutNodes]) - where the OpNode, InNode, or OutNode is the current node and - [OpNodes and OutNodes] is its successors in BFS order. + Returns an iterator of tuples of (OpNode, InNode, or OutNode, [OpNode or OutNode]) + where the OpNode, InNode, or OutNode is the current node and + [OpNode or OutNode] is its successors in BFS order. """ return iter(rx.bfs_successors(self._multi_graph, node._node_id)) @@ -1470,17 +1470,17 @@ def serial_layers(self): # Save the support of the operation we add to the layer support_list = [] # Operation data - op = copy.copy(next_node) - qa = copy.copy(next_node.qargs) - ca = copy.copy(next_node.cargs) - co = copy.copy(next_node.op.condition) - _ = self._bits_in_condition(co) + node = copy.copy(next_node) + qargs = copy.copy(next_node.qargs) + cargs = copy.copy(next_node.cargs) + condition = copy.copy(next_node.op.condition) + _ = self._bits_in_condition(condition) # Add node to new_layer - new_layer.apply_operation_back(op.op, qa, ca) + new_layer.apply_operation_back(node.op, qargs, cargs) # Add operation to partition if not next_node.op._directive: - support_list.append(list(qa)) + support_list.append(list(qargs)) l_dict = {"graph": new_layer, "partition": support_list} yield l_dict @@ -1535,7 +1535,7 @@ def nodes_on_wire(self, wire, only_ops=False): only_ops (bool): True if only the ops nodes are wanted; otherwise, all nodes are returned. Yield: - OpNodes, InNodes, or OutNodes: the successive nodes on the given wire + OpNode, InNode, or OutNode: the successive nodes on the given wire Raises: DAGCircuitError: if the given wire doesn't exist in the DAG diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index e5541f0ed1ca..50c8c01a8803 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -1,6 +1,6 @@ # This code is part of Qiskit. # -# (C) Copyright IBM 2017, 2019. +# (C) Copyright IBM 2017, 2019, 2021. # # 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 @@ -12,7 +12,7 @@ # pylint: disable=redefined-builtin -"""Object to represent the information at a node in the DAGCircuit.""" +"""Objects to represent the information at a node in the DAGCircuit.""" import warnings @@ -20,11 +20,7 @@ class DAGNodeP: - """Object to represent the information at a node in the DAGCircuit. - - It is used as the return value from `*_nodes()` functions and can - be supplied to functions that take a node. - """ + """Parent class for OpNode, InNode, and OutNode used by DAGCircuit.""" __slots__ = ["_qargs", "cargs", "sort_key", "_node_id"] @@ -37,14 +33,12 @@ def __init__(self, qargs=None, cargs=None, nid=-1): @property def qargs(self): - """ - Returns list of Qubit, else an empty list. - """ + """Returns list of Qubit, else an empty list.""" return self._qargs @qargs.setter def qargs(self, new_qargs): - """Sets the qargs to be the given list of qargs.""" + """Sets qargs to be the new list of qargs and updates sort_key.""" self._qargs = new_qargs self.sort_key = str(new_qargs) @@ -65,8 +59,8 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): Check if DAG nodes are considered equivalent, e.g., as a node_match for nx.is_isomorphic. Args: - node1 (DAGNode): A node to compare. - node2 (DAGNode): The other node to compare. + node1 (OpNode, InNode, or OutNode): A node to compare. + node2 (OpNode, InNode, or OutNode): The other node to compare. bit_indices1 (dict): Dictionary mapping Bit instances to their index within the circuit containing node1 bit_indices2 (dict): Dictionary mapping Bit instances to their index @@ -77,7 +71,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): """ if bit_indices1 is None or bit_indices2 is None: warnings.warn( - "DAGNode.semantic_eq now expects two bit-to-circuit index " + "DAGNodeP.semantic_eq now expects two bit-to-circuit index " "mappings as arguments. To ease the transition, these will be " "pre-populated based on the values found in Bit.index and " "Bit.register. However, this behavior is deprecated and a future " @@ -114,16 +108,12 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): class OpNode(DAGNodeP): - """Object to represent the information at a node in the DAGCircuit. - - It is used as the return value from `*_nodes()` functions and can - be supplied to functions that take a node. - """ + """Object to represent an Instruction at a node in the DAGCircuit.""" __slots__ = ["op"] def __init__(self, op, qargs=None, cargs=None): - """Create a node""" + """Create an Instruction node""" self.op = op super().__init__(qargs, cargs) @@ -139,31 +129,23 @@ def name(self, new_name): class InNode(DAGNodeP): - """Object to represent the information at a node in the DAGCircuit. - - It is used as the return value from `*_nodes()` functions and can - be supplied to functions that take a node. - """ + """Object to represent an incoming wire node in the DAGCircuit.""" __slots__ = ["wire"] def __init__(self, wire): - """Create a node""" + """Create an incoming node""" self.wire = wire super().__init__() class OutNode(DAGNodeP): - """Object to represent the information at a node in the DAGCircuit. - - It is used as the return value from `*_nodes()` functions and can - be supplied to functions that take a node. - """ + """Object to represent an outgoing wire node in the DAGCircuit.""" __slots__ = ["wire"] def __init__(self, wire): - """Create a node""" + """Create an outgoing node""" self.wire = wire super().__init__() diff --git a/qiskit/transpiler/passes/optimization/hoare_opt.py b/qiskit/transpiler/passes/optimization/hoare_opt.py index 553220a2fc34..1b9262bcef3c 100644 --- a/qiskit/transpiler/passes/optimization/hoare_opt.py +++ b/qiskit/transpiler/passes/optimization/hoare_opt.py @@ -239,7 +239,7 @@ def _target_successive_seq(self, qubit): Args: qubit (Qubit): qubit cache to inspect Returns: - list(list(OpNodes and OutNodes)): list of target successive gate sequences for + list(list(OpNode or OutNode)): list of target successive gate sequences for this qubit's cache """ seqs = [] diff --git a/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py b/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py index 855536404135..f17a93025fc1 100644 --- a/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +++ b/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py @@ -54,7 +54,7 @@ def run(self, dag): for creg in dag.cregs.values(): measure_layer.add_creg(creg) for successor in list(dag.successors(swap)): - if isinstance(successor, OpNode) and successor.op.name == "measure": + if isinstance(successor, OpNode) and isinstance(successor.op, Measure): # replace measure node with a new one, where qargs is set with the "other" # swap qarg. dag.remove_op_node(successor) diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 72fad3baef75..baa68c74deb6 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -64,7 +64,7 @@ def raise_if_dagcircuit_invalid(dag): elif isinstance(node, OpNode): continue else: - raise DAGCircuitError("Found node of unexpected type: {}".format(node)) + raise DAGCircuitError("Found node of unexpected type: {}".format(type(node))) # Shape of node.op should match shape of node. for node in dag.op_nodes(): From 2991e4db392a25b0e32f0e644ab77ace18a78dde Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Mon, 14 Jun 2021 08:12:37 -0700 Subject: [PATCH 15/37] Opflow bug --- qiskit/dagcircuit/dagcircuit.py | 6 +-- qiskit/dagcircuit/dagnode.py | 53 ++++++++++++++++++- .../gradients/circuit_qfis/overlap_diag.py | 2 +- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index e7a8a4a61a99..c209f92c33a3 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -808,7 +808,7 @@ def idle_wires(self, ignore=None): nodes = [ node for node in self.nodes_on_wire(wire, only_ops=False) - if (not isinstance(node, OpNode) or node.op.name not in ignore) + if ((not isinstance(node, OpNode) or node.op.name not in ignore)) ] if len(nodes) == 2: yield wire @@ -1470,14 +1470,14 @@ def serial_layers(self): # Save the support of the operation we add to the layer support_list = [] # Operation data - node = copy.copy(next_node) + op = copy.copy(next_node.op) qargs = copy.copy(next_node.qargs) cargs = copy.copy(next_node.cargs) condition = copy.copy(next_node.op.condition) _ = self._bits_in_condition(condition) # Add node to new_layer - new_layer.apply_operation_back(node.op, qargs, cargs) + new_layer.apply_operation_back(op, qargs, cargs) # Add operation to partition if not next_node.op._directive: support_list.append(list(qargs)) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 50c8c01a8803..6883f2b5fcac 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -69,7 +69,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): Return: Bool: If node1 == node2 """ - if bit_indices1 is None or bit_indices2 is None: + """if bit_indices1 is None or bit_indices2 is None: warnings.warn( "DAGNodeP.semantic_eq now expects two bit-to-circuit index " "mappings as arguments. To ease the transition, these will be " @@ -104,7 +104,56 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if bit_indices1.get(node1.wire, None) == bit_indices2.get(node2.wire, None): return True else: - return False + return False""" + if bit_indices1 is None or bit_indices2 is None: + warnings.warn( + "DAGNode.semantic_eq now expects two bit-to-circuit index " + "mappings as arguments. To ease the transition, these will be " + "pre-populated based on the values found in Bit.index and " + "Bit.register. However, this behavior is deprecated and a future " + "release will require the mappings to be provided as arguments.", + DeprecationWarning, + ) + + bit_indices1 = {arg: arg for arg in node1.qargs + node1.cargs} + bit_indices2 = {arg: arg for arg in node2.qargs + node2.cargs} + #print('\nbit1', bit_indices1) + #print('bit2', bit_indices2) + + node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs] + node1_cargs = [bit_indices1[carg] for carg in node1.cargs] + + node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs] + node2_cargs = [bit_indices2[carg] for carg in node2.cargs] + + #print(node1_qargs, node1_cargs, node2_qargs, node2_cargs) + + # For barriers, qarg order is not significant so compare as sets + if isinstance(node1, OpNode) and isinstance(node2, OpNode) and "barrier" == node1.name == node2.name: + return set(node1_qargs) == set(node2_qargs) + + #if node1.type == node2.type: + #if type(node1) == type(node2): + if isinstance(node1, type(node2)) and isinstance(node2, type(node1)): + #print('1', type(node1), type(node2))#, node1.op.name, node2.op.name) + #if (isinstance(node1, OpNode) and node1._op == node2._op: + if not isinstance(node1, OpNode) or node1.op.name == node2.op.name: + #print('2') + if node1_qargs == node2_qargs: + #print('3') + if node1_cargs == node2_cargs: + #print('4', type(node1)) + if not isinstance(node1, OpNode) or (isinstance(node1, OpNode) and node1.op.condition == node2.op.condition): + #print('False1') + #if not isinstance(node1, OpNode): + # #print('5', bit_indices1.get(node1.wire, None), bit_indices2.get(node2.wire, None)) + if isinstance(node1, OpNode) or bit_indices1.get(node1.wire, None) == bit_indices2.get( + node2.wire, None + ): + return True + #print('False2') + return False + class OpNode(DAGNodeP): diff --git a/qiskit/opflow/gradients/circuit_qfis/overlap_diag.py b/qiskit/opflow/gradients/circuit_qfis/overlap_diag.py index 5fae9bf97054..f997abb9c0f8 100644 --- a/qiskit/opflow/gradients/circuit_qfis/overlap_diag.py +++ b/qiskit/opflow/gradients/circuit_qfis/overlap_diag.py @@ -152,7 +152,7 @@ def _partition_circuit(circuit): layers = list( zip(dag_layers, [{x: False for x in range(0, num_qubits)} for layer in dag_layers]) ) - + print(layers) # initialize the ledger # The ledger tracks which qubits in each layer are available to have # gates from subsequent layers shifted backward. From 17d7745a4401abba19f0969b07218034f3f4cd04 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Mon, 14 Jun 2021 16:02:31 -0700 Subject: [PATCH 16/37] Finish doc changes and testing --- qiskit/dagcircuit/dagcircuit.py | 2 +- qiskit/dagcircuit/dagnode.py | 57 ++----------------- .../gradients/circuit_qfis/overlap_diag.py | 2 +- qiskit/visualization/dag_visualization.py | 2 +- test/python/dagcircuit/test_dagcircuit.py | 1 - 5 files changed, 7 insertions(+), 57 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index c209f92c33a3..9d2461e82050 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -1535,7 +1535,7 @@ def nodes_on_wire(self, wire, only_ops=False): only_ops (bool): True if only the ops nodes are wanted; otherwise, all nodes are returned. Yield: - OpNode, InNode, or OutNode: the successive nodes on the given wire + Iterator: the successive nodes on the given wire Raises: DAGCircuitError: if the given wire doesn't exist in the DAG diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 6883f2b5fcac..4f716c37861c 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -59,8 +59,8 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): Check if DAG nodes are considered equivalent, e.g., as a node_match for nx.is_isomorphic. Args: - node1 (OpNode, InNode, or OutNode): A node to compare. - node2 (OpNode, InNode, or OutNode): The other node to compare. + node1 (OpNode, InNode, OutNode): A node to compare. + node2 (OpNode, InNode, OutNode): The other node to compare. bit_indices1 (dict): Dictionary mapping Bit instances to their index within the circuit containing node1 bit_indices2 (dict): Dictionary mapping Bit instances to their index @@ -69,7 +69,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): Return: Bool: If node1 == node2 """ - """if bit_indices1 is None or bit_indices2 is None: + if bit_indices1 is None or bit_indices2 is None: warnings.warn( "DAGNodeP.semantic_eq now expects two bit-to-circuit index " "mappings as arguments. To ease the transition, these will be " @@ -104,56 +104,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if bit_indices1.get(node1.wire, None) == bit_indices2.get(node2.wire, None): return True else: - return False""" - if bit_indices1 is None or bit_indices2 is None: - warnings.warn( - "DAGNode.semantic_eq now expects two bit-to-circuit index " - "mappings as arguments. To ease the transition, these will be " - "pre-populated based on the values found in Bit.index and " - "Bit.register. However, this behavior is deprecated and a future " - "release will require the mappings to be provided as arguments.", - DeprecationWarning, - ) - - bit_indices1 = {arg: arg for arg in node1.qargs + node1.cargs} - bit_indices2 = {arg: arg for arg in node2.qargs + node2.cargs} - #print('\nbit1', bit_indices1) - #print('bit2', bit_indices2) - - node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs] - node1_cargs = [bit_indices1[carg] for carg in node1.cargs] - - node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs] - node2_cargs = [bit_indices2[carg] for carg in node2.cargs] - - #print(node1_qargs, node1_cargs, node2_qargs, node2_cargs) - - # For barriers, qarg order is not significant so compare as sets - if isinstance(node1, OpNode) and isinstance(node2, OpNode) and "barrier" == node1.name == node2.name: - return set(node1_qargs) == set(node2_qargs) - - #if node1.type == node2.type: - #if type(node1) == type(node2): - if isinstance(node1, type(node2)) and isinstance(node2, type(node1)): - #print('1', type(node1), type(node2))#, node1.op.name, node2.op.name) - #if (isinstance(node1, OpNode) and node1._op == node2._op: - if not isinstance(node1, OpNode) or node1.op.name == node2.op.name: - #print('2') - if node1_qargs == node2_qargs: - #print('3') - if node1_cargs == node2_cargs: - #print('4', type(node1)) - if not isinstance(node1, OpNode) or (isinstance(node1, OpNode) and node1.op.condition == node2.op.condition): - #print('False1') - #if not isinstance(node1, OpNode): - # #print('5', bit_indices1.get(node1.wire, None), bit_indices2.get(node2.wire, None)) - if isinstance(node1, OpNode) or bit_indices1.get(node1.wire, None) == bit_indices2.get( - node2.wire, None - ): - return True - #print('False2') - return False - + return False class OpNode(DAGNodeP): diff --git a/qiskit/opflow/gradients/circuit_qfis/overlap_diag.py b/qiskit/opflow/gradients/circuit_qfis/overlap_diag.py index f997abb9c0f8..5fae9bf97054 100644 --- a/qiskit/opflow/gradients/circuit_qfis/overlap_diag.py +++ b/qiskit/opflow/gradients/circuit_qfis/overlap_diag.py @@ -152,7 +152,7 @@ def _partition_circuit(circuit): layers = list( zip(dag_layers, [{x: False for x in range(0, num_qubits)} for layer in dag_layers]) ) - print(layers) + # initialize the ledger # The ledger tracks which qubits in each layer are available to have # gates from subsequent layers shifted backward. diff --git a/qiskit/visualization/dag_visualization.py b/qiskit/visualization/dag_visualization.py index 4fb57d15e05e..41f0dc976684 100644 --- a/qiskit/visualization/dag_visualization.py +++ b/qiskit/visualization/dag_visualization.py @@ -20,7 +20,7 @@ import sys import tempfile -from qiskit.dagcircuit import OpNode, InNode, OutNode +from qiskit.dagcircuit.dagnode import OpNode, InNode, OutNode from qiskit.exceptions import MissingOptionalLibraryError from .exceptions import VisualizationError diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index baa68c74deb6..3e59b434efd2 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -34,7 +34,6 @@ from qiskit.circuit.library.standard_gates.x import XGate from qiskit.circuit.library.standard_gates.y import YGate from qiskit.circuit.library.standard_gates.u1 import U1Gate -from qiskit.circuit.library.standard_gates.i import IGate from qiskit.circuit.barrier import Barrier from qiskit.dagcircuit.exceptions import DAGCircuitError from qiskit.converters import circuit_to_dag From c1f25b80aecef465c08689498da17c0dd736df25 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Tue, 15 Jun 2021 12:49:23 -0700 Subject: [PATCH 17/37] Deprecations --- qiskit/dagcircuit/dagnode.py | 45 ++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 4f716c37861c..f52ae6aff4d3 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -117,6 +117,17 @@ def __init__(self, op, qargs=None, cargs=None): self.op = op super().__init__(qargs, cargs) + @property + def type(self): + """DEPRECATED Returns 'op' for node.type""" + warnings.warn( + "The OpNode 'type' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date.", + DeprecationWarning, + 2, + ) + return "op" + @property def name(self): """Returns the Instruction name corresponding to the op for this node""" @@ -138,6 +149,17 @@ def __init__(self, wire): self.wire = wire super().__init__() + @property + def type(self): + """DEPRECATED Returns 'in' for node.type""" + warnings.warn( + "The InNode 'type' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date.", + DeprecationWarning, + 2, + ) + return "in" + class OutNode(DAGNodeP): """Object to represent an outgoing wire node in the DAGCircuit.""" @@ -149,10 +171,21 @@ def __init__(self, wire): self.wire = wire super().__init__() + @property + def type(self): + """DEPRECATED Returns 'out' for node.type""" + warnings.warn( + "The OutNode 'type' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date.", + DeprecationWarning, + 2, + ) + return "out" + class DAGNode: - """Object to represent the information at a node in the DAGCircuit. - It is used as the return value from `*_nodes()` functions and can + """DEPRECATED as of 0.18.0. Object to represent the information at a node in + the DAGCircuit. It is used as the return value from `*_nodes()` functions and can be supplied to functions that take a node. """ @@ -160,6 +193,14 @@ class DAGNode: def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=None, nid=-1): """Create a node""" + warnings.warn( + "The DAGNode class has been deprecated as of version 0.18.0 of qiskit and will be " + "removed no earlier than 3 months after the release date. You should use " + "OpNode if creating an Instruction node, InNode for an incoming node, or " + "OutNode for an outgoing node.", + DeprecationWarning, + 2, + ) self.type = type self._op = op if name is not None: From c9124f5d816458162444ed7282cda1a03c8d203d Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Tue, 15 Jun 2021 13:41:50 -0700 Subject: [PATCH 18/37] Fix merge conflict --- qiskit/transpiler/passes/routing/sabre_swap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index b92cefad178e..e3d5c754c861 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -270,7 +270,7 @@ def _reset_qubits_decay(self): def _successors(self, node, dag): for _, successor, edge_data in dag.edges(node): - if successor.type != "op": + if not isinstance(successor, OpNode): continue if isinstance(edge_data, Qubit): yield successor From 09dfa0a5eaf7b6beaa50fcaf312bbcf4f64097d1 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Wed, 16 Jun 2021 12:02:49 -0700 Subject: [PATCH 19/37] Make DAGNode parent also --- qiskit/dagcircuit/dagcircuit.py | 4 +- qiskit/dagcircuit/dagnode.py | 315 ++++++++++---------------------- 2 files changed, 96 insertions(+), 223 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 9d2461e82050..13f3d9338c30 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -35,7 +35,7 @@ from qiskit.circuit.gate import Gate from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.dagcircuit.exceptions import DAGCircuitError -from qiskit.dagcircuit.dagnode import DAGNodeP, OpNode, InNode, OutNode +from qiskit.dagcircuit.dagnode import DAGNode, OpNode, InNode, OutNode from qiskit.exceptions import MissingOptionalLibraryError @@ -975,7 +975,7 @@ def __eq__(self, other): return False def node_eq(node_self, node_other): - return DAGNodeP.semantic_eq(node_self, node_other, self_bit_indices, other_bit_indices) + return DAGNode.semantic_eq(node_self, node_other, self_bit_indices, other_bit_indices) return rx.is_isomorphic_node_match(self._multi_graph, other._multi_graph, node_eq) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index f52ae6aff4d3..689b3aa04822 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -19,26 +19,107 @@ from qiskit.exceptions import QiskitError -class DAGNodeP: - """Parent class for OpNode, InNode, and OutNode used by DAGCircuit.""" +class DAGNode: + """DEPRECATED as of 0.18.0. Object to represent the information at a node in + the DAGCircuit. It is used as the return value from `*_nodes()` functions and can + be supplied to functions that take a node. + """ - __slots__ = ["_qargs", "cargs", "sort_key", "_node_id"] + __slots__ = ["type", "op", "_qargs", "cargs", "wire", "sort_key", "_node_id"] - def __init__(self, qargs=None, cargs=None, nid=-1): + def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=None, nid=-1): """Create a node""" + if type is not None: + warnings.warn( + "The DAGNode 'type' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use OpNode, InNode, or OutNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + self.type = type + if op is not None: + warnings.warn( + "The DAGNode 'op' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date." + "Use OpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + self.op = op + if name is not None: + warnings.warn( + "The DAGNode 'name' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use 'DAGNode.op.name' if the DAGNode is of type 'op'.", + DeprecationWarning, + 2, + ) self._qargs = qargs if qargs is not None else [] self.cargs = cargs if cargs is not None else [] - self.sort_key = str(self._qargs) + if wire is not None: + warnings.warn( + "The DAGNode 'wire' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date." + "Use InNode or OutNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + self.wire = wire self._node_id = nid + self.sort_key = str(self._qargs) + + @property + def name(self): + """Returns the Instruction name corresponding to the op for this node""" + if self.type and self.type == "op": + return self.op.name + return None + + @name.setter + def name(self, name): + """Sets the Instruction name corresponding to the op for this node""" + if self.type and self.type == "op": + self.op.name = name + + @property + def condition(self): + """Returns the condition of the node.op""" + if not self.type or self.type != "op": + raise QiskitError("The node %s is not an op node" % (str(self))) + warnings.warn( + "The DAGNode 'condition' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use 'DAGNode.op.condition' if the DAGNode is of type 'op'.", + DeprecationWarning, + 2, + ) + return self._op.condition + + @condition.setter + def condition(self, new_condition): + """Sets the node.condition which sets the node.op.condition.""" + if not self.type or self.type != "op": + raise QiskitError("The node %s is not an op node" % (str(self))) + warnings.warn( + "The DAGNode 'condition' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use 'DAGNode.op.condition' if the DAGNode is of type 'op'.", + DeprecationWarning, + 2, + ) + self._op.condition = new_condition @property def qargs(self): - """Returns list of Qubit, else an empty list.""" + """ + Returns list of Qubit, else an empty list. + """ return self._qargs @qargs.setter def qargs(self, new_qargs): - """Sets qargs to be the new list of qargs and updates sort_key.""" + """Sets the qargs to be the given list of qargs.""" self._qargs = new_qargs self.sort_key = str(new_qargs) @@ -103,11 +184,11 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): ): if bit_indices1.get(node1.wire, None) == bit_indices2.get(node2.wire, None): return True - else: - return False + return False -class OpNode(DAGNodeP): + +class OpNode(DAGNode): """Object to represent an Instruction at a node in the DAGCircuit.""" __slots__ = ["op"] @@ -115,18 +196,7 @@ class OpNode(DAGNodeP): def __init__(self, op, qargs=None, cargs=None): """Create an Instruction node""" self.op = op - super().__init__(qargs, cargs) - - @property - def type(self): - """DEPRECATED Returns 'op' for node.type""" - warnings.warn( - "The OpNode 'type' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date.", - DeprecationWarning, - 2, - ) - return "op" + super().__init__(qargs=qargs, cargs=cargs) @property def name(self): @@ -139,7 +209,7 @@ def name(self, new_name): self.op.name = new_name -class InNode(DAGNodeP): +class InNode(DAGNode): """Object to represent an incoming wire node in the DAGCircuit.""" __slots__ = ["wire"] @@ -149,19 +219,8 @@ def __init__(self, wire): self.wire = wire super().__init__() - @property - def type(self): - """DEPRECATED Returns 'in' for node.type""" - warnings.warn( - "The InNode 'type' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date.", - DeprecationWarning, - 2, - ) - return "in" - -class OutNode(DAGNodeP): +class OutNode(DAGNode): """Object to represent an outgoing wire node in the DAGCircuit.""" __slots__ = ["wire"] @@ -170,189 +229,3 @@ def __init__(self, wire): """Create an outgoing node""" self.wire = wire super().__init__() - - @property - def type(self): - """DEPRECATED Returns 'out' for node.type""" - warnings.warn( - "The OutNode 'type' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date.", - DeprecationWarning, - 2, - ) - return "out" - - -class DAGNode: - """DEPRECATED as of 0.18.0. Object to represent the information at a node in - the DAGCircuit. It is used as the return value from `*_nodes()` functions and can - be supplied to functions that take a node. - """ - - __slots__ = ["type", "_op", "_qargs", "cargs", "_wire", "sort_key", "_node_id"] - - def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=None, nid=-1): - """Create a node""" - warnings.warn( - "The DAGNode class has been deprecated as of version 0.18.0 of qiskit and will be " - "removed no earlier than 3 months after the release date. You should use " - "OpNode if creating an Instruction node, InNode for an incoming node, or " - "OutNode for an outgoing node.", - DeprecationWarning, - 2, - ) - self.type = type - self._op = op - if name is not None: - warnings.warn( - "The DAGNode 'name' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date. " - "You can use 'DAGNode.op.name' if the DAGNode is of type 'op'.", - DeprecationWarning, - 2, - ) - self._qargs = qargs if qargs is not None else [] - self.cargs = cargs if cargs is not None else [] - self._wire = wire - self._node_id = nid - self.sort_key = str(self._qargs) - - @property - def op(self): - """Returns the Instruction object corresponding to the op for the node, else None""" - if not self.type or self.type != "op": - raise QiskitError("The node %s is not an op node" % (str(self))) - return self._op - - @op.setter - def op(self, data): - self._op = data - - @property - def name(self): - """Returns the Instruction name corresponding to the op for this node""" - if self.type and self.type == "op": - return self._op.name - return None - - @name.setter - def name(self, name): - """Sets the Instruction name corresponding to the op for this node""" - if self.type and self.type == "op": - self._op.name = name - - @property - def condition(self): - """Returns the condition of the node.op""" - if not self.type or self.type != "op": - raise QiskitError("The node %s is not an op node" % (str(self))) - warnings.warn( - "The DAGNode 'condition' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date. " - "You can use 'DAGNode.op.condition' if the DAGNode is of type 'op'.", - DeprecationWarning, - 2, - ) - return self._op.condition - - @condition.setter - def condition(self, new_condition): - """Sets the node.condition which sets the node.op.condition.""" - if not self.type or self.type != "op": - raise QiskitError("The node %s is not an op node" % (str(self))) - warnings.warn( - "The DAGNode 'condition' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date. " - "You can use 'DAGNode.op.condition' if the DAGNode is of type 'op'.", - DeprecationWarning, - 2, - ) - self._op.condition = new_condition - - @property - def qargs(self): - """ - Returns list of Qubit, else an empty list. - """ - return self._qargs - - @qargs.setter - def qargs(self, new_qargs): - """Sets the qargs to be the given list of qargs.""" - self._qargs = new_qargs - self.sort_key = str(new_qargs) - - @property - def wire(self): - """ - Returns the Bit object, else None. - """ - if self.type not in ["in", "out"]: - raise QiskitError("The node %s is not an input/output node" % str(self)) - return self._wire - - @wire.setter - def wire(self, data): - self._wire = data - - def __lt__(self, other): - return self._node_id < other._node_id - - def __gt__(self, other): - return self._node_id > other._node_id - - def __str__(self): - # TODO is this used anywhere other than in DAG drawing? - # needs to be unique as it is what pydot uses to distinguish nodes - return str(id(self)) - - @staticmethod - def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): - """ - Check if DAG nodes are considered equivalent, e.g., as a node_match for nx.is_isomorphic. - Args: - node1 (DAGNode): A node to compare. - node2 (DAGNode): The other node to compare. - bit_indices1 (dict): Dictionary mapping Bit instances to their index - within the circuit containing node1 - bit_indices2 (dict): Dictionary mapping Bit instances to their index - within the circuit containing node2 - Return: - Bool: If node1 == node2 - """ - if bit_indices1 is None or bit_indices2 is None: - warnings.warn( - "DAGNode.semantic_eq now expects two bit-to-circuit index " - "mappings as arguments. To ease the transition, these will be " - "pre-populated based on the values found in Bit.index and " - "Bit.register. However, this behavior is deprecated and a future " - "release will require the mappings to be provided as arguments.", - DeprecationWarning, - ) - - bit_indices1 = {arg: arg for arg in node1.qargs + node1.cargs} - bit_indices2 = {arg: arg for arg in node2.qargs + node2.cargs} - - node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs] - node1_cargs = [bit_indices1[carg] for carg in node1.cargs] - - node2_qargs = [bit_indices2[qarg] for qarg in node2.qargs] - node2_cargs = [bit_indices2[carg] for carg in node2.cargs] - - # For barriers, qarg order is not significant so compare as sets - if "barrier" == node1.name == node2.name: - return set(node1_qargs) == set(node2_qargs) - - if node1.type == node2.type: - if node1._op == node2._op: - if node1.name == node2.name: - if node1_qargs == node2_qargs: - if node1_cargs == node2_cargs: - if node1.type == "op": - if node1._op.condition != node2._op.condition: - return False - if bit_indices1.get(node1._wire, None) == bit_indices2.get( - node2._wire, None - ): - return True - return False From 5324544a5e06e303d0d1946075b1b0be820c937d Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Wed, 16 Jun 2021 12:42:05 -0700 Subject: [PATCH 20/37] Fix _op --- qiskit/dagcircuit/dagnode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 689b3aa04822..8d6f86d33f33 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -94,7 +94,7 @@ def condition(self): DeprecationWarning, 2, ) - return self._op.condition + return self.op.condition @condition.setter def condition(self, new_condition): @@ -108,7 +108,7 @@ def condition(self, new_condition): DeprecationWarning, 2, ) - self._op.condition = new_condition + self.op.condition = new_condition @property def qargs(self): From e4d5a9faa9c7014083345a76e57101ae7c2319f7 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Wed, 16 Jun 2021 20:19:02 -0700 Subject: [PATCH 21/37] Final deprecations for DAGNode --- qiskit/dagcircuit/__init__.py | 3 ++- qiskit/dagcircuit/dagnode.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/qiskit/dagcircuit/__init__.py b/qiskit/dagcircuit/__init__.py index 470f6007c030..6513b6974469 100644 --- a/qiskit/dagcircuit/__init__.py +++ b/qiskit/dagcircuit/__init__.py @@ -24,6 +24,7 @@ :toctree: ../stubs/ DAGCircuit + DAGNode OpNode InNode OutNode @@ -39,7 +40,7 @@ DAGCircuitError """ from .dagcircuit import DAGCircuit -from .dagnode import OpNode, InNode, OutNode +from .dagnode import DAGNode, OpNode, InNode, OutNode from .dagdepnode import DAGDepNode from .exceptions import DAGCircuitError from .dagdependency import DAGDependency diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 8d6f86d33f33..395e2ffd95ee 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -20,12 +20,9 @@ class DAGNode: - """DEPRECATED as of 0.18.0. Object to represent the information at a node in - the DAGCircuit. It is used as the return value from `*_nodes()` functions and can - be supplied to functions that take a node. - """ + """Parent class for OpNode, InNode, and OutNode.""" - __slots__ = ["type", "op", "_qargs", "cargs", "wire", "sort_key", "_node_id"] + __slots__ = ["type", "_op", "_qargs", "cargs", "_wire", "sort_key", "_node_id"] def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=None, nid=-1): """Create a node""" @@ -46,7 +43,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N DeprecationWarning, 2, ) - self.op = op + self._op = op if name is not None: warnings.warn( "The DAGNode 'name' attribute is deprecated as of 0.18.0 and " @@ -65,10 +62,21 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N DeprecationWarning, 2, ) - self.wire = wire + self._wire = wire self._node_id = nid self.sort_key = str(self._qargs) + @property + def op(self): + """Returns the Instruction object corresponding to the op for the node, else None""" + if not self.type or self.type != "op": + raise QiskitError("The node %s is not an op node" % (str(self))) + return self._op + + @op.setter + def op(self, data): + self._op = data + @property def name(self): """Returns the Instruction name corresponding to the op for this node""" @@ -123,6 +131,19 @@ def qargs(self, new_qargs): self._qargs = new_qargs self.sort_key = str(new_qargs) + @property + def wire(self): + """ + Returns the Bit object, else None. + """ + if self.type not in ["in", "out"]: + raise QiskitError("The node %s is not an input/output node" % str(self)) + return self._wire + + @wire.setter + def wire(self, data): + self._wire = data + def __lt__(self, other): return self._node_id < other._node_id From de56e10f6d55307866709d4f90753a4ee72908ce Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 17 Jun 2021 08:48:25 -0700 Subject: [PATCH 22/37] Fix semantic_eq --- qiskit/dagcircuit/dagnode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 395e2ffd95ee..6041c03fd235 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -195,7 +195,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if "barrier" == node1.op.name == node2.op.name: return set(node1_qargs) == set(node2_qargs) - if node1.op.name == node2.op.name: + if node1.op == node2.op: if node1_qargs == node2_qargs: if node1_cargs == node2_cargs: if node1.op.condition == node2.op.condition: From 88a487593e048375a74541b30832d783008ac654 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 17 Jun 2021 09:35:42 -0700 Subject: [PATCH 23/37] Update semantic_eq op check --- qiskit/dagcircuit/dagnode.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 6041c03fd235..dd343df4c1b9 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -34,7 +34,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N DeprecationWarning, 2, ) - self.type = type + self.type = type if op is not None: warnings.warn( "The DAGNode 'op' attribute is deprecated as of 0.18.0 and " @@ -195,10 +195,10 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if "barrier" == node1.op.name == node2.op.name: return set(node1_qargs) == set(node2_qargs) - if node1.op == node2.op: - if node1_qargs == node2_qargs: - if node1_cargs == node2_cargs: - if node1.op.condition == node2.op.condition: + if node1_qargs == node2_qargs: + if node1_cargs == node2_cargs: + if node1.op.condition == node2.op.condition: + if node1.op == node2.op: return True elif (isinstance(node1, InNode) and isinstance(node2, InNode)) or ( isinstance(node1, OutNode) and isinstance(node2, OutNode) From b99faa8326440f7a33e954459f34645a7fcb2492 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 17 Jun 2021 10:23:43 -0700 Subject: [PATCH 24/37] Add semantic_eq test --- test/python/dagcircuit/test_dagcircuit.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 3e59b434efd2..8c61ce13686c 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -17,6 +17,7 @@ from ddt import ddt, data import retworkx as rx +from numpy import pi as pi from qiskit.dagcircuit import DAGCircuit, OpNode, InNode, OutNode from qiskit.circuit import QuantumRegister @@ -1465,5 +1466,23 @@ def test_clbit_conditional(self): ) +class TestNodeEqual(QiskitTestCase): + """Test dag nodes are equal.""" + + def test_node_params_equal_unequal(self): + """Test node params are equal or unequal.""" + qc1 = QuantumCircuit(1) + qc2 = QuantumCircuit(1) + qc3 = QuantumCircuit(1) + qc1.p(pi / 4, 0) + dag1 = circuit_to_dag(qc1) + qc2.p(pi / 4, 0) + dag2 = circuit_to_dag(qc2) + qc3.p(pi / 2, 0) + dag3 = circuit_to_dag(qc3) + self.assertEqual(dag1, dag2) + self.assertNotEqual(dag2, dag3) + + if __name__ == "__main__": unittest.main() From f6a97f3786c7d33cb5d567c95cfeebc9f2e458e5 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 17 Jun 2021 11:18:57 -0700 Subject: [PATCH 25/37] Lint --- test/python/dagcircuit/test_dagcircuit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 8c61ce13686c..2fbdef69a720 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -17,7 +17,7 @@ from ddt import ddt, data import retworkx as rx -from numpy import pi as pi +from numpy import pi from qiskit.dagcircuit import DAGCircuit, OpNode, InNode, OutNode from qiskit.circuit import QuantumRegister From 95f3b47ec4e47870cb507bb57bea57645f7be45f Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 17 Jun 2021 17:32:08 -0700 Subject: [PATCH 26/37] Fix node.condition and reno --- qiskit/dagcircuit/dagnode.py | 24 +++++++++++++++++++ ...de_to_op_in_out_node-af2cf9c3e7686285.yaml | 9 +++++++ 2 files changed, 33 insertions(+) create mode 100644 releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index dd343df4c1b9..e39a2b428e84 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -229,6 +229,30 @@ def name(self, new_name): """Sets the Instruction name corresponding to the op for this node""" self.op.name = new_name + @property + def condition(self): + """Returns the condition of the node.op""" + warnings.warn( + "The OpNode 'condition' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use 'OpNode.op.condition'.", + DeprecationWarning, + 2, + ) + return self.op.condition + + @condition.setter + def condition(self, new_condition): + """Sets the node.condition which sets the node.op.condition.""" + warnings.warn( + "The OpNode 'condition' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use 'OpNode.op.condition'.", + DeprecationWarning, + 2, + ) + self.op.condition = new_condition + class InNode(DAGNode): """Object to represent an incoming wire node in the DAGCircuit.""" diff --git a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml new file mode 100644 index 000000000000..7fde91ec5932 --- /dev/null +++ b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml @@ -0,0 +1,9 @@ +--- +deprecations: + - | + The :class:`qiskit.dagcircuit.DAGNode` is being deprecated as a + standalone class and will be used in the future only as the parent class + for :class:`qiskit.dagcircuit.OpNode`, :class:`qiskit.dagcircuit.InNode`, + and :class:`qiskit.dagcircuit.OutNode`. As part of this deprecation, the + following kwargs in DAGNode are being deprecated - ``type``, ``op``, + and ``wire``. From 8f87581cdd93ce54114b51b871385fc522bf08df Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Sun, 20 Jun 2021 13:53:59 -0700 Subject: [PATCH 27/37] Cleanup doc and reno --- qiskit/dagcircuit/dagcircuit.py | 2 +- qiskit/dagcircuit/dagnode.py | 2 +- .../dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 8291ff52cb9f..b7668c6b8843 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -1416,7 +1416,7 @@ def layers(self): The returned layer contains new (but semantically equivalent) OpNodes, InNodes, and OutNodes. These are not the same as nodes of the original dag, but are equivalent - via DAGNodeP.semantic_eq(node1, node2). + via DAGNode.semantic_eq(node1, node2). TODO: Gates that use the same cbits will end up in different layers as this is currently implemented. This may not be diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index e39a2b428e84..bf116669db5e 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -173,7 +173,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): """ if bit_indices1 is None or bit_indices2 is None: warnings.warn( - "DAGNodeP.semantic_eq now expects two bit-to-circuit index " + "DAGNode.semantic_eq now expects two bit-to-circuit index " "mappings as arguments. To ease the transition, these will be " "pre-populated based on the values found in Bit.index and " "Bit.register. However, this behavior is deprecated and a future " diff --git a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml index 7fde91ec5932..db10928da7ac 100644 --- a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml +++ b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml @@ -1,9 +1,9 @@ --- deprecations: - | - The :class:`qiskit.dagcircuit.DAGNode` is being deprecated as a - standalone class and will be used in the future only as the parent class - for :class:`qiskit.dagcircuit.OpNode`, :class:`qiskit.dagcircuit.InNode`, - and :class:`qiskit.dagcircuit.OutNode`. As part of this deprecation, the + The :class:`qiskit.dagcircuit.dagnode.DAGNode` is being deprecated as a standalone + class and will be used in the future only as the parent class for + :class:`qiskit.dagcircuit.dagnode.OpNode`, :class:`qiskit.dagcircuit.dagnode.InNode`, + and :class:`qiskit.dagcircuit.dagnode.OutNode`. As part of this deprecation, the following kwargs in DAGNode are being deprecated - ``type``, ``op``, and ``wire``. From 205ac2606600c88cf47ebc652623e1ca1fa68035 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 24 Jun 2021 12:52:22 -0700 Subject: [PATCH 28/37] Put DAG in class names, cleanup isinstances, add type to new classes-deprecated in DAGNode --- qiskit/dagcircuit/__init__.py | 8 +- qiskit/dagcircuit/dagcircuit.py | 128 +++++++++--------- qiskit/dagcircuit/dagnode.py | 117 ++++++++++++---- .../passes/analysis/dag_longest_path.py | 2 +- .../transpiler/passes/layout/apply_layout.py | 7 +- .../passes/optimization/collect_2q_blocks.py | 13 +- .../optimization/commutation_analysis.py | 4 +- .../optimization/commutative_cancellation.py | 4 +- .../passes/optimization/consolidate_blocks.py | 8 +- .../crosstalk_adaptive_schedule.py | 4 +- .../passes/optimization/hoare_opt.py | 6 +- .../optimize_swap_before_measure.py | 8 +- .../remove_diagonal_gates_before_measure.py | 8 +- .../remove_reset_in_zero_state.py | 4 +- .../template_matching/backward_match.py | 6 +- .../template_matching/forward_match.py | 10 +- .../passes/routing/lookahead_swap.py | 8 +- .../transpiler/passes/routing/sabre_swap.py | 10 +- .../passes/scheduling/calibration_creators.py | 8 +- .../barrier_before_final_measurements.py | 4 +- .../passes/utils/merge_adjacent_barriers.py | 4 +- .../passes/utils/remove_final_measurements.py | 4 +- qiskit/visualization/dag_visualization.py | 8 +- qiskit/visualization/latex.py | 2 +- qiskit/visualization/matplotlib.py | 7 +- ...de_to_op_in_out_node-af2cf9c3e7686285.yaml | 8 +- test/python/compiler/test_transpiler.py | 4 +- test/python/dagcircuit/test_dagcircuit.py | 35 +++-- .../transpiler/test_consolidate_blocks.py | 4 +- test/python/transpiler/test_faulty_backend.py | 4 +- test/python/transpiler/test_hoare_opt.py | 10 +- 31 files changed, 259 insertions(+), 198 deletions(-) diff --git a/qiskit/dagcircuit/__init__.py b/qiskit/dagcircuit/__init__.py index 6513b6974469..2c5ed3dbd03e 100644 --- a/qiskit/dagcircuit/__init__.py +++ b/qiskit/dagcircuit/__init__.py @@ -25,9 +25,9 @@ DAGCircuit DAGNode - OpNode - InNode - OutNode + DAGOpNode + DAGInNode + DAGOutNode DAGDepNode DAGDependency @@ -40,7 +40,7 @@ DAGCircuitError """ from .dagcircuit import DAGCircuit -from .dagnode import DAGNode, OpNode, InNode, OutNode +from .dagnode import DAGNode, DAGOpNode, DAGInNode, DAGOutNode from .dagdepnode import DAGDepNode from .exceptions import DAGCircuitError from .dagdependency import DAGDependency diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index b7668c6b8843..1b3b47e0cafd 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -35,7 +35,7 @@ from qiskit.circuit.gate import Gate from qiskit.circuit.parameterexpression import ParameterExpression from qiskit.dagcircuit.exceptions import DAGCircuitError -from qiskit.dagcircuit.dagnode import DAGNode, OpNode, InNode, OutNode +from qiskit.dagcircuit.dagnode import DAGNode, DAGOpNode, DAGInNode, DAGOutNode from qiskit.exceptions import MissingOptionalLibraryError @@ -136,16 +136,16 @@ def from_networkx(cls, graph): ) from ex dag = DAGCircuit() for node in nx.topological_sort(graph): - if isinstance(node, OutNode): + if isinstance(node, DAGOutNode): continue - if isinstance(node, InNode): + if isinstance(node, DAGInNode): if isinstance(node.wire, Qubit): dag.add_qubits([node.wire]) elif isinstance(node.wire, Clbit): dag.add_clbits([node.wire]) else: raise DAGCircuitError(f"unknown node wire type: {node.wire}") - elif isinstance(node, OpNode): + elif isinstance(node, DAGOpNode): dag.apply_operation_back(node.op.copy(), node.qargs, node.cargs) return dag @@ -306,8 +306,8 @@ def _add_wire(self, wire): if wire not in self._wires: self._wires.add(wire) - inp_node = InNode(wire=wire) - outp_node = OutNode(wire=wire) + inp_node = DAGInNode(wire=wire) + outp_node = DAGOutNode(wire=wire) input_map_id, output_map_id = self._multi_graph.add_nodes_from([inp_node, outp_node]) inp_node._node_id = input_map_id outp_node._node_id = output_map_id @@ -385,7 +385,7 @@ def _add_op_node(self, op, qargs, cargs): int: The integer node index for the new op node on the DAG """ # Add a new operation node to the graph - new_node = OpNode(op=op, qargs=qargs, cargs=cargs) + new_node = DAGOpNode(op=op, qargs=qargs, cargs=cargs) node_index = self._multi_graph.add_node(new_node) new_node._node_id = node_index return node_index @@ -416,7 +416,7 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): cargs (list[Clbit]): cbits that op will be applied to condition (tuple or None): DEPRECATED optional condition (ClassicalRegister, int) Returns: - OpNode or OutNode: the current max node + DAGOpNode or DAGOutNode: the current max node Raises: DAGCircuitError: if a leaf node is connected to multiple outputs @@ -460,7 +460,7 @@ def apply_operation_front(self, op, qargs, cargs, condition=None): cargs (list[Clbit]): cbits that op will be applied to condition (tuple or None): DEPRECATED optional condition (ClassicalRegister, int) Returns: - OpNode or OutNode: the current max node + DAGOpNode or DAGOutNode: the current max node Raises: DAGCircuitError: if initial nodes connected to multiple out edges @@ -746,7 +746,7 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i dag._calibrations[gate].update(cals) for nd in other.topological_nodes(): - if isinstance(nd, InNode): + if isinstance(nd, DAGInNode): # if in edge_map, get new name, else use existing name m_wire = edge_map.get(nd.wire, nd.wire) # the mapped wire should already exist @@ -759,10 +759,10 @@ def compose(self, other, edge_map=None, qubits=None, clbits=None, front=False, i "inconsistent wire type for %s[%d] in other" % (nd.register.name, nd.wire.index) ) - elif isinstance(nd, OutNode): + elif isinstance(nd, DAGOutNode): # ignore output nodes pass - elif isinstance(nd, OpNode): + elif isinstance(nd, DAGOpNode): condition = dag._map_condition(edge_map, nd.op.condition, dag.cregs.values()) dag._check_condition(nd.op.name, condition) m_qargs = list(map(lambda x: edge_map.get(x, x), nd.qargs)) @@ -808,7 +808,7 @@ def idle_wires(self, ignore=None): nodes = [ node for node in self.nodes_on_wire(wire, only_ops=False) - if ((not isinstance(node, OpNode) or node.op.name not in ignore)) + if ((not isinstance(node, DAGOpNode) or node.op.name not in ignore)) ] if len(nodes) == 2: yield wire @@ -866,7 +866,7 @@ def _check_wires_list(self, wires, node): Args: wires (list[Bit]): gives an order for (qu)bits in the input circuit that is replacing the node. - node (OpNode): a node in the dag + node (DAGOpNode): a node in the dag Raises: DAGCircuitError: if check doesn't pass. @@ -885,7 +885,7 @@ def _make_pred_succ_maps(self, node): """Return predecessor and successor dictionaries. Args: - node (OpNode): reference to multi_graph node + node (DAGOpNode): reference to multi_graph node Returns: tuple(dict): tuple(predecessor_map, successor_map) @@ -984,7 +984,7 @@ def topological_nodes(self): Yield nodes in topological order. Returns: - generator(OpNode, InNode, or OutNode): node in topological order + generator(DAGOpNode, DAGInNode, or DAGOutNode): node in topological order """ def _key(x): @@ -997,15 +997,15 @@ def topological_op_nodes(self): Yield op nodes in topological order. Returns: - generator(OpNode): op node in topological order + generator(DAGOpNode): op node in topological order """ - return (nd for nd in self.topological_nodes() if isinstance(nd, OpNode)) + return (nd for nd in self.topological_nodes() if isinstance(nd, DAGOpNode)) def substitute_node_with_dag(self, node, input_dag, wires=None): """Replace one node with dag. Args: - node (OpNode): node to substitute + node (DAGOpNode): node to substitute input_dag (DAGCircuit): circuit that will substitute the node wires (list[Bit]): gives an order for (qu)bits in the input circuit. This order gets matched to the node wires @@ -1015,18 +1015,18 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): DAGCircuitError: if met with unexpected predecessor/successors """ in_dag = input_dag - condition = None if not isinstance(node, OpNode) else node.op.condition + # condition = None if not isinstance(node, DAGOpNode) else node.op.condition # the dag must be amended if used in a # conditional context. delete the op nodes and replay # them with the condition. - if condition: + if node.op.condition: in_dag = copy.deepcopy(input_dag) - in_dag.add_creg(condition[0]) + in_dag.add_creg(node.op.condition[0]) to_replay = [] for sorted_node in in_dag.topological_nodes(): - if isinstance(sorted_node, OpNode): - sorted_node.op.condition = condition + if isinstance(sorted_node, DAGOpNode): + sorted_node.op.condition = node.op.condition to_replay.append(sorted_node) for input_node in in_dag.op_nodes(): in_dag.remove_op_node(input_node) @@ -1055,10 +1055,10 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): # Constructing and checking the validity of the wire_map. # If a gate is conditioned, we expect the replacement subcircuit # to depend on those condition bits as well. - if not isinstance(node, OpNode): - raise DAGCircuitError("expected node OpNode, got %s" % type(node)) + if not isinstance(node, DAGOpNode): + raise DAGCircuitError("expected node DAGOpNode, got %s" % type(node)) - condition_bit_list = self._bits_in_condition(condition) + condition_bit_list = self._bits_in_condition(node.op.condition) wire_map = dict(zip(wires, list(node.qargs) + list(node.cargs) + list(condition_bit_list))) self._check_wiremap_validity(wire_map, wires, self.input_map) @@ -1094,7 +1094,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): # Add edges from predecessor nodes to new node # and update predecessor nodes that change - all_cbits = self._bits_in_condition(condition) + all_cbits = self._bits_in_condition(node.op.condition) all_cbits.extend(m_cargs) al = [m_qargs, all_cbits] for q in itertools.chain(*al): @@ -1117,13 +1117,13 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): self._multi_graph.remove_edge(p[0], self.output_map[w]) def substitute_node(self, node, op, inplace=False): - """Replace an OpNode with a single instruction. qargs, cargs and + """Replace an DAGOpNode with a single instruction. qargs, cargs and conditions for the new instruction will be inferred from the node to be replaced. The new instruction will be checked to match the shape of the replaced instruction. Args: - node (OpNode): Node to be replaced + node (DAGOpNode): Node to be replaced op (qiskit.circuit.Instruction): The :class:`qiskit.circuit.Instruction` instance to be added to the DAG inplace (bool): Optional, default False. If True, existing DAG node @@ -1131,15 +1131,15 @@ def substitute_node(self, node, op, inplace=False): be used. Returns: - OpNode: the new node containing the added instruction. + DAGOpNode: the new node containing the added instruction. Raises: DAGCircuitError: If replacement instruction was incompatible with location of target node. """ - if not isinstance(node, OpNode): - raise DAGCircuitError("Only OpNodes can be replaced.") + if not isinstance(node, DAGOpNode): + raise DAGCircuitError("Only DAGOpNodes can be replaced.") if node.op.num_qubits != op.num_qubits or node.op.num_clbits != op.num_clbits: raise DAGCircuitError( @@ -1188,7 +1188,7 @@ def edges(self, nodes=None): no nodes are specified all edges from the graph are returned. Args: - nodes(OpNode, InNode, or OutNode|list(OpNode, InNode, or OutNode): + nodes(DAGOpNode, DAGInNode, or DAGOutNode|list(DAGOpNode, DAGInNode, or DAGOutNode): Either a list of nodes or a single input node. If none is specified, all edges are returned from the graph. @@ -1199,7 +1199,7 @@ def edges(self, nodes=None): if nodes is None: nodes = self._multi_graph.nodes() - elif isinstance(nodes, (OpNode, InNode, OutNode)): + elif isinstance(nodes, (DAGOpNode, DAGInNode, DAGOutNode)): nodes = [nodes] for node in nodes: raw_nodes = self._multi_graph.out_edges(node._node_id) @@ -1215,11 +1215,11 @@ def op_nodes(self, op=None, include_directives=True): include_directives (bool): include `barrier`, `snapshot` etc. Returns: - list[OpNode]: the list of node ids containing the given op. + list[DAGOpNode]: the list of node ids containing the given op. """ nodes = [] for node in self._multi_graph.nodes(): - if isinstance(node, OpNode): + if isinstance(node, DAGOpNode): if not include_directives and node.op._directive: continue if op is None or isinstance(node.op, op): @@ -1230,7 +1230,7 @@ def gate_nodes(self): """Get the list of gate nodes in the dag. Returns: - list[OpNode]: the list of OpNodes that represent gates. + list[DAGOpNode]: the list of DAGOpNodes that represent gates. """ nodes = [] for node in self.op_nodes(): @@ -1242,7 +1242,7 @@ def named_nodes(self, *names): """Get the set of "op" nodes with the given name.""" named_nodes = [] for node in self._multi_graph.nodes(): - if isinstance(node, OpNode) and node.op.name in names: + if isinstance(node, DAGOpNode) and node.op.name in names: named_nodes.append(node) return named_nodes @@ -1291,15 +1291,15 @@ def multi_qubit_ops(self): return ops def longest_path(self): - """Returns the longest path in the dag as a list of OpNodes, InNodes, and OutNodes.""" + """Returns the longest path in the dag as a list of DAGOpNodes, DAGInNodes, and DAGOutNodes.""" return [self._multi_graph[x] for x in rx.dag_longest_path(self._multi_graph)] def successors(self, node): - """Returns iterator of the successors of a node as OpNodes and OutNodes.""" + """Returns iterator of the successors of a node as DAGOpNodes and DAGOutNodes.""" return iter(self._multi_graph.successors(node._node_id)) def predecessors(self, node): - """Returns iterator of the predecessors of a node as OpNodes and InNodes.""" + """Returns iterator of the predecessors of a node as DAGOpNodes and DAGInNodes.""" return iter(self._multi_graph.predecessors(node._node_id)) def is_successor(self, node, node_succ): @@ -1312,7 +1312,7 @@ def is_predecessor(self, node, node_pred): def quantum_predecessors(self, node): """Returns iterator of the predecessors of a node that are - connected by a quantum edge as OpNodes and InNodes.""" + connected by a quantum edge as DAGOpNodes and DAGInNodes.""" return iter( self._multi_graph.find_predecessors_by_edge( node._node_id, lambda edge_data: isinstance(edge_data, Qubit) @@ -1320,24 +1320,24 @@ def quantum_predecessors(self, node): ) def ancestors(self, node): - """Returns set of the ancestors of a node as OpNodes and InNodes.""" + """Returns set of the ancestors of a node as DAGOpNodes and DAGInNodes.""" return {self._multi_graph[x] for x in rx.ancestors(self._multi_graph, node._node_id)} def descendants(self, node): - """Returns set of the descendants of a node as OpNodes and OutNodes.""" + """Returns set of the descendants of a node as DAGOpNodes and DAGOutNodes.""" return {self._multi_graph[x] for x in rx.descendants(self._multi_graph, node._node_id)} def bfs_successors(self, node): """ - Returns an iterator of tuples of (OpNode, InNode, or OutNode, [OpNode or OutNode]) - where the OpNode, InNode, or OutNode is the current node and - [OpNode or OutNode] is its successors in BFS order. + Returns an iterator of tuples of (DAGOpNode, DAGInNode, or DAGOutNode, [DAGOpNode or DAGOutNode]) + where the DAGOpNode, DAGInNode, or DAGOutNode is the current node and + [DAGOpNode or DAGOutNode] is its successors in BFS order. """ return iter(rx.bfs_successors(self._multi_graph, node._node_id)) def quantum_successors(self, node): """Returns iterator of the successors of a node that are - connected by a quantum edge as Opnodes and OutNodes.""" + connected by a quantum edge as Opnodes and DAGOutNodes.""" return iter( self._multi_graph.find_successors_by_edge( node._node_id, lambda edge_data: isinstance(edge_data, Qubit) @@ -1349,9 +1349,9 @@ def remove_op_node(self, node): Add edges from predecessors to successors. """ - if not isinstance(node, OpNode): + if not isinstance(node, DAGOpNode): raise DAGCircuitError( - 'The method remove_op_node only works on OpNodes. A "%s" ' + 'The method remove_op_node only works on DAGOpNodes. A "%s" ' "node type was wrongly provided." % type(node) ) @@ -1366,14 +1366,14 @@ def remove_ancestors_of(self, node): # multi_graph.remove_nodes_from; same for related functions ... for anc_node in anc: - if isinstance(anc_node, OpNode): + if isinstance(anc_node, DAGOpNode): self.remove_op_node(anc_node) def remove_descendants_of(self, node): """Remove all of the descendant operation nodes of node.""" desc = rx.descendants(self._multi_graph, node) for desc_node in desc: - if isinstance(desc_node, OpNode): + if isinstance(desc_node, DAGOpNode): self.remove_op_node(desc_node) def remove_nonancestors_of(self, node): @@ -1381,7 +1381,7 @@ def remove_nonancestors_of(self, node): anc = rx.ancestors(self._multi_graph, node) comp = list(set(self._multi_graph.nodes()) - set(anc)) for n in comp: - if isinstance(n, OpNode): + if isinstance(n, DAGOpNode): self.remove_op_node(n) def remove_nondescendants_of(self, node): @@ -1389,7 +1389,7 @@ def remove_nondescendants_of(self, node): dec = rx.descendants(self._multi_graph, node) comp = list(set(self._multi_graph.nodes()) - set(dec)) for n in comp: - if isinstance(n, OpNode): + if isinstance(n, DAGOpNode): self.remove_op_node(n) def front_layer(self): @@ -1400,7 +1400,7 @@ def front_layer(self): except StopIteration: return [] - op_nodes = [node for node in next(graph_layers) if isinstance(node, OpNode)] + op_nodes = [node for node in next(graph_layers) if isinstance(node, DAGOpNode)] return op_nodes @@ -1414,8 +1414,8 @@ def layers(self): greedy algorithm. Each returned layer is a dict containing {"graph": circuit graph, "partition": list of qubit lists}. - The returned layer contains new (but semantically equivalent) OpNodes, InNodes, - and OutNodes. These are not the same as nodes of the original dag, but are equivalent + The returned layer contains new (but semantically equivalent) DAGOpNodes, DAGInNodes, + and DAGOutNodes. These are not the same as nodes of the original dag, but are equivalent via DAGNode.semantic_eq(node1, node2). TODO: Gates that use the same cbits will end up in different @@ -1431,7 +1431,7 @@ def layers(self): for graph_layer in graph_layers: # Get the op nodes from the layer, removing any input and output nodes. - op_nodes = [node for node in graph_layer if isinstance(node, OpNode)] + op_nodes = [node for node in graph_layer if isinstance(node, DAGOpNode)] # Sort to make sure they are in the order they were added to the original DAG # It has to be done by node_id as graph_layer is just a list of nodes @@ -1448,7 +1448,7 @@ def layers(self): new_layer = self._copy_circuit_metadata() for node in op_nodes: - # this creates new OpNodes in the new_layer + # this creates new DAGOpNodes in the new_layer new_layer.apply_operation_back(node.op, node.qargs, node.cargs) # The quantum registers that have an operation in this layer. @@ -1504,7 +1504,9 @@ def collect_runs(self, namelist): def filter_fn(node): return ( - isinstance(node, OpNode) and node.op.name in namelist and node.op.condition is None + isinstance(node, DAGOpNode) + and node.op.name in namelist + and node.op.condition is None ) group_list = rx.collect_runs(self._multi_graph, filter_fn) @@ -1515,7 +1517,7 @@ def collect_1q_runs(self): def filter_fn(node): return ( - isinstance(node, OpNode) + isinstance(node, DAGOpNode) and len(node.qargs) == 1 and len(node.cargs) == 0 and node.op.condition is None @@ -1549,7 +1551,7 @@ def nodes_on_wire(self, wire, only_ops=False): while more_nodes: more_nodes = False # allow user to just get ops on the wire - not the input/output nodes - if isinstance(current_node, OpNode) or not only_ops: + if isinstance(current_node, DAGOpNode) or not only_ops: yield current_node try: diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index bf116669db5e..e3c7aa51bbeb 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -20,26 +20,26 @@ class DAGNode: - """Parent class for OpNode, InNode, and OutNode.""" + """Parent class for DAGOpNode, DAGInNode, and DAGOutNode.""" - __slots__ = ["type", "_op", "_qargs", "cargs", "_wire", "sort_key", "_node_id"] + __slots__ = ["_type", "_op", "_qargs", "cargs", "_wire", "sort_key", "_node_id"] def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=None, nid=-1): """Create a node""" if type is not None: warnings.warn( - "The DAGNode 'type' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'type' kwarg is deprecated as of 0.18.0 and " "will be removed no earlier than 3 months after the release date. " - "Use OpNode, InNode, or OutNode instead of DAGNode.", + "Use DAGOpNode, DAGInNode, or DAGOutNode instead of DAGNode.", DeprecationWarning, 2, ) - self.type = type + self._type = type if op is not None: warnings.warn( - "The DAGNode 'op' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'op' kwarg is deprecated as of 0.18.0 and " "will be removed no earlier than 3 months after the release date." - "Use OpNode instead of DAGNode.", + "Use DAGOpNode instead of DAGNode.", DeprecationWarning, 2, ) @@ -56,9 +56,9 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N self.cargs = cargs if cargs is not None else [] if wire is not None: warnings.warn( - "The DAGNode 'wire' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'wire' kwarg is deprecated as of 0.18.0 and " "will be removed no earlier than 3 months after the release date." - "Use InNode or OutNode instead of DAGNode.", + "Use DAGInNode or DAGOutNode instead of DAGNode.", DeprecationWarning, 2, ) @@ -66,15 +66,56 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N self._node_id = nid self.sort_key = str(self._qargs) + @property + def type(self): + """Returns the type object""" + warnings.warn( + "The DAGNode 'type' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGOpNode, DAGInNode, or DAGOutNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + return self._type + + @type.setter + def type(self, dag_type): + """Sets the value of the type object""" + warnings.warn( + "The DAGNode 'type' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGOpNode, DAGInNode, or DAGOutNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + if dag_type not in ["op", "in", "out"]: + raise QiskitError("The DAGNode type must be 'op', 'in', or 'out'") + self._type = dag_type + @property def op(self): """Returns the Instruction object corresponding to the op for the node, else None""" + warnings.warn( + "The DAGNode 'op' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGOpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) if not self.type or self.type != "op": raise QiskitError("The node %s is not an op node" % (str(self))) return self._op @op.setter def op(self, data): + """Sets the op for the node""" + warnings.warn( + "The DAGNode 'op' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGOpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) self._op = data @property @@ -133,15 +174,28 @@ def qargs(self, new_qargs): @property def wire(self): - """ - Returns the Bit object, else None. - """ + """Returns the Bit object, else None.""" + warnings.warn( + "The DAGNode 'wire' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGInNode or DAGOutNode instead of DAGNode.", + DeprecationWarning, + 2, + ) if self.type not in ["in", "out"]: raise QiskitError("The node %s is not an input/output node" % str(self)) return self._wire @wire.setter def wire(self, data): + """Sets the Bit object""" + warnings.warn( + "The DAGNode 'wire' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGInNode or DAGOutNode instead of DAGNode.", + DeprecationWarning, + 2, + ) self._wire = data def __lt__(self, other): @@ -161,8 +215,8 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): Check if DAG nodes are considered equivalent, e.g., as a node_match for nx.is_isomorphic. Args: - node1 (OpNode, InNode, OutNode): A node to compare. - node2 (OpNode, InNode, OutNode): The other node to compare. + node1 (DAGOpNode, DAGInNode, DAGOutNode): A node to compare. + node2 (DAGOpNode, DAGInNode, DAGOutNode): The other node to compare. bit_indices1 (dict): Dictionary mapping Bit instances to their index within the circuit containing node1 bit_indices2 (dict): Dictionary mapping Bit instances to their index @@ -184,7 +238,7 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): bit_indices1 = {arg: arg for arg in node1.qargs + node1.cargs} bit_indices2 = {arg: arg for arg in node2.qargs + node2.cargs} - if isinstance(node1, OpNode) and isinstance(node2, OpNode): + if isinstance(node1, DAGOpNode) and isinstance(node2, DAGOpNode): node1_qargs = [bit_indices1[qarg] for qarg in node1.qargs] node1_cargs = [bit_indices1[carg] for carg in node1.cargs] @@ -200,8 +254,8 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): if node1.op.condition == node2.op.condition: if node1.op == node2.op: return True - elif (isinstance(node1, InNode) and isinstance(node2, InNode)) or ( - isinstance(node1, OutNode) and isinstance(node2, OutNode) + elif (isinstance(node1, DAGInNode) and isinstance(node2, DAGInNode)) or ( + isinstance(node1, DAGOutNode) and isinstance(node2, DAGOutNode) ): if bit_indices1.get(node1.wire, None) == bit_indices2.get(node2.wire, None): return True @@ -209,15 +263,16 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): return False -class OpNode(DAGNode): +class DAGOpNode(DAGNode): """Object to represent an Instruction at a node in the DAGCircuit.""" - __slots__ = ["op"] + __slots__ = ["_type", "op"] def __init__(self, op, qargs=None, cargs=None): """Create an Instruction node""" - self.op = op super().__init__(qargs=qargs, cargs=cargs) + self._type = "op" + self.op = op @property def name(self): @@ -233,9 +288,9 @@ def name(self, new_name): def condition(self): """Returns the condition of the node.op""" warnings.warn( - "The OpNode 'condition' attribute is deprecated as of 0.18.0 and " + "The DAGOpNode 'condition' attribute is deprecated as of 0.18.0 and " "will be removed no earlier than 3 months after the release date. " - "You can use 'OpNode.op.condition'.", + "You can use 'DAGOpNode.op.condition'.", DeprecationWarning, 2, ) @@ -245,32 +300,34 @@ def condition(self): def condition(self, new_condition): """Sets the node.condition which sets the node.op.condition.""" warnings.warn( - "The OpNode 'condition' attribute is deprecated as of 0.18.0 and " + "The DAGOpNode 'condition' attribute is deprecated as of 0.18.0 and " "will be removed no earlier than 3 months after the release date. " - "You can use 'OpNode.op.condition'.", + "You can use 'DAGOpNode.op.condition'.", DeprecationWarning, 2, ) self.op.condition = new_condition -class InNode(DAGNode): +class DAGInNode(DAGNode): """Object to represent an incoming wire node in the DAGCircuit.""" - __slots__ = ["wire"] + __slots__ = ["_type", "wire"] def __init__(self, wire): """Create an incoming node""" - self.wire = wire super().__init__() + self._type = "in" + self.wire = wire -class OutNode(DAGNode): +class DAGOutNode(DAGNode): """Object to represent an outgoing wire node in the DAGCircuit.""" - __slots__ = ["wire"] + __slots__ = ["_type", "wire"] def __init__(self, wire): """Create an outgoing node""" - self.wire = wire super().__init__() + self._type = "out" + self.wire = wire diff --git a/qiskit/transpiler/passes/analysis/dag_longest_path.py b/qiskit/transpiler/passes/analysis/dag_longest_path.py index 366adca06a24..e35d86ca63ba 100644 --- a/qiskit/transpiler/passes/analysis/dag_longest_path.py +++ b/qiskit/transpiler/passes/analysis/dag_longest_path.py @@ -16,7 +16,7 @@ class DAGLongestPath(AnalysisPass): - """Return the longest path in a DAGcircuit as a list of OpNodes, InNodes, and OutNodes.""" + """Return the longest path in a DAGcircuit as a list of DAGOpNodes, DAGInNodes, and DAGOutNodes.""" def run(self, dag): """Run the DAGLongestPath pass on `dag`.""" diff --git a/qiskit/transpiler/passes/layout/apply_layout.py b/qiskit/transpiler/passes/layout/apply_layout.py index 36be3bd4d3c1..48e38bd21b3f 100644 --- a/qiskit/transpiler/passes/layout/apply_layout.py +++ b/qiskit/transpiler/passes/layout/apply_layout.py @@ -13,7 +13,7 @@ """Transform a circuit with virtual qubits into a circuit with physical qubits.""" from qiskit.circuit import QuantumRegister -from qiskit.dagcircuit import DAGCircuit, OpNode +from qiskit.dagcircuit import DAGCircuit, DAGOpNode from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError @@ -59,9 +59,8 @@ def run(self, dag): for creg in dag.cregs.values(): new_dag.add_creg(creg) for node in dag.topological_op_nodes(): - if isinstance(node, OpNode): - qargs = [q[layout[qarg]] for qarg in node.qargs] - new_dag.apply_operation_back(node.op, qargs, node.cargs) + qargs = [q[layout[qarg]] for qarg in node.qargs] + new_dag.apply_operation_back(node.op, qargs, node.cargs) new_dag._global_phase = dag._global_phase return new_dag diff --git a/qiskit/transpiler/passes/optimization/collect_2q_blocks.py b/qiskit/transpiler/passes/optimization/collect_2q_blocks.py index c1359859d9ec..eea3ef2358b6 100644 --- a/qiskit/transpiler/passes/optimization/collect_2q_blocks.py +++ b/qiskit/transpiler/passes/optimization/collect_2q_blocks.py @@ -15,7 +15,7 @@ from collections import defaultdict from qiskit.circuit import Gate -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.transpiler.basepasses import AnalysisPass @@ -58,8 +58,7 @@ def run(self, dag): group = [] # Explore predecessors and successors of 2q gates if ( # pylint: disable=too-many-boolean-expressions - isinstance(nd, OpNode) - and isinstance(nd.op, Gate) + isinstance(nd.op, Gate) and len(nd._qargs) == 2 and not nodes_seen[nd] and nd.op.condition is None @@ -75,7 +74,7 @@ def run(self, dag): if len(pred) == 1 and not nodes_seen[pred[0]]: pnd = pred[0] if ( - isinstance(pnd, OpNode) + isinstance(pnd, DAGOpNode) and isinstance(pnd.op, Gate) and len(pnd._qargs) <= 2 and pnd.op.condition is None @@ -113,7 +112,7 @@ def run(self, dag): # Examine each predecessor for pnd in sorted_pred: if ( - not isinstance(pnd, OpNode) + not isinstance(pnd, DAGOpNode) or not isinstance(pnd.op, Gate) or len(pnd._qargs) > 2 or pnd.op.condition is not None @@ -165,7 +164,7 @@ def run(self, dag): if len(succ) == 1 and not nodes_seen[succ[0]]: snd = succ[0] if ( - isinstance(snd, OpNode) + isinstance(snd, DAGOpNode) and isinstance(snd.op, Gate) and len(snd._qargs) <= 2 and snd.op.condition is None @@ -203,7 +202,7 @@ def run(self, dag): # Examine each successor for snd in sorted_succ: if ( - not isinstance(snd, OpNode) + not isinstance(snd, DAGOpNode) or not isinstance(snd.op, Gate) or len(snd._qargs) > 2 or snd.op.condition is not None diff --git a/qiskit/transpiler/passes/optimization/commutation_analysis.py b/qiskit/transpiler/passes/optimization/commutation_analysis.py index 3c0d067627f6..82b1b0a699a1 100644 --- a/qiskit/transpiler/passes/optimization/commutation_analysis.py +++ b/qiskit/transpiler/passes/optimization/commutation_analysis.py @@ -17,7 +17,7 @@ from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.basepasses import AnalysisPass from qiskit.quantum_info.operators import Operator -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode _CUTOFF_PRECISION = 1e-10 @@ -89,7 +89,7 @@ def run(self, dag): def _commute(node1, node2, cache): - if not isinstance(node1, OpNode) or not isinstance(node2, OpNode): + if not isinstance(node1, DAGOpNode) or not isinstance(node2, DAGOpNode): return False for nd in [node1, node2]: diff --git a/qiskit/transpiler/passes/optimization/commutative_cancellation.py b/qiskit/transpiler/passes/optimization/commutative_cancellation.py index c568ee98068c..c3e956a9bbb8 100644 --- a/qiskit/transpiler/passes/optimization/commutative_cancellation.py +++ b/qiskit/transpiler/passes/optimization/commutative_cancellation.py @@ -19,7 +19,7 @@ from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.passes.optimization.commutation_analysis import CommutationAnalysis -from qiskit.dagcircuit import DAGCircuit, InNode, OutNode +from qiskit.dagcircuit import DAGCircuit, DAGInNode, DAGOutNode from qiskit.circuit.library.standard_gates.u1 import U1Gate from qiskit.circuit.library.standard_gates.rx import RXGate from qiskit.circuit.library.standard_gates.p import PhaseGate @@ -97,7 +97,7 @@ def run(self, dag): wire_commutation_set = self.property_set["commutation_set"][wire] for com_set_idx, com_set in enumerate(wire_commutation_set): - if isinstance(com_set[0], (InNode, OutNode)): + if isinstance(com_set[0], (DAGInNode, DAGOutNode)): continue for node in com_set: num_qargs = len(node.qargs) diff --git a/qiskit/transpiler/passes/optimization/consolidate_blocks.py b/qiskit/transpiler/passes/optimization/consolidate_blocks.py index 63ae9dbb0c84..ae50e58d52e1 100644 --- a/qiskit/transpiler/passes/optimization/consolidate_blocks.py +++ b/qiskit/transpiler/passes/optimization/consolidate_blocks.py @@ -16,7 +16,7 @@ from qiskit.circuit import QuantumRegister, ClassicalRegister, QuantumCircuit, Gate -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.quantum_info.operators import Operator from qiskit.quantum_info.synthesis import TwoQubitBasisDecomposer from qiskit.extensions import UnitaryGate @@ -84,7 +84,7 @@ def run(self, dag): for node in dag.topological_op_nodes(): if node not in all_block_nodes: # need to add this node to find out where in the list it goes - preds = [nd for nd in dag.predecessors(node) if isinstance(nd, OpNode)] + preds = [nd for nd in dag.predecessors(node) if isinstance(nd, DAGOpNode)] block_count = 0 while preds: @@ -113,7 +113,7 @@ def run(self, dag): if len(block) == 1 and block[0].name != basis_gate_name: # pylint: disable=too-many-boolean-expressions if ( - isinstance(block[0], OpNode) + isinstance(block[0], DAGOpNode) and self.basis_gates and block[0].name not in self.basis_gates and len(block[0].cargs) == 0 @@ -134,7 +134,7 @@ def run(self, dag): block_cargs = set() for nd in block: block_qargs |= set(nd.qargs) - if isinstance(nd, OpNode) and nd.op.condition: + if isinstance(nd, DAGOpNode) and nd.op.condition: block_cargs |= set(nd.op.condition[0]) # convert block to a sub-circuit, then simulate unitary and add q = QuantumRegister(len(block_qargs)) diff --git a/qiskit/transpiler/passes/optimization/crosstalk_adaptive_schedule.py b/qiskit/transpiler/passes/optimization/crosstalk_adaptive_schedule.py index 32395ab02f96..0f3c6f864279 100644 --- a/qiskit/transpiler/passes/optimization/crosstalk_adaptive_schedule.py +++ b/qiskit/transpiler/passes/optimization/crosstalk_adaptive_schedule.py @@ -43,7 +43,7 @@ from qiskit.circuit.library.standard_gates import U1Gate, U2Gate, U3Gate, CXGate from qiskit.circuit import Measure from qiskit.circuit.barrier import Barrier -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.transpiler.exceptions import TranspilerError NUM_PREC = 10 @@ -341,7 +341,7 @@ def scheduling_constraints(self): """ for gate in self.gate_start_time: for dep_gate in self.dag.successors(gate): - if not isinstance(dep_gate, OpNode): + if not isinstance(dep_gate, DAGOpNode): continue if isinstance(dep_gate.op, Measure): continue diff --git a/qiskit/transpiler/passes/optimization/hoare_opt.py b/qiskit/transpiler/passes/optimization/hoare_opt.py index 1b9262bcef3c..35b0417ad92d 100644 --- a/qiskit/transpiler/passes/optimization/hoare_opt.py +++ b/qiskit/transpiler/passes/optimization/hoare_opt.py @@ -239,7 +239,7 @@ def _target_successive_seq(self, qubit): Args: qubit (Qubit): qubit cache to inspect Returns: - list(list(OpNode or OutNode)): list of target successive gate sequences for + list(list(DAGOpNode or DAGOutNode)): list of target successive gate sequences for this qubit's cache """ seqs = [] @@ -269,7 +269,7 @@ def _is_identity(self, sequence): """determine whether the sequence of gates combines to the identity (consider sequences of length 2 for now) Args: - sequence (list(OpNode)): gate sequence to inspect + sequence (list(DAGOpNode)): gate sequence to inspect Returns: bool: if gate sequence combines to identity """ @@ -304,7 +304,7 @@ def _seq_as_one(self, sequence): all executed or none of them are executed, based on control qubits (consider sequences of length 2 for now) Args: - sequence (list(OpNode)): gate sequence to inspect + sequence (list(DAGOpNode)): gate sequence to inspect Returns: bool: if gate sequence is only executed completely or not at all """ diff --git a/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py b/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py index f17a93025fc1..a736b9438639 100644 --- a/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py +++ b/qiskit/transpiler/passes/optimization/optimize_swap_before_measure.py @@ -16,7 +16,7 @@ from qiskit.circuit import Measure from qiskit.circuit.library.standard_gates import SwapGate from qiskit.transpiler.basepasses import TransformationPass -from qiskit.dagcircuit import DAGCircuit, OpNode, OutNode +from qiskit.dagcircuit import DAGCircuit, DAGOpNode, DAGOutNode class OptimizeSwapBeforeMeasure(TransformationPass): @@ -42,8 +42,8 @@ def run(self, dag): final_successor = [] for successor in dag.successors(swap): final_successor.append( - isinstance(successor, OutNode) - or (isinstance(successor, OpNode) and isinstance(successor.op, Measure)) + isinstance(successor, DAGOutNode) + or (isinstance(successor, DAGOpNode) and isinstance(successor.op, Measure)) ) if all(final_successor): # the node swap needs to be removed and, if a measure follows, needs to be adapted @@ -54,7 +54,7 @@ def run(self, dag): for creg in dag.cregs.values(): measure_layer.add_creg(creg) for successor in list(dag.successors(swap)): - if isinstance(successor, OpNode) and isinstance(successor.op, Measure): + if isinstance(successor, DAGOpNode) and isinstance(successor.op, Measure): # replace measure node with a new one, where qargs is set with the "other" # swap qarg. dag.remove_op_node(successor) diff --git a/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py b/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py index 0787f28cd2e4..62066d518852 100644 --- a/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py +++ b/qiskit/transpiler/passes/optimization/remove_diagonal_gates_before_measure.py @@ -26,7 +26,7 @@ CU1Gate, RZZGate, ) -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.transpiler.basepasses import TransformationPass @@ -53,12 +53,12 @@ def run(self, dag): for measure in dag.op_nodes(Measure): predecessor = next(dag.quantum_predecessors(measure)) - if isinstance(predecessor, OpNode) and isinstance(predecessor.op, diagonal_1q_gates): + if isinstance(predecessor, DAGOpNode) and isinstance(predecessor.op, diagonal_1q_gates): nodes_to_remove.add(predecessor) - if isinstance(predecessor, OpNode) and isinstance(predecessor.op, diagonal_2q_gates): + if isinstance(predecessor, DAGOpNode) and isinstance(predecessor.op, diagonal_2q_gates): successors = dag.quantum_successors(predecessor) - if all(isinstance(s, OpNode) and isinstance(s.op, Measure) for s in successors): + if all(isinstance(s, DAGOpNode) and isinstance(s.op, Measure) for s in successors): nodes_to_remove.add(predecessor) for node_to_remove in nodes_to_remove: diff --git a/qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py b/qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py index 6c1e19d78771..4cf29ad54163 100644 --- a/qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py +++ b/qiskit/transpiler/passes/optimization/remove_reset_in_zero_state.py @@ -13,7 +13,7 @@ """Remove reset gate when the qubit is in zero state.""" from qiskit.circuit import Reset -from qiskit.dagcircuit import InNode +from qiskit.dagcircuit import DAGInNode from qiskit.transpiler.basepasses import TransformationPass @@ -32,6 +32,6 @@ def run(self, dag): resets = dag.op_nodes(Reset) for reset in resets: predecessor = next(dag.predecessors(reset)) - if isinstance(predecessor, InNode): + if isinstance(predecessor, DAGInNode): dag.remove_op_node(reset) return dag diff --git a/qiskit/transpiler/passes/optimization/template_matching/backward_match.py b/qiskit/transpiler/passes/optimization/template_matching/backward_match.py index e5274ad366c8..e46e3ca19023 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/backward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/backward_match.py @@ -27,7 +27,7 @@ import heapq from qiskit.circuit.controlledgate import ControlledGate -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode class Match: @@ -304,9 +304,9 @@ def _is_same_c_conf(self, node_circuit, node_template, carg_circuit): bool: True if possible, False otherwise. """ if ( - isinstance(node_circuit, OpNode) + node_circuit.type == "op" and node_circuit.op.condition - and isinstance(node_template, OpNode) + and node_template.type == "op" and node_template.op.condition ): if set(carg_circuit) != set(node_template.cindices): diff --git a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py index d7389b047d88..cdc2323309d7 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py @@ -25,7 +25,7 @@ """ from qiskit.circuit.controlledgate import ControlledGate -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode class ForwardMatch: @@ -199,7 +199,7 @@ def _update_successor(self, node, successor_id): successor_id (int): successor id to remove. Returns: - OpNode or OutNode: Node with updated attribute 'SuccessorToVisit'. + DAGOpNode or DAGOutNode: Node with updated attribute 'SuccessorToVisit'. """ node_update = node node_update.successorstovisit.pop(successor_id) @@ -209,7 +209,7 @@ def _get_successors_to_visit(self, node, list_id): """ Return the successor for a given node and id. Args: - node (OpNode or OutNode): current node. + node (DAGOpNode or DAGOutNode): current node. list_id (int): id in the list for the successor to get. Returns: @@ -313,9 +313,9 @@ def _is_same_c_conf(self, node_circuit, node_template): bool: True if possible, False otherwise. """ if ( - isinstance(node_circuit, OpNode) + node_circuit.type == "op" and node_circuit.op.condition - and isinstance(node_template, OpNode) + and node_template.type == "op" and node_template.op.conditon ): if set(self.carg_indices) != set(node_template.cindices): diff --git a/qiskit/transpiler/passes/routing/lookahead_swap.py b/qiskit/transpiler/passes/routing/lookahead_swap.py index 57e0dab20b63..2727d4bf1bb5 100644 --- a/qiskit/transpiler/passes/routing/lookahead_swap.py +++ b/qiskit/transpiler/passes/routing/lookahead_swap.py @@ -20,7 +20,7 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.layout import Layout -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode logger = logging.getLogger(__name__) @@ -273,7 +273,7 @@ def _map_free_gates(layout, gates, coupling_map): # Gates without a partition (barrier, snapshot, save, load, noise) may # still have associated qubits. Look for them in the qargs. if not gate["partition"]: - qubits = [n for n in gate["graph"].nodes() if isinstance(n, OpNode)][0].qargs + qubits = [n for n in gate["graph"].nodes() if isinstance(n, DAGOpNode)][0].qargs if not qubits: continue @@ -328,7 +328,7 @@ def _score_step(step): def _transform_gate_for_layout(gate, layout): """Return op implementing a virtual gate on given layout.""" - mapped_op_node = deepcopy([n for n in gate["graph"].nodes() if isinstance(n, OpNode)][0]) + mapped_op_node = deepcopy([n for n in gate["graph"].nodes() if isinstance(n, DAGOpNode)][0]) device_qreg = QuantumRegister(len(layout.get_physical_bits()), "q") mapped_qargs = [device_qreg[layout[a]] for a in mapped_op_node.qargs] @@ -343,4 +343,4 @@ def _swap_ops_from_edge(edge, layout): qreg_edge = [device_qreg[i] for i in edge] # TODO shouldn't be making other nodes not by the DAG!! - return [OpNode(op=SwapGate(), qargs=qreg_edge, cargs=[])] + return [DAGOpNode(op=SwapGate(), qargs=qreg_edge, cargs=[])] diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index 07fe1a5e1ca6..98f0118f7b5a 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -22,7 +22,7 @@ from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.layout import Layout -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode logger = logging.getLogger(__name__) @@ -204,13 +204,13 @@ def run(self, dag): logger.debug( "free! %s", [ - (n.name if isinstance(n, OpNode) else None, n.qargs) + (n.name if isinstance(n, DAGOpNode) else None, n.qargs) for n in execute_gate_list ], ) logger.debug( "front_layer: %s", - [(n.name if isinstance(n, OpNode) else None, n.qargs) for n in front_layer], + [(n.name if isinstance(n, DAGOpNode) else None, n.qargs) for n in front_layer], ) continue @@ -232,7 +232,7 @@ def run(self, dag): best_swaps = [k for k, v in swap_scores.items() if v == min_score] best_swaps.sort(key=lambda x: (self._bit_indices[x[0]], self._bit_indices[x[1]])) best_swap = rng.choice(best_swaps) - swap_node = OpNode(op=SwapGate(), qargs=best_swap) + swap_node = DAGOpNode(op=SwapGate(), qargs=best_swap) self._apply_gate(mapped_dag, swap_node, current_layout, canonical_register) current_layout.swap(*best_swap) @@ -270,7 +270,7 @@ def _reset_qubits_decay(self): def _successors(self, node, dag): for _, successor, edge_data in dag.edges(node): - if not isinstance(successor, OpNode): + if not isinstance(successor, DAGOpNode): continue if isinstance(edge_data, Qubit): yield successor diff --git a/qiskit/transpiler/passes/scheduling/calibration_creators.py b/qiskit/transpiler/passes/scheduling/calibration_creators.py index b72e0e79872e..ad40e1cef524 100644 --- a/qiskit/transpiler/passes/scheduling/calibration_creators.py +++ b/qiskit/transpiler/passes/scheduling/calibration_creators.py @@ -29,7 +29,7 @@ from qiskit.pulse.instructions.instruction import Instruction from qiskit.exceptions import QiskitError from qiskit.providers import basebackend -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.circuit.library.standard_gates import RZXGate from qiskit.transpiler.basepasses import TransformationPass @@ -38,7 +38,7 @@ class CalibrationCreator(TransformationPass): """Abstract base class to inject calibrations into circuits.""" @abstractmethod - def supported(self, node_op: OpNode) -> bool: + def supported(self, node_op: DAGOpNode) -> bool: """Determine if a given name supports the calibration.""" @abstractmethod @@ -57,7 +57,7 @@ def run(self, dag): bit_indices = {bit: index for index, bit in enumerate(dag.qubits)} for node in dag.nodes(): - if isinstance(node, OpNode): + if isinstance(node, DAGOpNode): if self.supported(node.op): params = node.op.params qubits = [bit_indices[qarg] for qarg in node.qargs] @@ -103,7 +103,7 @@ def __init__(self, backend: basebackend): self._config = backend.configuration() self._channel_map = backend.configuration().qubit_channel_mapping - def supported(self, node_op: OpNode) -> bool: + def supported(self, node_op: DAGOpNode) -> bool: """ Args: node_op: The node from the dag dep. diff --git a/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py b/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py index b6dddcdd8bd1..da70fa6576bd 100644 --- a/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py +++ b/qiskit/transpiler/passes/utils/barrier_before_final_measurements.py @@ -15,7 +15,7 @@ from qiskit.circuit.barrier import Barrier from qiskit.transpiler.basepasses import TransformationPass -from qiskit.dagcircuit import DAGCircuit, OpNode +from qiskit.dagcircuit import DAGCircuit, DAGOpNode from .merge_adjacent_barriers import MergeAdjacentBarriers @@ -38,7 +38,7 @@ def run(self, dag): for _, child_successors in dag.bfs_successors(candidate_node): if any( - isinstance(suc, OpNode) and suc.name not in final_op_types + isinstance(suc, DAGOpNode) and suc.name not in final_op_types for suc in child_successors ): is_final_op = False diff --git a/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py b/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py index 0eca133740bc..0614eeb0ac09 100644 --- a/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py +++ b/qiskit/transpiler/passes/utils/merge_adjacent_barriers.py @@ -76,8 +76,8 @@ def run(self, dag): def _collect_potential_merges(dag, barriers): """Return the potential merges. - Returns a dict of OpNode: Barrier objects, where the barrier needs to be - inserted where the corresponding OpNode appears in the main DAG. + Returns a dict of DAGOpNode: Barrier objects, where the barrier needs to be + inserted where the corresponding DAGOpNode appears in the main DAG. """ # if only got 1 or 0 barriers then can't merge if len(barriers) < 2: diff --git a/qiskit/transpiler/passes/utils/remove_final_measurements.py b/qiskit/transpiler/passes/utils/remove_final_measurements.py index fc7aa7dbc067..5bf156970203 100644 --- a/qiskit/transpiler/passes/utils/remove_final_measurements.py +++ b/qiskit/transpiler/passes/utils/remove_final_measurements.py @@ -13,7 +13,7 @@ """Remove final measurements and barriers at the end of a circuit.""" from qiskit.transpiler.basepasses import TransformationPass -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode class RemoveFinalMeasurements(TransformationPass): @@ -45,7 +45,7 @@ def run(self, dag): for _, child_successors in dag.bfs_successors(candidate_node): if any( - isinstance(suc, OpNode) and suc.name not in final_op_types + isinstance(suc, DAGOpNode) and suc.name not in final_op_types for suc in child_successors ): is_final_op = False diff --git a/qiskit/visualization/dag_visualization.py b/qiskit/visualization/dag_visualization.py index f21819d1920c..8d443bcb025f 100644 --- a/qiskit/visualization/dag_visualization.py +++ b/qiskit/visualization/dag_visualization.py @@ -20,7 +20,7 @@ import sys import tempfile -from qiskit.dagcircuit.dagnode import OpNode, InNode, OutNode +from qiskit.dagcircuit.dagnode import DAGOpNode, DAGInNode, DAGOutNode from qiskit.exceptions import MissingOptionalLibraryError from .exceptions import VisualizationError @@ -138,17 +138,17 @@ def node_attr_func(node): return {} if style == "color": n = {} - if isinstance(node, OpNode): + if isinstance(node, DAGOpNode): n["label"] = node.name n["color"] = "blue" n["style"] = "filled" n["fillcolor"] = "lightblue" - if isinstance(node, InNode): + if isinstance(node, DAGInNode): n["label"] = bit_labels[node.wire] n["color"] = "black" n["style"] = "filled" n["fillcolor"] = "green" - if isinstance(node, OutNode): + if isinstance(node, DAGOutNode): n["label"] = bit_labels[node.wire] n["color"] = "black" n["style"] = "filled" diff --git a/qiskit/visualization/latex.py b/qiskit/visualization/latex.py index a3a45ded9741..e501b8c7dd9c 100644 --- a/qiskit/visualization/latex.py +++ b/qiskit/visualization/latex.py @@ -56,7 +56,7 @@ def __init__( Args: qubits (list[Qubit]): list of qubits clbits (list[Clbit]): list of clbits - ops (list[list[OpNode]]): list of circuit instructions, grouped by layer + ops (list[list[DAGOpNode]]): list of circuit instructions, grouped by layer scale (float): image scaling reverse_bits (bool): when True, reverse the bit ordering of the registers plot_barriers (bool): Enable/disable drawing barriers in the output diff --git a/qiskit/visualization/matplotlib.py b/qiskit/visualization/matplotlib.py index 01893e555625..fb7508e55037 100644 --- a/qiskit/visualization/matplotlib.py +++ b/qiskit/visualization/matplotlib.py @@ -32,7 +32,7 @@ HAS_PYLATEX = False from qiskit.circuit import ControlledGate, Gate, Instruction -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.exceptions import MissingOptionalLibraryError from qiskit.visualization.qcstyle import DefaultStyle, set_style from qiskit.circuit import Delay @@ -1312,8 +1312,7 @@ def _draw_ops(self, verbose=False): # load param if ( - isinstance(op, OpNode) - and hasattr(op.op, "params") + hasattr(op.op, "params") and len(op.op.params) > 0 and not any(isinstance(param, np.ndarray) for param in op.op.params) ): @@ -1322,7 +1321,7 @@ def _draw_ops(self, verbose=False): param = "" # conditional gate - if isinstance(op, OpNode) and op.op.condition: + if op.op.condition: c_xy = [ c_anchors[ii].plot_coord(this_anc, layer_width, self._x_offset) for ii in self._clbit_dict diff --git a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml index db10928da7ac..08823b0baeea 100644 --- a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml +++ b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml @@ -3,7 +3,7 @@ deprecations: - | The :class:`qiskit.dagcircuit.dagnode.DAGNode` is being deprecated as a standalone class and will be used in the future only as the parent class for - :class:`qiskit.dagcircuit.dagnode.OpNode`, :class:`qiskit.dagcircuit.dagnode.InNode`, - and :class:`qiskit.dagcircuit.dagnode.OutNode`. As part of this deprecation, the - following kwargs in DAGNode are being deprecated - ``type``, ``op``, - and ``wire``. + :class:`qiskit.dagcircuit.dagnode.DAGOpNode`, :class:`qiskit.dagcircuit.dagnode.DAGInNode`, + and :class:`qiskit.dagcircuit.dagnode.DAGOutNode`. As part of this deprecation, the + following kwargs and associated attributes in DAGNode are being deprecated - ``type``, + ``op``, and ``wire``. diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index e76948ff3321..ac585a2eba36 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -32,7 +32,7 @@ from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, pulse from qiskit.circuit import Parameter, Gate, Qubit, Clbit from qiskit.compiler import transpile -from qiskit.dagcircuit import OutNode +from qiskit.dagcircuit import DAGOutNode from qiskit.converters import circuit_to_dag from qiskit.circuit.library import CXGate, U3Gate, U2Gate, U1Gate, RXGate, RYGate, RZGate from qiskit.test import QiskitTestCase @@ -679,7 +679,7 @@ def test_move_measurements(self): meas_nodes = out_dag.named_nodes("measure") for meas_node in meas_nodes: is_last_measure = all( - isinstance(after_measure, OutNode) + isinstance(after_measure, DAGOutNode) for after_measure in out_dag.quantum_successors(meas_node) ) self.assertTrue(is_last_measure) diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index 12898dad4ee7..ff5d8467c099 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -19,7 +19,7 @@ import retworkx as rx from numpy import pi -from qiskit.dagcircuit import DAGCircuit, OpNode, InNode, OutNode +from qiskit.dagcircuit import DAGCircuit, DAGOpNode, DAGInNode, DAGOutNode from qiskit.circuit import QuantumRegister from qiskit.circuit import ClassicalRegister, Clbit from qiskit.circuit import QuantumCircuit, Qubit @@ -57,11 +57,11 @@ def raise_if_dagcircuit_invalid(dag): # Every node should be of type in, out, or op. # All input/output nodes should be present in input_map/output_map. for node in dag._multi_graph.nodes(): - if isinstance(node, InNode): + if isinstance(node, DAGInNode): assert node is dag.input_map[node.wire] - elif isinstance(node, OutNode): + elif isinstance(node, DAGOutNode): assert node is dag.output_map[node.wire] - elif isinstance(node, OpNode): + elif isinstance(node, DAGOpNode): continue else: raise DAGCircuitError(f"Found node of unexpected type: {type(node)}") @@ -88,8 +88,8 @@ def raise_if_dagcircuit_invalid(dag): assert in_node.wire == wire assert out_node.wire == wire - assert isinstance(in_node, InNode) - assert isinstance(out_node, OutNode) + assert isinstance(in_node, DAGInNode) + assert isinstance(out_node, DAGOutNode) # Every wire should be propagated by exactly one edge between nodes. for wire in dag.wires: @@ -512,8 +512,8 @@ def test_quantum_successors(self): next(successor_cnot) self.assertTrue( - (isinstance(successor1, OutNode) and isinstance(successor2.op, Reset)) - or (isinstance(successor2, OutNode) and isinstance(successor1.op, Reset)) + (isinstance(successor1, DAGOutNode) and isinstance(successor2.op, Reset)) + or (isinstance(successor2, DAGOutNode) and isinstance(successor1.op, Reset)) ) def test_is_successor(self): @@ -561,8 +561,8 @@ def test_quantum_predecessors(self): next(predecessor_cnot) self.assertTrue( - (isinstance(predecessor1, InNode) and isinstance(predecessor2.op, Reset)) - or (isinstance(predecessor2, InNode) and isinstance(predecessor1.op, Reset)) + (isinstance(predecessor1, DAGInNode) and isinstance(predecessor2.op, Reset)) + or (isinstance(predecessor2, DAGInNode) and isinstance(predecessor1.op, Reset)) ) def test_is_predecessor(self): @@ -660,7 +660,7 @@ def test_topological_nodes(self): (cr[1], []), ] self.assertEqual( - [(i.op.name if isinstance(i, OpNode) else i.wire, i.qargs) for i in named_nodes], + [(i.op.name if isinstance(i, DAGOpNode) else i.wire, i.qargs) for i in named_nodes], expected, ) @@ -703,7 +703,7 @@ def test_dag_nodes_on_wire(self): def test_dag_nodes_on_wire_multiple_successors(self): """ - Test that if an OpNode has multiple successors in the DAG along one wire, they are all + Test that if an DAGOpNode has multiple successors in the DAG along one wire, they are all retrieved in order. This could be the case for a circuit such as q0_0: |0>──■─────────■── @@ -958,7 +958,7 @@ def test_layers_basic(self): self.assertEqual(5, len(layers)) name_layers = [ - [node.op.name for node in layer["graph"].nodes() if isinstance(node, OpNode)] + [node.op.name for node in layer["graph"].nodes() if isinstance(node, DAGOpNode)] for layer in layers ] @@ -970,7 +970,12 @@ def test_layers_maintains_order(self): qr = QuantumRegister(1, "q0") # the order the nodes should be in - truth = [(InNode, qr[0], 0), (OpNode, "x", 2), (OpNode, "id", 3), (OutNode, qr[0], 1)] + truth = [ + (DAGInNode, qr[0], 0), + (DAGOpNode, "x", 2), + (DAGOpNode, "id", 3), + (DAGOutNode, qr[0], 1), + ] # this only occurred sometimes so has to be run more than once # (10 times seemed to always be enough for this bug to show at least once) @@ -982,7 +987,7 @@ def test_layers_maintains_order(self): dag1.apply_operation_back(IGate(), [qr[0]], []) comp = [ - (type(nd), nd.op.name if isinstance(nd, OpNode) else nd.wire, nd._node_id) + (type(nd), nd.op.name if isinstance(nd, DAGOpNode) else nd.wire, nd._node_id) for nd in dag1.topological_nodes() ] self.assertEqual(comp, truth) diff --git a/test/python/transpiler/test_consolidate_blocks.py b/test/python/transpiler/test_consolidate_blocks.py index 4ab243ac91f6..3fbe663352b0 100644 --- a/test/python/transpiler/test_consolidate_blocks.py +++ b/test/python/transpiler/test_consolidate_blocks.py @@ -19,7 +19,7 @@ from qiskit.circuit import QuantumCircuit, QuantumRegister from qiskit.circuit.library import U2Gate -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.extensions import UnitaryGate from qiskit.converters import circuit_to_dag from qiskit.transpiler.passes import ConsolidateBlocks @@ -95,7 +95,7 @@ def test_topological_order_preserved(self): pass_.property_set["block_list"] = [block_1, block_2] new_dag = pass_.run(dag) - new_topo_ops = [i for i in new_dag.topological_op_nodes() if isinstance(i, OpNode)] + new_topo_ops = [i for i in new_dag.topological_op_nodes()] self.assertEqual(len(new_topo_ops), 2) self.assertEqual(new_topo_ops[0].qargs, [qr[1], qr[2]]) self.assertEqual(new_topo_ops[1].qargs, [qr[0], qr[1]]) diff --git a/test/python/transpiler/test_faulty_backend.py b/test/python/transpiler/test_faulty_backend.py index f75ff63fcb94..df3408a355f4 100644 --- a/test/python/transpiler/test_faulty_backend.py +++ b/test/python/transpiler/test_faulty_backend.py @@ -19,7 +19,7 @@ from qiskit.test import QiskitTestCase from qiskit.converters import circuit_to_dag from qiskit.circuit.library import CXGate -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.transpiler import TranspilerError from ..providers.faulty_backends import ( FakeOurenseFaultyQ1, @@ -224,7 +224,7 @@ def assertIdleQ1(self, circuit): physical_qubits = QuantumRegister(5, "q") nodes = circuit_to_dag(circuit).nodes_on_wire(physical_qubits[1]) for node in nodes: - if isinstance(node, OpNode): + if isinstance(node, DAGOpNode): raise AssertionError("Faulty Qubit Q1 not totally idle") @data(0, 1, 2, 3) diff --git a/test/python/transpiler/test_hoare_opt.py b/test/python/transpiler/test_hoare_opt.py index d1ffebddc19b..926879bb37b0 100644 --- a/test/python/transpiler/test_hoare_opt.py +++ b/test/python/transpiler/test_hoare_opt.py @@ -20,7 +20,7 @@ from qiskit import QuantumCircuit from qiskit.test import QiskitTestCase from qiskit.circuit.library import XGate, RZGate, CSwapGate, SwapGate -from qiskit.dagcircuit import OpNode +from qiskit.dagcircuit import DAGOpNode from qiskit.quantum_info import Statevector @@ -335,16 +335,16 @@ def test_is_identity(self): """The is_identity function determines whether a pair of gates forms the identity, when ignoring control qubits. """ - seq = [OpNode(op=XGate().control()), OpNode(op=XGate().control(2))] + seq = [DAGOpNode(op=XGate().control()), DAGOpNode(op=XGate().control(2))] self.assertTrue(HoareOptimizer()._is_identity(seq)) seq = [ - OpNode(op=RZGate(-pi / 2).control()), - OpNode(op=RZGate(pi / 2).control(2)), + DAGOpNode(op=RZGate(-pi / 2).control()), + DAGOpNode(op=RZGate(pi / 2).control(2)), ] self.assertTrue(HoareOptimizer()._is_identity(seq)) - seq = [OpNode(op=CSwapGate()), OpNode(op=SwapGate())] + seq = [DAGOpNode(op=CSwapGate()), DAGOpNode(op=SwapGate())] self.assertTrue(HoareOptimizer()._is_identity(seq)) def test_multiple_pass(self): From fe1ab4806fae19110387e164c1eeb61b91a50ec8 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 24 Jun 2021 13:49:43 -0700 Subject: [PATCH 29/37] Lint --- qiskit/dagcircuit/dagcircuit.py | 2 +- qiskit/transpiler/passes/layout/apply_layout.py | 2 +- .../passes/optimization/template_matching/backward_match.py | 1 - .../passes/optimization/template_matching/forward_match.py | 1 - qiskit/visualization/matplotlib.py | 1 - test/python/transpiler/test_consolidate_blocks.py | 3 +-- 6 files changed, 3 insertions(+), 7 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 1b3b47e0cafd..8165b0f83b0f 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -1094,7 +1094,7 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): # Add edges from predecessor nodes to new node # and update predecessor nodes that change - all_cbits = self._bits_in_condition(node.op.condition) + all_cbits = self._bits_in_condition(condition) all_cbits.extend(m_cargs) al = [m_qargs, all_cbits] for q in itertools.chain(*al): diff --git a/qiskit/transpiler/passes/layout/apply_layout.py b/qiskit/transpiler/passes/layout/apply_layout.py index 48e38bd21b3f..63cf3b1fd710 100644 --- a/qiskit/transpiler/passes/layout/apply_layout.py +++ b/qiskit/transpiler/passes/layout/apply_layout.py @@ -13,7 +13,7 @@ """Transform a circuit with virtual qubits into a circuit with physical qubits.""" from qiskit.circuit import QuantumRegister -from qiskit.dagcircuit import DAGCircuit, DAGOpNode +from qiskit.dagcircuit import DAGCircuit from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError diff --git a/qiskit/transpiler/passes/optimization/template_matching/backward_match.py b/qiskit/transpiler/passes/optimization/template_matching/backward_match.py index e46e3ca19023..df817c701f92 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/backward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/backward_match.py @@ -27,7 +27,6 @@ import heapq from qiskit.circuit.controlledgate import ControlledGate -from qiskit.dagcircuit import DAGOpNode class Match: diff --git a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py index cdc2323309d7..3e996a572004 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py @@ -25,7 +25,6 @@ """ from qiskit.circuit.controlledgate import ControlledGate -from qiskit.dagcircuit import DAGOpNode class ForwardMatch: diff --git a/qiskit/visualization/matplotlib.py b/qiskit/visualization/matplotlib.py index fb7508e55037..1702385cedce 100644 --- a/qiskit/visualization/matplotlib.py +++ b/qiskit/visualization/matplotlib.py @@ -32,7 +32,6 @@ HAS_PYLATEX = False from qiskit.circuit import ControlledGate, Gate, Instruction -from qiskit.dagcircuit import DAGOpNode from qiskit.exceptions import MissingOptionalLibraryError from qiskit.visualization.qcstyle import DefaultStyle, set_style from qiskit.circuit import Delay diff --git a/test/python/transpiler/test_consolidate_blocks.py b/test/python/transpiler/test_consolidate_blocks.py index 3fbe663352b0..3276839cbeac 100644 --- a/test/python/transpiler/test_consolidate_blocks.py +++ b/test/python/transpiler/test_consolidate_blocks.py @@ -19,7 +19,6 @@ from qiskit.circuit import QuantumCircuit, QuantumRegister from qiskit.circuit.library import U2Gate -from qiskit.dagcircuit import DAGOpNode from qiskit.extensions import UnitaryGate from qiskit.converters import circuit_to_dag from qiskit.transpiler.passes import ConsolidateBlocks @@ -95,7 +94,7 @@ def test_topological_order_preserved(self): pass_.property_set["block_list"] = [block_1, block_2] new_dag = pass_.run(dag) - new_topo_ops = [i for i in new_dag.topological_op_nodes()] + new_topo_ops = list(new_dag.topological_op_nodes()) self.assertEqual(len(new_topo_ops), 2) self.assertEqual(new_topo_ops[0].qargs, [qr[1], qr[2]]) self.assertEqual(new_topo_ops[1].qargs, [qr[0], qr[1]]) From a990ded1c0e477fd1e72d5305950d65289178459 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Thu, 24 Jun 2021 16:42:28 -0700 Subject: [PATCH 30/37] Remove condition from apply_operation_back and front --- qiskit/dagcircuit/dagcircuit.py | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 8165b0f83b0f..3add1e78cc57 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -407,14 +407,13 @@ def _copy_circuit_metadata(self): return target_dag - def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): + def apply_operation_back(self, op, qargs=None, cargs=None): """Apply an operation to the output of the circuit. Args: op (qiskit.circuit.Instruction): the operation associated with the DAG node qargs (list[Qubit]): qubits that op will be applied to cargs (list[Clbit]): cbits that op will be applied to - condition (tuple or None): DEPRECATED optional condition (ClassicalRegister, int) Returns: DAGOpNode or DAGOutNode: the current max node @@ -422,13 +421,6 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): DAGCircuitError: if a leaf node is connected to multiple outputs """ - if condition: - warnings.warn( - "Use of condition arg is deprecated, set condition in instruction", - DeprecationWarning, - ) - op.condition = condition if op.condition is None else op.condition - qargs = qargs or [] cargs = cargs or [] @@ -451,27 +443,19 @@ def apply_operation_back(self, op, qargs=None, cargs=None, condition=None): ) return self._multi_graph[node_index] - def apply_operation_front(self, op, qargs, cargs, condition=None): + def apply_operation_front(self, op, qargs, cargs): """Apply an operation to the input of the circuit. Args: op (qiskit.circuit.Instruction): the operation associated with the DAG node qargs (list[Qubit]): qubits that op will be applied to cargs (list[Clbit]): cbits that op will be applied to - condition (tuple or None): DEPRECATED optional condition (ClassicalRegister, int) Returns: DAGOpNode or DAGOutNode: the current max node Raises: DAGCircuitError: if initial nodes connected to multiple out edges """ - if condition: - warnings.warn( - "Use of condition arg is deprecated, set condition in instruction", - DeprecationWarning, - ) - - op.condition = condition if op.condition is None else op.condition all_cbits = self._bits_in_condition(op.condition) all_cbits.extend(cargs) From be2002f4c2b4e37e1f3cdb019972ba29d33b318c Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Mon, 28 Jun 2021 09:09:48 -0700 Subject: [PATCH 31/37] Unused import --- qiskit/transpiler/passes/optimization/collect_2q_blocks.py | 1 - 1 file changed, 1 deletion(-) diff --git a/qiskit/transpiler/passes/optimization/collect_2q_blocks.py b/qiskit/transpiler/passes/optimization/collect_2q_blocks.py index 82903c1d9fa3..10e5c848b7e8 100644 --- a/qiskit/transpiler/passes/optimization/collect_2q_blocks.py +++ b/qiskit/transpiler/passes/optimization/collect_2q_blocks.py @@ -15,7 +15,6 @@ from collections import defaultdict from qiskit.circuit import Gate -from qiskit.dagcircuit import DAGOpNode from qiskit.transpiler.basepasses import AnalysisPass From 92c369385b428bf10fb68fdd8d2fd44f6baa6d90 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Tue, 29 Jun 2021 08:07:12 -0700 Subject: [PATCH 32/37] Fix sort_key, qargs, and cargs and add deprecation testing --- qiskit/dagcircuit/dagnode.py | 87 +++++++++++++++++++---- test/python/dagcircuit/test_dagcircuit.py | 79 +++++++++++++------- 2 files changed, 127 insertions(+), 39 deletions(-) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index e3c7aa51bbeb..04f558b1072a 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -22,7 +22,7 @@ class DAGNode: """Parent class for DAGOpNode, DAGInNode, and DAGOutNode.""" - __slots__ = ["_type", "_op", "_qargs", "cargs", "_wire", "sort_key", "_node_id"] + __slots__ = ["_type", "_op", "_qargs", "_cargs", "_wire", "_node_id"] def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=None, nid=-1): """Create a node""" @@ -52,8 +52,24 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N DeprecationWarning, 2, ) - self._qargs = qargs if qargs is not None else [] - self.cargs = cargs if cargs is not None else [] + if qargs is not None: + warnings.warn( + "The DAGNode 'qargs' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use DAGOpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + self._qargs = qargs + if cargs is not None: + warnings.warn( + "The DAGNode 'cargs' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "You can use DAGOpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + self._cargs = cargs if wire is not None: warnings.warn( "The DAGNode 'wire' kwarg is deprecated as of 0.18.0 and " @@ -64,7 +80,6 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N ) self._wire = wire self._node_id = nid - self.sort_key = str(self._qargs) @property def type(self): @@ -164,13 +179,52 @@ def qargs(self): """ Returns list of Qubit, else an empty list. """ + warnings.warn( + "The DAGNode 'qargs' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGOpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) return self._qargs @qargs.setter def qargs(self, new_qargs): """Sets the qargs to be the given list of qargs.""" + warnings.warn( + "The DAGNode 'qargs' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGOpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) self._qargs = new_qargs - self.sort_key = str(new_qargs) + + @property + def cargs(self): + """ + Returns list of Clbit, else an empty list. + """ + warnings.warn( + "The DAGNode 'cargs' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGOpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + return self._cargs + + @cargs.setter + def cargs(self, new_cargs): + """Sets the cargs to be the given list of cargs.""" + warnings.warn( + "The DAGNode 'cargs' attribute is deprecated as of 0.18.0 and " + "will be removed no earlier than 3 months after the release date. " + "Use DAGOpNode instead of DAGNode.", + DeprecationWarning, + 2, + ) + self._cargs = new_cargs @property def wire(self): @@ -266,13 +320,16 @@ def semantic_eq(node1, node2, bit_indices1=None, bit_indices2=None): class DAGOpNode(DAGNode): """Object to represent an Instruction at a node in the DAGCircuit.""" - __slots__ = ["_type", "op"] + __slots__ = ["_type", "op", "qargs", "cargs", "sort_key"] def __init__(self, op, qargs=None, cargs=None): """Create an Instruction node""" - super().__init__(qargs=qargs, cargs=cargs) - self._type = "op" + super().__init__() + self._type = "op" # Remove when DAGNode.type is removed self.op = op + self.qargs = qargs + self.cargs = cargs + self.sort_key = str(self.qargs) @property def name(self): @@ -312,22 +369,28 @@ def condition(self, new_condition): class DAGInNode(DAGNode): """Object to represent an incoming wire node in the DAGCircuit.""" - __slots__ = ["_type", "wire"] + __slots__ = ["_type", "wire", "sort_key"] def __init__(self, wire): """Create an incoming node""" super().__init__() - self._type = "in" + self._type = "in" # Remove when DAGNode.type is removed self.wire = wire + # TODO sort_key which is used in dagcircuit.topological_nodes + # only works as str([]) for DAGInNodes. Need to figure out why. + self.sort_key = str([]) class DAGOutNode(DAGNode): """Object to represent an outgoing wire node in the DAGCircuit.""" - __slots__ = ["_type", "wire"] + __slots__ = ["_type", "wire", "sort_key"] def __init__(self, wire): """Create an outgoing node""" super().__init__() - self._type = "out" + self._type = "out" # Remove when DAGNode.type is removed self.wire = wire + # TODO sort_key which is used in dagcircuit.topological_nodes + # only works as str([]) for DAGOutNodes. Need to figure out why. + self.sort_key = str([]) diff --git a/test/python/dagcircuit/test_dagcircuit.py b/test/python/dagcircuit/test_dagcircuit.py index ff5d8467c099..5cbf2fe739fa 100644 --- a/test/python/dagcircuit/test_dagcircuit.py +++ b/test/python/dagcircuit/test_dagcircuit.py @@ -643,24 +643,24 @@ def test_topological_nodes(self): qr = self.dag.qregs["qr"] cr = self.dag.cregs["cr"] expected = [ - (qr[0], []), - (qr[1], []), + qr[0], + qr[1], ("cx", [self.qubit0, self.qubit1]), ("h", [self.qubit0]), - (qr[2], []), + qr[2], ("cx", [self.qubit2, self.qubit1]), ("cx", [self.qubit0, self.qubit2]), ("h", [self.qubit2]), - (qr[0], []), - (qr[1], []), - (qr[2], []), - (cr[0], []), - (cr[0], []), - (cr[1], []), - (cr[1], []), + qr[0], + qr[1], + qr[2], + cr[0], + cr[0], + cr[1], + cr[1], ] self.assertEqual( - [(i.op.name if isinstance(i, DAGOpNode) else i.wire, i.qargs) for i in named_nodes], + [((i.op.name, i.qargs) if isinstance(i, DAGOpNode) else i.wire) for i in named_nodes], expected, ) @@ -1134,6 +1134,20 @@ def test_dag_from_networkx(self): self.assertEqual(dag, from_nx_dag) + def test_node_params_equal_unequal(self): + """Test node params are equal or unequal.""" + qc1 = QuantumCircuit(1) + qc2 = QuantumCircuit(1) + qc3 = QuantumCircuit(1) + qc1.p(pi / 4, 0) + dag1 = circuit_to_dag(qc1) + qc2.p(pi / 4, 0) + dag2 = circuit_to_dag(qc2) + qc3.p(pi / 2, 0) + dag3 = circuit_to_dag(qc3) + self.assertEqual(dag1, dag2) + self.assertNotEqual(dag2, dag3) + class TestDagSubstitute(QiskitTestCase): """Test substituting a dag node with a sub-dag""" @@ -1471,22 +1485,33 @@ def test_clbit_conditional(self): ) -class TestNodeEqual(QiskitTestCase): - """Test dag nodes are equal.""" - - def test_node_params_equal_unequal(self): - """Test node params are equal or unequal.""" - qc1 = QuantumCircuit(1) - qc2 = QuantumCircuit(1) - qc3 = QuantumCircuit(1) - qc1.p(pi / 4, 0) - dag1 = circuit_to_dag(qc1) - qc2.p(pi / 4, 0) - dag2 = circuit_to_dag(qc2) - qc3.p(pi / 2, 0) - dag3 = circuit_to_dag(qc3) - self.assertEqual(dag1, dag2) - self.assertNotEqual(dag2, dag3) +class TestDAGDeprecations(QiskitTestCase): + """Test DAG deprecations""" + + def test_DAGNode_deprecations(self): + """Test DAGNode deprecations.""" + from qiskit.dagcircuit import DAGNode + + qr = QuantumRegister(1, "qr") + cr = ClassicalRegister(1, "cr") + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + op_node = DAGNode(type="op", op=HGate(), qargs=[qr[0]], cargs=[cr[0]]) + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + in_node = DAGNode(type="in", wire=qr[0]) + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + out_node = DAGNode(type="out", wire=cr[0]) + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + _ = op_node.type + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + _ = op_node.op + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + _ = op_node.qargs + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + _ = op_node.cargs + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + _ = in_node.wire + with self.assertWarnsRegex(DeprecationWarning, "deprecated"): + _ = out_node.wire if __name__ == "__main__": From 794706172859fe264227f938ad58d0ef1d0076ac Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Wed, 7 Jul 2021 16:18:34 -0700 Subject: [PATCH 33/37] Move deprecations to 0.19.0 and remove DAGOpNode condition deprecation --- qiskit/dagcircuit/dagnode.py | 56 +++++++++++------------------------- 1 file changed, 16 insertions(+), 40 deletions(-) diff --git a/qiskit/dagcircuit/dagnode.py b/qiskit/dagcircuit/dagnode.py index 04f558b1072a..1fe6d9d238a8 100644 --- a/qiskit/dagcircuit/dagnode.py +++ b/qiskit/dagcircuit/dagnode.py @@ -28,7 +28,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N """Create a node""" if type is not None: warnings.warn( - "The DAGNode 'type' kwarg is deprecated as of 0.18.0 and " + "The DAGNode 'type' kwarg is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode, DAGInNode, or DAGOutNode instead of DAGNode.", DeprecationWarning, @@ -37,7 +37,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N self._type = type if op is not None: warnings.warn( - "The DAGNode 'op' kwarg is deprecated as of 0.18.0 and " + "The DAGNode 'op' kwarg is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date." "Use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -46,7 +46,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N self._op = op if name is not None: warnings.warn( - "The DAGNode 'name' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'name' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "You can use 'DAGNode.op.name' if the DAGNode is of type 'op'.", DeprecationWarning, @@ -54,7 +54,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N ) if qargs is not None: warnings.warn( - "The DAGNode 'qargs' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'qargs' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "You can use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -63,7 +63,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N self._qargs = qargs if cargs is not None: warnings.warn( - "The DAGNode 'cargs' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'cargs' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "You can use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -72,7 +72,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N self._cargs = cargs if wire is not None: warnings.warn( - "The DAGNode 'wire' kwarg is deprecated as of 0.18.0 and " + "The DAGNode 'wire' kwarg is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date." "Use DAGInNode or DAGOutNode instead of DAGNode.", DeprecationWarning, @@ -85,7 +85,7 @@ def __init__(self, type=None, op=None, name=None, qargs=None, cargs=None, wire=N def type(self): """Returns the type object""" warnings.warn( - "The DAGNode 'type' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'type' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode, DAGInNode, or DAGOutNode instead of DAGNode.", DeprecationWarning, @@ -97,7 +97,7 @@ def type(self): def type(self, dag_type): """Sets the value of the type object""" warnings.warn( - "The DAGNode 'type' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'type' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode, DAGInNode, or DAGOutNode instead of DAGNode.", DeprecationWarning, @@ -111,7 +111,7 @@ def type(self, dag_type): def op(self): """Returns the Instruction object corresponding to the op for the node, else None""" warnings.warn( - "The DAGNode 'op' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'op' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -125,7 +125,7 @@ def op(self): def op(self, data): """Sets the op for the node""" warnings.warn( - "The DAGNode 'op' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'op' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -180,7 +180,7 @@ def qargs(self): Returns list of Qubit, else an empty list. """ warnings.warn( - "The DAGNode 'qargs' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'qargs' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -192,7 +192,7 @@ def qargs(self): def qargs(self, new_qargs): """Sets the qargs to be the given list of qargs.""" warnings.warn( - "The DAGNode 'qargs' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'qargs' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -206,7 +206,7 @@ def cargs(self): Returns list of Clbit, else an empty list. """ warnings.warn( - "The DAGNode 'cargs' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'cargs' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -218,7 +218,7 @@ def cargs(self): def cargs(self, new_cargs): """Sets the cargs to be the given list of cargs.""" warnings.warn( - "The DAGNode 'cargs' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'cargs' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGOpNode instead of DAGNode.", DeprecationWarning, @@ -230,7 +230,7 @@ def cargs(self, new_cargs): def wire(self): """Returns the Bit object, else None.""" warnings.warn( - "The DAGNode 'wire' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'wire' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGInNode or DAGOutNode instead of DAGNode.", DeprecationWarning, @@ -244,7 +244,7 @@ def wire(self): def wire(self, data): """Sets the Bit object""" warnings.warn( - "The DAGNode 'wire' attribute is deprecated as of 0.18.0 and " + "The DAGNode 'wire' attribute is deprecated as of 0.19.0 and " "will be removed no earlier than 3 months after the release date. " "Use DAGInNode or DAGOutNode instead of DAGNode.", DeprecationWarning, @@ -341,30 +341,6 @@ def name(self, new_name): """Sets the Instruction name corresponding to the op for this node""" self.op.name = new_name - @property - def condition(self): - """Returns the condition of the node.op""" - warnings.warn( - "The DAGOpNode 'condition' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date. " - "You can use 'DAGOpNode.op.condition'.", - DeprecationWarning, - 2, - ) - return self.op.condition - - @condition.setter - def condition(self, new_condition): - """Sets the node.condition which sets the node.op.condition.""" - warnings.warn( - "The DAGOpNode 'condition' attribute is deprecated as of 0.18.0 and " - "will be removed no earlier than 3 months after the release date. " - "You can use 'DAGOpNode.op.condition'.", - DeprecationWarning, - 2, - ) - self.op.condition = new_condition - class DAGInNode(DAGNode): """Object to represent an incoming wire node in the DAGCircuit.""" From d763557c986aa31ca0730c7864208c1d6d5fbd8a Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Wed, 21 Jul 2021 15:01:48 -0700 Subject: [PATCH 34/37] Convert type to DAGOpNode and DAGInNode in bip_mapping and dynamical_coupling --- qiskit/transpiler/passes/routing/bip_mapping.py | 4 ++-- .../transpiler/passes/scheduling/dynamical_decoupling.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/qiskit/transpiler/passes/routing/bip_mapping.py b/qiskit/transpiler/passes/routing/bip_mapping.py index cb6306c3707b..cead72da8092 100644 --- a/qiskit/transpiler/passes/routing/bip_mapping.py +++ b/qiskit/transpiler/passes/routing/bip_mapping.py @@ -19,7 +19,7 @@ from qiskit.circuit import QuantumRegister from qiskit.circuit.library.standard_gates import SwapGate -from qiskit.dagcircuit import DAGCircuit +from qiskit.dagcircuit import DAGCircuit, DAGOpNode from qiskit.exceptions import MissingOptionalLibraryError from qiskit.transpiler import TransformationPass from qiskit.transpiler.exceptions import TranspilerError @@ -194,7 +194,7 @@ def run(self, dag): # map gates in k-th layer for node in layer["graph"].nodes(): - if node.type == "op": + if isinstance(node, DAGOpNode): mapped_dag.apply_operation_back( op=copy.deepcopy(node.op), qargs=[canonical_qreg[layout[q]] for q in node.qargs], diff --git a/qiskit/transpiler/passes/scheduling/dynamical_decoupling.py b/qiskit/transpiler/passes/scheduling/dynamical_decoupling.py index 23c5d64495f0..ed6e806eb4a5 100644 --- a/qiskit/transpiler/passes/scheduling/dynamical_decoupling.py +++ b/qiskit/transpiler/passes/scheduling/dynamical_decoupling.py @@ -18,6 +18,7 @@ from qiskit.circuit.delay import Delay from qiskit.circuit.reset import Reset from qiskit.circuit.library.standard_gates import IGate, UGate, U3Gate +from qiskit.dagcircuit import DAGOpNode, DAGInNode from qiskit.quantum_info.operators.predicates import matrix_equal from qiskit.quantum_info.synthesis import OneQubitEulerDecomposer from qiskit.transpiler.passes.optimization import Optimize1qGates @@ -191,7 +192,7 @@ def run(self, dag): pred = next(dag.predecessors(nd)) succ = next(dag.successors(nd)) if self._skip_reset_qubits: # discount initial delays - if pred.type == "in" or isinstance(pred.op, Reset): + if isinstance(pred, DAGInNode) or isinstance(pred.op, Reset): new_dag.apply_operation_back(nd.op, nd.qargs, nd.cargs) continue @@ -205,14 +206,14 @@ def run(self, dag): u_inv = self._dd_sequence[0].inverse().to_matrix() theta, phi, lam, phase = OneQubitEulerDecomposer().angles_and_phase(u_inv) # absorb the inverse into the successor (from left in circuit) - if succ.type == "op" and isinstance(succ.op, (UGate, U3Gate)): + if isinstance(succ, DAGOpNode) and isinstance(succ.op, (UGate, U3Gate)): theta_r, phi_r, lam_r = succ.op.params succ.op.params = Optimize1qGates.compose_u3( theta_r, phi_r, lam_r, theta, phi, lam ) sequence_gphase += phase # absorb the inverse into the predecessor (from right in circuit) - elif pred.type == "op" and isinstance(pred.op, (UGate, U3Gate)): + elif isinstance(pred, DAGOpNode) and isinstance(pred.op, (UGate, U3Gate)): theta_l, phi_l, lam_l = pred.op.params pred.op.params = Optimize1qGates.compose_u3( theta, phi, lam, theta_l, phi_l, lam_l From ddbc425ee02f8b81d7290d884e9c51ed43664f42 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Mon, 2 Aug 2021 15:44:35 -0700 Subject: [PATCH 35/37] Several dagcircuit changes and more release note --- qiskit/dagcircuit/dagcircuit.py | 10 ++++------ .../dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml | 4 ++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index cb085407a309..3d09e26ed0f3 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -417,7 +417,7 @@ def apply_operation_back(self, op, qargs=None, cargs=None): qargs (list[Qubit]): qubits that op will be applied to cargs (list[Clbit]): cbits that op will be applied to Returns: - DAGOpNode or DAGOutNode: the current max node + DAGOpNode: the node for the op that was added to the dag Raises: DAGCircuitError: if a leaf node is connected to multiple outputs @@ -453,7 +453,7 @@ def apply_operation_front(self, op, qargs, cargs): qargs (list[Qubit]): qubits that op will be applied to cargs (list[Clbit]): cbits that op will be applied to Returns: - DAGOpNode or DAGOutNode: the current max node + DAGOpNode: the node for the op that was added to the dag Raises: DAGCircuitError: if initial nodes connected to multiple out edges @@ -1000,7 +1000,6 @@ def substitute_node_with_dag(self, node, input_dag, wires=None): DAGCircuitError: if met with unexpected predecessor/successors """ in_dag = input_dag - # condition = None if not isinstance(node, DAGOpNode) else node.op.condition # the dag must be amended if used in a # conditional context. delete the op nodes and replay @@ -1314,9 +1313,8 @@ def descendants(self, node): def bfs_successors(self, node): """ - Returns an iterator of tuples of (DAGOpNode, DAGInNode, or DAGOutNode, [DAGOpNode or DAGOutNode]) - where the DAGOpNode, DAGInNode, or DAGOutNode is the current node and - [DAGOpNode or DAGOutNode] is its successors in BFS order. + Returns an iterator of tuples of (DAGNode, [DAGNodes]) where the DAGNode is the current node + and [DAGNode] is its successors in BFS order. """ return iter(rx.bfs_successors(self._multi_graph, node._node_id)) diff --git a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml index 08823b0baeea..ea9af9d297cb 100644 --- a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml +++ b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml @@ -7,3 +7,7 @@ deprecations: and :class:`qiskit.dagcircuit.dagnode.DAGOutNode`. As part of this deprecation, the following kwargs and associated attributes in DAGNode are being deprecated - ``type``, ``op``, and ``wire``. + + The previously deprecated `condition` kwarg has been removed from + :method:`qiskit.dagcircuit.dagcircuit.apply_operation_back` and + :method:`qiskit.dagcircuit.dagcircuit.apply_operation_front`. \ No newline at end of file From 054c487d3efc5365bb82b37d12257a730a34d2a3 Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Mon, 2 Aug 2021 15:58:14 -0700 Subject: [PATCH 36/37] Simplify idle_wires --- qiskit/dagcircuit/dagcircuit.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qiskit/dagcircuit/dagcircuit.py b/qiskit/dagcircuit/dagcircuit.py index 3d09e26ed0f3..04243b9c52a8 100644 --- a/qiskit/dagcircuit/dagcircuit.py +++ b/qiskit/dagcircuit/dagcircuit.py @@ -792,10 +792,10 @@ def idle_wires(self, ignore=None): for wire in self._wires: nodes = [ node - for node in self.nodes_on_wire(wire, only_ops=False) - if ((not isinstance(node, DAGOpNode) or node.op.name not in ignore)) + for node in self.nodes_on_wire(wire, only_ops=True) + if node.op.name not in ignore ] - if len(nodes) == 2: + if len(nodes) == 0: yield wire def size(self): From 8d5a4305f76dbbd2c3f136ef9e57fead6daa5cfd Mon Sep 17 00:00:00 2001 From: Edwin Navarro Date: Mon, 2 Aug 2021 20:39:36 -0700 Subject: [PATCH 37/37] Fix meth --- .../notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml index ea9af9d297cb..35582b9506ed 100644 --- a/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml +++ b/releasenotes/notes/dag_node_to_op_in_out_node-af2cf9c3e7686285.yaml @@ -9,5 +9,5 @@ deprecations: ``op``, and ``wire``. The previously deprecated `condition` kwarg has been removed from - :method:`qiskit.dagcircuit.dagcircuit.apply_operation_back` and - :method:`qiskit.dagcircuit.dagcircuit.apply_operation_front`. \ No newline at end of file + :meth:`qiskit.dagcircuit.dagcircuit.apply_operation_back` and + :meth:`qiskit.dagcircuit.dagcircuit.apply_operation_front`.