def convert_shift_frequency(self, instruction): """Return converted `ShiftFrequency`. Args: instruction (PulseQobjInstruction): Shift frequency qobj instruction. Returns: Schedule: Converted and scheduled Instruction """ t0 = instruction.t0 channel = self.get_channel(instruction.ch) frequency = instruction.frequency * 1e9 if isinstance(frequency, str): frequency_expr = parse_string_expr(frequency, partial_binding=False) def gen_sf_schedule(*args, **kwargs): _frequency = frequency_expr(*args, **kwargs) return instructions.ShiftFrequency(_frequency, channel) << t0 return ParameterizedSchedule(gen_sf_schedule, parameters=frequency_expr.params) return instructions.ShiftFrequency(frequency, channel) << t0
def test_sequenced_parameterized_schedule(self): """Test parametrized schedule consist of multiple instruction. """ cmd_def = CmdDef() converter = QobjToInstructionConverter([]) qobjs = [PulseQobjInstruction(name='fc', ch='d0', t0=10, phase='P1'), PulseQobjInstruction(name='fc', ch='d0', t0=20, phase='P2'), PulseQobjInstruction(name='fc', ch='d0', t0=30, phase='P3')] converted_instruction = [converter(qobj) for qobj in qobjs] cmd_def.add('inst_seq', 0, ParameterizedSchedule(*converted_instruction, name='inst_seq')) with self.assertRaises(PulseError): cmd_def.get('inst_seq', 0, P1=1, P2=2, P3=3, P4=4, P5=5) with self.assertRaises(PulseError): cmd_def.get('inst_seq', 0, P1=1) with self.assertRaises(PulseError): cmd_def.get('inst_seq', 0, 1, 2, 3, P1=1) sched = cmd_def.get('inst_seq', 0, 1, 2, 3) self.assertEqual(sched.instructions[0][-1].command.phase, 1) self.assertEqual(sched.instructions[1][-1].command.phase, 2) self.assertEqual(sched.instructions[2][-1].command.phase, 3) sched = cmd_def.get('inst_seq', 0, P1=1, P2=2, P3=3) self.assertEqual(sched.instructions[0][-1].command.phase, 1) self.assertEqual(sched.instructions[1][-1].command.phase, 2) self.assertEqual(sched.instructions[2][-1].command.phase, 3) sched = cmd_def.get('inst_seq', 0, 1, 2, P3=3) self.assertEqual(sched.instructions[0][-1].command.phase, 1) self.assertEqual(sched.instructions[1][-1].command.phase, 2) self.assertEqual(sched.instructions[2][-1].command.phase, 3)
def convert_shift_phase(self, instruction): """Return converted `ShiftPhase`. Args: instruction (PulseQobjInstruction): phase shift qobj instruction Returns: Schedule: Converted and scheduled Instruction """ t0 = instruction.t0 channel = self.get_channel(instruction.ch) phase = instruction.phase # This is parameterized if isinstance(phase, str): phase_expr = parse_string_expr(phase, partial_binding=False) def gen_fc_sched(*args, **kwargs): # this should be real value _phase = phase_expr(*args, **kwargs) return instructions.ShiftPhase(_phase, channel) << t0 return ParameterizedSchedule(gen_fc_sched, parameters=phase_expr.params) return instructions.ShiftPhase(phase, channel) << t0
def __init__(self, qubit_freq_est: List[float], meas_freq_est: List[float], buffer: int, pulse_library: List[PulseLibraryItem], cmd_def: List[Command], **kwargs: Dict[str, Any]): """ Validate and reformat transport layer inputs to initialize. Args: qubit_freq_est: Estimated qubit frequencies in GHz. meas_freq_est: Estimated measurement cavity frequencies in GHz. buffer: Default buffer time (in units of dt) between pulses. pulse_library: Pulse name and sample definitions. cmd_def: Operation name and definition in terms of Commands. **kwargs: Other attributes for the super class. """ super().__init__(**kwargs) self.buffer = buffer self.qubit_freq_est = [freq * 1e9 for freq in qubit_freq_est] """Qubit frequencies in Hertz.""" self.meas_freq_est = [freq * 1e9 for freq in meas_freq_est] """Measurement frequencies in Hertz.""" self.pulse_library = pulse_library self.cmd_def = cmd_def self.instruction_schedule_map = InstructionScheduleMap() self.converter = QobjToInstructionConverter(pulse_library) for inst in cmd_def: pulse_insts = [self.converter(inst) for inst in inst.sequence] schedule = ParameterizedSchedule(*pulse_insts, name=inst.name) self.instruction_schedule_map.add(inst.name, inst.qubits, schedule)
def convert_shift_frequency(self, instruction): """Return converted `ShiftFrequency`. Args: instruction (PulseQobjInstruction): Shift frequency qobj instruction. The input frequency is expressed in GHz, so it will be scaled by a factor 1e9. Returns: Schedule: Converted and scheduled Instruction """ t0 = instruction.t0 channel = self.get_channel(instruction.ch) frequency = instruction.frequency if isinstance(frequency, str): frequency_expr = parse_string_expr(frequency, partial_binding=False) def gen_sf_schedule(*args, **kwargs): _frequency = frequency_expr(*args, **kwargs) return instructions.ShiftFrequency( _frequency * GIGAHERTZ_TO_SI_UNITS, channel) << t0 return ParameterizedSchedule(gen_sf_schedule, parameters=frequency_expr.params) else: frequency = frequency * GIGAHERTZ_TO_SI_UNITS return instructions.ShiftFrequency(frequency, channel) << t0
def test_multiple_parameters_not_returned(self): """Constructing ParameterizedSchedule object from multiple ParameterizedSchedules sharing arguments should not produce repeated parameters in resulting ParameterizedSchedule object.""" def my_test_par_sched_one(x, y, z): result = Play(Waveform(np.array([x, y, z]), name="sample"), self.config.drive(0)) return 0, result def my_test_par_sched_two(x, y, z): result = Play(Waveform(np.array([x, y, z]), name="sample"), self.config.drive(0)) return 5, result par_sched_in_0 = ParameterizedSchedule( my_test_par_sched_one, parameters={"x": 0, "y": 1, "z": 2} ) par_sched_in_1 = ParameterizedSchedule( my_test_par_sched_two, parameters={"x": 0, "y": 1, "z": 2} ) par_sched = ParameterizedSchedule(par_sched_in_0, par_sched_in_1) actual = par_sched(0.01, 0.02, 0.03) expected = par_sched_in_0.bind_parameters( 0.01, 0.02, 0.03 ) | par_sched_in_1.bind_parameters(0.01, 0.02, 0.03) self.assertEqual(actual.start_time, expected.start_time) self.assertEqual(actual.stop_time, expected.stop_time) self.assertEqual(par_sched.parameters, ("x", "y", "z"))
def test_multiple_parameters_not_returned(self): """Constructing ParameterizedSchedule object from multiple ParameterizedSchedules sharing arguments should not produce repeated parameters in resulting ParameterizedSchedule object.""" def my_test_par_sched_one(x, y, z): result = PulseInstruction( SamplePulse(np.array([x, y, z]), name='sample'), self.config.drive(0) ) return 0, result def my_test_par_sched_two(x, y, z): result = PulseInstruction( SamplePulse(np.array([x, y, z]), name='sample'), self.config.drive(0) ) return 5, result par_sched_in_0 = ParameterizedSchedule( my_test_par_sched_one, parameters={'x': 0, 'y': 1, 'z': 2} ) par_sched_in_1 = ParameterizedSchedule( my_test_par_sched_two, parameters={'x': 0, 'y': 1, 'z': 2} ) par_sched = ParameterizedSchedule(par_sched_in_0, par_sched_in_1) actual = par_sched(0.01, 0.02, 0.03) expected = par_sched_in_0.bind_parameters(0.01, 0.02, 0.03) |\ par_sched_in_1.bind_parameters(0.01, 0.02, 0.03) self.assertEqual(actual.start_time, expected.start_time) self.assertEqual(actual.stop_time, expected.stop_time) self.assertEqual(par_sched.parameters, ('x', 'y', 'z'))
def test_negative_phases(self): """Test bind parameters with negative values.""" cmd_def = CmdDef() converter = QobjToInstructionConverter([]) qobjs = [PulseQobjInstruction(name='fc', ch='d0', t0=10, phase='P1'), PulseQobjInstruction(name='fc', ch='d0', t0=20, phase='-(P2)')] converted_instruction = [converter(qobj) for qobj in qobjs] cmd_def.add('inst_seq', 0, ParameterizedSchedule(*converted_instruction, name='inst_seq')) sched = cmd_def.get('inst_seq', 0, -1, 2) self.assertEqual(sched.instructions[0][-1].command.phase, -1) self.assertEqual(sched.instructions[1][-1].command.phase, -2)
def test_filter(self): """Test _filter method.""" device = self.two_qubit_device lp0 = self.linear(duration=3, slope=0.2, intercept=0.1) sched = Schedule(name='fake_experiment') sched = sched.insert(0, lp0(device.drives[0])) sched = sched.insert(10, lp0(device.drives[1])) sched = sched.insert(30, FrameChange(phase=-1.57)(device.drives[0])) for i in sched._filter([lambda x: True]).instructions: self.assertTrue(i in sched.instructions) self.assertEqual(len(sched._filter([lambda x: False]).instructions), 0) self.assertEqual( len(sched._filter([lambda x: x[0] < 30]).instructions), 2) def my_test_par_sched_one(x, y, z): result = PulseInstruction( SamplePulse(np.array([x, y, z]), name='sample'), device.drives[0]) return 0, result def my_test_par_sched_two(x, y, z): result = PulseInstruction( SamplePulse(np.array([x, y, z]), name='sample'), device.drives[0]) return 5, result par_sched_in_0 = ParameterizedSchedule(my_test_par_sched_one, parameters={ 'x': 0, 'y': 1, 'z': 2 }) par_sched_in_1 = ParameterizedSchedule(my_test_par_sched_two, parameters={ 'x': 0, 'y': 1, 'z': 2 }) par_sched = ParameterizedSchedule(par_sched_in_0, par_sched_in_1) cmd_def = CmdDef() cmd_def.add('test', 0, par_sched) actual = cmd_def.get('test', 0, 0.01, 0.02, 0.03) expected = par_sched_in_0.bind_parameters(0.01, 0.02, 0.03) |\ par_sched_in_1.bind_parameters(0.01, 0.02, 0.03) self.assertEqual(actual.start_time, expected.start_time) self.assertEqual(actual.stop_time, expected.stop_time) self.assertEqual(cmd_def.get_parameters('test', 0), ('x', 'y', 'z'))
def test_sequenced_parameterized_schedule(self): """Test parametrized schedule consists of multiple instruction. """ converter = QobjToInstructionConverter([], buffer=0) qobjs = [ PulseQobjInstruction(name='fc', ch='d0', t0=10, phase='P1'), PulseQobjInstruction(name='fc', ch='d0', t0=20, phase='P2'), PulseQobjInstruction(name='fc', ch='d0', t0=30, phase='P3') ] converted_instruction = [converter(qobj) for qobj in qobjs] inst_map = InstructionScheduleMap() inst_map.add( 'inst_seq', 0, ParameterizedSchedule(*converted_instruction, name='inst_seq')) with self.assertRaises(PulseError): inst_map.get('inst_seq', 0, P1=1, P2=2, P3=3, P4=4, P5=5) with self.assertRaises(PulseError): inst_map.get('inst_seq', 0, P1=1) with self.assertRaises(PulseError): inst_map.get('inst_seq', 0, 1, 2, 3, P1=1) p3_expr = Parameter('p3') p3_expr = p3_expr.bind({p3_expr: 3}) sched = inst_map.get('inst_seq', 0, 1, 2, p3_expr) self.assertEqual(sched.instructions[0][-1].phase, 1) self.assertEqual(sched.instructions[1][-1].phase, 2) self.assertEqual(sched.instructions[2][-1].phase, 3) sched = inst_map.get('inst_seq', 0, P1=1, P2=2, P3=p3_expr) self.assertEqual(sched.instructions[0][-1].phase, 1) self.assertEqual(sched.instructions[1][-1].phase, 2) self.assertEqual(sched.instructions[2][-1].phase, 3) sched = inst_map.get('inst_seq', 0, 1, 2, P3=p3_expr) self.assertEqual(sched.instructions[0][-1].phase, 1) self.assertEqual(sched.instructions[1][-1].phase, 2) self.assertEqual(sched.instructions[2][-1].phase, 3)
def test_multiple_parameters_not_returned(self): """Constructing ParameterizedSchedule object from multiple ParameterizedSchedules sharing arguments should not produce repeated parameters in resulting ParameterizedSchedule object.""" device = self.two_qubit_device def my_test_par_sched_one(x, y, z): result = PulseInstruction( SamplePulse(np.array([x, y, z]), name='sample'), device.drives[0]) return 0, result def my_test_par_sched_two(x, y, z): result = PulseInstruction( SamplePulse(np.array([x, y, z]), name='sample'), device.drives[0]) return 5, result par_sched_in_0 = ParameterizedSchedule(my_test_par_sched_one, parameters={ 'x': 0, 'y': 1, 'z': 2 }) par_sched_in_1 = ParameterizedSchedule(my_test_par_sched_two, parameters={ 'x': 0, 'y': 1, 'z': 2 }) par_sched = ParameterizedSchedule(par_sched_in_0, par_sched_in_1) cmd_def = CmdDef() cmd_def.add('test', 0, par_sched) actual = cmd_def.get('test', 0, 0.01, 0.02, 0.03) expected = par_sched_in_0.bind_parameters(0.01, 0.02, 0.03) |\ par_sched_in_1.bind_parameters(0.01, 0.02, 0.03) self.assertEqual(actual.start_time, expected.start_time) self.assertEqual(actual.stop_time, expected.stop_time) self.assertEqual(cmd_def.get_parameters('test', 0), ('x', 'y', 'z'))
def convert_persistent_value(self, instruction): """Return converted `PersistentValueInstruction`. Args: instruction (PulseQobjInstruction): persistent value qobj Returns: Schedule: Converted and scheduled Instruction """ t0 = instruction.t0 channel = self.get_channel(instruction.ch) val = instruction.val # This is parameterized if isinstance(val, str): val_expr = parse_string_expr(val, partial_binding=False) def gen_pv_sched(*args, **kwargs): val = complex(val_expr(*args, **kwargs)) return commands.PersistentValue(val)(channel) << t0 return ParameterizedSchedule(gen_pv_sched, parameters=val_expr.params) return commands.PersistentValue(val)(channel) << t0
def convert_frame_change(self, instruction): """Return converted `FrameChangeInstruction`. Args: instruction (PulseQobjInstruction): frame change qobj Returns: Schedule: Converted and scheduled Instruction """ t0 = instruction.t0 channel = self.get_channel(instruction.ch) phase = instruction.phase # This is parameterized if isinstance(phase, str): phase_expr, params = _parse_string_expr(phase) def gen_fc_sched(*args, **kwargs): phase = abs(phase_expr(*args, **kwargs)) return commands.FrameChange(phase)(channel) << t0 return ParameterizedSchedule(gen_fc_sched, parameters=params) return commands.FrameChange(phase)(channel) << t0
def update_u_gates(drag_params, pi2_pulse_schedules=None, qubits=None, inst_map=None, cmd_def=None, drives=None): """Update the cmd_def with new single qubit gate values Will update U2, U3 Args: drag_params: list of drag params pi2_pulse_schedules: list of new pi/2 gate as a pulse schedule will use the drag_params if this is None. qubits: list of qubits to update inst_map: InstructionScheduleMap providing circuit instruction to schedule definitions. cmd_def: CmdDef object for the device (deprecated) drives: List of drive chs Returns: updated cmd_def """ # U2 is -P1.Y90p.-P0 # U3 is -P2.X90p.-P0.X90m.-P1 if cmd_def and not inst_map: inst_map = cmd_def def parametrized_fc(kw_name, phi0, chan, t_offset): def _parametrized_fc(**kwargs): return FrameChange(phase=-kwargs[kw_name]+phi0)(chan) << t_offset return _parametrized_fc for qubit in qubits: drive_ch = drives[qubit] if pi2_pulse_schedules is None: x90_pulse = pulse_lib.drag(**drag_params[qubit]) x90_pulse = Schedule(x90_pulse(drive_ch)) else: x90_pulse = pi2_pulse_schedules[qubit] pulse_dur = x90_pulse.duration # find channel dependency for u2 for _u2_group in _find_channel_groups('u2', qubits=qubit, inst_map=inst_map): if drive_ch in _u2_group: break else: _u2_group = (drive_ch, ) u2_fc1s = [parametrized_fc('P1', np.pi/2, ch, 0) for ch in _u2_group] u2_fc2s = [parametrized_fc('P0', -np.pi/2, ch, pulse_dur) for ch in _u2_group] # find channel dependency for u2 for _u3_group in _find_channel_groups('u3', qubits=qubit, inst_map=inst_map): if drive_ch in _u3_group: break else: _u3_group = (drive_ch, ) u3_fc1s = [parametrized_fc('P2', 0, ch, 0) for ch in _u3_group] u3_fc2s = [parametrized_fc('P0', -np.pi, ch, pulse_dur) for ch in _u3_group] u3_fc3s = [parametrized_fc('P1', np.pi, ch, 2*pulse_dur) for ch in _u3_group] # add commands to schedule # u2 schedule1 = ParameterizedSchedule(*[*u2_fc1s, x90_pulse, *u2_fc2s], parameters=['P0', 'P1'], name='u2_%d' % qubit) # u3 schedule2 = ParameterizedSchedule(*[*u3_fc1s, x90_pulse, *u3_fc2s, x90_pulse << pulse_dur, *u3_fc3s], parameters=['P0', 'P1', 'P2'], name='u3_%d' % qubit) inst_map.add('u2', qubits=qubit, schedule=schedule1) inst_map.add('u3', qubits=qubit, schedule=schedule2)
def update_u_gates(drag_params, pi2_pulse_schedules=None, qubits=None, inst_map=None, drives=None): """Update the cmd_def with new single qubit gate values Will update U2, U3 Args: drag_params (list): list of drag params pi2_pulse_schedules (list): list of new pi/2 gate as a pulse schedule will use the drag_params if this is None. qubits (list): list of qubits to update inst_map (InstructionScheduleMap): InstructionScheduleMap providing circuit instruction to schedule definitions. drives (list): List of drive chs """ # U2 is -P1.Y90p.-P0 # U3 is -P2.X90p.-P0.X90m.-P1 def parametrized_fc(kw_name, phi0, chan, t_offset): def _parametrized_fc(**kwargs): return ShiftPhase(phase=-kwargs[kw_name]+phi0, channel=chan).shift(t_offset) return _parametrized_fc for qubit in qubits: drive_ch = drives[qubit] if pi2_pulse_schedules is None: x90_pulse = pulse_lib.drag(**drag_params[qubit]) x90_sched = Schedule() x90_sched += Play(x90_pulse, drive_ch).shift(0) else: x90_sched = pi2_pulse_schedules[qubit] pulse_dur = x90_sched.duration # find channel dependency for u2 for _u2_group in _find_channel_groups('u2', qubits=qubit, inst_map=inst_map): if drive_ch in _u2_group: break else: _u2_group = (drive_ch, ) u2_fc1s = [parametrized_fc('P1', np.pi/2, ch, 0) for ch in _u2_group] u2_fc2s = [parametrized_fc('P0', -np.pi/2, ch, pulse_dur) for ch in _u2_group] # find channel dependency for u3 for _u3_group in _find_channel_groups('u3', qubits=qubit, inst_map=inst_map): if drive_ch in _u3_group: break else: _u3_group = (drive_ch, ) u3_fc1s = [parametrized_fc('P2', 0, ch, 0) for ch in _u3_group] u3_fc2s = [parametrized_fc('P0', -np.pi, ch, pulse_dur) for ch in _u3_group] u3_fc3s = [parametrized_fc('P1', np.pi, ch, 2*pulse_dur) for ch in _u3_group] # add commands to schedule # u2 sched_components = [*u2_fc1s, x90_sched, *u2_fc2s] schedule1 = ParameterizedSchedule(*sched_components, parameters=['P0', 'P1'], name='u2_%d' % qubit) # u3 sched_components = [*u3_fc1s, x90_sched, *u3_fc2s, x90_sched.shift(pulse_dur), *u3_fc3s] schedule2 = ParameterizedSchedule(*sched_components, parameters=['P0', 'P1', 'P2'], name='u3_%d' % qubit) inst_map.add('u2', qubits=qubit, schedule=schedule1) inst_map.add('u3', qubits=qubit, schedule=schedule2)