示例#1
0
def make_hard_thetas_oneq(smallest=1e-18,
                          factor=3.2,
                          steps=22,
                          phi=0.7,
                          lam=0.9):
    """Make 1q gates with theta/2 close to 0, pi/2, pi, 3pi/2"""
    return (
        [U3Gate(smallest * factor**i, phi, lam) for i in range(steps)] +
        [U3Gate(-smallest * factor**i, phi, lam) for i in range(steps)] + [
            U3Gate(np.pi / 2 + smallest * factor**i, phi, lam)
            for i in range(steps)
        ] + [
            U3Gate(np.pi / 2 - smallest * factor**i, phi, lam)
            for i in range(steps)
        ] +
        [U3Gate(np.pi + smallest * factor**i, phi, lam)
         for i in range(steps)] +
        [U3Gate(np.pi - smallest * factor**i, phi, lam)
         for i in range(steps)] + [
             U3Gate(3 * np.pi / 2 + smallest * factor**i, phi, lam)
             for i in range(steps)
         ] + [
             U3Gate(3 * np.pi / 2 - smallest * factor**i, phi, lam)
             for i in range(steps)
         ])
示例#2
0
def simplify_U(theta, phi, lam):
    """Return the gate u1, u2, or u3 implementing U with the fewest pulses.

    The returned gate implements U exactly, not up to a global phase.

    Args:
        theta, phi, lam: input Euler rotation angles for a general U gate

    Returns:
        Gate: one of IdGate, U1Gate, U2Gate, U3Gate.
    """
    gate = U3Gate(theta, phi, lam)
    # Y rotation is 0 mod 2*pi, so the gate is a u1
    if abs(gate.params[0] % (2.0 * math.pi)) < _CUTOFF_PRECISION:
        gate = U1Gate(gate.params[0] + gate.params[1] + gate.params[2])
    # Y rotation is pi/2 or -pi/2 mod 2*pi, so the gate is a u2
    if isinstance(gate, U3Gate):
        # theta = pi/2 + 2*k*pi
        if abs((gate.params[0] - math.pi / 2) % (2.0 * math.pi)) < _CUTOFF_PRECISION:
            gate = U2Gate(gate.params[1],
                          gate.params[2] + (gate.params[0] - math.pi / 2))
        # theta = -pi/2 + 2*k*pi
        if abs((gate.params[0] + math.pi / 2) % (2.0 * math.pi)) < _CUTOFF_PRECISION:
            gate = U2Gate(gate.params[1] + math.pi,
                          gate.params[2] - math.pi + (gate.params[0] + math.pi / 2))
    # u1 and lambda is 0 mod 4*pi so gate is nop
    if isinstance(gate, U1Gate) and abs(gate.params[0] % (4.0 * math.pi)) < _CUTOFF_PRECISION:
        gate = IdGate()
    return gate
示例#3
0
    def swap_to_u_dag(wire_status, qubit1, qubit2):
        new_dag = DAGCircuit()
        reg = QuantumRegister(2)
        new_dag.add_qreg(reg)

        #TODO: This part can be optimized by selecting u1 and u2 gate rather than using u3 gate.
        # theta1, phi1, lambda1 = WireStatus.u3_to_u3(wire_status[qubit1], wire_status[qubit2])
        # theta2, phi2, lambda2 = WireStatus.u3_to_u3(wire_status[qubit2], wire_status[qubit1])
        op1 = U3Gate(wire_status[qubit1][0], wire_status[qubit1][1], wire_status[qubit1][2])
        op2 = U3Gate(wire_status[qubit2][0], wire_status[qubit2][1], wire_status[qubit2][2])
        #swap the operations when apply them back
        if PureStateOnU.check_zero_state(wire_status[qubit1]) is not True:
            new_dag.apply_operation_back(op1, [reg[1]])
        if PureStateOnU.check_zero_state(wire_status[qubit2]) is not True:
            new_dag.apply_operation_back(op2, [reg[0]])
        return new_dag
