예제 #1
0
    def test_prepare_negative_amplitudes_four_qubits(self):
        """Tests state preparation for a vector on three qubits with negative amplitudes."""
        # Input vector
        vec = np.array(
            [-1, -2, 3, -4, -5, 6, -7, 8, 9, 10, 11, -12, -13, -14, 15, -16],
            dtype=np.float64)

        # Get the BinaryTree
        tree = BinaryTree(vec)

        # Create the state preparation circuit
        qreg = QuantumRegister(4)
        circ = QuantumCircuit(qreg)
        tree.preparation_circuit(circ, qreg)

        # Add swaps to compare with normal vector ordering
        circ.swap(qreg[0], qreg[3])
        circ.swap(qreg[1], qreg[2])

        # Get the final state of the circuit
        state = np.real(self.final_state(circ))

        # Only compare the first 16 amplitudes as ancillae may be used to do multi-controlled gates
        self.assertTrue(
            np.allclose(state[:len(vec)], vec / np.linalg.norm(vec, ord=2)))
예제 #2
0
    def test_prepare_negative_amplitudes_two_qubits2(self):
        """Tests preparing a vector with negative amplitudes on a single qubit."""
        # Generate all sign configurations
        one_neg = set(permutations((-1, 1, 1, 1)))
        two_neg = set(permutations((-1, -1, 1, 1)))
        three_neg = set(permutations((-1, -1, -1, 1)))
        four_neg = {(-1, -1, -1, -1)}

        for sign in one_neg | two_neg | three_neg | four_neg:
            # Input vector
            vec = np.array([1, 2, 3, 4], dtype=np.float64)
            vec *= np.array(sign, dtype=np.float64)

            # Get a BinaryTree
            tree = BinaryTree(vec)

            # Get a quantum register
            qreg = QuantumRegister(2)
            circ = QuantumCircuit(qreg)

            # Get the state preparation circuit
            tree.preparation_circuit(circ, qreg)

            # Swap qubits to compare with natural ordering of vector
            circ.swap(qreg[0], qreg[1])

            # Make sure the final state is the same as the input vector
            state = np.real(self.final_state(circ))
            self.assertTrue(
                np.allclose(state, vec / np.linalg.norm(vec, ord=2)))
예제 #3
0
    def test_prep_ctrl_initial_state(self):
        """Creates a state other than all |0> for the control register and tests controlled state preparation."""
        # Get a vector and BinaryTree
        vec = np.array([0, 1])
        tree = BinaryTree(vec)

        # Registers and a circuit
        reg = QuantumRegister(1)
        ctrl_reg = QuantumRegister(2)
        circ = QuantumCircuit(reg, ctrl_reg)

        # Do a NOT on the first qubit. This makes the control_key = 2 = "10" for preparation to happen.
        circ.x(ctrl_reg[0])

        # Add the state preparation circuit
        tree.preparation_circuit(circ,
                                 reg,
                                 control_register=ctrl_reg,
                                 control_key=2)

        # Swap to get normal ordering of amplitudes
        circ.swap(reg[0], ctrl_reg[1])

        # Make sure the correct state is prepared
        # The correct state of the circuit should be |110> = [0, 0, 0, 0, 0, 0, 1, 0].
        correct = np.array([0, 0, 0, 0, 0, 0, 1, 0])
        state = np.real(self.final_state(circ))
        self.assertTrue(np.allclose(state, correct))
예제 #4
0
    def test_prep_with_ctrl_twoq_control_all_keys(self):
        """Tests a one qubit state is created when the correct key is provided, else nothing happens in the circuit."""
        # Input vector
        vec = np.array([1, 1], dtype=np.float64)

        # Zero state
        zero = np.array([1, 0], dtype=np.float64)

        # Make a binary tree from the vector
        tree = BinaryTree(vec)

        for control_key in range(4):
            # Register to store the vector
            register = QuantumRegister(1)
            control_register = QuantumRegister(2)
            circ = QuantumCircuit(register, control_register)

            # Build the circuit
            tree.preparation_circuit(circ,
                                     register,
                                     control_register=control_register,
                                     control_key=control_key)

            # Get the final state of the circuit
            state = self.final_state(circ)

            # Make sure the state is the input vector if the correct control key is given, otherwise the |0> state.
            if control_key == 0:
                self.assertTrue(
                    np.allclose(state[:len(vec)],
                                vec / np.linalg.norm(vec, ord=2)))
            else:
                self.assertTrue(np.allclose(state[:len(vec)], zero))
