def test_apply_errors(self): """Test that apply fails for incorrect state preparation""" self.logTestName() with self.assertRaisesRegex( ValueError, 'incorrect size for the number of subsystems'): p = [thermal_state(0.5)] self.dev.apply('GaussianState', wires=[0], par=[p]) with self.assertRaisesRegex(ValueError, 'Incorrect number of subsystems'): p = U self.dev.apply('Interferometer', wires=[0], par=[p]) with self.assertRaisesRegex( ValueError, "Invalid target subsystems provided in 'wires' argument"): p = U2 dev = DefaultGaussian(wires=4, shots=0, hbar=hbar) self.dev.apply('Interferometer', wires=[0, 1, 2], par=[p])
def setUp(self): self.dev = DefaultGaussian(wires=2, shots=0, hbar=hbar)
class TestDefaultGaussianDevice(BaseTest): """Test the default gaussian device. The test ensures that the device is properly applying gaussian operations and calculating the correct observables.""" def setUp(self): self.dev = DefaultGaussian(wires=2, shots=0, hbar=hbar) def test_operation_map(self): """Test that default Gaussian device supports all PennyLane Gaussian CV gates.""" self.logTestName() non_supported = { 'FockDensityMatrix', 'FockStateVector', 'FockState', 'CrossKerr', 'CatState', 'CubicPhase', 'Kerr' } self.assertEqual( set(qml.ops._cv__ops__) - non_supported, set(self.dev._operation_map)) def test_observable_map(self): """Test that default Gaussian device supports all PennyLane Gaussian continuous observables.""" self.logTestName() self.assertEqual( set(qml.ops._cv__obs__) | {'Identity'} - {'Heterodyne'}, set(self.dev._observable_map)) def test_apply(self): """Test the application of gates to a state""" self.logTestName() # loop through all supported operations for gate_name, fn in self.dev._operation_map.items(): log.debug("\tTesting %s gate...", gate_name) self.dev.reset() # start in the displaced squeezed state alpha = 0.542 + 0.123j a = abs(alpha) phi_a = np.angle(alpha) r = 0.652 phi_r = -0.124 self.dev.apply('DisplacedSqueezedState', wires=[0], par=[a, phi_a, r, phi_r]) self.dev.apply('DisplacedSqueezedState', wires=[1], par=[a, phi_a, r, phi_r]) # get the equivalent pennylane operation class op = qml.ops.__getattribute__(gate_name) # the list of wires to apply the operation to w = list(range(op.num_wires)) if op.par_domain == 'A': # the parameter is an array if gate_name == 'GaussianState': p = [ np.array([0.432, 0.123, 0.342, 0.123]), np.diag([0.5234] * 4) ] w = list(range(2)) expected_out = p elif gate_name == 'Interferometer': w = list(range(2)) p = [U] S = fn(*p) expected_out = S @ self.dev._state[0], S @ self.dev._state[ 1] @ S.T else: # the parameter is a float p = [0.432423, -0.12312, 0.324, 0.751][:op.num_params] if gate_name == 'Displacement': alpha = p[0] * np.exp(1j * p[1]) state = self.dev._state mu = state[0].copy() mu[w[0]] += alpha.real * np.sqrt(2 * hbar) mu[w[0] + 2] += alpha.imag * np.sqrt(2 * hbar) expected_out = mu, state[1] elif 'State' in gate_name: mu, cov = fn(*p, hbar=hbar) expected_out = self.dev._state expected_out[0][[w[0], w[0] + 2]] = mu ind = np.concatenate( [np.array([w[0]]), np.array([w[0]]) + 2]) rows = ind.reshape(-1, 1) cols = ind.reshape(1, -1) expected_out[1][rows, cols] = cov else: # if the default.gaussian is an operation accepting parameters, # initialise it using the parameters generated above. S = fn(*p) # calculate the expected output if op.num_wires == 1: # reorder from symmetric ordering to xp-ordering S = block_diag( S, np.identity(2))[:, [0, 2, 1, 3]][[0, 2, 1, 3]] expected_out = S @ self.dev._state[0], S @ self.dev._state[ 1] @ S.T self.dev.apply(gate_name, wires=w, par=p) # verify the device is now in the expected state self.assertAllAlmostEqual(self.dev._state[0], expected_out[0], delta=self.tol) self.assertAllAlmostEqual(self.dev._state[1], expected_out[1], delta=self.tol) def test_apply_errors(self): """Test that apply fails for incorrect state preparation""" self.logTestName() with self.assertRaisesRegex( ValueError, 'incorrect size for the number of subsystems'): p = [thermal_state(0.5)] self.dev.apply('GaussianState', wires=[0], par=[p]) with self.assertRaisesRegex(ValueError, 'Incorrect number of subsystems'): p = U self.dev.apply('Interferometer', wires=[0], par=[p]) with self.assertRaisesRegex( ValueError, "Invalid target subsystems provided in 'wires' argument"): p = U2 dev = DefaultGaussian(wires=4, shots=0, hbar=hbar) self.dev.apply('Interferometer', wires=[0, 1, 2], par=[p]) def test_expectation(self): """Test that expectation values are calculated correctly""" self.logTestName() dev = qml.device('default.gaussian', wires=1, hbar=hbar) # test correct mean for <n> of a displaced thermal state nbar = 0.5431 alpha = 0.324 - 0.59j dev.apply('ThermalState', wires=[0], par=[nbar]) dev.apply('Displacement', wires=[0], par=[alpha, 0]) mean = dev.expval('NumberOperator', [0], []) self.assertAlmostEqual(mean, np.abs(alpha)**2 + nbar, delta=self.tol) # test correct mean for Homodyne P measurement alpha = 0.324 - 0.59j dev.apply('CoherentState', wires=[0], par=[alpha]) mean = dev.expval('P', [0], []) self.assertAlmostEqual(mean, alpha.imag * np.sqrt(2 * hbar), delta=self.tol) # test correct mean for Homodyne measurement mean = dev.expval('QuadOperator', [0], [np.pi / 2]) self.assertAlmostEqual(mean, alpha.imag * np.sqrt(2 * hbar), delta=self.tol) # test correct mean for number state expectation |<n|alpha>|^2 # on a coherent state for n in range(3): mean = dev.expval('FockStateProjector', [0], [np.array([n])]) expected = np.abs( np.exp(-np.abs(alpha)**2 / 2) * alpha**n / np.sqrt(fac(n)))**2 self.assertAlmostEqual(mean, expected, delta=self.tol) # test correct mean for number state expectation |<n|S(r)>|^2 # on a squeezed state n = 1 r = 0.4523 dev.apply('SqueezedState', wires=[0], par=[r, 0]) mean = dev.expval('FockStateProjector', [0], [np.array([2 * n])]) expected = np.abs( np.sqrt(fac(2 * n)) / (2**n * fac(n)) * (-np.tanh(r))**n / np.sqrt(np.cosh(r)))**2 self.assertAlmostEqual(mean, expected, delta=self.tol) def test_variance_displaced_thermal_mean_photon(self): """test correct variance for <n> of a displaced thermal state""" self.logTestName() dev = qml.device('default.gaussian', wires=1, hbar=hbar) nbar = 0.5431 alpha = 0.324 - 0.59j dev.apply('ThermalState', wires=[0], par=[nbar]) dev.apply('Displacement', wires=[0], par=[alpha, 0]) var = dev.var('NumberOperator', [0], []) self.assertAlmostEqual(var, nbar**2 + nbar + np.abs(alpha)**2 * (1 + 2 * nbar), delta=self.tol) def test_variance_coherent_homodyne(self): """test correct variance for Homodyne P measurement""" self.logTestName() dev = qml.device('default.gaussian', wires=1, hbar=hbar) alpha = 0.324 - 0.59j dev.apply('CoherentState', wires=[0], par=[alpha]) var = dev.var('P', [0], []) self.assertAlmostEqual(var, hbar / 2, delta=self.tol) # test correct mean and variance for Homodyne measurement var = dev.var('QuadOperator', [0], [np.pi / 2]) self.assertAlmostEqual(var, hbar / 2, delta=self.tol) def test_variance_coherent_numberstate(self): """test correct variance for number state expectation |<n|alpha>|^2 on a coherent state """ self.logTestName() dev = qml.device('default.gaussian', wires=1, hbar=hbar) alpha = 0.324 - 0.59j dev.apply('CoherentState', wires=[0], par=[alpha]) for n in range(3): var = dev.var('FockStateProjector', [0], [np.array([n])]) mean = np.abs( np.exp(-np.abs(alpha)**2 / 2) * alpha**n / np.sqrt(fac(n)))**2 self.assertAlmostEqual(var, mean * (1 - mean), delta=self.tol) def test_variance_squeezed_numberstate(self): """test correct variance for number state expectation |<n|S(r)>|^2 on a squeezed state """ self.logTestName() dev = qml.device('default.gaussian', wires=1, hbar=hbar) n = 1 r = 0.4523 dev.apply('SqueezedState', wires=[0], par=[r, 0]) var = dev.var('FockStateProjector', [0], [np.array([2 * n])]) mean = np.abs( np.sqrt(fac(2 * n)) / (2**n * fac(n)) * (-np.tanh(r))**n / np.sqrt(np.cosh(r)))**2 self.assertAlmostEqual(var, mean * (1 - mean), delta=self.tol) def test_reduced_state(self): """Test reduced state""" self.logTestName() # Test error is raised if requesting a non-existant subsystem with self.assertRaisesRegex( ValueError, "specified wires cannot be larger than the number of subsystems" ): self.dev.reduced_state([6, 4]) # Test requesting via an integer res = self.dev.reduced_state(0) expected = self.dev.reduced_state([0]) self.assertAllAlmostEqual(res[0], expected[0], delta=self.tol) self.assertAllAlmostEqual(res[1], expected[1], delta=self.tol) # Test requesting all wires returns the full state res = self.dev.reduced_state([0, 1]) expected = self.dev._state self.assertAllAlmostEqual(res[0], expected[0], delta=self.tol) self.assertAllAlmostEqual(res[1], expected[1], delta=self.tol)
def setUp(self): self.dev = DefaultGaussian(wires=2, shots=1000, hbar=hbar, analytic=True)