示例#4
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]], [])]
     if self.num_qubits == 2:
         self.definition = two_qubit_kak(self.to_matrix())
示例#5
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))
示例#6
0
 def _define(self):
     """Calculate a subcircuit that implements this unitary."""
     if self.num_qubits == 1:
         q = QuantumRegister(1, "q")
         theta, phi, lam = _DECOMPOSER1Q.angles(self.to_matrix())
         self.definition = [(U3Gate(theta, phi, lam), [q[0]], [])]
     elif self.num_qubits == 2:
         self.definition = two_qubit_cnot_decompose(self.to_matrix()).data
     else:
         raise NotImplementedError("Not able to generate a subcircuit for "
                                   "a {}-qubit unitary".format(
                                       self.num_qubits))
示例#7
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))
class TestParameterCtrlState(QiskitTestCase):
    """Test gate equality with ctrl_state parameter."""
    @data((RXGate(0.5), CRXGate(0.5)), (RYGate(0.5), CRYGate(0.5)),
          (RZGate(0.5), CRZGate(0.5)), (XGate(), CXGate()),
          (YGate(), CYGate()), (ZGate(), CZGate()),
          (U1Gate(0.5), CU1Gate(0.5)), (SwapGate(), CSwapGate()),
          (HGate(), CHGate()), (U3Gate(0.1, 0.2, 0.3), CU3Gate(0.1, 0.2, 0.3)))
    @unpack
    def test_ctrl_state_one(self, gate, controlled_gate):
        """Test controlled gates with ctrl_state
        See https://github.com/Qiskit/qiskit-terra/pull/4025
        """
        self.assertEqual(gate.control(1, ctrl_state='1'), controlled_gate)
示例#9
0
 def swap_u_dag(aswap_gate, params, which_swap):
     new_dag = DAGCircuit()
     reg = QuantumRegister(2)
     new_dag.add_qreg(reg)
     if which_swap == 'left':
         regList = [reg[0], reg[1]]
     elif which_swap == 'right':
         regList = [reg[1], reg[0]]
     else:
         raise TranspilerError('Unexpected direction of swap gate')
     new_dag.apply_operation_back(aswap_gate(), regList)
     if PureStateOnU.check_zero_state(params) is not True:
         new_dag.apply_operation_back(U3Gate(params[0], params[1], params[2]), [regList[1]])
     return new_dag
示例#10
0
 def test_controlled_u3(self):
     """Test creation of controlled u3 gate"""
     theta, phi, lamb = 0.1, 0.2, 0.3
     self.assertEqual(
         U3Gate(theta, phi, lamb).control(), Cu3Gate(theta, phi, lamb))
 def test_controlled_u3(self):
     """Test the creation of a controlled U3 gate."""
     theta, phi, lamb = 0.1, 0.2, 0.3
     self.assertEqual(
         U3Gate(theta, phi, lamb).control(), CU3Gate(theta, phi, lamb))
示例#12
0
             U3Gate(3 * np.pi / 2 - smallest * factor**i, phi, lam)
             for i in range(steps)
         ])


HARD_THETA_ONEQS = make_hard_thetas_oneq()

# It's too slow to use all 24**4 Clifford combos. If we can make it faster, use a larger set
K1K2S = [(ONEQ_CLIFFORDS[3], ONEQ_CLIFFORDS[5], ONEQ_CLIFFORDS[2],
          ONEQ_CLIFFORDS[21]),
         (ONEQ_CLIFFORDS[5], ONEQ_CLIFFORDS[6], ONEQ_CLIFFORDS[9],
          ONEQ_CLIFFORDS[7]),
         (ONEQ_CLIFFORDS[2], ONEQ_CLIFFORDS[1], ONEQ_CLIFFORDS[0],
          ONEQ_CLIFFORDS[4]),
         [
             Operator(U3Gate(x, y, z))
             for x, y, z in [(0.2, 0.3, 0.1), (0.7, 0.15,
                                               0.22), (0.001, 0.97,
                                                       2.2), (3.14, 2.1, 0.9)]
         ]]


