def _system_model_3d_oscillator(self, freq, anharm, r): """Model for a duffing oscillator truncated to 3 dimensions. Args: freq (float): frequency of the oscillator anharm (float): anharmonicity of the oscillator r (float): drive strength Returns: PulseSystemModel: model for oscillator system """ hamiltonian = {} hamiltonian['h_str'] = [ 'np.pi*(2*v-alpha)*O0', 'np.pi*alpha*O0*O0', '2*np.pi*r*X0||D0' ] hamiltonian['vars'] = {'v': freq, 'alpha': anharm, 'r': r} hamiltonian['qub'] = {'0': 3} ham_model = HamiltonianModel.from_dict(hamiltonian) u_channel_lo = [] subsystem_list = [0] dt = 1. return PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def _simple_system_model(self, v0=5.0, v1=5.1, j=0.01, r=0.02, alpha0=-0.33, alpha1=-0.33): hamiltonian = {} hamiltonian['h_str'] = [ 'np.pi*(2*v0-alpha0)*O0', 'np.pi*alpha0*O0*O0', '2*np.pi*r*X0||D0', '2*np.pi*r*X0||U1', '2*np.pi*r*X1||U0', 'np.pi*(2*v1-alpha1)*O1', 'np.pi*alpha1*O1*O1', '2*np.pi*r*X1||D1', '2*np.pi*j*(Sp0*Sm1+Sm0*Sp1)' ] hamiltonian['qub'] = {'0': 3, '1': 3} hamiltonian['vars'] = { 'v0': v0, 'v1': v1, 'j': j, 'r': r, 'alpha0': alpha0, 'alpha1': alpha1 } ham_model = HamiltonianModel.from_dict(hamiltonian) subsystem_list = [0, 1] dt = 1. return PulseSystemModel(hamiltonian=ham_model, qubit_freq_est=self._default_qubit_lo_freq, u_channel_lo=self._u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def _system_model_1Q(self, omega_0=5., r=0.02): """Constructs a standard model for a 1 qubit system. Args: omega_0 (float): qubit frequency r (float): drive strength Returns: PulseSystemModel: model for qubit system """ hamiltonian = {} hamiltonian['h_str'] = [ '2*np.pi*omega0*0.5*Z0', '2*np.pi*r*0.5*X0||D0' ] hamiltonian['vars'] = {'omega0': omega_0, 'r': r} hamiltonian['qub'] = {'0': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) u_channel_lo = [] subsystem_list = [0] dt = 1. return PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def _system_model_1Q(self, omega_0, omega_a, qubit_dim=2): """Constructs a simple 1 qubit system model. Args: omega_0 (float): frequency of qubit omega_a (float): strength of drive term qubit_dim (int): dimension of qubit Returns: PulseSystemModel: model for qubit system """ # make Hamiltonian hamiltonian = {} hamiltonian['h_str'] = ['-0.5*omega0*Z0', '0.5*omegaa*X0||D0'] hamiltonian['vars'] = {'omega0': omega_0, 'omegaa': omega_a} hamiltonian['qub'] = {'0': qubit_dim} ham_model = HamiltonianModel.from_dict(hamiltonian) u_channel_lo = [] subsystem_list = [0] dt = 1. return PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def _system_model_3Q(self, j, subsystem_list=[0, 2]): """Constructs a model for a 3 qubit system, with the goal that the restriction to [0, 2] and to qubits [1, 2] is the same as in _system_model_2Q Args: j (float): coupling strength subsystem_list (list): list of subsystems to include Returns: PulseSystemModel: model for qubit system """ hamiltonian = {} hamiltonian['h_str'] = [ '2*np.pi*j*0.25*(Z0*X2)||U0', '2*np.pi*j*0.25*(Z1*X2)||U1' ] hamiltonian['vars'] = {'j': j} hamiltonian['qub'] = {'0': 2, '1': 2, '2': 2} ham_model = HamiltonianModel.from_dict(hamiltonian, subsystem_list=subsystem_list) # set the U0 to have frequency of drive channel 0 u_channel_lo = [[UchannelLO(0, 1.0 + 0.0j)], [UchannelLO(0, 1.0 + 0.0j)]] dt = 1. return PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def _system_model_2Q(self, j): """Constructs a model for a 2 qubit system with a U channel controlling coupling and no other Hamiltonian terms. Args: j (float): coupling strength Returns: PulseSystemModel: model for qubit system """ hamiltonian = {} hamiltonian['h_str'] = [ 'a*X0||D0', 'a*X0||D1', '2*np.pi*j*0.25*(Z0*X1)||U0' ] hamiltonian['vars'] = {'a': 0, 'j': j} hamiltonian['qub'] = {'0': 2, '1': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) # set the U0 to have frequency of drive channel 0 u_channel_lo = [[UchannelLO(0, 1.0 + 0.0j)]] subsystem_list = [0, 1] dt = 1. return PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def _system_model_3Q(self, omega_0, omega_a, omega_i, qubit_dim=2, subsystem_list=None): """Constructs a 3 qubit model. Purpose of this is for testing subsystem restrictions - It is set up so that the system restricted to [0, 2] and [1, 2] is the same (up to channel labelling). Args: omega_0 (float): frequency of qubit omega_a (float): strength of drive term omega_i (float): strength of interaction qubit_dim (int): dimension of qubit Returns: PulseSystemModel: model for qubit system """ # make Hamiltonian hamiltonian = {} # qubit 0 terms hamiltonian['h_str'] = [ '-0.5*omega0*Z0', '0.5*omegaa*X0||D0', '-0.5*omega0*Z1', '0.5*omegaa*X1||D1' ] # interaction terms hamiltonian['h_str'].append('omegai*(Sp0*Sm2+Sm0*Sp2)||U1') hamiltonian['h_str'].append('omegai*(Sp1*Sm2+Sm1*Sp2)||U2') hamiltonian['vars'] = { 'omega0': omega_0, 'omegaa': omega_a, 'omegai': omega_i } hamiltonian['qub'] = {'0': qubit_dim, '1': qubit_dim, '2': qubit_dim} ham_model = HamiltonianModel.from_dict(hamiltonian, subsystem_list) u_channel_lo = [[{ 'q': 0, 'scale': [1.0, 0.0] }], [{ 'q': 0, 'scale': [-1.0, 0.0] }, { 'q': 2, 'scale': [1.0, 0.0] }], [{ 'q': 1, 'scale': [-1.0, 0.0] }, { 'q': 2, 'scale': [1.0, 0.0] }]] dt = 1. return PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def test_qubit_lo_from_configurable_backend(self): backend = FakeArmonk() test_model = PulseSystemModel.from_backend(backend) qubit_lo_from_hamiltonian = test_model.hamiltonian.get_qubit_lo_from_drift( ) freqs = test_model.calculate_channel_frequencies( qubit_lo_from_hamiltonian) self.assertAlmostEqual(freqs['D0'], 4.974286046328553)
def test_qubit_lo_from_configurable_backend(self): """Test computation of qubit_lo_freq from configurable backend.""" backend = FakeArmonk() test_model = PulseSystemModel.from_backend(backend) qubit_lo_from_hamiltonian = test_model.hamiltonian.get_qubit_lo_from_drift() freqs = test_model.calculate_channel_frequencies(qubit_lo_from_hamiltonian) expected = getattr(backend.configuration(), 'hamiltonian')['vars']['wq0'] / (2 * np. pi) self.assertAlmostEqual(freqs['D0'], expected, places=4)
def test_control_channel_labels_from_backend(self): """Test correct importing of backend control channel description.""" backend = FakeOpenPulse2Q() system_model = PulseSystemModel.from_backend(backend) expected = [{'driven_q': 1, 'freq': '(1+0j)q0'}, {'driven_q': 0, 'freq': '(-1+0j)q0 + (1+0j)q1'}] self.assertEqual(system_model.control_channel_labels, expected)
def test_simulation_without_variables(self): r"""Test behavior of subsystem_list subsystem restriction. Same setup as test_x_gate, but with explicit Hamiltonian construction without variables """ ham_dict = { 'h_str': ['-np.pi*Z0', '0.01*np.pi*X0||D0'], 'qub': { '0': 2 } } ham_model = HamiltonianModel.from_dict(ham_dict) u_channel_lo = [] subsystem_list = [0] dt = 1. system_model = PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt) # set up schedule and qobj total_samples = 50 schedule = self._simple_1Q_schedule(0, total_samples) qobj = assemble([schedule], backend=self.backend_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[1.], memory_slots=2, shots=256) # set backend backend_options backend_options = {'seed': 9000} # run simulation result = self.backend_sim.run( qobj, system_model=system_model, backend_options=backend_options).result() # test results counts = result.get_counts() exp_counts = {'1': 256} self.assertDictAlmostEqual(counts, exp_counts)
def _system_model_2Q(self, v0=5.0, v1=5.1, j=0.01, r=0.02, alpha0=-0.33, alpha1=-0.33, qub_dim=3): """Constructs a simple 2 transmon PulseSystemModel.""" hamiltonian = {} hamiltonian['h_str'] = [] # Q0 terms hamiltonian['h_str'].append('np.pi*(2*v0-alpha0)*O0') hamiltonian['h_str'].append('np.pi*alpha0*O0*O0') hamiltonian['h_str'].append('2*np.pi*r*X0||D0') # Q1 terms hamiltonian['h_str'].append('np.pi*(2*v1-alpha1)*O1') hamiltonian['h_str'].append('np.pi*alpha1*O1*O1') hamiltonian['h_str'].append('2*np.pi*r*X1||D1') # Exchange coupling and ControlChannel terms hamiltonian['h_str'].append('2*np.pi*j*(Sp0*Sm1+Sm0*Sp1)') hamiltonian['h_str'].append('2*np.pi*r*X0||U0') hamiltonian['h_str'].append('2*np.pi*r*X1||U1') # set vars and qubit dimensions hamiltonian['vars'] = {'v0': v0, 'v1': v1, 'j': j, 'r': r, 'alpha0': alpha0, 'alpha1': alpha1} hamiltonian['qub'] = {'0' : qub_dim, '1' : qub_dim} ham_model = HamiltonianModel.from_dict(hamiltonian) # set up u channel freqs, u_channel_lo = [[{'q': 1, 'scale': [1.0, 0.0]}], [{'q': 0, 'scale': [1.0, 0.0]}]] subsystem_list = [0, 1] dt = 1. return PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def _system_model_2Q(self, omega_0, omega_a, omega_i, qubit_dim=2): """Constructs a simple 1 qubit system model. Args: omega_0 (float): frequency of qubit omega_a (float): strength of drive term omega_i (float): strength of interaction qubit_dim (int): dimension of qubit Returns: PulseSystemModel: model for qubit system """ # make Hamiltonian hamiltonian = {} # qubit 0 terms hamiltonian['h_str'] = ['-0.5*omega0*Z0', '0.5*omegaa*X0||D0'] # interaction term hamiltonian['h_str'].append('omegai*(Sp0*Sm1+Sm0*Sp1)||U1') hamiltonian['vars'] = { 'omega0': omega_0, 'omegaa': omega_a, 'omegai': omega_i } hamiltonian['qub'] = {'0': qubit_dim, '1': qubit_dim} ham_model = HamiltonianModel.from_dict(hamiltonian) u_channel_lo = [[{ 'q': 0, 'scale': [1.0, 0.0] }], [{ 'q': 0, 'scale': [-1.0, 0.0] }, { 'q': 1, 'scale': [1.0, 0.0] }]] subsystem_list = [0, 1] dt = 1. return PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt)
def test_delay_instruction(self): """Test for delay instruction.""" # construct system model specifically for this hamiltonian = {} hamiltonian['h_str'] = ['0.5*r*X0||D0', '0.5*r*Y0||D1'] hamiltonian['vars'] = {'r': np.pi} hamiltonian['qub'] = {'0': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) u_channel_lo = [] subsystem_list = [0] dt = 1. system_model = PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt) # construct a schedule that should result in a unitary -Z if delays are correctly handled # i.e. do a pi rotation about x, sandwiched by pi/2 rotations about y in opposite directions # so that the x rotation is transformed into a z rotation. # if delays are not handled correctly this process should fail sched = Schedule() sched += Play(Waveform([0.5]), DriveChannel(1)) sched += Delay(1, DriveChannel(1)) sched += Play(Waveform([-0.5]), DriveChannel(1)) sched += Delay(1, DriveChannel(0)) sched += Play(Waveform([1.]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration # Result of schedule should be the unitary -1j*Z, so check rotation of an X eigenstate pulse_sim = PulseSimulator(system_model=system_model, initial_state=np.array([1., 1.]) / np.sqrt(2)) qobj = assemble([sched], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[0., 0.], memory_slots=2, shots=1) results = pulse_sim.run(qobj).result() statevector = results.get_statevector() expected_vector = np.array([-1j, 1j]) / np.sqrt(2) self.assertGreaterEqual(state_fidelity(statevector, expected_vector), 1 - (10**-5)) # verify validity of simulation when no delays included sched = Schedule() sched += Play(Waveform([0.5]), DriveChannel(1)) sched += Play(Waveform([-0.5]), DriveChannel(1)) sched += Play(Waveform([1.]), DriveChannel(0)) sched |= Acquire(1, AcquireChannel(0), MemorySlot(0)) << sched.duration qobj = assemble([sched], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=[0., 0.], memory_slots=2, shots=1) results = pulse_sim.run(qobj).result() statevector = results.get_statevector() U = expm(1j * np.pi * self.Y / 4) @ expm(-1j * np.pi * (self.Y / 4 + self.X / 2)) expected_vector = U @ np.array([1., 1.]) / np.sqrt(2) self.assertGreaterEqual(state_fidelity(statevector, expected_vector), 1 - (10**-5))
def test_2Q_exchange(self): r"""Test a more complicated 2q simulation""" q_freqs = [5., 5.1] r = 0.02 j = 0.02 total_samples = 25 hamiltonian = {} hamiltonian['h_str'] = [ '2*np.pi*v0*0.5*Z0', '2*np.pi*v1*0.5*Z1', '2*np.pi*r*0.5*X0||D0', '2*np.pi*r*0.5*X1||D1', '2*np.pi*j*0.5*I0*I1', '2*np.pi*j*0.5*X0*X1', '2*np.pi*j*0.5*Y0*Y1', '2*np.pi*j*0.5*Z0*Z1' ] hamiltonian['vars'] = { 'v0': q_freqs[0], 'v1': q_freqs[1], 'r': r, 'j': j } hamiltonian['qub'] = {'0': 2, '1': 2} ham_model = HamiltonianModel.from_dict(hamiltonian) # set the U0 to have frequency of drive channel 0 u_channel_lo = [] subsystem_list = [0, 1] dt = 1. system_model = PulseSystemModel(hamiltonian=ham_model, u_channel_lo=u_channel_lo, subsystem_list=subsystem_list, dt=dt) # try some random schedule schedule = Schedule() drive_pulse = Waveform(np.ones(total_samples)) schedule += Play(drive_pulse, DriveChannel(0)) schedule |= Play(drive_pulse, DriveChannel(1)) << 2 * total_samples schedule |= Acquire(total_samples, AcquireChannel(0), MemorySlot(0)) << 3 * total_samples schedule |= Acquire(total_samples, AcquireChannel(1), MemorySlot(1)) << 3 * total_samples y0 = np.array([1., 0., 0., 0.]) pulse_sim = PulseSimulator(system_model=system_model, initial_state=y0, seed=9000) qobj = assemble([schedule], backend=pulse_sim, meas_level=2, meas_return='single', meas_map=[[0]], qubit_lo_freq=q_freqs, memory_slots=2, shots=1000) result = pulse_sim.run(qobj).result() pulse_sim_yf = result.get_statevector() # set up and run independent simulation d0_samps = np.concatenate( (np.ones(total_samples), np.zeros(2 * total_samples))) d1_samps = np.concatenate( (np.zeros(2 * total_samples), np.ones(total_samples))) samples = np.array([d0_samps, d1_samps]).transpose() q_freqs = np.array(q_freqs) yf = simulate_2q_exchange_model(y0, q_freqs, r, j, q_freqs, samples, 1.) # Check fidelity of statevectors self.assertGreaterEqual(state_fidelity(pulse_sim_yf, yf), 1 - (10**-5))