예제 #5
0
 def test_depth_for_basis_vectors(self):
     """Tests that the circuit depth is one for computational basis vectors."""
     for ii in range(8):
         vec = np.zeros(8)
         vec[ii] = 1
         tree = BinaryTree(vec)
         qreg = QuantumRegister(3)
         circ = QuantumCircuit(qreg)
         tree.preparation_circuit(circ, qreg)
         circ.swap(qreg[0], qreg[2])
         state = np.real(self.final_state(circ))
         self.assertTrue(np.allclose(state, vec))
         self.assertTrue(circ.depth() <= 2)
예제 #6
0
    def test_prepare_all_zeros(self):
        """Tests that the preparation circuit is empty for a vector of all zero elements.

        TODO: What should the behavior be? Throw error? Or return an empty circuit?
        """
        vec = [0, 0]
        tree = BinaryTree(vec)

        reg = QuantumRegister(1)
        circ = QuantumCircuit(reg)

        tree.preparation_circuit(circ, reg)

        self.assertEqual(len(circ), 0)
예제 #7
0
 def test_prep_ctrl_for_basis_vectors(self):
     """Tests that controlled preparation for basis vectors is correct."""
     for ii in range(8):
         vec = np.zeros(8)
         vec[ii] = 1
         tree = BinaryTree(vec)
         qreg = QuantumRegister(3)
         ctrl_reg = QuantumRegister(1)
         circ = QuantumCircuit(qreg, ctrl_reg)
         tree.preparation_circuit(circ,
                                  qreg,
                                  control_register=ctrl_reg,
                                  control_key=0)
         circ.swap(qreg[0], qreg[2])
         state = np.real(self.final_state(circ))
         self.assertTrue(np.allclose(state[:len(vec)], vec))
예제 #8
0
    def test_number_levels(self):
        """Tests the number of levels is correct for a BinaryTree."""
        # Create a tree
        tree = BinaryTree(np.ones(32))

        # Make sure the number of leaves is correct
        self.assertEqual(tree.number_levels, 6)
예제 #9
0
    def test_prepare_negative_amplitudes3(self):
        """Tests preparing a vector with negative amplitudes on a single qubit."""
        # Input vector
        vec = [-0.6, -0.8]

        # Get a BinaryTree
        tree = BinaryTree(vec)

        # Get the state preparation circuit
        qreg = QuantumRegister(1)
        circ = QuantumCircuit(qreg)
        tree.preparation_circuit(circ, qreg)

        # Make sure the final state of the circuit is the same as the input vector
        state = np.real(self.final_state(circ))
        self.assertTrue(np.allclose(state, vec))
예제 #10
0
    def test_prep_with_ctrl_three_qubit_state(self):
        """Tests creating a three qubit state with a control register of three qubits."""
        # Input vector
        vec = np.array([1, 1, 1, -5, 1, 1, 1, 1], dtype=np.float64)

        # Zero state
        zero = np.array([1, 0, 0, 0, 0, 0, 0, 0], dtype=np.float64)

        # Make a binary tree from the vector
        tree = BinaryTree(vec)

        # Registers to store the vector
        regA = QuantumRegister(2)
        regB = QuantumRegister(1)

        # Register to control on
        control_register = QuantumRegister(3)

        # Circuit
        circ = QuantumCircuit(regA, regB, control_register)

        for control_key in range(8):
            # Build the circuit
            tree.preparation_circuit(circ,
                                     regA,
                                     regB,
                                     control_register=control_register,
                                     control_key=control_key)

            # Swap the qubits to compare with vector
            circ.swap(regA[0], regB[0])

            # Get the final state of the circuit
            state = np.real(self.final_state(circ))

            # Make sure the state is the input vector if the correct control key is given, otherwise the |0> state.
            if control_key == 0:
                self.assertTrue(
                    np.allclose(state[:len(vec)],
                                vec / np.linalg.norm(vec, ord=2)))
            else:
                self.assertTrue(np.allclose(state[:len(vec)], zero))

            # Reset the circuit (clear all operations)
            circ.data = []
