예제 #1
0
    def test_squared_equals_I(self):
        for Op_type in self.squared_equals_I_list:
            I = qc.Identity()
            U = Op_type()

            diff = max_absolute_difference(U(U), I)
            self.assertLess(diff, epsilon)

        I = qc.Identity(2)
        C = qc.CNOT()
        self.assertLess(max_absolute_difference(C(C), I), epsilon)
예제 #2
0
def QFT(t):
    Op = qc.Identity(t)
    H = qc.Hadamard()

    # The R_k gate applies a 2pi/2^k phase is the qubit is set
    C_Rs = {}
    for k in range(2, t + 1, 1):
        R_k = np.exp(np.pi * 1j / 2**k) * qc.RotationZ(2 * np.pi / 2**k)
        C_Rs[k] = qc.ControlledU(R_k)

    # For each qubit in order, apply the Hadamard gate, and then
    # apply the R_2, R_3, ... conditional on the remainder of the qubits
    for t_i in range(t):
        Op = H(Op, qubit_indices=[t_i])
        for k in range(2, t + 1 - t_i, 1):
            Op = C_Rs[k](Op, qubit_indices=[t_i + k - 1, t_i])

    # We have the QFT, but with the qubits in reverse order
    # Swap them back
    Swap = qc.Swap()
    for i, j in zip(range(t), range(t - 1, -1, -1)):
        if i >= j:
            break
        Op = Swap(Op, qubit_indices=[i, j])

    return Op
예제 #3
0
    def test_application_to_subsystem(self):
        num_tests = 10
        for test_i in range(num_tests):
            d_left = np.random.randint(2, 4)
            d_op = np.random.randint(2, 4)
            d_right = np.random.randint(2, 4)
            d_total = d_left + d_op + d_right
            M = random_unitary_operator(d_total)

            I1 = qc.Identity(d_left)
            I2 = qc.Identity(d_right)
            Op = random_unitary_operator(d_op)

            R1 = (I1 * Op * I2)(M)
            R2 = Op(M, qubit_indices=range(d_left, d_left + d_op))
            self.assertLess(max_absolute_difference(R1, R2), epsilon)
예제 #4
0
 def test_defined_operators_unitary(self):
     num_tests = 10
     for test_i in range(num_tests):
         d = np.random.randint(3, 8)
         I = qc.Identity(d)
         for Op_type, op_name in zip(self.d_ops, self.d_op_names):
             Op = Op_type(d=d)
             Op_adj = get_adjoint(Op)
             max_diff = max_absolute_difference(Op(Op_adj), I)
             self.assertLess(max_diff, epsilon)
             max_diff = max_absolute_difference(Op_adj(Op), I)
             self.assertLess(max_diff, epsilon)
     for Op_type, op_name, d in zip(self.non_d_ops, self.non_d_op_names, self.non_d_op_dims):
         Op = Op_type()
         Op_adj = get_adjoint(Op)
         I = qc.Identity(d)
         max_diff = max_absolute_difference(Op(Op_adj), I)
         self.assertLess(max_diff, epsilon)
         max_diff = max_absolute_difference(Op_adj(Op), I)
         self.assertLess(max_diff, epsilon)
예제 #5
0
 def test_random_operator_unitary(self):
     num_tests = 10
     for test_i in range(num_tests):
         d = np.random.randint(3, 8)
         Op = random_unitary_operator(d)
         Op_adj = get_adjoint(Op)
         I = qc.Identity(d)
         max_diff = max_absolute_difference(Op(Op_adj), I)
         self.assertLess(max_diff, epsilon)
         max_diff = max_absolute_difference(Op_adj(Op), I)
         self.assertLess(max_diff, epsilon)
예제 #6
0
    def test_operator_identity_composition(self):
        """
        The composition of an operator with the identity operator
        should be the same as the original operator.
        """

        for test_i, (d, U) in enumerate(zip(self.ds, self.U1s)):
            I = qc.Identity(d)
            R = I(U(I))

            max_diff = max_absolute_difference(U, R)
            self.assertLess(max_diff, epsilon)
