Beispiel #1
0
 def _define(self):
     """Calculate a subcircuit that implements this unitary."""
     if self.num_qubits == 1:
         q = QuantumRegister(1, "q")
         angles = euler_angles_1q(self.to_matrix())
         self.definition = [(U3Gate(*angles), [q[0]], [])]
     elif self.num_qubits == 2:
         self.definition = two_qubit_cnot_decompose(self.to_matrix())
     else:
         raise NotImplementedError("Not able to generate a subcircuit for "
                                   "a {}-qubit unitary".format(
                                       self.num_qubits))
Beispiel #2
0
 def _dec_ucg(self):
     """
     Call to create a circuit that implements the uniformly controlled gate. If
     up_to_diagonal=True, the circuit implements the gate up to a diagonal gate and
     the diagonal gate is also returned.
     """
     diag = np.ones(2 ** self.num_qubits).tolist()
     q = QuantumRegister(self.num_qubits)
     q_controls = q[1:]
     q_target = q[0]
     circuit = QuantumCircuit(q)
     # If there is no control, we use the ZYZ decomposition
     if not q_controls:
         theta, phi, lamb = euler_angles_1q(self.params[0])
         circuit.u3(theta, phi, lamb, q)
         return circuit, diag
         # if self.up_to_diagonal:
         #     squ = SingleQubitUnitary(self.params[0], mode="ZYZ", up_to_diagonal=True)
         #     circuit.append(squ, [q_target])
         #     return circuit, squ.get_diag()
         # else:
         #     squ = SingleQubitUnitary(self.params[0], mode="ZYZ")
         #     circuit.append(squ, [q_target])
         #     return circuit, diag
     # If there is at least one control, first,
     # we find the single qubit gates of the decomposition.
     (single_qubit_gates, diag) = self._dec_ucg_help()
     # Now, it is easy to place the C-NOT gates and some Hadamards and Rz(pi/2) gates
     # (which are absorbed into the single-qubit unitaries) to get back the full decomposition.
     for i, gate in enumerate(single_qubit_gates):
         # Absorb Hadamards and Rz(pi/2) gates
         if i == 0:
             squ = _h().dot(gate)
         elif i == len(single_qubit_gates) - 1:
             squ = gate.dot(_rz(np.pi / 2)).dot(_h())
         else:
             squ = _h().dot(gate.dot(_rz(np.pi / 2))).dot(_h())
         # Add single-qubit gate
         circuit.squ(squ, q_target)
         # The number of the control qubit is given by the number of zeros at the end
         # of the binary representation of (i+1)
         binary_rep = np.binary_repr(i + 1)
         num_trailing_zeros = len(binary_rep) - len(binary_rep.rstrip('0'))
         q_contr_index = num_trailing_zeros
         # Add C-NOT gate
         if not i == len(single_qubit_gates) - 1:
             circuit.cx(q_controls[q_contr_index], q_target)
     if not self.up_to_diagonal:
         # Important: the diagonal gate is given in the computational basis of the qubits
         # q[k-1],...,q[0],q_target (ordered with decreasing significance),
         # where q[i] are the control qubits and t denotes the target qubit.
         circuit.diag_gate(diag.tolist(), q)
     return circuit, diag
Beispiel #3
0
 def check_one_qubit_euler_angles(self, operator, tolerance=1e-14):
     """Check euler_angles_1q works for the given unitary
     """
     with self.subTest(operator=operator):
         target_unitary = operator.data
         angles = euler_angles_1q(target_unitary)
         decomp_unitary = U3Gate(*angles).to_matrix()
         target_unitary *= la.det(target_unitary)**(-0.5)
         decomp_unitary *= la.det(decomp_unitary)**(-0.5)
         maxdist = np.max(np.abs(target_unitary - decomp_unitary))
         if maxdist > 0.1:
             maxdist = np.max(np.abs(target_unitary + decomp_unitary))
         self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist))
