From c1b4d00ec2a2ca797b908673245d6382f5a32ca5 Mon Sep 17 00:00:00 2001 From: qci-chou Date: Tue, 6 Jul 2021 18:00:38 -0400 Subject: [PATCH 1/7] KSC: Add unitary option for rotate() --- sequencing/modes.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/sequencing/modes.py b/sequencing/modes.py index 02ecdfe..c3b653c 100644 --- a/sequencing/modes.py +++ b/sequencing/modes.py @@ -706,7 +706,7 @@ def anharmonicity(self, alpha): self.kerr = alpha @capture_operation - def rotate(self, angle, phase, pulse_name=None, **kwargs): + def rotate(self, angle, phase, pulse_name=None, unitary=False, **kwargs): """Generate a pulse to rotate the qubit by a given angle about a given axis. @@ -717,21 +717,30 @@ def rotate(self, angle, phase, pulse_name=None, **kwargs): phase (float): Rotation axis relative to the x axis. pulse_name (optional, str): Name of the pulse to use. If None, will use ``self.default_pulse``. Default: None. + unitary (optional, bool): Whether to return the corresponding + unitary operator instead of executing the pulse. + Default: False. Returns: - Operation: The resulting ``Operation`` object. + ``qutip.Qobj`` or Operation: If ``unitary`` is True, returns + the unitary operator Rx(angle), otherwise returns the resulting + ``Operation`` object. """ - pulse_name = pulse_name or self.default_pulse - pulse = getattr(self, pulse_name) - # Assuming that default_pulse.amp = 1 corresponds to rotation of pi - norm = gaussian_chop_norm(pulse.sigma, pulse.chop) - amp = angle * pulse.amp / norm - c_wave = pulse(amp=amp, phase=phase, **kwargs) - terms = { - f"{self.name}.x": HTerm(self.x, c_wave.real), - f"{self.name}.y": HTerm(self.y, c_wave.imag), - } - return Operation(len(c_wave), terms) + if unitary: + full_space = kwargs.get("full_space", True) + return self.Raxis(angle, phase, full_space=full_space) + else: + pulse_name = pulse_name or self.default_pulse + pulse = getattr(self, pulse_name) + # Assuming that default_pulse.amp = 1 corresponds to rotation of pi + norm = gaussian_chop_norm(pulse.sigma, pulse.chop) + amp = angle * pulse.amp / norm + c_wave = pulse(amp=amp, phase=phase, **kwargs) + terms = { + f"{self.name}.x": HTerm(self.x, c_wave.real), + f"{self.name}.y": HTerm(self.y, c_wave.imag), + } + return Operation(len(c_wave), terms) def rotate_x(self, angle, unitary=False, **kwargs): """Generate a rotation about the x axis. From 46c244a2387fae16371a30a8bc4f2beb56c996b6 Mon Sep 17 00:00:00 2001 From: qci-chou Date: Tue, 6 Jul 2021 18:02:48 -0400 Subject: [PATCH 2/7] KSC: Adding test coverage to compare qubit rotation sequences with unitary definition. WARNING: test_sequence_Raxis currently fails. --- sequencing/test/test_rotations.py | 86 +++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 sequencing/test/test_rotations.py diff --git a/sequencing/test/test_rotations.py b/sequencing/test/test_rotations.py new file mode 100644 index 0000000..5f8cd3f --- /dev/null +++ b/sequencing/test/test_rotations.py @@ -0,0 +1,86 @@ +import unittest +import numpy as np +import qutip +from sequencing import ( + Transmon, + Cavity, + System, + Sequence, + CTerm, + Operation, + capture_operation, + get_sequence, + sync, + delay, + delay_channels, + ket2dm, + ops2dms, +) +from sequencing.sequencing import ( + ValidatedList, + CompiledPulseSequence, + PulseSequence, + SyncOperation, + HamiltonianChannels, +) + + +class TestSequenceVsUnitary(unittest.TestCase): + @classmethod + def setUpClass(cls): + qubit = Transmon("qubit", levels=2) + system = System("system", modes=[qubit]) + cls.system = system + + def test_sequence_Rx(self): + + system = self.system + qubit = system.qubit + + init_state = system.ground_state() + + seq = Sequence(system) + qubit.rotate_x(np.pi/2) + sync() + + result = seq.run(init_state) + states = result.states + fidelity = qutip.fidelity(states[-1], qubit.Rx(np.pi/2) * init_state) ** 2 + self.assertGreater(fidelity, 0.999) + + def test_sequence_Ry(self): + + system = self.system + qubit = system.qubit + + init_state = system.ground_state() + + seq = Sequence(system) + qubit.rotate_y(np.pi/2) + sync() + + result = seq.run(init_state) + states = result.states + fidelity = qutip.fidelity(states[-1], qubit.Ry(np.pi/2) * init_state) ** 2 + self.assertGreater(fidelity, 0.999) + + def test_sequence_Raxis(self): + + system = self.system + qubit = system.qubit + + init_state = system.ground_state() + theta = np.pi*0.456 + phi = -np.pi*0.567 + + seq = Sequence(system) + qubit.rotate(theta, phi) + sync() + + result = seq.run(init_state) + states = result.states + fidelity = qutip.fidelity(states[-1], qubit.Raxis(theta, phi) * init_state) ** 2 + self.assertGreater(fidelity, 0.999) + +if __name__ == "__main__": + unittest.main() From 30ccd03040a02acc2f6b4974304e9d4755a56436 Mon Sep 17 00:00:00 2001 From: qci-chou Date: Tue, 6 Jul 2021 21:49:59 -0400 Subject: [PATCH 3/7] KSC: change sign of pulse phase kwarg --- sequencing/modes.py | 2 +- sequencing/pulses.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sequencing/modes.py b/sequencing/modes.py index c3b653c..17d65ff 100644 --- a/sequencing/modes.py +++ b/sequencing/modes.py @@ -784,7 +784,7 @@ def rotate_y(self, angle, unitary=False, **kwargs): if unitary: full_space = kwargs.get("full_space", True) return self.Ry(angle, full_space=full_space) - return self.rotate(-angle, np.pi / 2, **kwargs) + return self.rotate(angle, np.pi / 2, **kwargs) @attr.s diff --git a/sequencing/pulses.py b/sequencing/pulses.py index f7df8cd..548240d 100644 --- a/sequencing/pulses.py +++ b/sequencing/pulses.py @@ -83,7 +83,7 @@ def array_pulse( else: i_wave = amp * i_wave + i_noise q_wave = amp * q_wave + q_noise - c_wave = (i_wave + 1j * q_wave) * np.exp(-1j * phase) + c_wave = (i_wave + 1j * q_wave) * np.exp(1j * phase) return c_wave From 7670f7fbdc71cb74c9f025a4825e12377847c425 Mon Sep 17 00:00:00 2001 From: qci-chou Date: Tue, 6 Jul 2021 22:07:45 -0400 Subject: [PATCH 4/7] KSC: formatting updates --- sequencing/modes.py | 2 +- sequencing/sequencing/basic.py | 13 +---- sequencing/sequencing/main.py | 12 +---- sequencing/test/test_gates.py | 79 ++++--------------------------- sequencing/test/test_rotations.py | 19 ++++---- setup.py | 6 +-- 6 files changed, 25 insertions(+), 106 deletions(-) diff --git a/sequencing/modes.py b/sequencing/modes.py index 17d65ff..0fca373 100644 --- a/sequencing/modes.py +++ b/sequencing/modes.py @@ -726,7 +726,7 @@ def rotate(self, angle, phase, pulse_name=None, unitary=False, **kwargs): the unitary operator Rx(angle), otherwise returns the resulting ``Operation`` object. """ - if unitary: + if unitary: full_space = kwargs.get("full_space", True) return self.Raxis(angle, phase, full_space=full_space) else: diff --git a/sequencing/sequencing/basic.py b/sequencing/sequencing/basic.py index 3d73bbc..915721a 100644 --- a/sequencing/sequencing/basic.py +++ b/sequencing/sequencing/basic.py @@ -439,12 +439,7 @@ def build_hamiltonian(self): return self.hc.build_hamiltonian() def run( - self, - init_state, - c_ops=None, - e_ops=None, - options=None, - progress_bar=None, + self, init_state, c_ops=None, e_ops=None, options=None, progress_bar=None, ): """Simulate the sequence using qutip.mesolve. @@ -497,11 +492,7 @@ def run( ) def propagator( - self, - c_ops=None, - options=None, - unitary_mode="batch", - parallel=False, + self, c_ops=None, options=None, unitary_mode="batch", parallel=False, ): """Calculate the propagator using ``qutip.propagator()``. diff --git a/sequencing/sequencing/main.py b/sequencing/sequencing/main.py index bec7dff..0640566 100644 --- a/sequencing/sequencing/main.py +++ b/sequencing/sequencing/main.py @@ -99,12 +99,7 @@ def channels(self): return self.compile().channels def run( - self, - init_state, - c_ops=None, - e_ops=None, - options=None, - progress_bar=None, + self, init_state, c_ops=None, e_ops=None, options=None, progress_bar=None, ): """Simulate the sequence using qutip.mesolve. @@ -159,10 +154,7 @@ def propagator( if all(isinstance(op, SyncOperation) for op in self): return [self.system.I()] return self.compile().propagator( - c_ops=c_ops, - options=options, - unitary_mode=unitary_mode, - parallel=parallel, + c_ops=c_ops, options=options, unitary_mode=unitary_mode, parallel=parallel, ) def plot_coefficients(self, subplots=True, plot_imag=False, step=False): diff --git a/sequencing/test/test_gates.py b/sequencing/test/test_gates.py index db7cef0..c3174be 100644 --- a/sequencing/test/test_gates.py +++ b/sequencing/test/test_gates.py @@ -219,14 +219,7 @@ def test_cx(self): control, target = self.system.modes cx = gates.CXGate(control=control, target=target)() - ideal = np.array( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 0, 1], - [0, 0, 1, 0], - ] - ) + ideal = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0],]) self.assertTrue(np.array_equal(cx.full(), ideal)) cx = gates.cx(control, target) @@ -236,14 +229,7 @@ def test_cy(self): control, target = self.system.modes cy = gates.CYGate(control=control, target=target)() - ideal = np.array( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 0, -1j], - [0, 0, 1j, 0], - ] - ) + ideal = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0],]) self.assertTrue(np.array_equal(cy.full(), ideal)) cy = gates.cy(control, target) @@ -253,14 +239,7 @@ def test_cz(self): control, target = self.system.modes cz = gates.CZGate(control=control, target=target)() - ideal = np.array( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, -1], - ] - ) + ideal = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1],]) self.assertTrue(np.array_equal(cz.full(), ideal)) cz = gates.cz(control, target) @@ -273,12 +252,7 @@ def test_cphase(self): cphase = gates.CPhaseGate(control=control, target=target)(phi) ideal = np.array( - [ - [1, 0, 0, 0], - [0, 1, 0, 0], - [0, 0, 1, 0], - [0, 0, 0, np.exp(1j * phi)], - ] + [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, np.exp(1j * phi)],] ) self.assertTrue(np.array_equal(cphase.full(), ideal)) @@ -289,14 +263,7 @@ def test_swap(self): q1, q2 = self.system.modes swap = gates.SWAPGate(q1, q2)() - ideal = np.array( - [ - [1, 0, 0, 0], - [0, 0, 1, 0], - [0, 1, 0, 0], - [0, 0, 0, 1], - ] - ) + ideal = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1],]) self.assertTrue(np.array_equal(swap.full(), ideal)) swap = gates.swap(q1, q2) @@ -308,14 +275,7 @@ def test_swapphi(self): swapphi = gates.SWAPphiGate(q1, q2)(phi) p = -1j * np.exp(1j * phi) m = 1j * np.exp(-1j * phi) - ideal = np.array( - [ - [1, 0, 0, 0], - [0, 0, m, 0], - [0, p, 0, 0], - [0, 0, 0, 1], - ] - ) + ideal = np.array([[1, 0, 0, 0], [0, 0, m, 0], [0, p, 0, 0], [0, 0, 0, 1],]) self.assertTrue(np.array_equal(swapphi.full(), ideal)) swapphi = gates.swapphi(q1, q2, phi) @@ -329,14 +289,7 @@ def test_iswap(self): q1, q2 = self.system.modes iswap = gates.iSWAPGate(q1, q2)() - ideal = np.array( - [ - [1, 0, 0, 0], - [0, 0, 1j, 0], - [0, 1j, 0, 0], - [0, 0, 0, 1], - ] - ) + ideal = np.array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1],]) self.assertTrue(np.array_equal(iswap.full(), ideal)) iswap = gates.iswap(q1, q2) @@ -347,14 +300,7 @@ def test_eswap(self): theta_c = -np.pi / 4 eswap = gates.eSWAPGate(q1, q2)(theta_c, phi=np.pi / 2) - swap = np.array( - [ - [1, 0, 0, 0], - [0, 0, 1, 0], - [0, 1, 0, 0], - [0, 0, 0, 1], - ] - ) + swap = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1],]) ideal = np.cos(theta_c / 2) * np.eye(4) - 1j * np.sin(theta_c / 2) * swap self.assertTrue(np.allclose(eswap.full(), ideal)) @@ -367,14 +313,7 @@ def test_sqrtswap(self): sqrtswap = gates.SqrtSWAPGate(q1, q2)() p = (1 + 1j) / 2 m = (1 - 1j) / 2 - ideal = np.array( - [ - [1, 0, 0, 0], - [0, p, m, 0], - [0, m, p, 0], - [0, 0, 0, 1], - ] - ) + ideal = np.array([[1, 0, 0, 0], [0, p, m, 0], [0, m, p, 0], [0, 0, 0, 1],]) self.assertTrue(np.allclose(sqrtswap.full(), ideal)) sqrtswap = gates.sqrtswap(q1, q2) diff --git a/sequencing/test/test_rotations.py b/sequencing/test/test_rotations.py index 5f8cd3f..c24575f 100644 --- a/sequencing/test/test_rotations.py +++ b/sequencing/test/test_rotations.py @@ -40,12 +40,12 @@ def test_sequence_Rx(self): init_state = system.ground_state() seq = Sequence(system) - qubit.rotate_x(np.pi/2) + qubit.rotate_x(np.pi / 2) sync() - + result = seq.run(init_state) states = result.states - fidelity = qutip.fidelity(states[-1], qubit.Rx(np.pi/2) * init_state) ** 2 + fidelity = qutip.fidelity(states[-1], qubit.Rx(np.pi / 2) * init_state) ** 2 self.assertGreater(fidelity, 0.999) def test_sequence_Ry(self): @@ -56,12 +56,12 @@ def test_sequence_Ry(self): init_state = system.ground_state() seq = Sequence(system) - qubit.rotate_y(np.pi/2) + qubit.rotate_y(np.pi / 2) sync() - + result = seq.run(init_state) states = result.states - fidelity = qutip.fidelity(states[-1], qubit.Ry(np.pi/2) * init_state) ** 2 + fidelity = qutip.fidelity(states[-1], qubit.Ry(np.pi / 2) * init_state) ** 2 self.assertGreater(fidelity, 0.999) def test_sequence_Raxis(self): @@ -70,17 +70,18 @@ def test_sequence_Raxis(self): qubit = system.qubit init_state = system.ground_state() - theta = np.pi*0.456 - phi = -np.pi*0.567 + theta = np.pi * 0.456 + phi = -np.pi * 0.567 seq = Sequence(system) qubit.rotate(theta, phi) sync() - + result = seq.run(init_state) states = result.states fidelity = qutip.fidelity(states[-1], qubit.Raxis(theta, phi) * init_state) ** 2 self.assertGreater(fidelity, 0.999) + if __name__ == "__main__": unittest.main() diff --git a/setup.py b/setup.py index 7cec7d1..7152974 100644 --- a/setup.py +++ b/setup.py @@ -35,11 +35,7 @@ ] EXTRAS_REQUIRE = { - "docs": [ - "sphinx", - "sphinx_rtd_theme", - "nbsphinx", - ], + "docs": ["sphinx", "sphinx_rtd_theme", "nbsphinx",], } CLASSIFIERS = """\ From 8aacc77237b246223caa69dc767da851b9e8a12b Mon Sep 17 00:00:00 2001 From: qci-chou Date: Tue, 6 Jul 2021 22:09:15 -0400 Subject: [PATCH 5/7] KSC: remove unnecessary else --- sequencing/modes.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/sequencing/modes.py b/sequencing/modes.py index 0fca373..3c3b80b 100644 --- a/sequencing/modes.py +++ b/sequencing/modes.py @@ -729,18 +729,17 @@ def rotate(self, angle, phase, pulse_name=None, unitary=False, **kwargs): if unitary: full_space = kwargs.get("full_space", True) return self.Raxis(angle, phase, full_space=full_space) - else: - pulse_name = pulse_name or self.default_pulse - pulse = getattr(self, pulse_name) - # Assuming that default_pulse.amp = 1 corresponds to rotation of pi - norm = gaussian_chop_norm(pulse.sigma, pulse.chop) - amp = angle * pulse.amp / norm - c_wave = pulse(amp=amp, phase=phase, **kwargs) - terms = { - f"{self.name}.x": HTerm(self.x, c_wave.real), - f"{self.name}.y": HTerm(self.y, c_wave.imag), - } - return Operation(len(c_wave), terms) + pulse_name = pulse_name or self.default_pulse + pulse = getattr(self, pulse_name) + # Assuming that default_pulse.amp = 1 corresponds to rotation of pi + norm = gaussian_chop_norm(pulse.sigma, pulse.chop) + amp = angle * pulse.amp / norm + c_wave = pulse(amp=amp, phase=phase, **kwargs) + terms = { + f"{self.name}.x": HTerm(self.x, c_wave.real), + f"{self.name}.y": HTerm(self.y, c_wave.imag), + } + return Operation(len(c_wave), terms) def rotate_x(self, angle, unitary=False, **kwargs): """Generate a rotation about the x axis. From deacb7f1a7b69990444441f69e4ad7ce6b052533 Mon Sep 17 00:00:00 2001 From: qci-chou Date: Tue, 6 Jul 2021 22:25:52 -0400 Subject: [PATCH 6/7] KSC: fix formatting again --- sequencing/sequencing/basic.py | 13 +++++- sequencing/sequencing/main.py | 12 +++++- sequencing/test/test_gates.py | 79 ++++++++++++++++++++++++++++++---- setup.py | 6 ++- 4 files changed, 96 insertions(+), 14 deletions(-) diff --git a/sequencing/sequencing/basic.py b/sequencing/sequencing/basic.py index 915721a..3d73bbc 100644 --- a/sequencing/sequencing/basic.py +++ b/sequencing/sequencing/basic.py @@ -439,7 +439,12 @@ def build_hamiltonian(self): return self.hc.build_hamiltonian() def run( - self, init_state, c_ops=None, e_ops=None, options=None, progress_bar=None, + self, + init_state, + c_ops=None, + e_ops=None, + options=None, + progress_bar=None, ): """Simulate the sequence using qutip.mesolve. @@ -492,7 +497,11 @@ def run( ) def propagator( - self, c_ops=None, options=None, unitary_mode="batch", parallel=False, + self, + c_ops=None, + options=None, + unitary_mode="batch", + parallel=False, ): """Calculate the propagator using ``qutip.propagator()``. diff --git a/sequencing/sequencing/main.py b/sequencing/sequencing/main.py index 0640566..bec7dff 100644 --- a/sequencing/sequencing/main.py +++ b/sequencing/sequencing/main.py @@ -99,7 +99,12 @@ def channels(self): return self.compile().channels def run( - self, init_state, c_ops=None, e_ops=None, options=None, progress_bar=None, + self, + init_state, + c_ops=None, + e_ops=None, + options=None, + progress_bar=None, ): """Simulate the sequence using qutip.mesolve. @@ -154,7 +159,10 @@ def propagator( if all(isinstance(op, SyncOperation) for op in self): return [self.system.I()] return self.compile().propagator( - c_ops=c_ops, options=options, unitary_mode=unitary_mode, parallel=parallel, + c_ops=c_ops, + options=options, + unitary_mode=unitary_mode, + parallel=parallel, ) def plot_coefficients(self, subplots=True, plot_imag=False, step=False): diff --git a/sequencing/test/test_gates.py b/sequencing/test/test_gates.py index c3174be..db7cef0 100644 --- a/sequencing/test/test_gates.py +++ b/sequencing/test/test_gates.py @@ -219,7 +219,14 @@ def test_cx(self): control, target = self.system.modes cx = gates.CXGate(control=control, target=target)() - ideal = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0],]) + ideal = np.array( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, 1], + [0, 0, 1, 0], + ] + ) self.assertTrue(np.array_equal(cx.full(), ideal)) cx = gates.cx(control, target) @@ -229,7 +236,14 @@ def test_cy(self): control, target = self.system.modes cy = gates.CYGate(control=control, target=target)() - ideal = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1j], [0, 0, 1j, 0],]) + ideal = np.array( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0, -1j], + [0, 0, 1j, 0], + ] + ) self.assertTrue(np.array_equal(cy.full(), ideal)) cy = gates.cy(control, target) @@ -239,7 +253,14 @@ def test_cz(self): control, target = self.system.modes cz = gates.CZGate(control=control, target=target)() - ideal = np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1],]) + ideal = np.array( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, -1], + ] + ) self.assertTrue(np.array_equal(cz.full(), ideal)) cz = gates.cz(control, target) @@ -252,7 +273,12 @@ def test_cphase(self): cphase = gates.CPhaseGate(control=control, target=target)(phi) ideal = np.array( - [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, np.exp(1j * phi)],] + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, np.exp(1j * phi)], + ] ) self.assertTrue(np.array_equal(cphase.full(), ideal)) @@ -263,7 +289,14 @@ def test_swap(self): q1, q2 = self.system.modes swap = gates.SWAPGate(q1, q2)() - ideal = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1],]) + ideal = np.array( + [ + [1, 0, 0, 0], + [0, 0, 1, 0], + [0, 1, 0, 0], + [0, 0, 0, 1], + ] + ) self.assertTrue(np.array_equal(swap.full(), ideal)) swap = gates.swap(q1, q2) @@ -275,7 +308,14 @@ def test_swapphi(self): swapphi = gates.SWAPphiGate(q1, q2)(phi) p = -1j * np.exp(1j * phi) m = 1j * np.exp(-1j * phi) - ideal = np.array([[1, 0, 0, 0], [0, 0, m, 0], [0, p, 0, 0], [0, 0, 0, 1],]) + ideal = np.array( + [ + [1, 0, 0, 0], + [0, 0, m, 0], + [0, p, 0, 0], + [0, 0, 0, 1], + ] + ) self.assertTrue(np.array_equal(swapphi.full(), ideal)) swapphi = gates.swapphi(q1, q2, phi) @@ -289,7 +329,14 @@ def test_iswap(self): q1, q2 = self.system.modes iswap = gates.iSWAPGate(q1, q2)() - ideal = np.array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1],]) + ideal = np.array( + [ + [1, 0, 0, 0], + [0, 0, 1j, 0], + [0, 1j, 0, 0], + [0, 0, 0, 1], + ] + ) self.assertTrue(np.array_equal(iswap.full(), ideal)) iswap = gates.iswap(q1, q2) @@ -300,7 +347,14 @@ def test_eswap(self): theta_c = -np.pi / 4 eswap = gates.eSWAPGate(q1, q2)(theta_c, phi=np.pi / 2) - swap = np.array([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1],]) + swap = np.array( + [ + [1, 0, 0, 0], + [0, 0, 1, 0], + [0, 1, 0, 0], + [0, 0, 0, 1], + ] + ) ideal = np.cos(theta_c / 2) * np.eye(4) - 1j * np.sin(theta_c / 2) * swap self.assertTrue(np.allclose(eswap.full(), ideal)) @@ -313,7 +367,14 @@ def test_sqrtswap(self): sqrtswap = gates.SqrtSWAPGate(q1, q2)() p = (1 + 1j) / 2 m = (1 - 1j) / 2 - ideal = np.array([[1, 0, 0, 0], [0, p, m, 0], [0, m, p, 0], [0, 0, 0, 1],]) + ideal = np.array( + [ + [1, 0, 0, 0], + [0, p, m, 0], + [0, m, p, 0], + [0, 0, 0, 1], + ] + ) self.assertTrue(np.allclose(sqrtswap.full(), ideal)) sqrtswap = gates.sqrtswap(q1, q2) diff --git a/setup.py b/setup.py index 7152974..7cec7d1 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,11 @@ ] EXTRAS_REQUIRE = { - "docs": ["sphinx", "sphinx_rtd_theme", "nbsphinx",], + "docs": [ + "sphinx", + "sphinx_rtd_theme", + "nbsphinx", + ], } CLASSIFIERS = """\ From 8bb1055c8e099dc6e6681fa3705616fc9bf95fdc Mon Sep 17 00:00:00 2001 From: qci-chou Date: Wed, 7 Jul 2021 00:04:43 -0400 Subject: [PATCH 7/7] KSC: Adds more detailed tests --- sequencing/test/test_rotations.py | 106 +++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 23 deletions(-) diff --git a/sequencing/test/test_rotations.py b/sequencing/test/test_rotations.py index c24575f..524b2ab 100644 --- a/sequencing/test/test_rotations.py +++ b/sequencing/test/test_rotations.py @@ -23,6 +23,7 @@ SyncOperation, HamiltonianChannels, ) +from sequencing.calibration import tune_rabi class TestSequenceVsUnitary(unittest.TestCase): @@ -30,6 +31,7 @@ class TestSequenceVsUnitary(unittest.TestCase): def setUpClass(cls): qubit = Transmon("qubit", levels=2) system = System("system", modes=[qubit]) + _ = tune_rabi(system, system.ground_state(), plot=False, verify=False) cls.system = system def test_sequence_Rx(self): @@ -39,14 +41,19 @@ def test_sequence_Rx(self): init_state = system.ground_state() - seq = Sequence(system) - qubit.rotate_x(np.pi / 2) - sync() + angles = np.linspace(-np.pi, np.pi, 11) + for theta in angles: + seq = Sequence(system) + qubit.rotate_x(theta) + sync() + unitary = qubit.rotate_x(theta, unitary=True) - result = seq.run(init_state) - states = result.states - fidelity = qutip.fidelity(states[-1], qubit.Rx(np.pi / 2) * init_state) ** 2 - self.assertGreater(fidelity, 0.999) + result = seq.run(init_state) + states = result.states + fidelity = qutip.fidelity(states[-1], qubit.Rx(theta) * init_state) ** 2 + self.assertGreater(fidelity, 0.999) + fidelity = qutip.fidelity(states[-1], unitary * init_state) ** 2 + self.assertGreater(fidelity, 0.999) def test_sequence_Ry(self): @@ -55,14 +62,19 @@ def test_sequence_Ry(self): init_state = system.ground_state() - seq = Sequence(system) - qubit.rotate_y(np.pi / 2) - sync() + angles = np.linspace(-np.pi, np.pi, 11) + for theta in angles: + seq = Sequence(system) + qubit.rotate_y(theta) + sync() + unitary = qubit.rotate_y(theta, unitary=True) - result = seq.run(init_state) - states = result.states - fidelity = qutip.fidelity(states[-1], qubit.Ry(np.pi / 2) * init_state) ** 2 - self.assertGreater(fidelity, 0.999) + result = seq.run(init_state) + states = result.states + fidelity = qutip.fidelity(states[-1], qubit.Ry(theta) * init_state) ** 2 + self.assertGreater(fidelity, 0.999) + fidelity = qutip.fidelity(states[-1], unitary * init_state) ** 2 + self.assertGreater(fidelity, 0.999) def test_sequence_Raxis(self): @@ -70,17 +82,65 @@ def test_sequence_Raxis(self): qubit = system.qubit init_state = system.ground_state() - theta = np.pi * 0.456 - phi = -np.pi * 0.567 - seq = Sequence(system) - qubit.rotate(theta, phi) - sync() + angles = np.linspace(-np.pi, np.pi, 11) + for theta in angles: + for phi in angles: + seq = Sequence(system) + qubit.rotate(theta, phi) + sync() + unitary = qubit.rotate(theta, phi, unitary=True) + + result = seq.run(init_state) + states = result.states + fidelity = ( + qutip.fidelity(states[-1], qubit.Raxis(theta, phi) * init_state) + ** 2 + ) + self.assertGreater(fidelity, 0.999) + fidelity = qutip.fidelity(states[-1], unitary * init_state) ** 2 + self.assertGreater(fidelity, 0.999) + + def test_sequence_Raxis_vs_Rx_Ry(self): - result = seq.run(init_state) - states = result.states - fidelity = qutip.fidelity(states[-1], qubit.Raxis(theta, phi) * init_state) ** 2 - self.assertGreater(fidelity, 0.999) + system = self.system + qubit = system.qubit + + init_state = system.ground_state() + + angles = np.linspace(-np.pi, np.pi, 11) + for theta in angles: + # Test Raxis vs. Rx + seq = Sequence(system) + qubit.rotate(theta, 0) + sync() + unitary = qubit.rotate(theta, 0, unitary=True) + + result = seq.run(init_state) + states = result.states + fidelity = qutip.fidelity(states[-1], qubit.Rx(theta) * init_state) ** 2 + self.assertGreater(fidelity, 0.999) + + fidelity = ( + qutip.fidelity(unitary * init_state, qubit.Rx(theta) * init_state) ** 2 + ) + self.assertGreater(fidelity, 0.999) + + # Test Raxis vs. Ry + seq = Sequence(system) + qubit.rotate(theta, np.pi / 2) + sync() + unitary = qubit.rotate(theta, np.pi / 2, unitary=True) + + result = seq.run(init_state) + states = result.states + fidelity = qutip.fidelity(states[-1], qubit.Ry(theta) * init_state) ** 2 + self.assertGreater(fidelity, 0.999) + + fidelity = ( + qutip.fidelity(unitary * init_state, qubit.Ry(theta) * init_state) ** 2 + ) + self.assertGreater(fidelity, 0.999) if __name__ == "__main__":