예제 #7
0
 def test_U_f_unitary(self):
     num_tests = 10
     for test_i in range(num_tests):
         d = np.random.randint(3, 7)
         f = random_boolean_function(d)
         Op = qc.U_f(f, d=d+1)
         Op_adj = get_adjoint(Op)
         I = qc.Identity(d+1)
         max_diff = max_absolute_difference(Op(Op_adj), I)
         self.assertLess(max_diff, epsilon)
         max_diff = max_absolute_difference(Op_adj(Op), I)
         self.assertLess(max_diff, epsilon)
예제 #8
0
    def test_same_as_applying_to_substate(self):
        num_tests = 10
        for test_i in range(num_tests):
            state_d = np.random.randint(2, 8)
            op_d = np.random.randint(1, state_d + 1)
            x = random_state(state_d)
            I = qc.Identity(state_d)
            U = random_unitary_operator(op_d)
            qubit_indices = np.random.choice(state_d, size=op_d, replace=False)

            R1 = U(copy.deepcopy(x), qubit_indices=qubit_indices)
            R2 = (U(I, qubit_indices=qubit_indices))(copy.deepcopy(x))

            self.assertLess(max_absolute_difference(R1, R2), epsilon)
예제 #9
0
 def test_tensor_product_operator_unitary(self):
     num_tests = 10
     for test_i in range(num_tests):
         d1 = np.random.randint(3, 5)
         d2 = np.random.randint(3, 5)
         d = d1 + d2
         Op1 = random_unitary_operator(d1)
         Op2 = random_unitary_operator(d2)
         Op = Op1 * Op2
         Op_adj = get_adjoint(Op)
         I = qc.Identity(d)
         max_diff = max_absolute_difference(Op(Op_adj), I)
         self.assertLess(max_diff, epsilon)
         max_diff = max_absolute_difference(Op_adj(Op), I)
         self.assertLess(max_diff, epsilon)
예제 #10
0
    def test_application_to_qubit_subset(self):
        """
        Instead of applying the tensor product of the Identity
        operator with another operator to a state, we can apply
        the operator to a subset of axes of the state. We should
        get the same result. We can also permute the order of
        operators in the tensor product, and correspondingly
        permute the application order.
        """

        num_tests = 10
        I = qc.Identity()

        for test_i in range(num_tests):
            d = np.random.randint(3, 8)
            num_apply_to = np.random.randint(2, d)
            apply_to_indices = np.random.choice(d,
                                                size=num_apply_to,
                                                replace=False)

            M_all = None
            Ops = []
            for qubit_i in range(d):
                if qubit_i in apply_to_indices:
                    Op = random_unitary_operator(d=1)
                else:
                    Op = I
                Ops.append(Op)
                if M_all is None:
                    M_all = Op
                else:
                    M_all = M_all * Op

            M_subset = None
            for apply_to_index in apply_to_indices:
                Op = Ops[apply_to_index]
                if M_subset is None:
                    M_subset = Op
                else:
                    M_subset = M_subset * Op

            x = random_state(d)

            result1 = M_all(x)
            result2 = M_subset(x, qubit_indices=apply_to_indices)
            max_diff = max_absolute_difference(result1, result2)
            self.assertLess(max_diff, epsilon)
예제 #11
0
def grover_algorithm(d, f):
    # The operators we will need
    Oracle = qc.U_f(f, d=d+1)
    H_d = qc.Hadamard(d)
    H = qc.Hadamard()
    N = 2**d
    zero_projector = np.zeros((N, N))
    zero_projector[0, 0] = 1
    Inversion = H_d((2 * qc.Operator.from_matrix(zero_projector) - qc.Identity(d))(H_d))
    Grover = Inversion(Oracle, qubit_indices=range(d))

    # Initial state
    state = qc.zeros(d) * qc.ones(1)
    state = (H_d * H)(state)

    # Number of Grover iterations
    angle_to_rotate = np.arccos(np.sqrt(1 / N))
    rotation_angle = 2 * np.arcsin(np.sqrt(1 / N))
    iterations = int(round(angle_to_rotate / rotation_angle))
    for i in range(iterations):
        state = Grover(state)

    measurements = state.measure(qubit_indices=range(d))
    return measurements