Beispiel #4
0
 def check_one_qubit_euler_angles(self, operator, tolerance=1e-14):
     """Check euler_angles_1q works for the given unitary
     """
     with self.subTest(operator=operator):
         target_unitary = operator.data
         angles = euler_angles_1q(target_unitary)
         decomp_circuit = QuantumCircuit(1)
         decomp_circuit.u3(*angles, 0)
         result = execute(decomp_circuit, UnitarySimulatorPy()).result()
         decomp_unitary = result.get_unitary()
         target_unitary *= la.det(target_unitary)**(-0.5)
         decomp_unitary *= la.det(decomp_unitary)**(-0.5)
         maxdist = np.max(np.abs(target_unitary - decomp_unitary))
         if maxdist > 0.1:
             maxdist = np.max(np.abs(target_unitary + decomp_unitary))
         self.assertTrue(np.abs(maxdist) < tolerance, "Worst distance {}".format(maxdist))
Beispiel #5
0
 def test_one_qubit_euler_angles(self):
     """Verify euler_angles_1q produces correct Euler angles for
     a single-qubit unitary.
     """
     for _ in range(100):
         unitary = random_unitary(2)
         with self.subTest(unitary=unitary):
             angles = euler_angles_1q(unitary.data)
             decomp_circuit = QuantumCircuit(1)
             decomp_circuit.u3(*angles, 0)
             result = execute(decomp_circuit, UnitarySimulatorPy()).result()
             decomp_unitary = Operator(result.get_unitary())
             equal_up_to_phase = matrix_equal(unitary.data,
                                              decomp_unitary.data,
                                              ignore_phase=True,
                                              atol=1e-7)
             self.assertTrue(equal_up_to_phase)
Beispiel #6
0
def accreditation_parser(target_circuit):
    """
        Converts an input quantum circuit to lists representing the input
            Args:
                target_circuit (QuantumCircuit): Quantum circuit consisting of
                cZ gates and single qubit gates, followed by Pauli-Z measure-
                ments on all qubits
            Returns:
                gates_target (list): A 2D list of all 1-qubit gates in the
                    target circuit
                cz_gate (list): list of all cz gate in target circuit
        """
    # Initialize empty lists gates_target and cz_gate
    gates_target = []
    cz_gate = []

    # Qubits in the circuit
    circuit_qubits = target_circuit.qubits

    # Initialize empty list single_qubit_gates
    # This list will be used to store 1-qubit gates in the circuit
    single_qubit_gates = [[] for _ in circuit_qubits]

    # Initialize empty list
    # This is used to check if in a band, a qubit can still be entangled with
    # other qubits (qubits can be entanged one time per band)
    unavailiable_qubits = []

    # Keep track of current band
    current_band_no = 0

    # Loops over all gates in the circuit. An extra element is added so the
    # last band is closed at the end
    for gate in target_circuit.data + ['END STRING']:

        # Checks for special cases that need to be handled differently
        gate_qubits = gate[1]
        last_element = (gate == 'END STRING')
        is_measure = ((len(gate_qubits) == len(gate[2]))
                      and not gate == 'END STRING')

        # Records the position of the last cz gate
        if cz_gate:
            last_cz = cz_gate[-1][0]
        else:
            last_cz = -1

        # Makes sure measurements are ignored
        if not is_measure:
            circuit_end_band = last_element\
                and ((last_cz == current_band_no)
                     or (single_qubit_gates != [[] for _ in circuit_qubits]))

            # If a new band is required, converts the current band's single
            # qubit gates to Euler angles and prepares for the next band
            if((not set(gate_qubits).isdisjoint(set(unavailiable_qubits)))
               or circuit_end_band):
                band_gates_angles = []
                u3_gates_temp = []
                for qubit in single_qubit_gates:
                    matrix = np.array([[1, 0], [0, 1]])
                    for gate_index in qubit[::-1]:
                        matrix = np.matmul(matrix, gate_index[0].to_matrix())
                    band_gates_angles.append(euler_angles_1q(matrix))
                    u3_gates_temp.append(band_gates_angles[0])
                    band_gates_angles = []
                gates_target.append(u3_gates_temp)
                current_band_no += 1
                unavailiable_qubits = []
                single_qubit_gates = [[] for _ in circuit_qubits]
            if last_element:
                break

            # Adds single gates' gate object to the array corresponding to
            # their qubit in single_qubit_gates
            if len(gate_qubits) == 1:
                single_qubit_gates[gate_qubits[0].index].append(gate)
            # Records the location of 2 qubit gates
            else:
                cz_gate.append([current_band_no, gate_qubits[0].index,
                                gate_qubits[1].index])
                unavailiable_qubits += gate_qubits

    # Adds a band of identity gates if circuit ends with cz gates
    if last_cz == current_band_no - 1:
        last_band = []
        for qubit in circuit_qubits:
            last_band.append((0.0, 0.0, 0.0))
        gates_target.append(last_band)

    # Transposes the u3_gates matrix
    gates_target = [list(i) for i in zip(*gates_target)]

    return gates_target, cz_gate
