def test_block_spanning_two_regs_different_index(self): """blocks spanning wires on different quantum registers work when the wires could have conflicting indices. This was raised in #2806 when a CX was applied across multiple registers and their indices collided, raising an error.""" qr0 = QuantumRegister(1, "qr0") qr1 = QuantumRegister(2, "qr1") qc = QuantumCircuit(qr0, qr1) qc.cx(qr0[0], qr1[1]) dag = circuit_to_dag(qc) pass_ = ConsolidateBlocks(force_consolidate=True) pass_.property_set["block_list"] = [list(dag.topological_op_nodes())] new_dag = pass_.run(dag) original_unitary = UnitaryGate(Operator(qc)) from qiskit.converters import dag_to_circuit new_unitary = UnitaryGate(Operator(dag_to_circuit(new_dag))) self.assertEqual(original_unitary, new_unitary)
def _transpilation(circuit, backend=None, basis_gates=None, coupling_map=None, initial_layout=None, seed_mapper=None, pass_manager=None): """Perform transpilation of a single circuit. Args: circuit (QuantumCircuit): A circuit to transpile. backend (BaseBackend): a backend to compile for basis_gates (str): comma-separated basis gate set to compile to coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping seed_mapper (int): random seed for the swap_mapper pass_manager (PassManager): a pass_manager for the transpiler stage Returns: QuantumCircuit: A transpiled circuit. Raises: TranspilerError: if args are not complete for transpiler to function. """ dag = circuit_to_dag(circuit) if not backend and not initial_layout: raise TranspilerError('initial layout not supplied, and cannot ' 'be inferred from backend.') if (initial_layout is None and not backend.configuration().simulator and not _matches_coupling_map(dag, coupling_map)): initial_layout = _pick_best_layout(dag, backend) final_dag, final_layout = transpile_dag(dag, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, get_layout=True, format='dag', seed_mapper=seed_mapper, pass_manager=pass_manager) final_dag.layout = [[k, v] for k, v in final_layout.items()] if final_layout else None out_circuit = dag_to_circuit(final_dag) return out_circuit
def _remap_circuit_faulty_backend(circuit, num_qubits, backend_prop, faulty_qubits_map): faulty_qubits = backend_prop.faulty_qubits() if backend_prop else [] disconnected_qubits = {k for k, v in faulty_qubits_map.items() if v is None}.difference( faulty_qubits ) faulty_qubits_map_reverse = {v: k for k, v in faulty_qubits_map.items()} if faulty_qubits: faulty_qreg = circuit._create_qreg(len(faulty_qubits), "faulty") else: faulty_qreg = [] if disconnected_qubits: disconnected_qreg = circuit._create_qreg(len(disconnected_qubits), "disconnected") else: disconnected_qreg = [] new_layout = Layout() faulty_qubit = 0 disconnected_qubit = 0 for real_qubit in range(num_qubits): if faulty_qubits_map[real_qubit] is not None: new_layout[real_qubit] = circuit._layout[faulty_qubits_map[real_qubit]] else: if real_qubit in faulty_qubits: new_layout[real_qubit] = faulty_qreg[faulty_qubit] faulty_qubit += 1 else: new_layout[real_qubit] = disconnected_qreg[disconnected_qubit] disconnected_qubit += 1 physical_layout_dict = {} for index, qubit in enumerate(circuit.qubits): physical_layout_dict[qubit] = faulty_qubits_map_reverse[index] for qubit in faulty_qreg[:] + disconnected_qreg[:]: physical_layout_dict[qubit] = new_layout[qubit] dag_circuit = circuit_to_dag(circuit) apply_layout_pass = ApplyLayout() apply_layout_pass.property_set["layout"] = Layout(physical_layout_dict) circuit = dag_to_circuit(apply_layout_pass.run(dag_circuit)) circuit._layout = new_layout return circuit
def test_2q_hamiltonian(self): """test 2 qubit hamiltonian""" qr = QuantumRegister(2) cr = ClassicalRegister(2) qc = QuantumCircuit(qr, cr) matrix = Operator.from_label("XY") qc.x(qr[0]) theta = Parameter("theta") uni2q = HamiltonianGate(matrix, theta) qc.append(uni2q, [qr[0], qr[1]]) qc2 = qc.bind_parameters({theta: -np.pi / 2}) dag = circuit_to_dag(qc2) nodes = dag.two_qubit_ops() self.assertEqual(len(nodes), 1) dnode = nodes[0] self.assertIsInstance(dnode.op, HamiltonianGate) self.assertEqual(dnode.qargs, [qr[0], qr[1]]) # Equality based on Pauli exponential identity np.testing.assert_array_almost_equal(dnode.op.to_matrix(), 1j * matrix.data) qc3 = dag_to_circuit(dag) self.assertEqual(qc2, qc3)
def run(self, circuit): """Run all the passes on a QuantumCircuit Args: circuit (QuantumCircuit): circuit to transform via all the registered passes Returns: QuantumCircuit: Transformed circuit. """ name = circuit.name dag = circuit_to_dag(circuit) del circuit self.reset() # Reset passmanager instance before starting for passset in self.working_list: for pass_ in passset: dag = self._do_pass(pass_, dag, passset.options) circuit = dag_to_circuit(dag) circuit.name = name circuit.layout = self.property_set['layout'] return circuit
def test_cx_bell_to_crz(self): """Verify we can translate a CX bell to CRZ,U.""" bell = QuantumCircuit(2) bell.h(0) bell.cx(0, 1) in_dag = circuit_to_dag(bell) out_dag = BasisTranslator(std_eqlib, ["crz", "u"]).run(in_dag) self.assertTrue(set(out_dag.count_ops()).issubset(["crz", "u"])) self.assertEqual(Operator(bell), Operator(dag_to_circuit(out_dag))) qr = QuantumRegister(2, "q") expected = QuantumCircuit(qr) expected.u(pi / 2, 0, pi, 0) expected.u(0, 0, pi / 2, 0) expected.u(pi / 2, 0, pi, 1) expected.crz(pi, 0, 1) expected.u(pi / 2, 0, pi, 1) expected_dag = circuit_to_dag(expected) self.assertEqual(out_dag, expected_dag)
def replace_node(node, instr_map): target_params, target_dag = instr_map[node.op.name, node.op.num_qubits] if len(node.op.params) != len(target_params): raise TranspilerError( "Translation num_params not equal to op num_params." "Op: {} {} Translation: {}\n{}".format( node.op.params, node.op.name, target_params, target_dag ) ) if node.op.params: # Convert target to circ and back to assign_parameters, since # DAGCircuits won't have a ParameterTable. from qiskit.converters import dag_to_circuit, circuit_to_dag target_circuit = dag_to_circuit(target_dag) target_circuit.assign_parameters( dict(zip_longest(target_params, node.op.params)), inplace=True ) bound_target_dag = circuit_to_dag(target_circuit) else: bound_target_dag = target_dag if len(bound_target_dag.op_nodes()) == 1 and len( bound_target_dag.op_nodes()[0].qargs ) == len(node.qargs): dag_op = bound_target_dag.op_nodes()[0].op # dag_op may be the same instance as other ops in the dag, # so if there is a condition, need to copy if node.op.condition: dag_op = dag_op.copy() dag.substitute_node(node, dag_op, inplace=True) if bound_target_dag.global_phase: dag.global_phase += bound_target_dag.global_phase else: dag.substitute_node_with_dag(node, bound_target_dag)
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run a preconfigured optimisation pass on the circuit and route for the given backend. :param dag: The circuit to optimise and route :return: The modified circuit """ qc = dag_to_circuit(dag) old_parameters = qc.parameters circ = qiskit_to_tk(qc) self._pass.apply(circ) qc = tk_to_qiskit(circ) new_param_lookup = {p._symbol_expr: p for p in qc.parameters} subs_map = { new_param_lookup[p._symbol_expr]: p for p in old_parameters } qc.assign_parameters(subs_map, inplace=True) newdag = circuit_to_dag(qc) newdag.name = dag.name return newdag
def run(self, circuit:Circuit, shots:int, fit_to_constraints=True, seed:int=None) -> np.ndarray: """Run a circuit on Qiskit Aer Qasm simulator. :param circuit: The circuit to run :type circuit: Circuit :param shots: Number of shots (repeats) to run :type shots: int :param fit_to_constraints: Compile the circuit to meet the contstraints of the backend, defaults to True :type fit_to_constraints: bool, optional :param seed: random seed to for simulator :type seed: int :return: Table of shot results, each row is a shot, columns are ordered by qubit ordering. Values are 0 or 1, corresponding to qubit basis states. :rtype: numpy.ndarray """ c = circuit.copy() if fit_to_constraints : Transform.RebaseToQiskit().apply(c) dag = tk_to_dagcircuit(c) qc = dag_to_circuit(dag) qobj = assemble(qc, shots=shots, seed_simulator=seed, memory=True) job = self._backend.run(qobj, noise_model=self.noise_model) return bin_str_2_table(job.result().get_memory(qc))
def __call__(self, circuit, property_set=None): """Runs the pass on circuit. Args: circuit (QuantumCircuit): the dag on which the pass is run. property_set (PropertySet or dict or None): input/output property set. An analysis pass might change the property set in-place. Returns: QuantumCircuit: If on transformation pass, the resulting QuantumCircuit. If analysis pass, the input circuit. """ from qiskit.converters import circuit_to_dag, dag_to_circuit from qiskit.dagcircuit.dagcircuit import DAGCircuit property_set_ = None if isinstance(property_set, dict): # this includes (dict, PropertySet) property_set_ = PropertySet(property_set) if isinstance(property_set_, PropertySet): self.property_set = property_set_ result = self.run(circuit_to_dag(circuit)) result_circuit = circuit if isinstance(property_set, dict): # this includes (dict, PropertySet) property_set.clear() property_set.update(self.property_set) if isinstance(result, DAGCircuit): result_circuit = dag_to_circuit(result) elif result is None: result_circuit = circuit.copy() if self.property_set["layout"]: result_circuit._layout = self.property_set["layout"] return result_circuit
def test_plugin_configuration(self): """Tests plugin with a custom configuration.""" config = { "network_layout": "sequ", "connectivity_type": "full", "depth": 0, "seed": 12345, "optimizer": SLSQP(), } transpiler_pass = UnitarySynthesis( basis_gates=["rx", "ry", "rz", "cx"], method="aqc", plugin_config=config) dag = circuit_to_dag(self._qc) dag = transpiler_pass.run(dag) approx_circuit = dag_to_circuit(dag) approx_unitary = Operator(approx_circuit).data np.testing.assert_array_almost_equal(self._target_unitary, approx_unitary, 3)
def apply(self, operation, wires, par): # type: (Any, Sequence[int], List) -> None """Apply a quantum operation. Args: operation (str): name of the operation wires (Sequence[int]): subsystems the operation is applied on par (tuple): parameters for the operation """ mapped_operation = self._operation_map[operation] if isinstance(mapped_operation, BasisState) and not self._first_operation: raise DeviceError( "Operation {} cannot be used after other Operations have already been applied " "on a {} device.".format(operation, self.short_name)) self._first_operation = False qregs = [(self._reg, i) for i in wires] if isinstance(mapped_operation, str): dag = circuit_to_dag(QuantumCircuit(self._reg, self._creg, name='')) instruction = Instruction(mapped_operation, par, qregs, [], circuit=self._circuit) dag.apply_operation_back(instruction) qc = dag_to_circuit(dag) self._circuit = self._circuit + qc elif isinstance(mapped_operation, QiskitInstructions): op = mapped_operation # type: QiskitInstructions op.apply(qregs=qregs, param=list(par), circuit=self._circuit) else: raise ValueError( "The operation is not of an expected type. This is a software bug!" )
def apply(self, operation, wires, par): mapped_operation = self._operation_map[operation] qregs = [self._reg[i] for i in wires] if operation == "QubitStateVector": if self.backend_name == "unitary_simulator": raise QuantumFunctionError( "The QubitStateVector operation is not supported on the unitary simulator backend." ) if len(par[0]) != 2 ** len(wires): raise ValueError("State vector must be of length 2**wires.") qregs = list(reversed(qregs)) # TODO: Once a fix is available in Qiskit-Aer, remove the following: par = (x.tolist() for x in par if isinstance(x, np.ndarray)) if operation == "QubitUnitary": if len(par[0]) != 2 ** len(wires): raise ValueError("Unitary matrix must be of shape (2**wires, 2**wires).") qregs = list(reversed(qregs)) dag = circuit_to_dag(QuantumCircuit(self._reg, self._creg, name="")) gate = mapped_operation(*par) if operation.endswith(".inv"): gate = gate.inverse() dag.apply_operation_back(gate, qargs=qregs) qc = dag_to_circuit(dag) self._circuit = self._circuit + qc
def get_controlled_circuit(circuit, ctl_qubit, tgt_circuit=None, use_basis_gates=True): """ Construct the controlled version of a given circuit. Args: circuit (QuantumCircuit) : the base circuit ctl_qubit (Qubit) : the control qubit to use tgt_circuit (QuantumCircuit) : the target controlled circuit to be modified in-place use_basis_gates (bool) : boolean flag to indicate whether or not only basis gates should be used Return: QuantumCircuit: a QuantumCircuit object with the base circuit being controlled by ctl_qubit Raises: RuntimeError: unexpected operation """ if tgt_circuit is not None: qc = tgt_circuit else: qc = QuantumCircuit() # get all the qubits and clbits qregs = circuit.qregs qubits = [] for qreg in qregs: if not qc.has_register(qreg): qc.add_register(qreg) qubits.extend(qreg) cregs = circuit.cregs clbits = [] for creg in cregs: if not qc.has_register(creg): qc.add_register(creg) clbits.extend(creg) # get all operations unroller = Unroller(basis=['u', 'p', 'cx']) ops = dag_to_circuit(unroller.run(circuit_to_dag(circuit))).data # process all basis gates to add control if not qc.has_register(ctl_qubit.register): qc.add_register(ctl_qubit.register) for op in ops: if op[0].name == 'id': apply_cu(qc, 0, 0, 0, ctl_qubit, op[1][0], use_basis_gates=use_basis_gates) elif op[0].name == 'p': apply_cp(qc, *op[0].params, ctl_qubit, op[1][0], use_basis_gates=use_basis_gates) elif op[0].name == 'u': apply_cu(qc, *op[0].params, ctl_qubit, op[1][0], use_basis_gates=use_basis_gates) elif op[0].name == 'cx': apply_ccx(qc, ctl_qubit, op[1][0], op[1][1], use_basis_gates=use_basis_gates) elif op[0].name == 'measure': qc.measure(op[1], op[2]) elif op[0].name == 'barrier': qc.barrier(op[1]) else: raise RuntimeError('Unexpected operation {}.'.format(op[0].name)) return qc
def _compose_transforms(basis_transforms, source_basis, source_dag): """Compose a set of basis transforms into a set of replacements. Args: basis_transforms (List[Tuple[gate_name, params, equiv]]): List of transforms to compose. source_basis (Set[Tuple[gate_name: str, gate_num_qubits: int]]): Names of gates which need to be translated. source_dag (DAGCircuit): DAG with example gates from source_basis. (Used to determine num_params for gate in source_basis.) Returns: Dict[gate_name, Tuple(params, dag)]: Dictionary mapping between each gate in source_basis and a DAGCircuit instance to replace it. Gates in source_basis but not affected by basis_transforms will be included as a key mapping to itself. """ example_gates = {(node.op.name, node.op.num_qubits): node.op for node in source_dag.op_nodes()} mapped_instrs = {} for gate_name, gate_num_qubits in source_basis: # Need to grab a gate instance to find num_qubits and num_params. # Can be removed following https://github.com/Qiskit/qiskit-terra/pull/3947 . example_gate = example_gates[gate_name, gate_num_qubits] num_params = len(example_gate.params) placeholder_params = ParameterVector(gate_name, num_params) placeholder_gate = Gate(gate_name, gate_num_qubits, list(placeholder_params)) placeholder_gate.params = list(placeholder_params) dag = DAGCircuit() qr = QuantumRegister(gate_num_qubits) dag.add_qreg(qr) dag.apply_operation_back(placeholder_gate, qr[:], []) mapped_instrs[gate_name, gate_num_qubits] = placeholder_params, dag for gate_name, gate_num_qubits, equiv_params, equiv in basis_transforms: logger.debug( "Composing transform step: %s/%s %s =>\n%s", gate_name, gate_num_qubits, equiv_params, equiv, ) for mapped_instr_name, (dag_params, dag) in mapped_instrs.items(): doomed_nodes = [ node for node in dag.op_nodes() if (node.op.name, node.op.num_qubits) == (gate_name, gate_num_qubits) ] if doomed_nodes and logger.isEnabledFor(logging.DEBUG): from qiskit.converters import dag_to_circuit logger.debug( "Updating transform for mapped instr %s %s from \n%s", mapped_instr_name, dag_params, dag_to_circuit(dag), ) for node in doomed_nodes: from qiskit.converters import circuit_to_dag replacement = equiv.assign_parameters( dict(zip_longest(equiv_params, node.op.params)) ) replacement_dag = circuit_to_dag(replacement) dag.substitute_node_with_dag(node, replacement_dag) if doomed_nodes and logger.isEnabledFor(logging.DEBUG): from qiskit.converters import dag_to_circuit logger.debug( "Updated transform for mapped instr %s %s to\n%s", mapped_instr_name, dag_params, dag_to_circuit(dag), ) return mapped_instrs
def reverser(self, dag): circuit = dag_to_circuit(dag) return circuit
def _circuit_from_qasm(qasm): from qiskit.converters import ast_to_dag from qiskit.converters import dag_to_circuit ast = qasm.parse() dag = ast_to_dag(ast) return dag_to_circuit(dag)
def run(self, dag): """Translate an input DAGCircuit to the target basis. Args: dag (DAGCircuit): input dag Raises: TranspilerError: if the target basis cannot be reached Returns: DAGCircuit: translated circuit. """ if self._target_basis is None: return dag # Names of instructions assumed to supported by any backend. basic_instrs = ['measure', 'reset', 'barrier', 'snapshot'] target_basis = set(self._target_basis).union(basic_instrs) source_basis = set() for node in dag.op_nodes(): name = node.op.name qubit_params = (tuple([node.qargs[0].index]), tuple(node.op.params)) if (dag.calibrations and name in dag.calibrations and qubit_params in dag.calibrations[name]): pass else: source_basis.add((name, node.op.num_qubits)) logger.info('Begin BasisTranslator from source basis %s to target ' 'basis %s.', source_basis, target_basis) # Search for a path from source to target basis. search_start_time = time.time() basis_transforms = _basis_search(self._equiv_lib, source_basis, target_basis, _basis_heuristic) search_end_time = time.time() logger.info('Basis translation path search completed in %.3fs.', search_end_time - search_start_time) if basis_transforms is None: raise TranspilerError( 'Unable to map source basis {} to target basis {} ' 'over library {}.'.format( source_basis, target_basis, self._equiv_lib)) # Compose found path into a set of instruction substitution rules. compose_start_time = time.time() instr_map = _compose_transforms(basis_transforms, source_basis, dag) compose_end_time = time.time() logger.info('Basis translation paths composed in %.3fs.', compose_end_time - compose_start_time) # Replace source instructions with target translations. replace_start_time = time.time() for node in dag.op_nodes(): if node.name in target_basis: continue if dag.calibrations and node.name in dag.calibrations: qubit = tuple([node.qargs[0].index]) params = tuple(node.op.params) if (qubit, params) in dag.calibrations[node.name]: continue if (node.op.name, node.op.num_qubits) in instr_map: target_params, target_dag = instr_map[node.op.name, node.op.num_qubits] if len(node.op.params) != len(target_params): raise TranspilerError( 'Translation num_params not equal to op num_params.' 'Op: {} {} Translation: {}\n{}'.format( node.op.params, node.op.name, target_params, target_dag)) if node.op.params: # Convert target to circ and back to assign_parameters, since # DAGCircuits won't have a ParameterTable. from qiskit.converters import dag_to_circuit, circuit_to_dag target_circuit = dag_to_circuit(target_dag) target_circuit.assign_parameters( dict(zip_longest(target_params, node.op.params)), inplace=True) bound_target_dag = circuit_to_dag(target_circuit) else: bound_target_dag = target_dag if (len(bound_target_dag.op_nodes()) == 1 and len(bound_target_dag.op_nodes()[0].qargs) == len(node.qargs)): dag.substitute_node(node, bound_target_dag.op_nodes()[0].op, inplace=True) else: dag.substitute_node_with_dag(node, bound_target_dag) else: raise TranspilerError('BasisTranslator did not map {}.'.format(node.name)) replace_end_time = time.time() logger.info('Basis translation instructions replaced in %.3fs.', replace_end_time - replace_start_time) return dag
def _partition_circuit(circuit): dag = circuit_to_dag(circuit) dag_layers = ([i['graph'] for i in dag.serial_layers()]) num_qubits = circuit.num_qubits layers = list( zip(dag_layers, [{x: False for x in range(0, num_qubits)} for layer in dag_layers])) # initialize the ledger # The ledger tracks which qubits in each layer are available to have # gates from subsequent layers shifted backward. # The idea being that all parameterized gates should have # no descendants within their layer for i, (layer, ledger) in enumerate(layers): op_node = layer.op_nodes()[0] is_param = op_node.op.is_parameterized() qargs = op_node.qargs indices = [qarg.index for qarg in qargs] if is_param: for index in indices: ledger[index] = True def apply_node_op(node, dag, back=True): op = copy.copy(node.op) qargs = copy.copy(node.qargs) cargs = copy.copy(node.cargs) condition = copy.copy(node.condition) if back: dag.apply_operation_back(op, qargs, cargs, condition) else: dag.apply_operation_front(op, qargs, cargs, condition) converged = False for _ in range(dag.depth() + 1): if converged: break converged = True for i, (layer, ledger) in enumerate(layers): if i == len(layers) - 1: continue (next_layer, next_ledger) = layers[i + 1] for next_node in next_layer.op_nodes(): is_param = next_node.op.is_parameterized() qargs = next_node.qargs indices = [qarg.index for qarg in qargs] # If the next_node can be moved back a layer without # without becoming the descendant of a parameterized gate, # then do it. if not any([ledger[x] for x in indices]): apply_node_op(next_node, layer) next_layer.remove_op_node(next_node) if is_param: for index in indices: ledger[index] = True next_ledger[index] = False converged = False # clean up empty layers left behind. if len(next_layer.op_nodes()) == 0: layers.pop(i + 1) partitioned_circs = [dag_to_circuit(layer[0]) for layer in layers] return partitioned_circs
def _transpilation(circuit, basis_gates=None, coupling_map=None, initial_layout=None, seed_mapper=None, pass_manager=None): """Perform transpilation of a single circuit. Args: circuit (QuantumCircuit): A circuit to transpile. basis_gates (list[str]): list of basis gate names supported by the target. Default: ['u1','u2','u3','cx','id'] coupling_map (CouplingMap): coupling map (perhaps custom) to target in mapping initial_layout (Layout): initial layout of qubits in mapping seed_mapper (int): random seed for the swap_mapper pass_manager (PassManager): a pass_manager for the transpiler stage Returns: QuantumCircuit: A transpiled circuit. Raises: TranspilerError: If the Layout does not matches the circuit """ if initial_layout is not None and set( circuit.qregs) != initial_layout.get_registers(): raise TranspilerError( 'The provided initial layout does not match the registers in ' 'the circuit "%s"' % circuit.name) if pass_manager and not pass_manager.working_list: return circuit dag = circuit_to_dag(circuit) del circuit # if the circuit and layout already satisfy the coupling_constraints, use that layout # if there's no layout but the circuit is compatible, use a trivial layout # otherwise layout on the most densely connected physical qubit subset # FIXME: this should be simplified once it is ported to a PassManager if coupling_map: cm_object = CouplingMap(coupling_map) check_map = CheckMap(cm_object, initial_layout) check_map.run(dag) if check_map.property_set['is_swap_mapped']: if not initial_layout: trivial_layout = TrivialLayout(cm_object) trivial_layout.run(dag) initial_layout = trivial_layout.property_set['layout'] else: dense_layout = DenseLayout(cm_object) dense_layout.run(dag) initial_layout = dense_layout.property_set['layout'] final_dag = transpile_dag(dag, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, seed_mapper=seed_mapper, pass_manager=pass_manager) out_circuit = dag_to_circuit(final_dag) return out_circuit
def run(self, dag): """Translate an input DAGCircuit to the target basis. Args: dag (DAGCircuit): input dag Raises: TranspilerError: if the target basis cannot be reached Returns: DAGCircuit: translated circuit. """ if self._target_basis is None: return dag # Names of instructions assumed to supported by any backend. basic_instrs = ["measure", "reset", "barrier", "snapshot", "delay"] target_basis = set(self._target_basis).union(basic_instrs) source_basis = set() for node in dag.op_nodes(): if not dag.has_calibration_for(node): source_basis.add((node.name, node.op.num_qubits)) logger.info( "Begin BasisTranslator from source basis %s to target " "basis %s.", source_basis, target_basis, ) # Search for a path from source to target basis. search_start_time = time.time() basis_transforms = _basis_search( self._equiv_lib, source_basis, target_basis, _basis_heuristic ) search_end_time = time.time() logger.info( "Basis translation path search completed in %.3fs.", search_end_time - search_start_time ) if basis_transforms is None: raise TranspilerError( "Unable to map source basis {} to target basis {} " "over library {}.".format(source_basis, target_basis, self._equiv_lib) ) # Compose found path into a set of instruction substitution rules. compose_start_time = time.time() instr_map = _compose_transforms(basis_transforms, source_basis, dag) compose_end_time = time.time() logger.info( "Basis translation paths composed in %.3fs.", compose_end_time - compose_start_time ) # Replace source instructions with target translations. replace_start_time = time.time() for node in dag.op_nodes(): if node.name in target_basis: continue if dag.has_calibration_for(node): continue if (node.op.name, node.op.num_qubits) in instr_map: target_params, target_dag = instr_map[node.op.name, node.op.num_qubits] if len(node.op.params) != len(target_params): raise TranspilerError( "Translation num_params not equal to op num_params." "Op: {} {} Translation: {}\n{}".format( node.op.params, node.op.name, target_params, target_dag ) ) if node.op.params: # Convert target to circ and back to assign_parameters, since # DAGCircuits won't have a ParameterTable. from qiskit.converters import dag_to_circuit, circuit_to_dag target_circuit = dag_to_circuit(target_dag) target_circuit.assign_parameters( dict(zip_longest(target_params, node.op.params)), inplace=True ) bound_target_dag = circuit_to_dag(target_circuit) else: bound_target_dag = target_dag if len(bound_target_dag.op_nodes()) == 1 and len( bound_target_dag.op_nodes()[0].qargs ) == len(node.qargs): dag_op = bound_target_dag.op_nodes()[0].op # dag_op may be the same instance as other ops in the dag, # so if there is a condition, need to copy if node.op.condition: dag_op = dag_op.copy() dag.substitute_node(node, dag_op, inplace=True) if bound_target_dag.global_phase: dag.global_phase += bound_target_dag.global_phase else: dag.substitute_node_with_dag(node, bound_target_dag) else: raise TranspilerError(f"BasisTranslator did not map {node.name}.") replace_end_time = time.time() logger.info( "Basis translation instructions replaced in %.3fs.", replace_end_time - replace_start_time, ) return dag
def _transpilation(circuit, basis_gates=None, coupling_map=None, initial_layout=None, seed_mapper=None, pass_manager=None): """Perform transpilation of a single circuit. Args: circuit (QuantumCircuit): A circuit to transpile. basis_gates (list[str]): list of basis gate names supported by the target. Default: ['u1','u2','u3','cx','id'] coupling_map (list): coupling map (perhaps custom) to target in mapping initial_layout (list): initial layout of qubits in mapping seed_mapper (int): random seed for the swap_mapper pass_manager (PassManager): a pass_manager for the transpiler stage Returns: QuantumCircuit: A transpiled circuit. Raises: TranspilerError: if args are not complete for transpiler to function. """ if pass_manager and not pass_manager.working_list: return circuit dag = circuit_to_dag(circuit) del circuit # pick a trivial layout if the circuit already satisfies the coupling constraints # else layout on the most densely connected physical qubit subset # FIXME: this should be simplified once it is ported to a PassManager if coupling_map and initial_layout is None: cm_object = CouplingMap(coupling_map) check_cnot_direction = CheckCnotDirection(cm_object) check_cnot_direction.run(dag) if check_cnot_direction.property_set['is_direction_mapped']: trivial_layout = TrivialLayout(cm_object) trivial_layout.run(dag) initial_layout = trivial_layout.property_set['layout'] else: dense_layout = DenseLayout(cm_object) dense_layout.run(dag) initial_layout = dense_layout.property_set['layout'] # temporarily build old-style layout dict # (TODO: remove after transition to StochasticSwap pass) if isinstance(initial_layout, Layout): layout = initial_layout.copy() virtual_qubits = layout.get_virtual_bits() initial_layout = {(v[0].name, v[1]): ('q', layout[v]) for v in virtual_qubits} final_dag = transpile_dag(dag, basis_gates=basis_gates, coupling_map=coupling_map, initial_layout=initial_layout, seed_mapper=seed_mapper, pass_manager=pass_manager) out_circuit = dag_to_circuit(final_dag) return out_circuit
def _qiskit_ansatz(num_params, num_qubits, wires, tape): """Transform a quantum tape from PennyLane to a Qiskit circuit. Args: num_params (int): Number of parameters. num_qubits (int): Number of qubits. wires (qml.wire.Wires): Wires used in the tape and Hamiltonian. tape (qml.tape.QuantumTape): The quantum tape of the circuit ansatz in PennyLane. Returns: QuantumCircuit: Qiskit quantum circuit. """ consecutive_wires = qml.wires.Wires(range(num_qubits)) wires_map = OrderedDict(zip(wires, consecutive_wires)) # From here: Create the Qiskit ansatz circuit params_vector = ParameterVector("p", num_params) reg = QuantumRegister(num_qubits, "q") circuit_ansatz = QuantumCircuit(reg, name="vqe") circuits = [] j = 0 for operation in tape.operations: wires = operation.wires.map(wires_map) par = operation.parameters operation = operation.name mapped_operation = QiskitDevice._operation_map[operation] qregs = [reg[i] for i in wires.labels] if operation.split(".inv")[0] in ("QubitUnitary", "QubitStateVector"): # Need to revert the order of the quantum registers used in # Qiskit such that it matches the PennyLane ordering qregs = list(reversed(qregs)) dag = circuit_to_dag(QuantumCircuit(reg, name="")) if operation in ("QubitUnitary", "QubitStateVector"): # Parameters are matrices gate = mapped_operation(par[0]) else: # Parameters for the operation if par and qml.math.requires_grad(par[0]): op_num_params = len(par) par = [] for num in range(op_num_params): par.append(params_vector[j + num]) j += op_num_params gate = mapped_operation(*par) if operation.endswith(".inv"): gate = gate.inverse() dag.apply_operation_back(gate, qargs=qregs) circuit = dag_to_circuit(dag) circuits.append(circuit) for circuit in circuits: circuit_ansatz &= circuit return circuit_ansatz
def decompose_non_standard_non_unitary_gates_return(self) -> Tuple[QuantumCircuit, DAGCircuit]: decomposer = Decomposer() dag = decomposer.decompose_non_standard_non_unitary_gates(self.dag) circuit = dag_to_circuit(dag) return (circuit, dag)
def time_dag_to_circuit(self, *_): converters.dag_to_circuit(self.dag)
def test_compose_permuted(self): """Composing two dags of the same width, permuted wires. ┌───┐ lqr_1_0: |0>───┤ H ├─── rqr_0: |0>──■─────── ├───┤ │ ┌───┐ lqr_1_1: |0>───┤ X ├─── rqr_1: |0>──┼──┤ X ├ ┌──┴───┴──┐ │ ├───┤ lqr_1_2: |0>┤ U1(0.1) ├ rqr_2: |0>──┼──┤ Y ├ └─────────┘ ┌─┴─┐└───┘ lqr_2_0: |0>─────■───── + rqr_3: |0>┤ X ├───── = ┌─┴─┐ └───┘┌───┐ lqr_2_1: |0>───┤ X ├─── rqr_4: |0>─────┤ Z ├ └───┘ └───┘ lcr_0: 0 ══════════════ lcr_1: 0 ══════════════ ┌───┐ ┌───┐ lqr_1_0: |0>───┤ H ├───┤ Z ├ ├───┤ ├───┤ lqr_1_1: |0>───┤ X ├───┤ X ├ ┌──┴───┴──┐├───┤ lqr_1_2: |0>┤ U1(0.1) ├┤ Y ├ └─────────┘└───┘ lqr_2_0: |0>─────■───────■── ┌─┴─┐ ┌─┴─┐ lqr_2_1: |0>───┤ X ├───┤ X ├ └───┘ └───┘ lcr_0: 0 ═══════════════════ lcr_1: 0 ═══════════════════ """ qreg = QuantumRegister(5, 'rqr') right_qubit0 = qreg[0] right_qubit1 = qreg[1] right_qubit2 = qreg[2] right_qubit3 = qreg[3] right_qubit4 = qreg[4] circuit_right = QuantumCircuit(qreg) circuit_right.cx(qreg[0], qreg[3]) circuit_right.x(qreg[1]) circuit_right.y(qreg[2]) circuit_right.z(qreg[4]) dag_left = circuit_to_dag(self.circuit_left) dag_right = circuit_to_dag(circuit_right) # permuted wiring dag_left.compose(dag_right, edge_map={right_qubit0: self.left_qubit3, right_qubit1: self.left_qubit1, right_qubit2: self.left_qubit2, right_qubit3: self.left_qubit4, right_qubit4: self.left_qubit0}) circuit_composed = dag_to_circuit(dag_left) circuit_expected = self.circuit_left.copy() circuit_expected.z(self.left_qubit0) circuit_expected.x(self.left_qubit1) circuit_expected.y(self.left_qubit2) circuit_expected.cx(self.left_qubit3, self.left_qubit4) self.assertEqual(circuit_composed, circuit_expected)
def transpile_dag(dag, basis_gates=None, coupling_map=None, initial_layout=None, seed_mapper=None, pass_manager=None): """Deprecated - Use qiskit.compiler.transpile for transpiling from circuits to circuits. Transform a dag circuit into another dag circuit (transpile), through consecutive passes on the dag. Args: dag (DAGCircuit): dag circuit to transform via transpilation basis_gates (list[str]): list of basis gate names supported by the target. Default: ['u1','u2','u3','cx','id'] coupling_map (list): A graph of coupling:: [ [control0(int), target0(int)], [control1(int), target1(int)], ] eg. [[0, 2], [1, 2], [1, 3], [3, 4]} initial_layout (Layout or None): A layout object seed_mapper (int): random seed_mapper for the swap mapper pass_manager (PassManager): pass manager instance for the transpilation process If None, a default set of passes are run. Otherwise, the passes defined in it will run. If contains no passes in it, no dag transformations occur. Returns: DAGCircuit: transformed dag """ warnings.warn( "transpile_dag has been deprecated and will be removed in the " "0.9 release. Circuits can be transpiled directly to other " "circuits with the transpile function.", DeprecationWarning) if basis_gates is None: basis_gates = ['u1', 'u2', 'u3', 'cx', 'id'] if pass_manager is None: # default set of passes # if a coupling map is given compile to the map if coupling_map: pass_manager = default_pass_manager(basis_gates, CouplingMap(coupling_map), initial_layout, seed_transpiler=seed_mapper) else: pass_manager = default_pass_manager_simulator(basis_gates) # run the passes specified by the pass manager # TODO return the property set too. See #1086 name = dag.name circuit = dag_to_circuit(dag) circuit = pass_manager.run(circuit) dag = circuit_to_dag(circuit) dag.name = name return dag
def unroll(self, gates: List[str]) -> QuantumCircuit: unroll_pass = Unroller(gates) self.decompose_non_standard_non_unitary_gates() self.dag = unroll_pass.run(self.dag) self.circuit = dag_to_circuit(self.dag) return self.circuit
def test_compose_classical(self): """Composing on classical bits. ┌───┐ ┌─────┐┌─┐ lqr_1_0: |0>───┤ H ├─── rqr_0: |0>──■──┤ Tdg ├┤M├ ├───┤ ┌─┴─┐└─┬─┬─┘└╥┘ lqr_1_1: |0>───┤ X ├─── rqr_1: |0>┤ X ├──┤M├───╫─ ┌──┴───┴──┐ └───┘ └╥┘ ║ lqr_1_2: |0>┤ U1(0.1) ├ + rcr_0: 0 ════════╬════╩═ = └─────────┘ ║ lqr_2_0: |0>─────■───── rcr_1: 0 ════════╩══════ ┌─┴─┐ lqr_2_1: |0>───┤ X ├─── └───┘ lcr_0: 0 ══════════════ lcr_1: 0 ══════════════ ┌───┐ lqr_1_0: |0>───┤ H ├────────────────── ├───┤ ┌─────┐┌─┐ lqr_1_1: |0>───┤ X ├─────■──┤ Tdg ├┤M├ ┌──┴───┴──┐ │ └─────┘└╥┘ lqr_1_2: |0>┤ U1(0.1) ├──┼──────────╫─ └─────────┘ │ ║ lqr_2_0: |0>─────■───────┼──────────╫─ ┌─┴─┐ ┌─┴─┐ ┌─┐ ║ lqr_2_1: |0>───┤ X ├───┤ X ├──┤M├───╫─ └───┘ └───┘ └╥┘ ║ lcr_0: 0 ═══════════════════╩════╬═ ║ lcr_1: 0 ════════════════════════╩═ """ qreg = QuantumRegister(2, 'rqr') creg = ClassicalRegister(2, 'rcr') right_qubit0 = qreg[0] right_qubit1 = qreg[1] right_clbit0 = creg[0] right_clbit1 = creg[1] circuit_right = QuantumCircuit(qreg, creg) circuit_right.cx(qreg[0], qreg[1]) circuit_right.tdg(qreg[0]) circuit_right.measure(qreg, creg) dag_left = circuit_to_dag(self.circuit_left) dag_right = circuit_to_dag(circuit_right) # permuted subset of qubits and clbits dag_left.compose(dag_right, edge_map={right_qubit0: self.left_qubit1, right_qubit1: self.left_qubit4, right_clbit0: self.left_clbit1, right_clbit1: self.left_clbit0}) circuit_composed = dag_to_circuit(dag_left) circuit_expected = self.circuit_left.copy() circuit_expected.cx(self.left_qubit1, self.left_qubit4) circuit_expected.tdg(self.left_qubit1) circuit_expected.measure(self.left_qubit4, self.left_clbit0) circuit_expected.measure(self.left_qubit1, self.left_clbit1) self.assertEqual(circuit_composed, circuit_expected)
def test_unroll_all_instructions(self): """Test unrolling a circuit containing all standard instructions. """ qr = QuantumRegister(3, 'qr') cr = ClassicalRegister(3, 'cr') circuit = QuantumCircuit(qr, cr) circuit.crx(0.5, qr[1], qr[2]) circuit.cry(0.5, qr[1], qr[2]) circuit.ccx(qr[0], qr[1], qr[2]) circuit.ch(qr[0], qr[2]) circuit.crz(0.5, qr[1], qr[2]) circuit.cswap(qr[1], qr[0], qr[2]) circuit.append(CU1Gate(0.1), [qr[0], qr[2]]) circuit.append(CU3Gate(0.2, 0.1, 0.0), [qr[1], qr[2]]) circuit.cx(qr[1], qr[0]) circuit.cy(qr[1], qr[2]) circuit.cz(qr[2], qr[0]) circuit.h(qr[1]) circuit.i(qr[0]) circuit.rx(0.1, qr[0]) circuit.ry(0.2, qr[1]) circuit.rz(0.3, qr[2]) circuit.rzz(0.6, qr[1], qr[0]) circuit.s(qr[0]) circuit.sdg(qr[1]) circuit.swap(qr[1], qr[2]) circuit.t(qr[2]) circuit.tdg(qr[0]) circuit.append(U1Gate(0.1), [qr[1]]) circuit.append(U2Gate(0.2, -0.1), [qr[0]]) circuit.append(U3Gate(0.3, 0.0, -0.1), [qr[2]]) circuit.x(qr[2]) circuit.y(qr[1]) circuit.z(qr[0]) # circuit.snapshot('0') # circuit.measure(qr, cr) dag = circuit_to_dag(circuit) pass_ = UnrollCustomDefinitions(std_eqlib, ['u3', 'cx', 'id']) dag = pass_.run(dag) pass_ = BasisTranslator(std_eqlib, ['u3', 'cx', 'id']) unrolled_dag = pass_.run(dag) ref_circuit = QuantumCircuit(qr, cr) ref_circuit.append(U3Gate(0, 0, pi / 2), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(-0.25, 0, 0), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(0.25, -pi / 2, 0), [qr[2]]) ref_circuit.append(U3Gate(0.25, 0, 0), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(-0.25, 0, 0), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(0, 0, -pi / 4), [qr[2]]) ref_circuit.cx(qr[0], qr[2]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[1]]) ref_circuit.append(U3Gate(0, 0, -pi / 4), [qr[2]]) ref_circuit.cx(qr[0], qr[2]) ref_circuit.cx(qr[0], qr[1]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[0]]) ref_circuit.append(U3Gate(0, 0, -pi / 4), [qr[1]]) ref_circuit.cx(qr[0], qr[1]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[2]]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[2]]) ref_circuit.append(U3Gate(0, 0, pi / 2), [qr[2]]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[2]]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[2]]) ref_circuit.cx(qr[0], qr[2]) ref_circuit.append(U3Gate(0, 0, -pi / 4), [qr[2]]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[2]]) ref_circuit.append(U3Gate(0, 0, -pi / 2), [qr[2]]) ref_circuit.append(U3Gate(0, 0, 0.25), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(0, 0, -0.25), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.cx(qr[2], qr[0]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[2]]) ref_circuit.cx(qr[0], qr[2]) ref_circuit.append(U3Gate(0, 0, -pi / 4), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[2]]) ref_circuit.cx(qr[0], qr[2]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[0]]) ref_circuit.append(U3Gate(0, 0, -pi / 4), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.cx(qr[1], qr[0]) ref_circuit.append(U3Gate(0, 0, -pi / 4), [qr[0]]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[1]]) ref_circuit.cx(qr[1], qr[0]) ref_circuit.append(U3Gate(0, 0, 0.05), [qr[1]]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[2]]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[2]]) ref_circuit.cx(qr[2], qr[0]) ref_circuit.append(U3Gate(0, 0, 0.05), [qr[0]]) ref_circuit.cx(qr[0], qr[2]) ref_circuit.append(U3Gate(0, 0, -0.05), [qr[2]]) ref_circuit.cx(qr[0], qr[2]) ref_circuit.append(U3Gate(0, 0, 0.05), [qr[2]]) ref_circuit.append(U3Gate(0, 0, -0.05), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(-0.1, 0, -0.05), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.cx(qr[1], qr[0]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[0]]) ref_circuit.append(U3Gate(0.1, 0.1, 0), [qr[2]]) ref_circuit.append(U3Gate(0, 0, -pi / 2), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[1]]) ref_circuit.append(U3Gate(0.2, 0, 0), [qr[1]]) ref_circuit.append(U3Gate(0, 0, pi / 2), [qr[2]]) ref_circuit.cx(qr[2], qr[0]) ref_circuit.append(U3Gate(pi / 2, 0, pi), [qr[0]]) ref_circuit.i(qr[0]) ref_circuit.append(U3Gate(0.1, -pi / 2, pi / 2), [qr[0]]) ref_circuit.cx(qr[1], qr[0]) ref_circuit.append(U3Gate(0, 0, 0.6), [qr[0]]) ref_circuit.cx(qr[1], qr[0]) ref_circuit.append(U3Gate(0, 0, pi / 2), [qr[0]]) ref_circuit.append(U3Gate(0, 0, -pi / 4), [qr[0]]) ref_circuit.append(U3Gate(pi / 2, 0.2, -0.1), [qr[0]]) ref_circuit.append(U3Gate(0, 0, pi), [qr[0]]) ref_circuit.append(U3Gate(0, 0, -pi / 2), [qr[1]]) ref_circuit.append(U3Gate(0, 0, 0.3), [qr[2]]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.cx(qr[2], qr[1]) ref_circuit.cx(qr[1], qr[2]) ref_circuit.append(U3Gate(0, 0, 0.1), [qr[1]]) ref_circuit.append(U3Gate(pi, pi / 2, pi / 2), [qr[1]]) ref_circuit.append(U3Gate(0, 0, pi / 4), [qr[2]]) ref_circuit.append(U3Gate(0.3, 0.0, -0.1), [qr[2]]) ref_circuit.append(U3Gate(pi, 0, pi), [qr[2]]) # ref_circuit.snapshot('0') # ref_circuit.measure(qr, cr) # ref_dag = circuit_to_dag(ref_circuit) self.assertTrue( Operator(dag_to_circuit(unrolled_dag)).equiv(ref_circuit))