def test_unsafe_sample(self): time = np.linspace(10, 20, num=25) ch_a = np.exp(time) ch_b = np.exp(-time) ch_c = np.sinh(time) ch_d = np.cosh(time) ch_e = np.arctan(time) sample_output = {'a': ch_a, 'b': ch_b} expected_call_data = sample_output transformed = {'c': ch_c, 'd': ch_d, 'e': ch_e} trafo = TransformationDummy(transformed=transformed, input_channels={'a', 'b'}) inner_wf = DummyWaveform(duration=1.5, defined_channels={'a', 'b'}, sample_output=sample_output) trafo_wf = TransformingWaveform(inner_waveform=inner_wf, transformation=trafo) np.testing.assert_equal(ch_c, trafo_wf.unsafe_sample('c', time)) np.testing.assert_equal(ch_d, trafo_wf.unsafe_sample('d', time)) np.testing.assert_equal(ch_e, trafo_wf.unsafe_sample('e', time)) output = np.empty_like(time) ch_d_out = trafo_wf.unsafe_sample('d', time, output_array=output) self.assertIs(output, ch_d_out) np.testing.assert_equal(ch_d_out, ch_d) call_list = TransformationDummy.__call__.call_args_list self.assertEqual(len(call_list), 1) (pos_args, kw_args), = call_list self.assertEqual(kw_args, {}) c_time, c_data = pos_args np.testing.assert_equal((time, expected_call_data), pos_args)
def test_get_subset_for_channels(self): output_channels = {'c', 'd', 'e'} trafo = TransformationDummy(output_channels=output_channels) inner_wf = DummyWaveform(duration=1.5, defined_channels={'a', 'b'}) trafo_wf = TransformingWaveform(inner_waveform=inner_wf, transformation=trafo) subset_wf = trafo_wf.get_subset_for_channels({'c', 'd'}) self.assertIsInstance(subset_wf, SubsetWaveform) self.assertIs(subset_wf.inner_waveform, trafo_wf) self.assertEqual(subset_wf.defined_channels, {'c', 'd'})
def _internal_create_program( self, *, scope: Scope, measurement_mapping: Dict[str, Optional[str]], channel_mapping: Dict[ChannelID, Optional[ChannelID]], global_transformation: Optional[Transformation], to_single_waveform: Set[Union[str, 'PulseTemplate']], parent_loop: Loop) -> None: """Parameter constraints are validated in build_waveform because build_waveform is guaranteed to be called during sequencing""" ### current behavior (same as previously): only adds EXEC Loop and measurements if a waveform exists. ### measurements are directly added to parent_loop (to reflect behavior of Sequencer + MultiChannelProgram) assert not scope.get_volatile_parameters().keys( ) & self.parameter_names, "AtomicPT cannot be volatile" waveform = self.build_waveform(parameters=scope, channel_mapping=channel_mapping) if waveform: measurements = self.get_measurement_windows( parameters=scope, measurement_mapping=measurement_mapping) if global_transformation: waveform = TransformingWaveform(waveform, global_transformation) parent_loop.add_measurements(measurements=measurements) parent_loop.append_child(waveform=waveform)
def test_build_waveform(self): pt = DummyPulseTemplate(defined_channels={'a'}) parameters = dict(x=5., y=5.7) channel_mapping = dict(a='u', b='v') inner_wf = mock.Mock(spec=DummyWaveform) trafo = mock.Mock(spec=IdentityTransformation()) arith = ArithmeticPulseTemplate(pt, '-', 6) with mock.patch.object(pt, 'build_waveform', return_value=None) as inner_build: with mock.patch.object(arith, '_get_transformation') as _get_transformation: self.assertIsNone(arith.build_waveform(parameters=parameters, channel_mapping=channel_mapping)) inner_build.assert_called_once_with(parameters=parameters, channel_mapping=channel_mapping) _get_transformation.assert_not_called() expected = TransformingWaveform(inner_wf, trafo) with mock.patch.object(pt, 'build_waveform', return_value=inner_wf) as inner_build: with mock.patch.object(arith, '_get_transformation', return_value=trafo) as _get_transformation: result = arith.build_waveform(parameters=parameters, channel_mapping=channel_mapping) inner_build.assert_called_once_with(parameters=parameters, channel_mapping=channel_mapping) _get_transformation.assert_called_once_with(parameters=parameters, channel_mapping=channel_mapping) self.assertEqual(expected, result)
def _internal_create_program(self, *, parameters: Dict[str, Parameter], measurement_mapping: Dict[str, Optional[str]], channel_mapping: Dict[ChannelID, Optional[ChannelID]], global_transformation: Optional[Transformation], to_single_waveform: Set[Union[str, 'PulseTemplate']], parent_loop: Loop) -> None: """Parameter constraints are validated in build_waveform because build_waveform is guaranteed to be called during sequencing""" ### current behavior (same as previously): only adds EXEC Loop and measurements if a waveform exists. ### measurements are directly added to parent_loop (to reflect behavior of Sequencer + MultiChannelProgram) # todo (2018-08-08): could move measurements into own Loop object? # todo (2018-07-05): why are parameter constraints not validated here? try: parameters = {parameter_name: parameters[parameter_name].get_value() for parameter_name in self.parameter_names} except KeyError as e: raise ParameterNotProvidedException(str(e)) from e waveform = self.build_waveform(parameters=parameters, channel_mapping=channel_mapping) if waveform: measurements = self.get_measurement_windows(parameters=parameters, measurement_mapping=measurement_mapping) if global_transformation: waveform = TransformingWaveform(waveform, global_transformation) parent_loop.add_measurements(measurements=measurements) parent_loop.append_child(waveform=waveform)
def test_const_value(self): output_channels = {'c', 'd', 'e'} trafo = TransformationStub() inner_wf = WaveformStub() trafo_wf = TransformingWaveform(inner_wf, trafo) self.assertFalse(trafo_wf.is_constant()) self.assertIsNone(trafo_wf.constant_value_dict()) with mock.patch.object(trafo, 'is_constant_invariant', return_value=False) as is_constant_invariant: self.assertIsNone(trafo_wf.constant_value('A')) is_constant_invariant.assert_called_once_with() with mock.patch.object(trafo, 'is_constant_invariant', return_value=True): # all inputs constant inner_const_values = {'A': 1.1, 'B': 2.2} with mock.patch.object(trafo, 'get_input_channels', return_value=inner_const_values.keys()): with mock.patch.object(inner_wf, 'constant_value', side_effect=inner_const_values.values()) as constant_value: with mock.patch.object(TransformationStub, '__call__', return_value={'C': mock.sentinel}) as call: self.assertIs(trafo_wf.constant_value('C'), call.return_value['C']) call.assert_called_once_with(0., inner_const_values) self.assertEqual([mock.call(ch) for ch in inner_const_values], constant_value.call_args_list) inner_const_values['B'] = None with mock.patch.object(inner_wf, 'constant_value', side_effect=inner_const_values.values()) as constant_value: self.assertIsNone(trafo_wf.constant_value('C'))
def build_waveform(self, parameters: Dict[str, numbers.Real], channel_mapping: Dict[ChannelID, Optional[ChannelID]]) -> Optional[Waveform]: inner_waveform = self._template.build_waveform(parameters, channel_mapping) if inner_waveform: overwritten_channels = self._get_overwritten_channels_values(parameters=parameters, channel_mapping=channel_mapping) transformation = ParallelConstantChannelTransformation(overwritten_channels) return TransformingWaveform(inner_waveform, transformation)
def test_simple_properties(self): output_channels = {'c', 'd', 'e'} trafo = TransformationDummy(output_channels=output_channels) inner_wf = DummyWaveform(duration=1.5, defined_channels={'a', 'b'}) trafo_wf = TransformingWaveform(inner_waveform=inner_wf, transformation=trafo) self.assertIs(trafo_wf.inner_waveform, inner_wf) self.assertIs(trafo_wf.transformation, trafo) self.assertEqual(trafo_wf.compare_key, (inner_wf, trafo)) self.assertIs(trafo_wf.duration, inner_wf.duration) self.assertIs(trafo_wf.defined_channels, output_channels) trafo.get_output_channels.assert_called_once_with(inner_wf.defined_channels)
def build_waveform(self, parameters: Dict[str, Real], channel_mapping: Dict[ChannelID, ChannelID]) -> Optional[Waveform]: pt = cast(AtomicPulseTemplate, self._pulse_template) inner_waveform = pt.build_waveform(parameters=parameters, channel_mapping=channel_mapping) if inner_waveform is None: return None # put arithmetic into transformation transformation = self._get_transformation(parameters=parameters, channel_mapping=channel_mapping) return TransformingWaveform(inner_waveform, transformation=transformation)
def _create_program(self, *, scope: Scope, measurement_mapping: Dict[str, Optional[str]], channel_mapping: Dict[ChannelID, Optional[ChannelID]], global_transformation: Optional[Transformation], to_single_waveform: Set[Union[str, 'PulseTemplate']], parent_loop: Loop): """Generic part of create program. This method handles to_single_waveform and the configuration of the transformer.""" if self.identifier in to_single_waveform or self in to_single_waveform: root = Loop() if not scope.get_volatile_parameters().keys().isdisjoint( self.parameter_names): raise NotImplementedError( 'A pulse template that has volatile parameters cannot be transformed into a ' 'single waveform yet.') self._internal_create_program( scope=scope, measurement_mapping=measurement_mapping, channel_mapping=channel_mapping, global_transformation=None, to_single_waveform=to_single_waveform, parent_loop=root) waveform = to_waveform(root) if global_transformation: waveform = TransformingWaveform(waveform, global_transformation) # convert the nicely formatted measurement windows back into the old format again :( measurements = root.get_measurement_windows() measurement_window_list = [] for measurement_name, (begins, lengths) in measurements.items(): measurement_window_list.extend( zip(itertools.repeat(measurement_name), begins, lengths)) parent_loop.add_measurements(measurement_window_list) parent_loop.append_child(waveform=waveform) else: self._internal_create_program( scope=scope, measurement_mapping=measurement_mapping, channel_mapping=channel_mapping, to_single_waveform=to_single_waveform, global_transformation=global_transformation, parent_loop=parent_loop)
def _create_program(self, *, parameters: Dict[str, Parameter], measurement_mapping: Dict[str, Optional[str]], channel_mapping: Dict[ChannelID, Optional[ChannelID]], global_transformation: Optional[Transformation], to_single_waveform: Set[Union[str, 'PulseTemplate']], parent_loop: Loop): """Generic part of create program. This method handles to_single_waveform and the configuration of the transformer.""" if self.identifier in to_single_waveform or self in to_single_waveform: root = Loop() self._internal_create_program( parameters=parameters, measurement_mapping=measurement_mapping, channel_mapping=channel_mapping, global_transformation=None, to_single_waveform=to_single_waveform, parent_loop=root) waveform = to_waveform(root) if global_transformation: waveform = TransformingWaveform(waveform, global_transformation) # convert the nicely formatted measurement windows back into the old format again :( measurements = root.get_measurement_windows() measurement_window_list = [] for measurement_name, (begins, lengths) in measurements.items(): measurement_window_list.extend( zip(itertools.repeat(measurement_name), begins, lengths)) parent_loop.add_measurements(measurement_window_list) parent_loop.append_child(waveform=waveform) else: self._internal_create_program( parameters=parameters, measurement_mapping=measurement_mapping, channel_mapping=channel_mapping, to_single_waveform=to_single_waveform, global_transformation=global_transformation, parent_loop=parent_loop)
def test_from_transformation(self): const_output = {'c': 4.4, 'd': 5.5, 'e': 6.6} trafo = TransformationDummy(output_channels=const_output.keys(), constant_invariant=False) const_trafo = TransformationDummy(output_channels=const_output.keys(), constant_invariant=True, transformed=const_output) dummy_wf = DummyWaveform(duration=1.5, defined_channels={'a', 'b'}) const_wf = ConstantWaveform.from_mapping(3, {'a': 2.2, 'b': 3.3}) self.assertEqual(TransformingWaveform(inner_waveform=dummy_wf, transformation=trafo), TransformingWaveform.from_transformation(inner_waveform=dummy_wf, transformation=trafo)) self.assertEqual(TransformingWaveform(inner_waveform=dummy_wf, transformation=const_trafo), TransformingWaveform.from_transformation(inner_waveform=dummy_wf, transformation=const_trafo)) self.assertEqual(TransformingWaveform(inner_waveform=const_wf, transformation=trafo), TransformingWaveform.from_transformation(inner_waveform=const_wf, transformation=trafo)) with mock.patch.object(ConstantWaveform, 'from_mapping', return_value=mock.sentinel) as from_mapping: self.assertIs(from_mapping.return_value, TransformingWaveform.from_transformation(inner_waveform=const_wf, transformation=const_trafo)) from_mapping.assert_called_once_with(const_wf.duration, const_output)
def test_internal_create_program_transformation(self): inner_wf = DummyWaveform() template = AtomicPulseTemplateStub(parameter_names=set()) program = Loop() global_transformation = TransformationStub() scope = DictScope.from_kwargs() expected_program = Loop(children=[ Loop( waveform=TransformingWaveform(inner_wf, global_transformation)) ]) with mock.patch.object(template, 'build_waveform', return_value=inner_wf): template._internal_create_program( scope=scope, measurement_mapping={}, channel_mapping={}, parent_loop=program, to_single_waveform=set(), global_transformation=global_transformation) self.assertEqual(expected_program, program)
def test__create_program_single_waveform(self): template = PulseTemplateStub(identifier='pt_identifier', parameter_names={'alpha'}) for to_single_waveform in ({template}, {template.identifier}): for global_transformation in (None, TransformationStub()): scope = DictScope.from_kwargs(a=1., b=2., volatile={'a'}) measurement_mapping = {'M': 'N'} channel_mapping = {'B': 'A'} parent_loop = Loop() wf = DummyWaveform() single_waveform = DummyWaveform() measurements = [('m', 0, 1), ('n', 0.1, .9)] expected_inner_program = Loop(children=[Loop(waveform=wf)], measurements=measurements) appending_create_program = get_appending_internal_create_program( wf, measurements=measurements, always_append=True) if global_transformation: final_waveform = TransformingWaveform( single_waveform, global_transformation) else: final_waveform = single_waveform expected_program = Loop( children=[Loop(waveform=final_waveform)], measurements=measurements) with mock.patch.object(template, '_internal_create_program', wraps=appending_create_program ) as _internal_create_program: with mock.patch( 'qupulse.pulses.pulse_template.to_waveform', return_value=single_waveform) as to_waveform: template._create_program( scope=scope, measurement_mapping=measurement_mapping, channel_mapping=channel_mapping, global_transformation=global_transformation, to_single_waveform=to_single_waveform, parent_loop=parent_loop) _internal_create_program.assert_called_once_with( scope=scope, measurement_mapping=measurement_mapping, channel_mapping=channel_mapping, global_transformation=None, to_single_waveform=to_single_waveform, parent_loop=expected_inner_program) to_waveform.assert_called_once_with( expected_inner_program) expected_program._measurements = set( expected_program._measurements) parent_loop._measurements = set( parent_loop._measurements) self.assertEqual(expected_program, parent_loop)