예제 #11
0
    def test_num_gates_zero_vector(self):
        """Tests that zero gates are used to prepare |0> for multiple qubit numbers."""
        # Loop over different qubit numbers
        for n in range(2, 6):
            # Get the |0> state
            vec = np.zeros(2**n)
            vec[0] = 1

            # Get the BinaryTree
            tree = BinaryTree(vec)

            # Get the preparation circuit
            reg = QuantumRegister(n)
            circ = QuantumCircuit(reg)
            tree.preparation_circuit(circ, reg)

            # Make sure there are no gates
            self.assertEqual(len(circ.data), 0)
예제 #12
0
    def test_basic(self):
        """Basic checks for a BinaryTree."""
        # Instantiate a BinaryTree
        tree = BinaryTree([1, 1])

        # Simple checks
        self.assertTrue(np.isclose(tree.root, 2.0))
        self.assertEqual(tree.number_leaves, 2)
        self.assertEqual(tree.number_levels, 2)
예제 #13
0
    def test_prep_circuit_one_qubit3(self):
        """Tests for correctness in preparation circuit on a single qubit."""
        # Two element vector
        vec = [0.6, 0.8]

        # Make a BinaryTree
        tree = BinaryTree(vec)

        # Get a circuit and register to prepare the vector in
        qreg = QuantumRegister(1)
        circ = QuantumCircuit(qreg)

        # Get the state preparation circuit
        tree.preparation_circuit(circ, qreg)

        # Get the final state
        state = list(np.real(self.final_state(circ)))

        self.assertTrue(np.array_equal(state, vec))
예제 #14
0
    def test_prep_circuit_negative_amplitudes_large(self):
        """Tests the state preparation circuit produces the correct state for many qubits."""
        # Input vector
        vec = -1.0 * np.ones(64)

        # Make a tree from the vector
        tree = BinaryTree(vec)

        # Do the state preparation circuit
        qreg = QuantumRegister(6)
        circ = QuantumCircuit(qreg)
        tree.preparation_circuit(circ, qreg)

        # Check that the circuit produces the correct state
        # Note: No swaps are necessary here since all amplitudes are equal.
        state = np.real(self.final_state(circ))

        # Note: The output state has an additional ancilla needed to do the multi-controlled-Y rotations,
        # so we discard the additional (zero) amplitudes when comparing to the input vector
        self.assertTrue(
            np.allclose(state[:len(vec)], vec / np.linalg.norm(vec, ord=2)))
예제 #15
0
    def test_prep_circuit_three_qubits(self):
        """Tests the state preparation circuit produces the correct state on three qubits."""
        # Input vector
        vec = np.array([1, 2, 3, 4, 5, 6, 7, 8], dtype=np.float64)

        # Make a tree from the vector
        tree = BinaryTree(vec)

        # Get the state preparation circuit
        areg = QuantumRegister(2)
        breg = QuantumRegister(1)
        circ = QuantumCircuit(areg, breg)
        tree.preparation_circuit(circ, areg, breg)

        # Add a swaps to make the ordering of the qubits match the input vector
        # Note: This is because the last bit is the most significant in qiskit, not the first.
        circ.swap(areg[0], breg[0])

        # Check that the circuit produces the correct state
        state = list(np.real(self.final_state(circ)))
        self.assertTrue(np.allclose(state, vec / np.linalg.norm(vec, ord=2)))
예제 #16
0
    def test_parent_indices(self):
        """Tests correctness for getting parent indices.

        The relevant indexing structure here is:

                         (0, 0)
                           ^
                   (1, 0)     (1, 1)
                     ^          ^
               (2, 0) (2, 1) (2, 2) (2, 3)

        """
        tree = BinaryTree([1, 1, 1, 1])

        # Test that the parent of root is none
        self.assertIsNone(tree.parent_index(0, 0))

        # Test that the parent's of the first level are the root
        self.assertEqual(tree.parent_index(1, 0), (0, 0))
        self.assertEqual(tree.parent_index(1, 1), (0, 0))

        # Test that the parent's of the second level are correct
        self.assertEqual(tree.parent_index(2, 0), (1, 0))
        self.assertEqual(tree.parent_index(2, 1), (1, 0))
        self.assertEqual(tree.parent_index(2, 2), (1, 1))
        self.assertEqual(tree.parent_index(2, 3), (1, 1))