class TestEulerAngles1Q(QiskitTestCase):
    """Test euler_angles_1q()"""
    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)
示例#13
0
            [U3Gate(np.pi/2 + smallest * factor**i, phi, lam) for i in range(steps)] +
            [U3Gate(np.pi/2 - smallest * factor**i, phi, lam) for i in range(steps)] +
            [U3Gate(np.pi + smallest * factor**i, phi, lam) for i in range(steps)] +
            [U3Gate(np.pi - smallest * factor**i, phi, lam) for i in range(steps)] +
            [U3Gate(3*np.pi/2 + smallest * factor**i, phi, lam) for i in range(steps)] +
            [U3Gate(3*np.pi/2 - smallest * factor**i, phi, lam) for i in range(steps)])


HARD_THETA_ONEQS = make_hard_thetas_oneq()


# It's too slow to use all 24**4 Clifford combos. If we can make it faster, use a larger set
K1K2S = [(ONEQ_CLIFFORDS[3], ONEQ_CLIFFORDS[5], ONEQ_CLIFFORDS[2], ONEQ_CLIFFORDS[21]),
         (ONEQ_CLIFFORDS[5], ONEQ_CLIFFORDS[6], ONEQ_CLIFFORDS[9], ONEQ_CLIFFORDS[7]),
         (ONEQ_CLIFFORDS[2], ONEQ_CLIFFORDS[1], ONEQ_CLIFFORDS[0], ONEQ_CLIFFORDS[4]),
         [Operator(U3Gate(x, y, z)) for x, y, z in
          [(0.2, 0.3, 0.1), (0.7, 0.15, 0.22), (0.001, 0.97, 2.2), (3.14, 2.1, 0.9)]]]


class TestEulerAngles1Q(QiskitTestCase):
    """Test euler_angles_1q()"""

    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()
示例#14
0
 def _circuit_u3(theta, phi, lam):
     circuit = QuantumCircuit(1)
     circuit.append(U3Gate(theta, phi, lam), [0])
     return circuit