Beispiel #7
0
    def set_state(self, target_variables, qubit_label, q_if=None):
        def basis_change(pole, basis, qubit, dagger=False):
            '''
                Returns the circuit required to change from the Z basis to the eigenbasis
                of a particular Pauli. The opposite is done when `dagger=True`.
            '''

            if pole == '+' and dagger == True:
                self.qc.x(qubit)

            if basis == 'X':
                self.qc.h(qubit)
            elif basis == 'Y':
                if dagger:
                    self.qc.rx(-pi / 2, qubit)
                else:
                    self.qc.rx(pi / 2, qubit)

            if pole == '+' and dagger == False:
                self.qc.x(qubit)

        def normalize(expect):

            for pauli in ['X', 'Y', 'Z']:
                if pauli not in expect:
                    expect[pauli] = self.expect[qubit][pauli]

            R = sqrt(expect['X']**2 + expect['Y']**2 + expect['Z']**2)

            return {pauli: expect[pauli] / R for pauli in expect}

        def get_basis(expect):

            normalized_expect = normalize(expect)

            theta = arccos(normalized_expect['Z'])
            phi = arctan2(normalized_expect['Y'], normalized_expect['X'])

            state0 = [cos(theta / 2), exp(1j * phi) * sin(theta / 2)]
            state1 = [conj(state0[1]), -conj(state0[0])]

            return [state0, state1]

        target_expect = {}
        for label in target_variables:
            pauli = list(self.variables.keys())[list(
                self.variables.values()).index(label)]
            target_expect[pauli] = target_variables[label]

        qubit = self.labels.index(qubit_label)

        current_basis = get_basis(self.get_state(self.labels[qubit]))
        target_basis = get_basis(target_expect)

        U = array([[0 for _ in range(2)] for _ in range(2)], dtype=complex)
        for i in range(2):
            for j in range(2):
                for k in range(2):
                    U[j][k] += target_basis[i][j] * conj(current_basis[i][k])

        the, phi, lam = euler_angles_1q(U)

        if q_if:
            control_variable, pole, control_qubit_label = q_if[0], q_if[
                1], q_if[2]
            control_qubit = self.labels.index(control_qubit_label)
            control_pauli = list(self.variables.keys())[list(
                self.variables.values()).index(control_variable)]
            basis_change(pole, control_pauli, control_qubit, dagger=False)
            self.qc.cu3(the, phi, lam, control_qubit, qubit)
            basis_change(pole, control_pauli, control_qubit, dagger=True)
        else:
            self.qc.u3(the, phi, lam, qubit)

        self._update_expect()
Beispiel #8
0
def euler_angles_1q(unitary_matrix):
    """Deprecated after 0.8
    """
    warnings.warn("euler_angles_1q function is now accessible under "
                  "qiskit.quantum_info.synthesis", DeprecationWarning)
    return synthesis.euler_angles_1q(unitary_matrix)