예제 #17
0
    def test_prepare_negative_amplitudes_three_qubits(self):
        """Tests state preparation for a vector on three qubits with negative amplitudes."""
        # Input vector
        vec = np.array([-1, -2, 3, -4, -5, 6, -7, 8], dtype=np.float64)

        # Get the BinaryTree
        tree = BinaryTree(vec)

        # Quantum register
        regA = QuantumRegister(2)
        regB = QuantumRegister(1)
        circ = QuantumCircuit(regA, regB)

        # Get the state preparation circuit
        tree.preparation_circuit(circ, regA, regB)

        # Add swaps to compare amplitudes with normal vector ordering
        circ.swap(regA[0], regB[0])

        # Make sure the final state is equal to the input vector
        state = np.real(self.final_state(circ))
        self.assertTrue(np.allclose(state, vec / np.linalg.norm(vec, ord=2)))
예제 #18
0
    def test_prep_circuit_random_vector(self):
        """Tests that a random vector is correctly prepared."""
        # Input vector
        np.random.seed(8675309)
        vec = np.random.randn(4)

        # Make a tree from the vector
        tree = BinaryTree(vec)

        # Get a quantum register and circuit
        qreg = QuantumRegister(2)
        circ = QuantumCircuit(qreg)

        # Do the state preparation circuit
        tree.preparation_circuit(circ, qreg)

        # Swap the qubits to get normal ordering
        circ.swap(qreg[0], qreg[1])
        state = np.real(self.final_state(circ))

        # Make sure the prepared state is close to the input vector
        self.assertTrue(np.allclose(state, vec / np.linalg.norm(vec, ord=2)))
예제 #19
0
    def test_prep_circuit_example_in_paper(self):
        """Tests the state preparation circuit produces the correct state
        for the example given in the quantum recommendations system paper.
        """
        # The same vector used in the paper
        vec = [0.4, 0.4, 0.8, 0.2]

        # Construct the tree from the vector
        tree = BinaryTree(vec)

        # Construct the state preparation circuit
        qreg = QuantumRegister(2)
        circ = QuantumCircuit(qreg)
        tree.preparation_circuit(circ, qreg)

        # Add a swaps to make the ordering of the qubits match the input vector
        # Note: This is because the last bit is the most significant, not the first.
        circ.swap(qreg[0], qreg[1])

        # Check that the circuit produces the correct state
        state = list(np.real(self.final_state(circ)))
        self.assertTrue(np.allclose(state, vec))
예제 #20
0
    def test_prep_ctrl_random_threeq(self):
        """Tests preparing a random vector on three qubits, controlled on another register."""
        for _ in range(50):
            vec = np.random.randn(8)
            tree = BinaryTree(vec)

            register = QuantumRegister(3)
            ctrl_reg = QuantumRegister(2)
            circ = QuantumCircuit(register, ctrl_reg)
            ctrl_key = 0

            tree.preparation_circuit(circ,
                                     register,
                                     control_register=ctrl_reg,
                                     control_key=ctrl_key)

            circ.swap(register[0], register[2])

            state = np.real(TestBinaryTree.final_state(circ))

            self.assertTrue(
                np.allclose(state[:len(vec)],
                            vec / np.linalg.norm(vec, ord=2)))
예제 #21
0
    def test_prepare_negative_amplitudes_two_qubits(self):
        """Tests preparing a vector with negative amplitudes for the example from
        the quantum recommendations systems paper.
        """
        # Input vector
        vec = [-0.4, 0.4, -0.8, 0.2]

        # Get a BinaryTree
        tree = BinaryTree(vec)

        # Get a Quantum Register
        regA = QuantumRegister(1)
        regB = QuantumRegister(1)
        circ = QuantumCircuit(regA, regB)

        # Get the state preparation circuit
        tree.preparation_circuit(circ, regA, regB)

        # Swap the qubits to compare to the natural ordering of the vector
        circ.swap(regA[0], regB[0])

        # Make sure the final state of the circuit is the same as the input vector
        state = np.real(self.final_state(circ))
        self.assertTrue(np.allclose(state, vec))
