def test_nested_mapping_avoidance(self):
        template = DummyPulseTemplate(parameter_names={'foo', 'bar'})
        st_1 = MappingPulseTemplate(template,
                                    parameter_mapping={'foo': 't*k'},
                                    allow_partial_parameter_mapping=True)
        st_2 = MappingPulseTemplate(st_1,
                                    parameter_mapping={'bar': 't*l'},
                                    allow_partial_parameter_mapping=True)

        self.assertIs(st_2.template, template)
        self.assertEqual(st_2.parameter_mapping, {'foo': 't*k', 'bar': 't*l'})

        st_3 = MappingPulseTemplate(template,
                                    parameter_mapping={'foo': 't*k'},
                                    allow_partial_parameter_mapping=True,
                                    identifier='käse')
        st_4 = MappingPulseTemplate(st_3,
                                    parameter_mapping={'bar': 't*l'},
                                    allow_partial_parameter_mapping=True)
        self.assertIs(st_4.template, st_3)
        self.assertEqual(st_4.parameter_mapping, {
            't': 't',
            'k': 'k',
            'bar': 't*l'
        })
    def test_constrained(self):
        template = DummyPulseTemplate(parameter_names={'foo', 'bar'})
        st = MappingPulseTemplate(template,
                                  parameter_mapping={
                                      'foo': 't*k',
                                      'bar': 't*l'
                                  },
                                  parameter_constraints=['t < m'])
        external_params = {'t', 'l', 'k', 'm'}
        self.assertEqual(st.parameter_names, external_params)

        with self.assertRaises(ParameterConstraintViolation):
            st.map_parameters(dict(t=1, l=2, k=3, m=0))
 def test_get_updated_channel_mapping(self):
     template = DummyPulseTemplate(defined_channels={'foo', 'bar'})
     st = MappingPulseTemplate(template, channel_mapping={'bar': 'kneipe'})
     with self.assertRaises(KeyError):
         st.get_updated_channel_mapping(dict())
     self.assertEqual(
         st.get_updated_channel_mapping({
             'kneipe': 'meas1',
             'foo': 'meas2',
             'troet': 'meas3'
         }), {
             'foo': 'meas2',
             'bar': 'meas1'
         })
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

        # Setup test data
        self.square = TablePulseTemplate(
            {
                'default': [(0, 0), ('up', 'v', 'hold'), ('down', 0, 'hold'),
                            ('length', 0)]
            },
            measurements=[('mw1', 'up', 'length-up')])
        self.mapping1 = {
            'up': 'uptime',
            'down': 'uptime + length',
            'v': 'voltage',
            'length': '0.5 * pulse_length'
        }

        self.window_name_mapping = {'mw1': 'test_window'}

        self.outer_parameters = {'uptime', 'length', 'pulse_length', 'voltage'}

        self.parameters = dict()
        self.parameters['uptime'] = ConstantParameter(5)
        self.parameters['length'] = ConstantParameter(10)
        self.parameters['pulse_length'] = ConstantParameter(100)
        self.parameters['voltage'] = ConstantParameter(10)

        self.sequence = SequencePulseTemplate(
            MappingPulseTemplate(self.square,
                                 parameter_mapping=self.mapping1,
                                 measurement_mapping=self.window_name_mapping),
            external_parameters=self.outer_parameters)
    def test_partial_parameter_mapping(self):
        template = DummyPulseTemplate(parameter_names={'foo', 'bar'})
        st = MappingPulseTemplate(template,
                                  parameter_mapping={'foo': 't*k'},
                                  allow_partial_parameter_mapping=True)

        self.assertEqual(st.parameter_mapping, {'foo': 't*k', 'bar': 'bar'})
    def __init__(self,
                 *subtemplates: Union[PulseTemplate, MappingTuple],
                 external_parameters: Optional[Union[Iterable[str], Set[str]]]=None,
                 identifier: Optional[str]=None,
                 parameter_constraints: Optional[List[Union[str, Expression]]]=None,
                 measurements: Optional[List[MeasurementDeclaration]]=None) -> None:
        """Create a new SequencePulseTemplate instance.

        Requires a (correctly ordered) list of subtemplates in the form
        (PulseTemplate, Dict(str -> str)) where the dictionary is a mapping between the external
        parameters exposed by this SequencePulseTemplate to the parameters declared by the
        subtemplates, specifying how the latter are derived from the former, i.e., the mapping is
        subtemplate_parameter_name -> mapping_expression (as str) where the free variables in the
        mapping_expression are parameters declared by this SequencePulseTemplate.

        The following requirements must be satisfied:
            - for each parameter declared by a subtemplate, a mapping expression must be provided
            - each free variable in a mapping expression must be declared as an external parameter
                of this SequencePulseTemplate

        Args:
            subtemplates (List(Subtemplate)): The list of subtemplates of this
                SequencePulseTemplate as tuples of the form (PulseTemplate, Dict(str -> str)).
            external_parameters (List(str)): A set of names for external parameters of this
                SequencePulseTemplate.
            identifier (str): A unique identifier for use in serialization. (optional)
        Raises:
            MissingMappingException, if a parameter of a subtemplate is not mapped to the external
                parameters of this SequencePulseTemplate.
            MissingParameterDeclarationException, if a parameter mapping requires a parameter
                that was not declared in the external parameters of this SequencePulseTemplate.
        """
        PulseTemplate.__init__(self, identifier=identifier)
        ParameterConstrainer.__init__(self, parameter_constraints=parameter_constraints)
        MeasurementDefiner.__init__(self, measurements=measurements)

        self.__subtemplates = [MappingPulseTemplate.from_tuple(st) if isinstance(st, tuple) else st
                               for st in subtemplates]

        # check that all subtemplates live on the same channels
        defined_channels = self.__subtemplates[0].defined_channels
        for subtemplate in self.__subtemplates[1:]:
            if subtemplate.defined_channels != defined_channels:
                raise ValueError('The subtemplates are defined for different channels')

        if external_parameters:
            external_parameters = set(external_parameters)
            remaining = external_parameters.copy()
            for subtemplate in self.__subtemplates:
                missing = subtemplate.parameter_names - external_parameters
                if missing:
                    raise MissingParameterDeclarationException(subtemplate, missing.pop())
                remaining -= subtemplate.parameter_names
            if not external_parameters >= self.constrained_parameters:
                raise MissingParameterDeclarationException(self,
                                                           (self.constrained_parameters-external_parameters).pop())
            remaining -= self.constrained_parameters
            if remaining:
                raise MissingMappingException(self, remaining.pop())
 def test_measurement_names(self):
     template = DummyPulseTemplate(measurement_names={'foo', 'bar'})
     st = MappingPulseTemplate(template,
                               measurement_mapping={
                                   'foo': 'froop',
                                   'bar': 'kneipe'
                               })
     self.assertEqual(st.measurement_names, {'froop', 'kneipe'})
    def test_build_sequence(self):
        measurement_mapping = {'meas1': 'meas2'}
        parameter_mapping = {'t': 'k'}

        template = DummyPulseTemplate(
            measurement_names=set(measurement_mapping.keys()),
            parameter_names=set(parameter_mapping.keys()))
        st = MappingPulseTemplate(template,
                                  parameter_mapping=parameter_mapping,
                                  measurement_mapping=measurement_mapping)
        sequencer = DummySequencer()
        block = DummyInstructionBlock()
        pre_parameters = {'k': ConstantParameter(5)}
        pre_measurement_mapping = {'meas2': 'meas3'}
        pre_channel_mapping = {'default': 'A'}
        conditions = dict(a=True)
        st.build_sequence(sequencer, pre_parameters, conditions,
                          pre_measurement_mapping, pre_channel_mapping, block)

        self.assertEqual(template.build_sequence_calls, 1)
        forwarded_args = template.build_sequence_arguments[0]
        self.assertEqual(forwarded_args[0], sequencer)
        self.assertEqual(forwarded_args[1], st.map_parameters(pre_parameters))
        self.assertEqual(forwarded_args[2], conditions)
        self.assertEqual(
            forwarded_args[3],
            st.get_updated_measurement_mapping(pre_measurement_mapping))
        self.assertEqual(forwarded_args[4],
                         st.get_updated_channel_mapping(pre_channel_mapping))
        self.assertEqual(forwarded_args[5], block)
    def test_init_exceptions(self):
        template = DummyPulseTemplate(parameter_names={'foo', 'bar'},
                                      defined_channels={'A'},
                                      measurement_names={'B'})
        parameter_mapping = {'foo': 't*k', 'bar': 't*l'}

        with self.assertRaises(MissingMappingException):
            MappingPulseTemplate(template, parameter_mapping={})
        with self.assertRaises(MissingMappingException):
            MappingPulseTemplate(template, parameter_mapping={'bar': 'kneipe'})
        with self.assertRaises(UnnecessaryMappingException):
            MappingPulseTemplate(template,
                                 parameter_mapping=dict(**parameter_mapping,
                                                        foobar='asd'))

        with self.assertRaises(UnnecessaryMappingException):
            MappingPulseTemplate(template,
                                 parameter_mapping=parameter_mapping,
                                 measurement_mapping=dict(a='b'))
        with self.assertRaises(UnnecessaryMappingException):
            MappingPulseTemplate(template,
                                 parameter_mapping=parameter_mapping,
                                 channel_mapping=dict(a='b'))

        with self.assertRaises(TypeError):
            MappingPulseTemplate(template, parameter_mapping)

        MappingPulseTemplate(template, parameter_mapping=parameter_mapping)
        def test_mapping_permutations(template: DummyPulseTemplate, pmap, mmap,
                                      cmap):
            direct = MappingPulseTemplate(template,
                                          parameter_mapping=pmap,
                                          measurement_mapping=mmap,
                                          channel_mapping=cmap)

            mappings = [m for m in [pmap, mmap, cmap] if m is not None]

            for current_mapping_order in itertools.permutations(mappings):
                mapper = MappingPulseTemplate.from_tuple(
                    (template, *current_mapping_order))
                self.assertEqual(mapper.measurement_mapping,
                                 direct.measurement_mapping)
                self.assertEqual(mapper.channel_mapping,
                                 direct.channel_mapping)
                self.assertEqual(mapper.parameter_mapping,
                                 direct.parameter_mapping)
 def test_external_params(self):
     template = DummyPulseTemplate(parameter_names={'foo', 'bar'})
     st = MappingPulseTemplate(template,
                               parameter_mapping={
                                   'foo': 't*k',
                                   'bar': 't*l'
                               })
     external_params = {'t', 'l', 'k'}
     self.assertEqual(st.parameter_names, external_params)
    def test_map_parameters(self):
        template = DummyPulseTemplate(parameter_names={'foo', 'bar'})
        st = MappingPulseTemplate(template,
                                  parameter_mapping={
                                      'foo': 't*k',
                                      'bar': 't*l'
                                  })

        parameters = {
            't': ConstantParameter(3),
            'k': ConstantParameter(2),
            'l': ConstantParameter(7)
        }
        values = {'foo': 6, 'bar': 21}
        for k, v in st.map_parameters(parameters).items():
            self.assertEqual(v.get_value(), values[k])
        parameters.popitem()
        with self.assertRaises(ParameterNotProvidedException):
            st.map_parameters(parameters)

        parameters = dict(t=3, k=2, l=7)
        values = {'foo': 6, 'bar': 21}
        for k, v in st.map_parameters(parameters).items():
            self.assertEqual(v, values[k])
    def test_from_tuple_exceptions(self):
        template = DummyPulseTemplate(parameter_names={'foo', 'bar'},
                                      measurement_names={'foo', 'foobar'},
                                      defined_channels={'bar', 'foobar'})

        with self.assertRaises(ValueError):
            MappingPulseTemplate.from_tuple((template, {'A': 'B'}))
        with self.assertRaises(AmbiguousMappingException):
            MappingPulseTemplate.from_tuple((template, {'foo': 'foo'}))
        with self.assertRaises(AmbiguousMappingException):
            MappingPulseTemplate.from_tuple((template, {'bar': 'bar'}))
        with self.assertRaises(AmbiguousMappingException):
            MappingPulseTemplate.from_tuple((template, {'foobar': 'foobar'}))

        template = DummyPulseTemplate(parameter_names={'foo', 'bar'})
        with self.assertRaises(MappingCollisionException):
            MappingPulseTemplate.from_tuple((template, {
                'foo': '1',
                'bar': 2
            }, {
                'foo': '1',
                'bar': 4
            }))

        template = DummyPulseTemplate(defined_channels={'A'})
        with self.assertRaises(MappingCollisionException):
            MappingPulseTemplate.from_tuple((template, {'A': 'N'}, {'A': 'C'}))

        template = DummyPulseTemplate(measurement_names={'M'})
        with self.assertRaises(MappingCollisionException):
            MappingPulseTemplate.from_tuple((template, {'M': 'N'}, {'M': 'N'}))
 def test_defined_channels(self):
     mapping = {'asd': 'A', 'fgh': 'B'}
     template = DummyPulseTemplate(defined_channels=set(mapping.keys()))
     st = MappingPulseTemplate(template, channel_mapping=mapping)
     self.assertEqual(st.defined_channels, set(mapping.values()))
    def __init__(
            self,
            *subtemplates: Union[AtomicPulseTemplate, MappingTuple,
                                 MappingPulseTemplate],
            external_parameters: Optional[Set[str]] = None,
            identifier: Optional[str] = None,
            parameter_constraints: Optional[List] = None,
            measurements: Optional[List[MeasurementDeclaration]] = None
    ) -> None:
        AtomicPulseTemplate.__init__(self,
                                     identifier=identifier,
                                     measurements=measurements)
        ParameterConstrainer.__init__(
            self, parameter_constraints=parameter_constraints)

        self._subtemplates = [
            st if isinstance(st, PulseTemplate) else
            MappingPulseTemplate.from_tuple(st) for st in subtemplates
        ]

        for subtemplate in self._subtemplates:
            if isinstance(subtemplate, AtomicPulseTemplate):
                continue
            elif isinstance(subtemplate, MappingPulseTemplate):
                if isinstance(subtemplate.template, AtomicPulseTemplate):
                    continue
                else:
                    raise TypeError(
                        'Non atomic subtemplate of MappingPulseTemplate: {}'.
                        format(subtemplate.template))
            else:
                raise TypeError(
                    'Non atomic subtemplate: {}'.format(subtemplate))

        if not self._subtemplates:
            raise ValueError('Cannot create empty MultiChannelPulseTemplate')

        defined_channels = [st.defined_channels for st in self._subtemplates]

        # check there are no intersections between channels
        for i, channels_i in enumerate(defined_channels):
            for j, channels_j in enumerate(defined_channels[i + 1:]):
                if channels_i & channels_j:
                    raise ChannelMappingException(
                        'subtemplate {}'.format(i + 1),
                        'subtemplate {}'.format(i + 2 + j),
                        (channels_i | channels_j).pop())

        if external_parameters is not None:
            remaining = external_parameters.copy()
            for subtemplate in self._subtemplates:
                missing = subtemplate.parameter_names - external_parameters
                if missing:
                    raise MissingParameterDeclarationException(
                        subtemplate, missing.pop())
                remaining -= subtemplate.parameter_names
            missing = self.constrained_parameters - external_parameters
            if missing:
                raise MissingParameterDeclarationException(self, missing.pop())
            remaining -= self.constrained_parameters
            if remaining:
                raise MissingMappingException(self, remaining.pop())

        duration = self._subtemplates[0].duration
        for subtemplate in self._subtemplates[1:]:
            if (duration == subtemplate.duration) is True:
                continue
            else:
                raise ValueError(
                    'Could not assert duration equality of {} and {}'.format(
                        duration, subtemplate.duration))