def setUp(self): super().setUp() with pulse.build(name="sx_q0") as custom_sx_q0: pulse.play(pulse.Constant(100, 0.1), pulse.DriveChannel(0)) self.custom_sx_q0 = custom_sx_q0 with pulse.build(name="sx_q1") as custom_sx_q1: pulse.play(pulse.Constant(100, 0.2), pulse.DriveChannel(1)) self.custom_sx_q1 = custom_sx_q1 self.sched_param = circuit.Parameter("P0") with pulse.build(name="my_gate_q0") as my_gate_q0: pulse.shift_phase(self.sched_param, pulse.DriveChannel(0)) pulse.play(pulse.Constant(120, 0.1), pulse.DriveChannel(0)) self.my_gate_q0 = my_gate_q0 with pulse.build(name="my_gate_q1") as my_gate_q1: pulse.shift_phase(self.sched_param, pulse.DriveChannel(1)) pulse.play(pulse.Constant(120, 0.2), pulse.DriveChannel(1)) self.my_gate_q1 = my_gate_q1
def setUp(self): super().setUp() self.amp0 = circuit.Parameter("amp0") self.amp1 = circuit.Parameter("amp1") self.dur0 = circuit.Parameter("dur0") self.dur1 = circuit.Parameter("dur1") self.test_par_waveform0 = pulse.Constant(self.dur0, self.amp0) self.test_par_waveform1 = pulse.Constant(self.dur1, self.amp1)
def test_call_subroutine_with_parametrized_duration(self): """Test call subroutine containing a parametrized duration.""" dur = circuit.Parameter("dur") with pulse.build() as subroutine: pulse.play(pulse.Constant(dur, 0.1), pulse.DriveChannel(0)) pulse.play(pulse.Constant(dur, 0.2), pulse.DriveChannel(0)) with pulse.build() as main: pulse.call(subroutine) self.assertEqual(len(main.blocks), 1)
def test_complex_value_to_parameter(self): """Test complex value can be assigned to parameter object.""" amp = Parameter("amp") test_obj = pulse.Constant(duration=160, amp=amp) value_dict = {amp: 0.1j} visitor = ParameterSetter(param_map=value_dict) assigned = visitor.visit(test_obj) ref_obj = pulse.Constant(duration=160, amp=1j * 0.1) self.assertEqual(assigned, ref_obj)
def test_complex_parameter_expression(self): """Test assignment of complex-valued parameter expression to parameter.""" amp = Parameter("amp") mag = Parameter("A") phi = Parameter("phi") test_obj = pulse.Constant(duration=160, amp=amp) # generate parameter expression value_dict = {amp: mag * np.exp(1j * phi)} visitor = ParameterSetter(param_map=value_dict) assigned = visitor.visit(test_obj) # generate complex value value_dict = {mag: 0.1, phi: 0.5} visitor = ParameterSetter(param_map=value_dict) assigned = visitor.visit(assigned) # evaluated parameter expression: 0.0877582561890373 + 0.0479425538604203*I value_dict = {amp: 0.1 * np.exp(0.5j)} visitor = ParameterSetter(param_map=value_dict) ref_obj = visitor.visit(test_obj) self.assertEqual(assigned, ref_obj)
def test_parametrized_frame_change(self): """Test generating waveforms that are parameterized. Parametrized phase should be ignored when calculating waveform frame. This is due to phase modulated representation of waveforms, i.e. we cannot calculate the phase factor of waveform if the phase is unbound. """ param = circuit.Parameter('phase') test_fc1 = pulse.ShiftPhase(param, pulse.DriveChannel(0)) test_fc2 = pulse.ShiftPhase(1.57, pulse.DriveChannel(0)) test_waveform = pulse.Play(pulse.Constant(10, 0.1), pulse.DriveChannel(0)) ch_events = events.ChannelEvents(waveforms={0: test_waveform}, frames={0: [test_fc1, test_fc2]}, channel=pulse.DriveChannel(0)) # waveform frame pulse_inst = list(ch_events.get_waveforms())[0] self.assertFalse(pulse_inst.is_opaque) self.assertEqual(pulse_inst.frame.phase, 1.57) # framechange pulse_inst = list(ch_events.get_frame_changes())[0] self.assertTrue(pulse_inst.is_opaque) self.assertEqual(pulse_inst.frame.phase, param + 1.57)
def test_assemble_parametric(self): """Test that parametric pulses can be assembled properly into a PulseQobj.""" sched = pulse.Schedule(name='test_parametric') sched += Play(pulse.Gaussian(duration=25, sigma=4, amp=0.5j), DriveChannel(0)) sched += Play(pulse.Drag(duration=25, amp=0.2+0.3j, sigma=7.8, beta=4), DriveChannel(1)) sched += Play(pulse.Constant(duration=25, amp=1), DriveChannel(2)) sched += Play(pulse.GaussianSquare(duration=150, amp=0.2, sigma=8, width=140), MeasureChannel(0)) << sched.duration backend = FakeOpenPulse3Q() backend.configuration().parametric_pulses = ['gaussian', 'drag', 'gaussian_square', 'constant'] qobj = assemble(sched, backend) self.assertEqual(qobj.config.pulse_library, []) qobj_insts = qobj.experiments[0].instructions self.assertTrue(all(inst.name == 'parametric_pulse' for inst in qobj_insts)) self.assertEqual(qobj_insts[0].pulse_shape, 'gaussian') self.assertEqual(qobj_insts[1].pulse_shape, 'drag') self.assertEqual(qobj_insts[2].pulse_shape, 'constant') self.assertEqual(qobj_insts[3].pulse_shape, 'gaussian_square') self.assertDictEqual(qobj_insts[0].parameters, {'duration': 25, 'sigma': 4, 'amp': 0.5j}) self.assertDictEqual(qobj_insts[1].parameters, {'duration': 25, 'sigma': 7.8, 'amp': 0.2+0.3j, 'beta': 4}) self.assertDictEqual(qobj_insts[2].parameters, {'duration': 25, 'amp': 1}) self.assertDictEqual(qobj_insts[3].parameters, {'duration': 150, 'sigma': 8, 'amp': 0.2, 'width': 140}) self.assertEqual( qobj.to_dict()['experiments'][0]['instructions'][0]['parameters']['amp'], 0.5j)
def setUp(self) -> None: super().setUp() self.device = device_info.OpenPulseBackendInfo(name='test_backend', dt=1e-9) self.prog = pulse.Schedule(name='test_sched') self.prog.insert(0, pulse.Play(pulse.Constant(100, 0.1), pulse.DriveChannel(0)), inplace=True)
def setUp(self): super().setUp() self.pulse_target = Target( dt=3e-7, granularity=2, min_length=4, pulse_alignment=8, aquire_alignment=8 ) with pulse.build(name="sx_q0") as self.custom_sx_q0: pulse.play(pulse.Constant(100, 0.1), pulse.DriveChannel(0)) with pulse.build(name="sx_q1") as self.custom_sx_q1: pulse.play(pulse.Constant(100, 0.2), pulse.DriveChannel(1)) sx_props = { (0,): InstructionProperties( duration=35.5e-9, error=0.000413, calibration=self.custom_sx_q0 ), (1,): InstructionProperties( duration=35.5e-9, error=0.000502, calibration=self.custom_sx_q1 ), } self.pulse_target.add_instruction(SXGate(), sx_props)
def test_execute_block(self): """Test executing a ScheduleBlock on a Pulse backend""" with pulse.build(name="test_block") as sched_block: pulse.play(pulse.Constant(160, 1.0), pulse.DriveChannel(0)) pulse.acquire(50, pulse.MeasureChannel(0), pulse.MemorySlot(0)) backend = FakeArmonk() test_result = backend.run(sched_block).result() self.assertDictEqual(test_result.get_counts(), {"0": 1024})
def test_short_pulse_duration_multiple_pulse(self): """Kill pass manager if invalid pulse gate is found.""" # this is invalid duration pulse # however total gate schedule length is 64, which accidentally satisfies the constraints # this should fail in the validation custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert( 0, pulse.Play(pulse.Constant(32, 0.1), pulse.DriveChannel(0)), inplace=True ) custom_gate.insert( 32, pulse.Play(pulse.Constant(32, 0.1), pulse.DriveChannel(0)), inplace=True ) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0,), schedule=custom_gate) with self.assertRaises(TranspilerError): self.pulse_gate_validation_pass(circuit)
def setUp(self): super().setUp() self.backend = FakeOpenPulse2Q() self.test_waveform0 = pulse.Constant(100, 0.1) self.test_waveform1 = pulse.Constant(200, 0.1) self.d0 = pulse.DriveChannel(0) self.d1 = pulse.DriveChannel(1) self.left_context = transforms.AlignLeft() self.right_context = transforms.AlignRight() self.sequential_context = transforms.AlignSequential() self.equispaced_context = transforms.AlignEquispaced(duration=1000) def _align_func(j): return {1: 0.1, 2: 0.25, 3: 0.7, 4: 0.85}.get(j) self.func_context = transforms.AlignFunc(duration=1000, func=_align_func)
def test_update_from_instruction_schedule_map_with_dt_set(self): inst_map = InstructionScheduleMap() with pulse.build(name="sx_q1") as custom_sx: pulse.play(pulse.Constant(1000, 0.2), pulse.DriveChannel(1)) inst_map.add("sx", 0, self.custom_sx_q0) inst_map.add("sx", 1, custom_sx) self.pulse_target.dt = 1.0 self.pulse_target.update_from_instruction_schedule_map(inst_map, {"sx": SXGate()}) self.assertEqual(inst_map, self.pulse_target.instruction_schedule_map()) self.assertEqual(self.pulse_target["sx"][(1,)].duration, 1000.0) self.assertIsNone(self.pulse_target["sx"][(1,)].error) self.assertIsNone(self.pulse_target["sx"][(0,)].error)
def test_parameterized_parametric_pulse(self): """Test generating waveforms that are parameterized.""" param = circuit.Parameter('amp') test_waveform = pulse.Play(pulse.Constant(10, param), pulse.DriveChannel(0)) ch_events = events.ChannelEvents(waveforms={0: test_waveform}, frames={}, channel=pulse.DriveChannel(0)) pulse_inst = list(ch_events.get_waveforms())[0] self.assertTrue(pulse_inst.is_opaque) self.assertEqual(pulse_inst.inst, test_waveform)
def test_complex_valued_parameter(self): """Test complex valued parameter can be casted to a complex value.""" amp = Parameter("amp") test_sched = pulse.ScheduleBlock() test_sched.append( pulse.Play( pulse.Constant(160, amp=1j * amp), pulse.DriveChannel(0), ), inplace=True, ) test_assigned = test_sched.assign_parameters({amp: 0.1}, inplace=False) self.assertTrue(isinstance(test_assigned.blocks[0].pulse.amp, complex))
def test_invalid_pulse_amplitude(self): """Test that invalid parameters are still checked upon assignment.""" amp = Parameter("amp") test_sched = pulse.ScheduleBlock() test_sched.append( pulse.Play( pulse.Constant(160, amp=2 * amp), pulse.DriveChannel(0), ), inplace=True, ) with self.assertRaises(PulseError): test_sched.assign_parameters({amp: 0.6}, inplace=False)
def test_valid_pulse_duration(self): """No error raises if valid calibration is provided.""" # this is valid duration pulse custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert( 0, pulse.Play(pulse.Constant(160, 0.1), pulse.DriveChannel(0)), inplace=True ) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0,), schedule=custom_gate) # just not raise an error self.pulse_gate_validation_pass(circuit)
def test_assemble_parametric_unsupported(self): """Test that parametric pulses are translated to Waveform if they're not supported by the backend during assemble time. """ sched = pulse.Schedule(name='test_parametric_to_sample_pulse') sched += Play(pulse.Drag(duration=25, amp=0.2+0.3j, sigma=7.8, beta=4), DriveChannel(1)) sched += Play(pulse.Constant(duration=25, amp=1), DriveChannel(2)) backend = FakeOpenPulse3Q() backend.configuration().parametric_pulses = ['something_extra'] qobj = assemble(sched, backend) self.assertNotEqual(qobj.config.pulse_library, []) qobj_insts = qobj.experiments[0].instructions self.assertFalse(hasattr(qobj_insts[0], 'pulse_shape'))
def test_short_pulse_duration(self): """Kill pass manager if invalid pulse gate is found.""" # this is invalid duration pulse # this will cause backend error since this doesn't fit with waveform memory chunk. custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert( 0, pulse.Play(pulse.Constant(32, 0.1), pulse.DriveChannel(0)), inplace=True ) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0,), schedule=custom_gate) with self.assertRaises(TranspilerError): self.pulse_gate_validation_pass(circuit)
def test_assigned_amplitude_is_complex(self): """Test pulse amp parameter is always complex valued. Note that IBM backend treats "amp" as a special parameter, and this should be complex value otherwise IBM backends raise 8042 error. "Pulse parameter "amp" must be specified as a list of the form [real, imag]" """ amp = circuit.Parameter("amp") block = pulse.ScheduleBlock() block += pulse.Play(pulse.Constant(100, amp), pulse.DriveChannel(0)) assigned_block = block.assign_parameters({amp: 0.1}, inplace=True) assigned_amp = assigned_block.blocks[0].pulse.amp self.assertIsInstance(assigned_amp, complex)
def test_valid_pulse_duration(self): """No error raises if valid calibration is provided.""" # this is valid duration pulse custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert(0, pulse.Play(pulse.Constant(160, 0.1), pulse.DriveChannel(0)), inplace=True) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0, ), schedule=custom_gate) # just not raise an error pm = PassManager(ValidatePulseGates(granularity=16, min_length=64)) pm.run(circuit)
def test_nested_parametrized_instructions(self): """Test parameters of nested schedule can be assigned.""" test_waveform = pulse.Constant(100, self.amp0) param_sched = pulse.Schedule(pulse.Play(test_waveform, self.d0)) call_inst = pulse.instructions.Call(param_sched) sub_block = pulse.ScheduleBlock() sub_block += call_inst block = pulse.ScheduleBlock() block += sub_block self.assertTrue(block.is_parameterized()) # assign durations block = block.assign_parameters({self.amp0: 0.1}) self.assertFalse(block.is_parameterized())
def test_invalid_pulse_duration(self): """Kill pass manager if invalid pulse gate is found.""" # this is invalid duration pulse # this will cause backend error since this doesn't fit with waveform memory chunk. custom_gate = pulse.Schedule(name="custom_x_gate") custom_gate.insert(0, pulse.Play(pulse.Constant(100, 0.1), pulse.DriveChannel(0)), inplace=True) circuit = QuantumCircuit(1) circuit.x(0) circuit.add_calibration("x", qubits=(0, ), schedule=custom_gate) pm = PassManager(ValidatePulseGates(granularity=16, min_length=64)) with self.assertRaises(TranspilerError): pm.run(circuit)
def test_replace_inplace(self): """Test replacing specific instruction with inplace.""" block = pulse.ScheduleBlock() for inst in self.test_blocks: block.append(inst) replaced = pulse.Play(pulse.Constant(300, 0.1), self.d1) target = pulse.Delay(50, self.d0) block.replace(target, replaced, inplace=True) ref_sched = pulse.Schedule() ref_sched = ref_sched.insert(0, pulse.Play(self.test_waveform0, self.d0)) ref_sched = ref_sched.insert(0, pulse.Play(self.test_waveform1, self.d1)) ref_sched = ref_sched.insert(200, replaced) ref_sched = ref_sched.insert(100, pulse.Play(self.test_waveform1, self.d0)) self.assertScheduleEqual(block, ref_sched)
def test_macro(self): """Test builder macro decorator.""" @pulse.macro def nested(a): pulse.play(pulse.Gaussian(100, a, 20), pulse.drive_channel(0)) return a * 2 @pulse.macro def test(): pulse.play(pulse.Constant(100, 1.0), pulse.drive_channel(0)) output = nested(0.5) return output with pulse.build(self.backend) as schedule: output = test() self.assertEqual(output, 0.5 * 2) reference = pulse.Schedule() reference += pulse.Play(pulse.Constant(100, 1.0), pulse.DriveChannel(0)) reference += pulse.Play(pulse.Gaussian(100, 0.5, 20), pulse.DriveChannel(0)) self.assertScheduleEqual(schedule, reference)
def test_replace(self): """Test replacing specific instruction.""" block = pulse.ScheduleBlock() for inst in self.test_blocks: block.append(inst) replaced = pulse.Play(pulse.Constant(300, 0.1), self.d1) target = pulse.Delay(50, self.d0) block_replaced = block.replace(target, replaced, inplace=False) # original schedule is not destroyed self.assertListEqual(list(block.blocks), self.test_blocks) ref_sched = pulse.Schedule() ref_sched = ref_sched.insert(0, pulse.Play(self.test_waveform0, self.d0)) ref_sched = ref_sched.insert(0, pulse.Play(self.test_waveform1, self.d1)) ref_sched = ref_sched.insert(200, replaced) ref_sched = ref_sched.insert(100, pulse.Play(self.test_waveform1, self.d0)) self.assertScheduleEqual(block_replaced, ref_sched)
def test(): pulse.play(pulse.Constant(100, 1.0), pulse.drive_channel(0)) output = nested(0.5) return output
def test_assemble_single_instruction(self): """Test assembling schedules, no lo config.""" inst = pulse.Play(pulse.Constant(100, 1.0), pulse.DriveChannel(0)) qobj = assemble(inst, self.backend) validate_qobj_against_schema(qobj)