def run(self, dag): # sorted to so that they are in the order they appear in the DAG # so ancestors/descendants makes sense barriers = [nd for nd in dag.topological_op_nodes() if nd.name == 'barrier'] # get dict of barrier merges node_to_barrier_qubits = MergeAdjacentBarriers._collect_potential_merges(dag, barriers) if not node_to_barrier_qubits: return dag # add the merged barriers to a new DAG new_dag = DAGCircuit() for qreg in dag.qregs.values(): new_dag.add_qreg(qreg) for creg in dag.cregs.values(): new_dag.add_creg(creg) # go over current nodes, and add them to the new dag for node in dag.topological_op_nodes(): if node.name == 'barrier': if node in node_to_barrier_qubits: qubits = node_to_barrier_qubits[node] # qubits are stored as a set, need to convert to a list new_dag.apply_operation_back(Barrier(len(qubits)), qargs=list(qubits)) else: # copy the condition over too if node.condition: new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs, condition=node.condition) else: new_dag.apply_operation_back(node.op, qargs=node.qargs, cargs=node.cargs) return new_dag
def create_updated_dag(self, layers, barriers): """ Given a set of layers and barries, construct a new dag """ new_dag = DAGCircuit() for qreg in self.dag.qregs.values(): new_dag.add_qreg(qreg) for creg in self.dag.cregs.values(): new_dag.add_creg(creg) canonical_register = new_dag.qregs['q'] for i, layer in enumerate(layers): curr_barriers = barriers[i] for b in curr_barriers: current_qregs = [] for idx in b: current_qregs.append(canonical_register[idx]) new_dag.apply_operation_back(Barrier(len(b)), current_qregs, []) for triplet in layer: gate = triplet[0] new_dag.apply_operation_back(gate.op, gate.qargs, gate.cargs) for node in self.dag.op_nodes(): if isinstance(node.op, Measure): new_dag.apply_operation_back(node.op, node.qargs, node.cargs) return new_dag
def barrier(self, qubitlists): """Barrier instruction. """ if self.listen: qubits = [] for qubit in qubitlists: for j, _ in enumerate(qubit): qubits.append(qubit[j]) self.circuit.apply_operation_back(Barrier(qubits))
def run(self, dag): """Run the BarrierBeforeFinalMeasurements pass on `dag`.""" # Collect DAG nodes which are followed only by barriers or other measures. final_op_types = ['measure', 'barrier'] final_ops = [] for candidate_node in dag.named_nodes(*final_op_types): is_final_op = True 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): is_final_op = False break if is_final_op: final_ops.append(candidate_node) if not final_ops: return dag # Create a layer with the barrier and add registers from the original dag. barrier_layer = DAGCircuit() for qreg in dag.qregs.values(): barrier_layer.add_qreg(qreg) for creg in dag.cregs.values(): barrier_layer.add_creg(creg) # Add a barrier across all qubits so swap mapper doesn't add a swap # from an unmeasured qubit after a measure. final_qubits = dag.qubits() barrier_layer.apply_operation_back(Barrier(len(final_qubits)), list(final_qubits), []) # Preserve order of final ops collected earlier from the original DAG. ordered_final_nodes = [ node for node in dag.topological_op_nodes() if node in set(final_ops) ] # Move final ops to the new layer and append the new layer to the DAG. for final_node in ordered_final_nodes: barrier_layer.apply_operation_back(final_node.op, final_node.qargs, final_node.cargs) for final_op in final_ops: dag.remove_op_node(final_op) dag.compose(barrier_layer) # Merge the new barrier into any other barriers adjacent_pass = MergeAdjacentBarriers() return adjacent_pass.run(dag)
def run(self, dag): """Return a circuit with a barrier before last measurments.""" last_measures = [] for measure in dag.get_named_nodes('measure'): is_last_measurement = all([ after_measure in dag.output_map.values() for after_measure in dag.successors(measure) ]) if is_last_measurement: last_measures.append(measure) if not last_measures: return dag # create a laywer with the barrier and the measurements in last_measures operation dag.add_basis_element('barrier', len(last_measures), 0, 0) barried_layer = DAGCircuit() last_measures_nodes = [ dag.multi_graph.node[node] for node in last_measures ] last_measures_qubits = [ node['qargs'][0] for node in last_measures_nodes ] # Add registers from the original dag. for qreg in dag.qregs.values(): barried_layer.add_qreg(qreg) for creg in dag.cregs.values(): barried_layer.add_creg(creg) # Add the barrier operation barried_layer.apply_operation_back( Barrier(qubits=last_measures_qubits)) # Add the measurements to the behind the barrier for last_measures_node in last_measures_nodes: barried_layer.apply_operation_back(last_measures_node['op']) # Remove barriers in front the measurements in the original dag for last_measure in last_measures: for predecesor in dag.multi_graph.predecessors(last_measure): if dag.multi_graph.nodes[predecesor]['type'] == 'op' and \ isinstance(dag.multi_graph.nodes[predecesor]['op'], Barrier): dag._remove_op_node(predecesor) # Remove the measurements from the original dag for last_measure in last_measures: dag._remove_op_node(last_measure) # Extend the original dag with the barried layer dag.extend_back(barried_layer) return dag
def test_two_q_gates(self): """The method dag.twoQ_gates() returns all 2Q gate nodes""" self.dag.apply_operation_back(HGate(), [self.qubit0], []) self.dag.apply_operation_back(CnotGate(), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Barrier(2), [self.qubit0, self.qubit1], []) self.dag.apply_operation_back(Reset(), [self.qubit0], []) op_nodes = self.dag.twoQ_gates() self.assertEqual(len(op_nodes), 1) op_node = op_nodes.pop() self.assertIsInstance(op_node.op, Gate) self.assertEqual(len(op_node.qargs), 2)
def test_two_q_gates(self): """The method dag.twoQ_gates() returns all 2Q gate nodes""" self.dag.apply_operation_back(HGate(self.qubit0)) self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1)) self.dag.apply_operation_back(Barrier((self.qubit0, self.qubit1))) self.dag.apply_operation_back(Reset(self.qubit0)) op_nodes = self.dag.twoQ_gates() self.assertEqual(len(op_nodes), 1) op_node = op_nodes.pop() self.assertIsInstance(op_node["op"], Gate) self.assertEqual(len(op_node['qargs']), 2)
def test_get_gates_nodes(self): """The method dag.gate_nodes() returns all gate nodes""" self.dag.apply_operation_back(HGate(self.qubit0)) self.dag.apply_operation_back(CnotGate(self.qubit0, self.qubit1)) self.dag.apply_operation_back(Barrier((self.qubit0, self.qubit1))) self.dag.apply_operation_back(Reset(self.qubit0)) op_nodes = self.dag.gate_nodes() self.assertEqual(len(op_nodes), 2) op_node_1 = op_nodes.pop() op_node_2 = op_nodes.pop() self.assertIsInstance(self.dag.node(op_node_1)["op"], Gate) self.assertIsInstance(self.dag.node(op_node_2)["op"], Gate)
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. """ # if only got 1 or 0 barriers then can't merge if len(barriers) < 2: return None # mapping from the node that will be the main barrier to the # barrier object that gets built up node_to_barrier_qubits = {} # Start from the first barrier current_barrier = barriers[0] end_of_barrier = current_barrier current_barrier_nodes = [current_barrier] current_qubits = set(current_barrier.qargs) current_ancestors = dag.ancestors(current_barrier) current_descendants = dag.descendants(current_barrier) barrier_to_add = Barrier(len(current_qubits)) for next_barrier in barriers[1:]: # Ensure barriers are adjacent before checking if they are mergeable. if dag._multi_graph.has_edge(end_of_barrier, next_barrier): # Remove all barriers that have already been included in this new barrier from the # set of ancestors/descendants as they will be removed from the new DAG when it is # created. next_ancestors = { nd for nd in dag.ancestors(next_barrier) if nd not in current_barrier_nodes } next_descendants = { nd for nd in dag.descendants(next_barrier) if nd not in current_barrier_nodes } next_qubits = set(next_barrier.qargs) if (not current_qubits.isdisjoint(next_qubits) and current_ancestors.isdisjoint(next_descendants) and current_descendants.isdisjoint(next_ancestors)): # can be merged current_ancestors = current_ancestors | next_ancestors current_descendants = current_descendants | next_descendants current_qubits = current_qubits | next_qubits # update the barrier that will be added back to include this barrier barrier_to_add = Barrier(len(current_qubits)) end_of_barrier = next_barrier current_barrier_nodes.append(end_of_barrier) continue # Fallback if barriers are not adjacent or not mergeable. # store the previously made barrier if barrier_to_add: node_to_barrier_qubits[end_of_barrier] = current_qubits # reset the properties current_qubits = set(next_barrier.qargs) current_ancestors = dag.ancestors(next_barrier) current_descendants = dag.descendants(next_barrier) barrier_to_add = Barrier(len(current_qubits)) current_barrier_nodes = [] end_of_barrier = next_barrier current_barrier_nodes.append(end_of_barrier) if barrier_to_add: node_to_barrier_qubits[end_of_barrier] = current_qubits return node_to_barrier_qubits
def _process_node(self, node): """Carry out the action associated with a node.""" if node.type == "program": self._process_children(node) elif node.type == "qreg": qreg = QuantumRegister(node.index, node.name) self.dag.add_qreg(qreg) elif node.type == "creg": creg = ClassicalRegister(node.index, node.name) self.dag.add_creg(creg) elif node.type == "id": raise QiskitError("internal error: _process_node on id") elif node.type == "int": raise QiskitError("internal error: _process_node on int") elif node.type == "real": raise QiskitError("internal error: _process_node on real") elif node.type == "indexed_id": raise QiskitError("internal error: _process_node on indexed_id") elif node.type == "id_list": # We process id_list nodes when they are leaves of barriers. return [ self._process_bit_id(node_children) for node_children in node.children ] elif node.type == "primary_list": # We should only be called for a barrier. return [self._process_bit_id(m) for m in node.children] elif node.type == "gate": self._process_gate(node) elif node.type == "custom_unitary": self._process_custom_unitary(node) elif node.type == "universal_unitary": args = self._process_node(node.children[0]) qid = self._process_bit_id(node.children[1]) for element in qid: self.dag.apply_operation_back(UBase(*args, element), self.condition) elif node.type == "cnot": self._process_cnot(node) elif node.type == "expression_list": return node.children elif node.type == "binop": raise QiskitError("internal error: _process_node on binop") elif node.type == "prefix": raise QiskitError("internal error: _process_node on prefix") elif node.type == "measure": self._process_measure(node) elif node.type == "format": self.version = node.version() elif node.type == "barrier": ids = self._process_node(node.children[0]) qubits = [] for qubit in ids: for j, _ in enumerate(qubit): qubits.append(qubit[j]) self.dag.apply_operation_back(Barrier(len(qubits)), qubits, []) elif node.type == "reset": id0 = self._process_bit_id(node.children[0]) for i, _ in enumerate(id0): self.dag.apply_operation_back(Reset(), [id0[i]], [], self.condition) elif node.type == "if": self._process_if(node) elif node.type == "opaque": self._process_gate(node, opaque=True) elif node.type == "external": raise QiskitError("internal error: _process_node on external") else: raise QiskitError("internal error: undefined node type", node.type, "line=%s" % node.line, "file=%s" % node.file) return None
def run(self, dag): """Return a circuit with a barrier before last measurments.""" # Collect DAG nodes which are followed only by barriers or other measures. final_op_types = ['measure', 'barrier'] final_ops = [] for candidate_op in dag.named_nodes(*final_op_types): is_final_op = True for _, child_successors in dag.bfs_successors(candidate_op): if any( dag.node(suc)['type'] == 'op' and dag.node(suc)['op'].name not in final_op_types for suc in child_successors): is_final_op = False break if is_final_op: final_ops.append(candidate_op) if not final_ops: return dag # Create a layer with the barrier and add registers from the original dag. barrier_layer = DAGCircuit() for qreg in dag.qregs.values(): barrier_layer.add_qreg(qreg) for creg in dag.cregs.values(): barrier_layer.add_creg(creg) final_qubits = set( dag.node(final_op)['qargs'][0] for final_op in final_ops) new_barrier_id = barrier_layer.apply_operation_back( Barrier(qubits=final_qubits)) # Preserve order of final ops collected earlier from the original DAG. ordered_node_ids = [ node_id for node_id in dag.node_nums_in_topological_order() if node_id in set(final_ops) ] ordered_final_nodes = [dag.node(node) for node in ordered_node_ids] # Move final ops to the new layer and append the new layer to the DAG. for final_node in ordered_final_nodes: barrier_layer.apply_operation_back(final_node['op']) for final_op in final_ops: dag._remove_op_node(final_op) # Check to see if the new barrier added to the DAG is equivalent to any # existing barriers, and if so, consolidate the two. our_ancestors = barrier_layer.ancestors(new_barrier_id) our_descendants = barrier_layer.descendants(new_barrier_id) our_qubits = final_qubits existing_barriers = barrier_layer.named_nodes('barrier') existing_barriers.remove(new_barrier_id) for candidate_barrier in existing_barriers: their_ancestors = barrier_layer.ancestors(candidate_barrier) their_descendants = barrier_layer.descendants(candidate_barrier) their_qubits = set( barrier_layer.node(candidate_barrier)['op'].qargs) if (not our_qubits.isdisjoint(their_qubits) and our_ancestors.isdisjoint(their_descendants) and our_descendants.isdisjoint(their_ancestors)): merge_barrier = Barrier(qubits=(our_qubits | their_qubits)) merge_barrier_id = barrier_layer.apply_operation_front( merge_barrier) our_ancestors = our_ancestors | their_ancestors our_descendants = our_descendants | their_descendants barrier_layer._remove_op_node(candidate_barrier) barrier_layer._remove_op_node(new_barrier_id) new_barrier_id = merge_barrier_id dag.extend_back(barrier_layer) return dag
def run(self, dag): """Return a circuit with a barrier before last measurments.""" # Collect DAG nodes which are followed only by barriers or other measures. final_op_types = ['measure', 'barrier'] final_ops = [] for candidate_node in dag.named_nodes(*final_op_types): is_final_op = True 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): is_final_op = False break if is_final_op: final_ops.append(candidate_node) if not final_ops: return dag # Create a layer with the barrier and add registers from the original dag. barrier_layer = DAGCircuit() for qreg in dag.qregs.values(): barrier_layer.add_qreg(qreg) for creg in dag.cregs.values(): barrier_layer.add_creg(creg) final_qubits = set(final_op.qargs[0] for final_op in final_ops) new_barrier_node = barrier_layer.apply_operation_back( Barrier(len(final_qubits)), list(final_qubits), []) # Preserve order of final ops collected earlier from the original DAG. ordered_final_nodes = [node for node in dag.nodes_in_topological_order() if node in set(final_ops)] # Move final ops to the new layer and append the new layer to the DAG. for final_node in ordered_final_nodes: barrier_layer.apply_operation_back(final_node.op, final_node.qargs, final_node.cargs) for final_op in final_ops: dag.remove_op_node(final_op) # Check to see if the new barrier added to the DAG is equivalent to any # existing barriers, and if so, consolidate the two. our_ancestors = barrier_layer.ancestors(new_barrier_node) our_descendants = barrier_layer.descendants(new_barrier_node) our_qubits = final_qubits existing_barriers = sorted(barrier_layer.named_nodes('barrier')) # remove element from the list for i, node in enumerate(existing_barriers): if node == new_barrier_node: del existing_barriers[i] break for candidate_barrier in existing_barriers: their_ancestors = barrier_layer.ancestors(candidate_barrier) their_descendants = barrier_layer.descendants(candidate_barrier) their_qubits = set(candidate_barrier.qargs) if ( not our_qubits.isdisjoint(their_qubits) and our_ancestors.isdisjoint(their_descendants) and our_descendants.isdisjoint(their_ancestors) ): merge_barrier_qubits = (our_qubits | their_qubits) merge_barrier_node = barrier_layer.apply_operation_front( Barrier(len(merge_barrier_qubits)), merge_barrier_qubits, []) our_ancestors = our_ancestors | their_ancestors our_descendants = our_descendants | their_descendants barrier_layer.remove_op_node(candidate_barrier) barrier_layer.remove_op_node(new_barrier_node) new_barrier_node = merge_barrier_node dag.extend_back(barrier_layer) return dag