示例#15
0
def two_qubit_kak(unitary):
    """Decompose a two-qubit gate over SU(2)+CNOT using the KAK decomposition.

    Args:
        unitary (Unitary): a 4x4 unitary operator to decompose.

    Returns:
        QuantumCircuit: a circuit implementing the unitary over SU(2)+CNOT

    Raises:
        QiskitError: input not a unitary, or error in KAK decomposition.
    """
    unitary_matrix = unitary.representation
    if unitary_matrix.shape != (4, 4):
        raise QiskitError("two_qubit_kak: Expected 4x4 matrix")
    phase = la.det(unitary_matrix)**(-1.0/4.0)
    # Make it in SU(4), correct phase at the end
    U = phase * unitary_matrix
    # B changes to the Bell basis
    B = (1.0/math.sqrt(2)) * np.array([[1, 1j, 0, 0],
                                       [0, 0, 1j, 1],
                                       [0, 0, 1j, -1],
                                       [1, -1j, 0, 0]], dtype=complex)

    # We also need B.conj().T below
    Bdag = B.conj().T
    # U' = Bdag . U . B
    Uprime = Bdag.dot(U.dot(B))
    # M^2 = trans(U') . U'
    M2 = Uprime.T.dot(Uprime)

    # Diagonalize M2
    # Must use diagonalization routine which finds a real orthogonal matrix P
    # when M2 is real.
    D, P = la.eig(M2)
    D = np.diag(D)
    # If det(P) == -1 then in O(4), apply a swap to make P in SO(4)
    if abs(la.det(P)+1) < 1e-5:
        swap = np.array([[1, 0, 0, 0],
                         [0, 0, 1, 0],
                         [0, 1, 0, 0],
                         [0, 0, 0, 1]], dtype=complex)
        P = P.dot(swap)
        D = swap.dot(D.dot(swap))

    Q = np.sqrt(D)  # array from elementwise sqrt
    # Want to take square root so that Q has determinant 1
    if abs(la.det(Q)+1) < 1e-5:
        Q[0, 0] = -Q[0, 0]

    # Q^-1*P.T = P' -> QP' = P.T (solve for P' using Ax=b)
    Pprime = la.solve(Q, P.T)
    # K' now just U' * P * P'
    Kprime = Uprime.dot(P.dot(Pprime))

    K1 = B.dot(Kprime.dot(P.dot(Bdag)))
    A = B.dot(Q.dot(Bdag))
    K2 = B.dot(P.T.dot(Bdag))
    # KAK = K1 * A * K2
    KAK = K1.dot(A.dot(K2))

    # Verify decomp matches input unitary.
    if la.norm(KAK - U) > 1e-6:
        raise QiskitError("two_qubit_kak: KAK decomposition " +
                          "does not return input unitary.")

    # Compute parameters alpha, beta, gamma so that
    # A = exp(i * (alpha * XX + beta * YY + gamma * ZZ))
    xx = np.array([[0, 0, 0, 1],
                   [0, 0, 1, 0],
                   [0, 1, 0, 0],
                   [1, 0, 0, 0]], dtype=complex)

    yy = np.array([[0, 0, 0, -1],
                   [0, 0, 1, 0],
                   [0, 1, 0, 0],
                   [-1, 0, 0, 0]], dtype=complex)

    zz = np.array([[1, 0, 0, 0],
                   [0, -1, 0, 0],
                   [0, 0, -1, 0],
                   [0, 0, 0, 1]], dtype=complex)

    A_real_tr = A.real.trace()
    alpha = math.atan2(A.dot(xx).imag.trace(), A_real_tr)
    beta = math.atan2(A.dot(yy).imag.trace(), A_real_tr)
    gamma = math.atan2(A.dot(zz).imag.trace(), A_real_tr)

    # K1 = kron(U1, U2) and K2 = kron(V1, V2)
    # Find the matrices U1, U2, V1, V2

    # Find a block in K1 where U1_ij * [U2] is not zero
    L = K1[0:2, 0:2]
    if la.norm(L) < 1e-9:
        L = K1[0:2, 2:4]
        if la.norm(L) < 1e-9:
            L = K1[2:4, 2:4]
    # Remove the U1_ij prefactor
    Q = L.dot(L.conj().T)
    U2 = L / math.sqrt(Q[0, 0].real)

    # Now grab U1 given we know U2
    R = K1.dot(np.kron(np.identity(2), U2.conj().T))
    U1 = np.zeros((2, 2), dtype=complex)
    U1[0, 0] = R[0, 0]
    U1[0, 1] = R[0, 2]
    U1[1, 0] = R[2, 0]
    U1[1, 1] = R[2, 2]

    # Repeat K1 routine for K2
    L = K2[0:2, 0:2]
    if la.norm(L) < 1e-9:
        L = K2[0:2, 2:4]
        if la.norm(L) < 1e-9:
            L = K2[2:4, 2:4]
    Q = np.dot(L, np.transpose(L.conjugate()))
    V2 = L / np.sqrt(Q[0, 0])
    R = np.dot(K2, np.kron(np.identity(2), np.transpose(V2.conjugate())))

    V1 = np.zeros_like(U1)
    V1[0, 0] = R[0, 0]
    V1[0, 1] = R[0, 2]
    V1[1, 0] = R[2, 0]
    V1[1, 1] = R[2, 2]

    if la.norm(np.kron(U1, U2) - K1) > 1e-4:
        raise QiskitError("two_qubit_kak: K1 != U1 x U2")
    if la.norm(np.kron(V1, V2) - K2) > 1e-4:
        raise QiskitError("two_qubit_kak: K2 != V1 x V2")

    test = la.expm(1j*(alpha * xx + beta * yy + gamma * zz))
    if la.norm(A - test) > 1e-4:
        raise QiskitError("two_qubit_kak: " +
                          "Matrix A does not match xx,yy,zz decomposition.")

    # Circuit that implements K1 * A * K2 (up to phase), using
    # Vatan and Williams Fig. 6 of quant-ph/0308006v3
    # Include prefix and suffix single-qubit gates into U2, V1 respectively.

    V2 = np.array([[np.exp(1j*np.pi/4), 0],
                   [0, np.exp(-1j*np.pi/4)]], dtype=complex).dot(V2)
    U1 = U1.dot(np.array([[np.exp(-1j*np.pi/4), 0],
                          [0, np.exp(1j*np.pi/4)]], dtype=complex))

    # Corrects global phase: exp(ipi/4)*phase'
    U1 = U1.dot(np.array([[np.exp(1j*np.pi/4), 0],
                          [0, np.exp(1j*np.pi/4)]], dtype=complex))
    U1 = phase.conjugate() * U1

    # Test
    g1 = np.kron(V1, V2)
    g2 = np.array([[1, 0, 0, 0],
                   [0, 0, 0, 1],
                   [0, 0, 1, 0],
                   [0, 1, 0, 0]], dtype=complex)

    theta = 2*gamma - np.pi/2

    Ztheta = np.array([[np.exp(1j*theta/2), 0],
                       [0, np.exp(-1j*theta/2)]], dtype=complex)

    kappa = np.pi/2 - 2*alpha
    Ykappa = np.array([[math.cos(kappa/2), math.sin(kappa/2)],
                       [-math.sin(kappa/2), math.cos(kappa/2)]], dtype=complex)
    g3 = np.kron(Ztheta, Ykappa)
    g4 = np.array([[1, 0, 0, 0],
                   [0, 1, 0, 0],
                   [0, 0, 0, 1],
                   [0, 0, 1, 0]], dtype=complex)

    zeta = 2*beta - np.pi/2
    Yzeta = np.array([[math.cos(zeta/2), math.sin(zeta/2)],
                      [-math.sin(zeta/2), math.cos(zeta/2)]], dtype=complex)
    g5 = np.kron(np.identity(2), Yzeta)
    g6 = g2
    g7 = np.kron(U1, U2)

    V = g2.dot(g1)
    V = g3.dot(V)
    V = g4.dot(V)
    V = g5.dot(V)
    V = g6.dot(V)
    V = g7.dot(V)

    if la.norm(V - U*phase.conjugate()) > 1e-6:
        raise QiskitError("two_qubit_kak: " +
                          "sequence incorrect, unknown error")

    v1_param = euler_angles_1q(V1)
    v2_param = euler_angles_1q(V2)
    u1_param = euler_angles_1q(U1)
    u2_param = euler_angles_1q(U2)

    v1_gate = U3Gate(v1_param[0], v1_param[1], v1_param[2])
    v2_gate = U3Gate(v2_param[0], v2_param[1], v2_param[2])
    u1_gate = U3Gate(u1_param[0], u1_param[1], u1_param[2])
    u2_gate = U3Gate(u2_param[0], u2_param[1], u2_param[2])

    q = QuantumRegister(2)
    return_circuit = QuantumCircuit(q)

    return_circuit.append(v1_gate, [q[1]])

    return_circuit.append(v2_gate, [q[0]])

    return_circuit.append(CnotGate(), [q[0], q[1]])

    gate = U3Gate(0.0, 0.0, -2.0*gamma + np.pi/2.0)
    return_circuit.append(gate, [q[1]])

    gate = U3Gate(-np.pi/2.0 + 2.0*alpha, 0.0, 0.0)
    return_circuit.append(gate, [q[0]])

    return_circuit.append(CnotGate(), [q[1], q[0]])

    gate = U3Gate(-2.0*beta + np.pi/2.0, 0.0, 0.0)
    return_circuit.append(gate, [q[0]])

    return_circuit.append(CnotGate(), [q[0], q[1]])

    return_circuit.append(u1_gate, [q[1]])

    return_circuit.append(u2_gate, [q[0]])

    return return_circuit
 def _circuit_u3(theta, phi, lam, simplify=True, atol=DEFAULT_ATOL):
     # pylint: disable=unused-argument
     circuit = QuantumCircuit(1)
     circuit.append(U3Gate(theta, phi, lam), [0])
     return circuit