def test_known_operation_results(self): ''' Verifies the resulting state of several operations. ''' test_results = [] # Takes |0> to |1> some_reg = qReg() X.on(some_reg) test_results.append(some_reg.dump_state()) # Takes |0> to |0001> some_reg = qReg() X.on(some_reg) I.on(some_reg, 3) test_results.append(some_reg.dump_state()) # Takes |0> to (1/sqrt(2))(|000> - |100>) some_reg = qReg() X.on(some_reg, 2) H.on(some_reg, 2) test_results.append(some_reg.dump_state()) expected_results = [ np.array([0, 1]), np.array([0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), 1 / np.sqrt(2) * np.array([1, 0, 0, 0, -1, 0, 0, 0]) ] for test_pair in zip(test_results, expected_results): np.testing.assert_array_almost_equal(test_pair[0], test_pair[1])
def test_operator_overloading_imul_dereferences_arg(self): ''' Checks that `*=` dereferences the right hand operand. ''' q = qReg() p = qReg() q *= p self.assertTrue(p._qReg__is_dereferenced) self.assertFalse(q._qReg__is_dereferenced)
def test_operator_overloading_imul_on_dereferenced_args_fails(self): ''' Checks that `*=` fails when either involved register is dereferenced. ''' q = qReg() p = qReg() q *= p r = qReg() self.assertRaises(IllegalRegisterReference, q.__imul__, p) self.assertRaises(IllegalRegisterReference, p.__imul__, r)
def test_mult_checks_both_regs_for_dereference(self): ''' Verifies that multiplication checks whether both argument registers are dereferenced. ''' a = qReg() b = a * qReg() self.assertRaises(IllegalRegisterReference, a.__mul__, b) self.assertRaises(IllegalRegisterReference, b.__mul__, a) self.assertRaises(IllegalRegisterReference, a.__imul__, b) self.assertRaises(IllegalRegisterReference, b.__imul__, a)
def deutschJozsa(input_register, black_box): # Take |input_reg> to |input_reg>|1> input_register *= qReg() X.on(input_register, 0) # Prep qubits 1 to n in the Hadamard state. for i in range(1, n + 1): H.on(input_register, i) # Flip the answer qubit and apply H. H.on(input_register, 0) # Query the oracle. black_box.on(input_register, *list(range(n + 1))) # Apply H to the qubits 1 through n. for i in range(1, n + 1): H.on(input_register, i) # Measure the first n qubits. If the any of the results # are nonzero, the oracle is balanced. Else, it is constant. results = [] for i in range(1, n + 1): results.append(input_register.measure(i)) return results
def test_measurement_on_five_qubit_state(self): register = qReg(5) X.on(register, 3) X.on(register, 0) H.on(register, 1) self.assertEqual(register.measure(3), 1) self.assertEqual(register.measure(4), 0)
def test_operator_overloading_imul_fails_for_non_qreg_arg(self): ''' Checks that `*=` throws a TypeError when the right hand operand is not a `qReg`. ''' q = qReg() self.assertRaises(TypeError, q.__imul__, 4)
def test_operator_overloading_iadd(self): ''' Tests that `+=` adds one or more qubits to register. ''' q = qReg() q += 3 self.assertEqual(4, len(q))
def test_operator_overloading_iadd_fails_for_negative_arg(self): ''' Checks that a ValueError is throws for negative right hand operand to `+=`. ''' q = qReg() self.assertRaises(ValueError, q.__iadd__, -2)
def test_operator_overloading_iadd_fails_for_nonint(self): ''' Checks that a ValueError is thrown for noninteger right hand operand to `+=`. ''' q = qReg() self.assertRaises(ValueError, q.__iadd__, 3.2)
def test_apply_noisy_gate(self): ''' Deterministic verification of application of gate with some NoiseModel set (using prob 1 amplitude damping). ''' registerInZeroStateInitially = qReg() registerInOneStateInitially = qReg() X.on(registerInOneStateInitially) self.test_op.set_noise_model(damping_map(1.0)) self.test_op.on(registerInZeroStateInitially) self.test_op.on(registerInOneStateInitially) np.testing.assert_array_equal( registerInZeroStateInitially.dump_state(), [1, 0]) np.testing.assert_array_equal(registerInOneStateInitially.dump_state(), [1, 0])
def test_qOpFailsWhenAppliedToDereferencedqReg(self): ''' ``IllegalRegisterReference`` is raised when attempting to operate on a ``qReg``. ''' q_reg = qReg() q_reg._qReg__is_dereferenced = True self.assertRaises(IllegalRegisterReference, self.test_op.on, q_reg)
def test_operator_overloading_misc(self): ''' Tests that several operator overloading methods behave correctly for ``qReg`` objects. ''' temp_reg = qReg() X.on(temp_reg) temp_reg += 1 self.test_reg *= temp_reg state_001 = np.array([0, 1, 0, 0, 0, 0, 0, 0]) np.testing.assert_array_equal(state_001, self.test_reg.dump_state()) temp_reg = qReg() X.on(temp_reg) a_new_reg = self.test_reg * temp_reg state_0011 = np.zeros(16) state_0011[3] = 1 np.testing.assert_array_equal(state_0011, a_new_reg.dump_state())
def test_identity_swap_for_no_targets(self): ''' Verifies that the private ``qOp.__generate_swap()`` retuns identity matrices as permutation operators when no nargets are specified. ''' two_qubits = qReg(2) permutation, inverse = CNOT._qOp__generate_swap(two_qubits) np.testing.assert_array_equal(np.eye(4, 4), permutation) np.testing.assert_array_equal(np.eye(4, 4), inverse)
def test_swap_non_int_input(self): ''' The private ``qOp.__generate_swap()`` method must fail if any of the targets are not nonnegative integers. ''' some_reg = qReg() some_reg += 3 self.assertRaises(IndexError, self.test_op._qOp__generate_swap, some_reg, 0, 0.1) self.assertRaises(IndexError, self.test_op._qOp__generate_swap, some_reg, 2, 0, -1)
def test__generateStateTransitionProbabilities(self): ''' Checks that a ``NonUnitaryInputError`` is thrown for nonunitary arguments. ''' nonUnitaryMatrix = np.eye(4) nonUnitaryMatrix[0, 0] = 0 twoQubitRegister = qReg(2) self.assertRaises( NonUnitaryInputError, twoQubitRegister._generateStateTransitionProbabilities, nonUnitaryMatrix)
def test_apply_noisy_gate_with_raised_register(self): ''' Deterministic verification of application of gate with some NoiseModel set (using prob 1 amplitude damping) where qReg needs to be raised. ''' singleQubitInOneStateInitialy = qReg() X.on(singleQubitInOneStateInitialy) self.test_op.set_noise_model(damping_map(1.0)) self.test_op.on(singleQubitInOneStateInitialy, 1) np.testing.assert_array_equal( singleQubitInOneStateInitialy.dump_state(), [0, 1, 0, 0])
def test_register_dereferencing(self): ''' Verifies that ``qReg`` instances get dereferenced in cases where the no-cloning theorem would be violated. ''' # Multiplication operation dereferences register. a = qReg() X.on(a) b = qReg() c = a * b d = qReg() d *= c state_010 = np.zeros(8) state_010[2] = 1 # a, b, and c should all be dereferenced. D should be in |0010> np.testing.assert_array_equal(state_010, d.dump_state()) deref = [a, b, c] for register in deref: # Checks that the dereferenced register is fully dead (i.e. all # methods called with or on it raise an exception. self.assertRaises(IllegalRegisterReference, register.measure, 0) self.assertRaises(IllegalRegisterReference, register.measure_observable, Z) self.assertRaises(IllegalRegisterReference, register.peek) self.assertRaises(IllegalRegisterReference, register.dump_state) self.assertRaises(IllegalRegisterReference, register.__iadd__, 1) self.assertRaises(IllegalRegisterReference, register.__mul__, qReg()) self.assertRaises(IllegalRegisterReference, register.__imul__, qReg()) self.assertRaises(IllegalRegisterReference, len, register) self.assertRaises(IllegalRegisterReference, X.on, register, 0)
def test_measurement_collapses_register_state(self): ''' Check that a ``qReg`` in the normalized version of the state |00> + |10> correctly collapses on measurement of qubit 0 to either |00> or |10>. ''' initiallySuperposedRegister = qReg(2) H.on(initiallySuperposedRegister, 1) measurement_outcome = initiallySuperposedRegister.measure(1) if measurement_outcome == 0: np.testing.assert_array_equal( initiallySuperposedRegister.dump_state(), [1, 0, 0, 0]) else: np.testing.assert_array_equal( initiallySuperposedRegister.dump_state(), [0, 0, 1, 0])
else: prob = 0.1 theory_success = (1 - prob)**3 + 3 * prob * (1 - prob)**2 theory_failure = 1 - theory_success successes = 0 failures = 0 noisy_channel = qOp(np.eye(2), kraus_ops=b_flip_map(prob)) # Check that we are getting the correct statistics out of our noisy channel. print("Initialized noisy channel with {:.1f}% chance of bit flip.".format( 100 * prob)) print("Probing channel with single qubit {} times...".format(n_trials)) flip_amount = 0 for i in range(n_trials): register = qReg() noisy_channel.on(register) if not np.array_equal([1, 0], register.dump_state()): flip_amount += 1 flip_percent = 100 * flip_amount / n_trials print("Bit flip occured ({:.1f} +/- {:.1f})% of the time.\n".format( flip_percent, 0.5 * flip_percent / np.sqrt(n_trials))) print("With bit flip probability of {:.1f}%:".format(100 * prob)) print("Theoretical transmission success rate: {:.1f}%".format(100 * theory_success)) print("Theoretical transmission failure rate: {:.1f}%\n".format( 100 * theory_failure)) # Now we send an encoded state through our noisy channel n_trials times.
# are nonzero, the oracle is balanced. Else, it is constant. results = [] for i in range(1, n + 1): results.append(input_register.measure(i)) return results # Let's try this out a whole bunch of times! if len(sys.argv) > 1 and int(sys.argv[1]) > 0: n_tries = int(sys.argv[1]) else: n_tries = 10 zeros = 0 ones = 0 print("Conducting {} trials...".format(n_tries)) for i in range(n_tries): input_register = qReg(n) oracle_list = make_black_box() black_box = qOracle(lambda i: oracle_list[i], n) results = deutschJozsa(input_register, black_box) if any(results): ones += 1 else: zeros += 1 print("Number of zero measurements (constant oracle): {}".format(zeros)) print("Number of one measurements (balanced oracle): {}".format(ones))
import context # Remove this import if running with pip installed version. import numpy as np from pypsqueak.api import qReg, qOp from pypsqueak.gates import X, I from pypsqueak.noise import damping_map import sys # Prep a qReg in the |1> state qubit = qReg() X.on(qubit) # Send it through an amp decay channel with 0.3 chance of decay. if len(sys.argv) > 1 and int(sys.argv[1]) > 0: n_runs = int(sys.argv[1]) else: n_runs = 1000 if len(sys.argv) > 2 and float(sys.argv[2]) >= 0 and float(sys.argv[2]) <= 1: prob = float(sys.argv[2]) else: prob = 0.3 noisy_channel = qOp(kraus_ops=damping_map(prob)) zeros = 0 ones = 0 print("Sending the state |1> through a noisy channel {} times with amplitude decay probability={}...".format(n_runs, prob)) for i in range(n_runs): noisy_channel.on(qubit) result = qubit.measure(0)
def setUp(self): # Test register and operator self.test_reg = qReg() self.test_op = qOp()