def test_serialize(self):
        sts = [DummyPulseTemplate(duration='t1', defined_channels={'A'}, parameter_names={'a', 'b'}),
               DummyPulseTemplate(duration='t1', defined_channels={'B'}, parameter_names={'a', 'c'})]
        constraints = ['a < d']
        template = AtomicMultiChannelPulseTemplate(*sts,
                                                   parameter_constraints=constraints)

        expected_data = dict(subtemplates=['0', '1'], parameter_constraints=['a < d'])

        def serialize_callback(obj) -> str:
            self.assertIn(obj, sts)
            return str(sts.index(obj))

        serializer = DummySerializer(serialize_callback=serialize_callback, identifier_callback=serialize_callback)

        data = template.get_serialization_data(serializer=serializer)

        self.assertEqual(expected_data, data)
    def test_mapping_template_mixed_conversion(self):
        subtemp_args = [
            (self.subtemplates[0], self.param_maps[0], self.chan_maps[0]),
            MappingPulseTemplate(self.subtemplates[1], parameter_mapping=self.param_maps[1], channel_mapping=self.chan_maps[1]),
            (self.subtemplates[2], self.param_maps[2], self.chan_maps[2])
        ]
        template = AtomicMultiChannelPulseTemplate(*subtemp_args)

        for st, pm, cm in zip(template.subtemplates, self.param_maps, self.chan_maps):
            self.assertEqual(st.parameter_names, set(pm.values()))
            self.assertEqual(st.defined_channels, set(cm.values()))
    def test_external_parameters(self):
        sts = [DummyPulseTemplate(duration='t1', defined_channels={'A'}, parameter_names={'a', 'b'}),
               DummyPulseTemplate(duration='t1', defined_channels={'B'}, parameter_names={'a', 'c'})]
        constraints = ['a < d']
        template = AtomicMultiChannelPulseTemplate(*sts,
                                                   parameter_constraints=constraints,
                                                   external_parameters={'a', 'b', 'c', 'd'})

        with self.assertRaises(MissingParameterDeclarationException):
            AtomicMultiChannelPulseTemplate(*sts,
                                            external_parameters={'a', 'c', 'd'},
                                            parameter_constraints=constraints)
        with self.assertRaises(MissingParameterDeclarationException):
            AtomicMultiChannelPulseTemplate(*sts, external_parameters={'a', 'b', 'd'},
                                            parameter_constraints=constraints)
        with self.assertRaises(MissingParameterDeclarationException):
            AtomicMultiChannelPulseTemplate(*sts, external_parameters={'b', 'c', 'd'},
                                            parameter_constraints=constraints)
        with self.assertRaises(MissingParameterDeclarationException):
            AtomicMultiChannelPulseTemplate(*sts, external_parameters={'a', 'c', 'b'},
                                            parameter_constraints=constraints)

        with self.assertRaises(MissingMappingException):
            AtomicMultiChannelPulseTemplate(*sts, external_parameters={'a', 'b', 'c', 'd', 'e'},
                                            parameter_constraints=constraints)

        self.assertEqual(template.parameter_names, {'a', 'b', 'c', 'd'})
    def test_build_waveform(self):
        wfs = [DummyWaveform(duration=1.1, defined_channels={'A'}), DummyWaveform(duration=1.1, defined_channels={'B'})]

        sts = [DummyPulseTemplate(duration='t1', defined_channels={'A'}, parameter_names={'a', 'b'},
                                  measurement_names={'A', 'C'}, waveform=wfs[0]),
               DummyPulseTemplate(duration='t1', defined_channels={'B'}, parameter_names={'a', 'c'},
                                  measurement_names={'A', 'B'}, waveform=wfs[1])]

        pt = AtomicMultiChannelPulseTemplate(*sts, parameter_constraints=['a < b'])

        parameters = dict(a=2.2, b = 1.1, c=3.3)
        channel_mapping = dict()
        with self.assertRaises(ParameterConstraintViolation):
            pt.build_waveform(parameters, channel_mapping=dict())

        parameters['a'] = 0.5
        wf = pt.build_waveform(parameters, channel_mapping=channel_mapping)
        self.assertEqual(wf['A'], wfs[0])
        self.assertEqual(wf['B'], wfs[1])

        for st in sts:
            self.assertEqual(st.build_waveform_calls, [(parameters, channel_mapping)])
            self.assertIs(parameters, st.build_waveform_calls[0][0])
            self.assertIs(channel_mapping, st.build_waveform_calls[0][1])
    def test_deserialize(self):
        sts = [DummyPulseTemplate(duration='t1', defined_channels={'A'}, parameter_names={'a', 'b'}),
               DummyPulseTemplate(duration='t1', defined_channels={'B'}, parameter_names={'a', 'c'})]

        def deserialization_callback(ident: str):
            self.assertIn(ident, ('0', '1'))

            if ident == '0':
                return 0
            else:
                return 1

        serializer = DummySerializer(deserialize_callback=deserialization_callback)
        serializer.subelements = sts

        data = dict(subtemplates=['0', '1'], parameter_constraints=['a < d'])

        template = AtomicMultiChannelPulseTemplate.deserialize(serializer, **data)

        self.assertIs(template.subtemplates[0], sts[0])
        self.assertIs(template.subtemplates[1], sts[1])
        self.assertEqual(template.parameter_constraints, [ParameterConstraint('a < d')])
    def test_measurement_names(self):
        sts = [DummyPulseTemplate(duration='t1', defined_channels={'A'}, parameter_names={'a', 'b'}, measurement_names={'A', 'C'}),
               DummyPulseTemplate(duration='t1', defined_channels={'B'}, parameter_names={'a', 'c'}, measurement_names={'A', 'B'})]

        self.assertEqual(AtomicMultiChannelPulseTemplate(*sts).measurement_names, {'A', 'B', 'C'})
 def test_defined_channels(self):
     subtemp_args = [*zip(self.subtemplates, self.param_maps, self.chan_maps)]
     template = AtomicMultiChannelPulseTemplate(*subtemp_args)
     self.assertEqual(template.defined_channels, {'cc1', 'cc2', 'cc3'})
 def test_channel_intersection(self):
     chan_maps = self.chan_maps.copy()
     chan_maps[-1]['c3'] = 'cc1'
     with self.assertRaises(ChannelMappingException):
         AtomicMultiChannelPulseTemplate(*zip(self.subtemplates, self.param_maps, chan_maps))
    def test_mapping_template_pure_conversion(self):
        template = AtomicMultiChannelPulseTemplate(*zip(self.subtemplates, self.param_maps, self.chan_maps))

        for st, pm, cm in zip(template.subtemplates, self.param_maps, self.chan_maps):
            self.assertEqual(st.parameter_names, set(pm.values()))
            self.assertEqual(st.defined_channels, set(cm.values()))