예제 #22
0
    def test_prep_circuit_large2(self):
        """Tests the state preparation circuit produces the correct state for many qubits."""
        # Input vector (normalized)
        vec = np.array(list(np.ones(32)) + list(np.zeros(32)))

        # Make a tree from the vector
        tree = BinaryTree(vec)

        # Do the state preparation circuit
        qreg = QuantumRegister(6)
        circ = QuantumCircuit(qreg)
        tree.preparation_circuit(circ, qreg)

        # Do the swaps to get the ordering of amplitudes to match with the input vector
        for ii in range(len(qreg) // 2):
            circ.swap(qreg[ii], qreg[-ii - 1])

        # Check that the circuit produces the correct state
        state = np.real(self.final_state(circ))

        # Note: The output state has an additional ancilla needed to do the multi-controlled-Y rotations,
        # so we discard the additional (zero) amplitudes when comparing to the input vector
        self.assertTrue(
            np.allclose(state[:len(vec)], vec / np.linalg.norm(vec, ord=2)))
예제 #23
0
    def test_example_in_paper(self):
        """Tests correctness for the binary tree in the example given in
        Appendix A of the quantum recommendation systems paper.
        """
        # The same vector used in the paper
        row = [0.4, 0.4, 0.8, 0.2]

        # Construct the tree from the vector
        tree = BinaryTree(row)

        # Make sure the elements are equal
        self.assertTrue(np.isclose(tree.data[0][0], 1.0))
        self.assertTrue(np.isclose(tree.data[1][0], 0.32))
        self.assertTrue(np.isclose(tree.data[1][1], 0.68))
        self.assertTrue(np.isclose(tree.data[2][0], 0.16))
        self.assertTrue(np.isclose(tree.data[2][1], 0.16))
        self.assertTrue(np.isclose(tree.data[2][2], 0.64))
        self.assertTrue(np.isclose(tree.data[2][3], 0.04))
예제 #24
0
    def test_prep_circuit_with_control(self):
        """Basic test for the state preparation circuit with a control register.

        This test makes sure the state is created when the control key is correct and *not* created otherwise.
        """
        # Input vector
        vec = np.ones(2, dtype=np.float64)

        # Zero state
        zero = np.array([1, 0], dtype=np.float64)

        # Make a tree from the vector
        tree = BinaryTree(vec)

        # Registers and circuit
        register = QuantumRegister(1)
        control_register = QuantumRegister(1)
        circ = QuantumCircuit(register, control_register)

        # Do controlled state preparation (control_key = 0). This should create the state in "register."
        tree.preparation_circuit(circ,
                                 register,
                                 control_register=control_register,
                                 control_key=0)

        # Get the final state of the circuit
        state = self.final_state(circ)

        # Make sure we get the correct state
        self.assertTrue(
            np.allclose(state[:len(vec)], vec / np.linalg.norm(vec, ord=2)))

        # Do controlled state preparation (control_key=1). This should not create the state in "register."
        # Registers and circuit
        register = QuantumRegister(1)
        control_register = QuantumRegister(1)
        circ = QuantumCircuit(register, control_register)
        tree.preparation_circuit(circ,
                                 register,
                                 control_register=control_register,
                                 control_key=1)

        # Get the final state of the circuit
        state = self.final_state(circ)

        # Make sure it's the |0> state (i.e., nothing has happened)
        self.assertTrue(np.allclose(state[:len(vec)], zero))
예제 #25
0
    def test_parent_value(self):
        """Tests correctness for getting the parent value of a node."""
        # Get a BinaryTree
        tree = BinaryTree([1, 1, 1, 1])

        # Make sure the parent of the root is None
        self.assertIsNone(tree.parent_value(0, 0))

        # Make sure the parent's of the first level (root) are correct
        self.assertTrue(np.isclose(tree.parent_value(1, 0), 4.0))
        self.assertTrue(np.isclose(tree.parent_value(1, 1), 4.0))

        # Make sure the parent's of the second level are correct
        self.assertTrue(np.isclose(tree.parent_value(2, 0), 2.0))
        self.assertTrue(np.isclose(tree.parent_value(2, 1), 2.0))
        self.assertTrue(np.isclose(tree.parent_value(2, 2), 2.0))
        self.assertTrue(np.isclose(tree.parent_value(2, 3), 2.0))
예제 #26
0
    def test_left_child_index(self):
        """Tests getting the index of the left child."""
        # Get a BinaryTree
        tree = BinaryTree([1, 2, 3, 4])

        # Left child of the root
        self.assertEqual(tree.left_child_index(0, 0), (1, 0))

        # Left child indices for the first level
        self.assertEqual(tree.left_child_index(1, 0), (2, 0))
        self.assertEqual(tree.left_child_index(1, 1), (2, 2))

        # Left child indices for leaves
        self.assertIsNone(tree.left_child_index(2, 0))
        self.assertIsNone(tree.left_child_index(2, 1))
        self.assertIsNone(tree.left_child_index(2, 2))
        self.assertIsNone(tree.left_child_index(2, 3))
예제 #27
0
    def test_prep_with_ctrl_string_keys(self):
        """Does the above test with string control keys."""
        # Input vector
        vec = np.ones(2, dtype=np.float64)

        # Zero state
        zero = np.array([1, 0], dtype=np.float64)

        # Make a tree from the vector
        tree = BinaryTree(vec)

        # Register to store the vector
        register = QuantumRegister(1)

        # Register to control on
        control_register = QuantumRegister(1)

        # Circuit
        circ = QuantumCircuit(register, control_register)

        # Do controlled state preparation (control_key = 0). This should create the state in "register."
        tree.preparation_circuit(circ,
                                 register,
                                 control_register=control_register,
                                 control_key="0")

        # Get the final state of the circuit
        state = self.final_state(circ)

        # Make sure it's the |0> state (i.e., nothing has happened)
        self.assertTrue(
            np.allclose(state[:len(vec)], vec / np.linalg.norm(vec, ord=2)))

        # Do anti-controlled state preparation (control_key="1"). This should not create the state in "register."
        register = QuantumRegister(1)
        control_register = QuantumRegister(1)
        circ = QuantumCircuit(register, control_register)
        tree.preparation_circuit(circ,
                                 register,
                                 control_register=control_register,
                                 control_key="1")

        # Get the final state of the circuit
        state = self.final_state(circ)

        self.assertTrue(np.allclose(state[:len(vec)], zero))
예제 #28
0
    def test_right_child_index(self):
        """Tests getting the index of a right child for a set of nodes."""
        # Get a BinaryTree
        tree = BinaryTree([1, 2, 3, 4])

        # Right child of the root
        self.assertEqual(tree.right_child_index(0, 0), (1, 1))

        # Right child indices for the first level
        self.assertEqual(tree.right_child_index(1, 0), (2, 1))
        self.assertEqual(tree.right_child_index(1, 1), (2, 3))

        # Right child indices for leaves
        self.assertIsNone(tree.right_child_index(2, 0))
        self.assertIsNone(tree.right_child_index(2, 1))
        self.assertIsNone(tree.right_child_index(2, 2))
        self.assertIsNone(tree.right_child_index(2, 3))
예제 #29
0
    def test_right_child_value(self):
        """Tests getting the value of a right child for a set of nodes."""
        # Get a BinaryTree
        tree = BinaryTree([1, 1, 1, 1])

        # Check root value
        self.assertTrue(np.isclose(tree.root, 4.0))

        # Right child of the root
        self.assertTrue(np.isclose(tree.right_child_value(0, 0), 2.0))

        # Right child indices for the first level
        self.assertTrue(np.isclose(tree.right_child_value(1, 0), 1.0))
        self.assertTrue(np.isclose(tree.right_child_value(1, 1), 1.0))

        # Right child indices for leaves
        self.assertIsNone(tree.right_child_value(2, 0))
        self.assertIsNone(tree.right_child_value(2, 1))
        self.assertIsNone(tree.right_child_value(2, 2))
        self.assertIsNone(tree.right_child_value(2, 3))
예제 #30
0
 def test_print_small(self):
     """Tests the correct string format is obtained when printing a small tree."""
     tree = BinaryTree([1, 1])
     correct = "    2.00    \n1.00    1.00\n"
     self.assertEqual(tree.__str__(), correct)