def _define(self): diag_circuit = self._dec_diag() gate = diag_circuit.to_instruction() q = QuantumRegister(self.num_qubits) diag_circuit = QuantumCircuit(q) diag_circuit.append(gate, q[:]) self.definition = diag_circuit
def _define(self): mcg_up_diag_circuit, _ = self._dec_mcg_up_diag() gate = mcg_up_diag_circuit.to_instruction() q = QuantumRegister(self.num_qubits) mcg_up_diag_circuit = QuantumCircuit(q) mcg_up_diag_circuit.append(gate, q[:]) self.definition = mcg_up_diag_circuit
def _dec_mcg_up_diag(self): """ Call to create a circuit with gates that implement the MCG up to a diagonal gate. Remark: The qubits the gate acts on are ordered in the following way: q=[q_target,q_controls,q_ancilla_zero,q_ancilla_dirty] """ diag = np.ones(2**(self.num_controls + 1)).tolist() q = QuantumRegister(self.num_qubits) circuit = QuantumCircuit(q) (q_target, q_controls, q_ancillas_zero, q_ancillas_dirty) = self._define_qubit_role(q) # ToDo: Keep this threshold updated such that the lowest gate count is achieved: # ToDo: we implement the MCG with a UCGate up to diagonal if the number of controls is # ToDo: smaller than the threshold. threshold = float("inf") if self.num_controls < threshold: # Implement the MCG as a UCGate (up to diagonal) gate_list = [np.eye(2, 2) for i in range(2**self.num_controls)] gate_list[-1] = self.params[0] ucg = UCGate(gate_list, up_to_diagonal=True) circuit.append(ucg, [q_target] + q_controls) diag = ucg._get_diagonal() # else: # ToDo: Use the best decomposition for MCGs up to diagonal gates here # ToDo: (with all available ancillas) return circuit, diag
def _dec_single_qubit_unitary(self): """ Call to create a circuit with gates that implement the single qubit unitary u. Returns: QuantumCircuit: circuit for implementing u (up to a diagonal if up_to_diagonal=True) """ diag = [1., 1.] q = QuantumRegister(self.num_qubits) circuit = QuantumCircuit(q) # First, we find the rotation angles (where we can ignore the global phase) (a, b, c, _) = self._zyz_dec() # Add the gates to o the circuit is_identity = True if abs(a) > _EPS: circuit.rz(a, q[0]) is_identity = False if abs(b) > _EPS: circuit.ry(b, q[0]) is_identity = False if abs(c) > _EPS: if self.up_to_diagonal: diag = [np.exp(-1j * c / 2.), np.exp(1j * c / 2.)] else: circuit.rz(c, q[0]) is_identity = False if is_identity: circuit.iden(q[0]) return circuit, diag
def _define(self): squ_circuit, _ = self._dec_single_qubit_unitary() gate = squ_circuit.to_instruction() q = QuantumRegister(self.num_qubits) squ_circuit = QuantumCircuit(q) squ_circuit.append(gate, q[:]) self.definition = squ_circuit.data
def _define(self): ucr_circuit = self._dec_ucrot() gate = ucr_circuit.to_instruction() q = QuantumRegister(self.num_qubits) ucr_circuit = QuantumCircuit(q) ucr_circuit.append(gate, q[:]) self.definition = ucr_circuit
def _dec_ucrot(self): """ finds a decomposition of a UC rotation gate into elementary gates (C-NOTs and single-qubit rotations). """ q = QuantumRegister(self.num_qubits) circuit = QuantumCircuit(q) q_target = q[0] q_controls = q[1:] if not q_controls: # equivalent to: if len(q_controls) == 0 if self.rot_axes == "X": if np.abs(self.params[0]) > _EPS: circuit.rx(self.params[0], q_target) if self.rot_axes == "Y": if np.abs(self.params[0]) > _EPS: circuit.ry(self.params[0], q_target) if self.rot_axes == "Z": if np.abs(self.params[0]) > _EPS: circuit.rz(self.params[0], q_target) else: # First, we find the rotation angles of the single-qubit rotations acting # on the target qubit angles = self.params.copy() _dec_uc_rotations(angles, 0, len(angles), False) # Now, it is easy to place the C-NOT gates to get back the full decomposition.s for (i, angle) in enumerate(angles): if self.rot_axes == "X": if np.abs(angle) > _EPS: circuit.rx(angle, q_target) if self.rot_axes == "Y": if np.abs(angle) > _EPS: circuit.ry(angle, q_target) if self.rot_axes == "Z": if np.abs(angle) > _EPS: circuit.rz(angle, q_target) # Determine the index of the qubit we want to control the C-NOT gate. # Note that it corresponds # to the number of trailing zeros in the binary representaiton of i+1 if not i == len(angles) - 1: binary_rep = np.binary_repr(i + 1) q_contr_index = len(binary_rep) - len( binary_rep.rstrip('0')) else: # Handle special case: q_contr_index = len(q_controls) - 1 # For X rotations, we have to additionally place some Ry gates around the # C-NOT gates. They change the basis of the NOT operation, such that the # decomposition of for uniformly controlled X rotations works correctly by symmetry # with the decomposition of uniformly controlled Z or Y rotations if self.rot_axes == "X": circuit.ry(np.pi / 2, q_target) circuit.cx(q_controls[q_contr_index], q_target) if self.rot_axes == "X": circuit.ry(-np.pi / 2, q_target) return circuit
def _define(self): ucr_circuit = self._dec_ucrot() gate_num = len(ucr_circuit.data) gate = ucr_circuit.to_instruction() q = QuantumRegister(self.num_qubits) ucr_circuit = QuantumCircuit(q) if gate_num == 0: # ToDo: if we would not add the identity here, this would lead to troubles # ToDo: simulating the circuit afterwards. # this should probably be fixed in the bahaviour of QuantumCircuit. ucr_circuit.iden(q[0]) else: ucr_circuit.append(gate, q[:]) self.definition = ucr_circuit.data
def _compose_dag(dag_list): """Compose each dag and return new multitask dag""" """FIXME 下記と同様 """ name_list = [] ################# qubit_counter = 0 clbit_counter = 0 composed_multidag = DAGCircuit() for i, dag in enumerate(dag_list): num_qubits = dag.num_qubits() num_clbits = dag.num_clbits() """FIXME Problem: register_name: register nameを定義すると、outputの `new_dag` に対して `dag_to_circuit()` を実行した時、 qiskit.circuit.exceptions.CircuitError: 'register name "定義した名前" already exists' が発生するため、任意のレジスター名をつけることができない Code: reg_name_tmp = dag.qubits[0].register.name register_name = reg_name_tmp if (reg_name_tmp not in name_list) and ( not reg_name_tmp == 'q') else None name_list.append(register_name) """ ############################################################ reg_name_tmp = dag.qubits[0].register.name register_name = reg_name_tmp if (reg_name_tmp not in name_list) and (not reg_name_tmp == 'q') else None name_list.append(register_name) ############################################################ qr = QuantumRegister(size=num_qubits, name=register_name) composed_multidag.add_qreg(qr) qubits = composed_multidag.qubits[qubit_counter : qubit_counter + num_qubits] if num_clbits > 0: cr = ClassicalRegister(size=num_clbits, name=None) composed_multidag.add_creg(cr) clbits = composed_multidag.clbits[clbit_counter : clbit_counter + num_clbits] composed_multidag.compose(dag, qubits=qubits, clbits=clbits) else: composed_multidag.compose(dag, qubits=qubits) qubit_counter += num_qubits clbit_counter += num_clbits return composed_multidag
def _dec_diag(self): """ Call to create a circuit implementing the diagonal gate. """ q = QuantumRegister(self.num_qubits) circuit = QuantumCircuit(q) # Since the diagonal is a unitary, all its entries have absolute value one and the diagonal # is fully specified by the phases of its entries diag_phases = [cmath.phase(z) for z in self.params] n = len(self.params) while n >= 2: angles_rz = [] for i in range(0, n, 2): diag_phases[i // 2], rz_angle = _extract_rz(diag_phases[i], diag_phases[i + 1]) angles_rz.append(rz_angle) num_act_qubits = int(np.log2(n)) contr_qubits = q[self.num_qubits - num_act_qubits + 1:self.num_qubits] target_qubit = q[self.num_qubits - num_act_qubits] circuit.ucrz(angles_rz, contr_qubits, target_qubit) n //= 2 return circuit