Пример #1
0
    def test_format(self):
        expr = ExpressionScalar('17')
        e_format = '{:.4e}'.format(expr)
        self.assertEqual(e_format, "1.7000e+01")

        empty_format = "{}".format(expr)
        self.assertEqual(empty_format, '17')

        expr_with_var = ExpressionScalar('17*a')
        with self.assertRaises(TypeError):
            # throw error on implicit float cast
            '{:.4e}'.format(expr_with_var)

        empty_format = "{}".format(expr_with_var)
        self.assertEqual(empty_format, '17*a')
Пример #2
0
    def __init__(self,
                 duration: float,
                 amplitude_dict: Dict[str, Any],
                 identifier: Optional[str] = None,
                 name: Optional[str] = None,
                 measurements: Optional[List[MeasurementDeclaration]] = [],
                 **kwargs: Any) -> None:
        """ A qupulse waveform representing a multi-channel pulse with constant values
        
        Args:
            duration: Duration of the template
            amplitude_dict: Dictionary with values for the channels
            name: Name for the template
        
        """
        super().__init__(identifier=identifier,
                         measurements=measurements,
                         **kwargs)

        self._duration = ExpressionScalar(duration)
        self._amplitude_dict = amplitude_dict

        if name is None:
            name = 'constant_pulse'
        self._name = name
Пример #3
0
    def test_body_scope_generator(self):
        dt = DummyPulseTemplate(parameter_names={'i', 'k'})
        flt = ForLoopPulseTemplate(body=dt,
                                   loop_index='i',
                                   loop_range=('a', 'b', 'c'))

        expected_range = range(2, 17, 3)
        outer_scope = DictScope.from_kwargs(k=5,
                                            a=expected_range.start,
                                            b=expected_range.stop,
                                            c=expected_range.step,
                                            volatile={'i', 'j'})

        forward_scopes = list(
            flt._body_scope_generator(outer_scope, forward=True))
        backward_scopes = list(
            flt._body_scope_generator(outer_scope, forward=False))
        volatile_dict = FrozenDict(j=ExpressionScalar('j'))

        self.assertEqual(forward_scopes, list(reversed(backward_scopes)))

        for scope, i in zip(forward_scopes, expected_range):
            self.assertEqual(volatile_dict, scope.get_volatile_parameters())

            expected_dict_equivalent = dict(k=5,
                                            i=i,
                                            a=expected_range.start,
                                            b=expected_range.stop,
                                            c=expected_range.step)
            self.assertEqual(expected_dict_equivalent, dict(scope.items()))
Пример #4
0
    def test_expression_variable_missing(self):
        variable = 's'
        expression = ExpressionScalar('s*t')

        self.assertEqual(
            str(ExpressionVariableMissingException(variable, expression)),
            "Could not evaluate <s*t>: A value for variable <s> is missing!")
Пример #5
0
 def integral(self) -> Dict[ChannelID, ExpressionScalar]:
     return {
         self.__channel:
         ExpressionScalar(
             sympy.integrate(self.__expression.sympified_expression,
                             ('t', 0, self.duration.sympified_expression)))
     }
Пример #6
0
 def calculate_duration(self) -> ExpressionScalar:
     duration_expressions = [
         entries[-1].t for entries in self._entries.values()
     ]
     duration_expression = sympy.Max(*(expr.sympified_expression
                                       for expr in duration_expressions))
     return ExpressionScalar(duration_expression)
Пример #7
0
    def __init__(self,
                 requires_stop: bool = False,
                 is_interruptable: bool = False,
                 parameter_names: Set[str] = {},
                 defined_channels: Set[ChannelID] = {'default'},
                 duration: Any = 0,
                 waveform: Waveform = tuple(),
                 measurement_names: Set[str] = set(),
                 measurements: list = list(),
                 integrals: Dict[ChannelID, ExpressionScalar] = {
                     'default': ExpressionScalar(0)
                 },
                 program: Optional[Loop] = None,
                 identifier=None,
                 registry=None) -> None:
        super().__init__(identifier=identifier, measurements=measurements)
        self.requires_stop_ = requires_stop
        self.requires_stop_arguments = []

        self.is_interruptable_ = is_interruptable
        self.parameter_names_ = parameter_names
        self.build_sequence_arguments = []
        self.defined_channels_ = defined_channels
        self._duration = Expression(duration)
        self.waveform = waveform
        self.build_waveform_calls = []
        self.measurement_names_ = set(measurement_names)
        self._integrals = integrals
        self.create_program_calls = []
        self._program = program
        self._register(registry=registry)
Пример #8
0
    def duration(self) -> ExpressionScalar:
        step_size = self._loop_range.step.sympified_expression
        loop_index = sympy.symbols(self._loop_index)
        sum_index = sympy.symbols(self._loop_index)

        # replace loop_index with sum_index dependable expression
        body_duration = self.body.duration.sympified_expression.subs({
            loop_index:
            self._loop_range.start.sympified_expression + sum_index * step_size
        })

        # number of sum contributions
        step_count = sympy.ceiling(
            (self._loop_range.stop.sympified_expression -
             self._loop_range.start.sympified_expression) / step_size)
        sum_start = 0
        sum_stop = sum_start + (sympy.functions.Max(step_count, 1) - 1)

        # expression used if step_count >= 0
        finite_duration_expression = sympy.Sum(
            body_duration, (sum_index, sum_start, sum_stop))

        duration_expression = sympy.Piecewise(
            (0, step_count <= 0), (finite_duration_expression, True))

        return ExpressionScalar(duration_expression)
Пример #9
0
    def integral(self) -> Dict[ChannelID, ExpressionScalar]:

        step_size = self._loop_range.step.sympified_expression
        loop_index = sympy.symbols(self._loop_index)
        sum_index = sympy.symbols(self._loop_index)

        body_integrals = self.body.integral
        body_integrals = {
            c: body_integrals[c].sympified_expression.subs({
                loop_index:
                self._loop_range.start.sympified_expression +
                sum_index * step_size
            })
            for c in body_integrals
        }

        # number of sum contributions
        step_count = sympy.ceiling(
            (self._loop_range.stop.sympified_expression -
             self._loop_range.start.sympified_expression) / step_size)
        sum_start = 0
        sum_stop = sum_start + (sympy.functions.Max(step_count, 1) - 1)

        for c in body_integrals:
            channel_integral_expr = sympy.Sum(body_integrals[c],
                                              (sum_index, sum_start, sum_stop))
            body_integrals[c] = ExpressionScalar(channel_integral_expr)

        return body_integrals
Пример #10
0
    def integral(self) -> Dict[ChannelID, ExpressionScalar]:
        expressions = {channel: 0 for channel in self._channels}
        for first_entry, second_entry in zip(self._entries[:-1],
                                             self._entries[1:]):
            substitutions = {
                't0': first_entry.t.sympified_expression,
                't1': second_entry.t.sympified_expression
            }

            v0 = sympy.IndexedBase(
                Broadcast(first_entry.v.underlying_expression,
                          (len(self.defined_channels), )))
            v1 = sympy.IndexedBase(
                Broadcast(second_entry.v.underlying_expression,
                          (len(self.defined_channels), )))

            for i, channel in enumerate(self._channels):
                substitutions['v0'] = v0[i]
                substitutions['v1'] = v1[i]

                expressions[
                    channel] += first_entry.interp.integral.sympified_expression.subs(
                        substitutions)

        expressions = {
            c: ExpressionScalar(expressions[c])
            for c in expressions
        }
        return expressions
Пример #11
0
    def __init__(self,
                 requires_stop: bool=False,
                 parameter_names: Set[str]=set(),
                 defined_channels: Set[ChannelID]=None,
                 duration: Any=0,
                 waveform: Waveform=tuple(),
                 measurement_names: Set[str] = set(),
                 measurements: list=list(),
                 integrals: Dict[ChannelID, ExpressionScalar]=None,
                 program: Optional[Loop]=None,
                 identifier=None,
                 registry=None) -> None:
        super().__init__(identifier=identifier, measurements=measurements)
        self.requires_stop_ = requires_stop
        self.requires_stop_arguments = []

        if defined_channels is None:
            defined_channels = {'default'}
        if integrals is None:
            integrals = {ch: ExpressionScalar(0) for ch in defined_channels}

        self.parameter_names_ = parameter_names
        self.defined_channels_ = defined_channels
        self._duration = Expression(duration)
        self.waveform = waveform
        self.build_waveform_calls = []
        self.measurement_names_ = set(measurement_names)
        self._integrals = integrals
        self.create_program_calls = []
        self._program = program
        self._register(registry=registry)

        if integrals is not None:
            assert isinstance(integrals, Mapping)
Пример #12
0
def concatenate(*table_pulse_templates: TablePulseTemplate, **kwargs) -> TablePulseTemplate:
    """Concatenate two or more table pulse templates"""
    first_template, *other_templates = table_pulse_templates

    entries = {channel: [] for channel in first_template.defined_channels}
    duration = ExpressionScalar(0)

    for i, template in enumerate(table_pulse_templates):
        if not isinstance(template, TablePulseTemplate):
            raise TypeError('Template number %d is not a TablePulseTemplate' % i)

        new_duration = duration + template.duration

        if template.defined_channels != first_template.defined_channels:
            raise ValueError('Template number %d has differing defined channels' % i,
                             first_template.defined_channels, template.defined_channels)

        for channel, channel_entries in template.entries.items():
            first_t, first_v, _ = channel_entries[0]
            if i > 0 and first_t != 0:
                if (first_v == 0) is False:
                    entries[channel].append((duration, first_v, 'hold'))

            for t, v, interp in channel_entries:
                entries[channel].append((duration.sympified_expression + t, v, interp))

            last_t, last_v, _ = channel_entries[-1]
            if i < len(other_templates) and last_t != new_duration:
                entries[channel].append((new_duration, last_v, TablePulseTemplate.interpolation_strategies['hold']))

        duration = new_duration

    return TablePulseTemplate(entries, **kwargs)
Пример #13
0
 def test_simple_attributes(self):
     lhs = DummyPulseTemplate(defined_channels={'a', 'b'}, duration=ExpressionScalar('t_dur'),
                              measurement_names={'m1'})
     rhs = 4
     arith = ArithmeticPulseTemplate(lhs, '+', rhs)
     self.assertIs(lhs.duration, arith.duration)
     self.assertIs(lhs.measurement_names, arith.measurement_names)
Пример #14
0
    def _sequence_integral(
        cls, entry_sequence: Sequence['TableEntry'],
        expression_extractor: Callable[[Expression], sympy.Expr]
    ) -> ExpressionScalar:
        """Returns an expression for the time integral over the complete sequence of table entries.

        Args:
            entry_sequence: Sequence of table entries. Assumed to be ordered by time.
            expression_extractor: Convert each entry's voltage into a sympy expression. Can be used to select single
            channels from a vectorized expression.

        Returns:
            Scalar expression for the integral.
        """
        expr = 0
        for first_entry, second_entry in pairwise(entry_sequence):
            substitutions = {
                't0': first_entry.t.sympified_expression,
                'v0': expression_extractor(first_entry.v),
                't1': second_entry.t.sympified_expression,
                'v1': expression_extractor(second_entry.v)
            }
            expr += second_entry.interp.integral.sympified_expression.subs(
                substitutions, simultaneous=True)
        return ExpressionScalar(expr)
Пример #15
0
    def test_scaling(self):
        from qupulse.pulses import plotting

        parameters = {**self.parameters, 'foo': 5.3}
        t_ref, reference, _ = plotting.render(self.complex_pt.create_program(parameters=parameters))

        for factor in (5, 5.3, 'foo'):
            scaled = factor * self.complex_pt
            real_scale = ExpressionScalar(factor).evaluate_numeric(**parameters)
            program = scaled.create_program(parameters=parameters)

            t, rendered, _ = plotting.render(program, 10.)
            np.testing.assert_equal(t_ref, t)
            for ch, volts in rendered.items():
                np.testing.assert_allclose(reference[ch] * real_scale, volts)

            divided = self.complex_pt / factor
            t, rendered, _ = plotting.render(divided.create_program(parameters=parameters), 10.)
            np.testing.assert_equal(t_ref, t)
            for ch, volts in rendered.items():
                np.testing.assert_allclose(reference[ch] / real_scale, volts)

            sel_scaled = {'X': factor} * self.complex_pt
            t, rendered, _ = plotting.render(sel_scaled.create_program(parameters=parameters), 10.)
            np.testing.assert_equal(t_ref, t)
            for ch, volts in rendered.items():
                if ch == 'X':
                    np.testing.assert_allclose(reference[ch] * real_scale, volts)
                else:
                    np.testing.assert_equal(reference[ch], volts)
Пример #16
0
    def test_internal_create_program(self):
        sub_templates = PulseTemplateStub(defined_channels={'a'}, duration=ExpressionScalar('t1')),\
                        PulseTemplateStub(defined_channels={'a'}, duration=ExpressionScalar('t2'))

        wfs = DummyWaveform(duration=1), DummyWaveform(duration=2)

        spt = SequencePulseTemplate(*sub_templates,
                                    measurements=[('m', 'a', 'b')])

        kwargs = dict(scope=DictScope.from_kwargs(t1=.4,
                                                  t2=.5,
                                                  a=.1,
                                                  b=.2,
                                                  irrelevant=42),
                      measurement_mapping={'m': 'l'},
                      channel_mapping={'g': 'h'},
                      global_transformation=TransformationStub(),
                      to_single_waveform={'to', 'single', 'waveform'})

        program = Loop()

        expected_program = Loop(
            children=[Loop(waveform=wfs[0]),
                      Loop(waveform=wfs[1])],
            measurements=[('l', .1, .2)])

        with mock.patch.object(spt, 'validate_scope') as validate_scope:
            with mock.patch.object(spt,
                                   'get_measurement_windows',
                                   return_value=[('l', .1, .2)
                                                 ]) as get_measurement_windows:
                with mock.patch.object(sub_templates[0], '_create_program',
                                       wraps=get_appending_internal_create_program(wfs[0], True)) as create_0,\
                    mock.patch.object(sub_templates[1], '_create_program',
                                       wraps=get_appending_internal_create_program(wfs[1], True)) as create_1:

                    spt._internal_create_program(**kwargs, parent_loop=program)

                    self.assertEqual(expected_program, program)

                    validate_scope.assert_called_once_with(kwargs['scope'])
                    get_measurement_windows.assert_called_once_with(
                        kwargs['scope'], kwargs['measurement_mapping'])
                    create_0.assert_called_once_with(**kwargs,
                                                     parent_loop=program)
                    create_1.assert_called_once_with(**kwargs,
                                                     parent_loop=program)
Пример #17
0
    def test_number_math(self):
        a = ExpressionScalar('a')
        b = 3.3

        self.assertExpressionEqual(a + b, b + a)
        self.assertExpressionEqual(a - b, -(b - a))
        self.assertExpressionEqual(a * b, b * a)
        self.assertExpressionEqual(a / b, 1 / (b / a))
Пример #18
0
    def test_sympy_math(self):
        a = ExpressionScalar('a')
        b = sympify('b')

        self.assertExpressionEqual(a + b, b + a)
        self.assertExpressionEqual(a - b, -(b - a))
        self.assertExpressionEqual(a * b, b * a)
        self.assertExpressionEqual(a / b, 1 / (b / a))
Пример #19
0
    def test_parse_operand(self):
        operand = {'a': 3, 'b': 'x'}
        with self.assertRaises(ValueError):
            ArithmeticPulseTemplate._parse_operand(operand, {'a'})

        self.assertEqual(
            dict(a=ExpressionScalar(3), b=ExpressionScalar('x')),
            ArithmeticPulseTemplate._parse_operand(operand, {'a', 'b', 'c'}))

        expr_op = ExpressionScalar(3)
        self.assertIs(
            expr_op,
            ArithmeticPulseTemplate._parse_operand(expr_op, {'a', 'b', 'c'}))

        self.assertEqual(
            ExpressionScalar('foo'),
            ArithmeticPulseTemplate._parse_operand('foo', {'a', 'b', 'c'}))
Пример #20
0
    def test_integral(self):
        integrals_lhs = dict(a=ExpressionScalar('a_lhs'), b=ExpressionScalar('b'))
        integrals_rhs = dict(a=ExpressionScalar('a_rhs'), c=ExpressionScalar('c'))

        lhs = DummyPulseTemplate(duration=4, defined_channels={'a', 'b'},
                                 parameter_names={'x', 'y'}, integrals=integrals_lhs)
        rhs = DummyPulseTemplate(duration=4, defined_channels={'a', 'c'},
                                 parameter_names={'x', 'z'}, integrals=integrals_rhs)

        expected_plus = dict(a=ExpressionScalar('a_lhs + a_rhs'),
                             b=ExpressionScalar('b'),
                             c=ExpressionScalar('c'))
        expected_minus = dict(a=ExpressionScalar('a_lhs - a_rhs'),
                              b=ExpressionScalar('b'),
                              c=ExpressionScalar('-c'))
        self.assertEqual(expected_plus, (lhs + rhs).integral)
        self.assertEqual(expected_minus, (lhs - rhs).integral)
Пример #21
0
    def test_float_sample_time(self):
        # issue 624
        body_wf = FunctionWaveform.from_expression(ExpressionScalar('sin(t)'), 1./3., channel='a')
        rwf = RepetitionWaveform(body_wf, 2)

        sample_times = np.arange(160) / 80. / 3.
        sampled = rwf.unsafe_sample(sample_times=sample_times, channel='a')
        inner_sample_times = np.concatenate((sample_times[:80], sample_times[80:] - 1./3.))
        np.testing.assert_equal(sampled, np.sin(inner_sample_times))
Пример #22
0
    def __new__(cls, t: ValueInInit, v: ValueInInit, interp: Optional[Union[str, InterpolationStrategy]]='default'):
        if interp in TablePulseTemplate.interpolation_strategies:
            interp = TablePulseTemplate.interpolation_strategies[interp]
        if interp is not None and not isinstance(interp, InterpolationStrategy):
            raise KeyError(interp, 'is not a valid interpolation strategy')

        return super().__new__(cls, ExpressionScalar.make(t),
                                    Expression.make(v),
                                    interp)
Пример #23
0
 def from_expression(
         cls, expression: ExpressionScalar, duration: float,
         channel: ChannelID) -> Union['FunctionWaveform', ConstantWaveform]:
     if expression.variables:
         return cls(expression, duration, channel)
     else:
         return ConstantWaveform(amplitude=expression.evaluate_numeric(),
                                 duration=duration,
                                 channel=channel)
Пример #24
0
    def test_make(self):
        self.assertTrue(Expression.make('a') == 'a')
        self.assertTrue(Expression.make('a + b') == 'a + b')
        self.assertTrue(Expression.make(9) == 9)

        self.assertIsInstance(Expression.make([1, 'a']), ExpressionVector)

        self.assertIsInstance(ExpressionScalar.make('a'), ExpressionScalar)
        self.assertIsInstance(ExpressionVector.make(['a']), ExpressionVector)
Пример #25
0
    def test_update_volatile_parameters_with_depth1(self):
        parameters = {'s': 10, 'not': 13}
        s = VolatileRepetitionCount(expression=ExpressionScalar('s'),
                                    scope=DictScope(values=FrozenDict(s=3),
                                                    volatile=set('s')))

        wf_1 = DummyWaveform(defined_channels={'A'}, duration=1)
        wf_2 = DummyWaveform(defined_channels={'A'}, duration=1)

        program = Loop(children=[
            Loop(waveform=wf_1, repetition_count=s),
            Loop(waveform=wf_2, repetition_count=4),
            Loop(waveform=wf_1, repetition_count=1)
        ],
                       repetition_count=1)

        t_program = TaborProgram(program,
                                 channels=(None, 'A'),
                                 markers=(None, None),
                                 device_properties=self.instr_props,
                                 **self.program_entry_kwargs)

        self.assertEqual(t_program.get_sequencer_tables(),
                         [[(TableDescription(3, 0, 0), s.volatile_property),
                           (TableDescription(4, 1, 0), None),
                           (TableDescription(1, 0, 0), None)]])
        self.assertEqual(t_program.get_advanced_sequencer_table(),
                         [TableDescription(1, 1, 0)])

        modifications = t_program.update_volatile_parameters(parameters)

        expected_seq = VolatileRepetitionCount(
            expression=ExpressionScalar('s'),
            scope=DictScope(values=FrozenDict(s=10), volatile=set('s')))
        expected_modifications = {(0, 0): TableDescription(10, 0, 0)}

        self.assertEqual(
            t_program.get_sequencer_tables(),
            [[(TableDescription(10, 0, 0), expected_seq.volatile_property),
              (TableDescription(4, 1, 0), None),
              (TableDescription(1, 0, 0), None)]])
        self.assertEqual(t_program.get_advanced_sequencer_table(),
                         [TableDescription(1, 1, 0)])
        self.assertEqual(modifications, expected_modifications)
    def test_sequence_as_expression(self):
        def get_sympy(v):
            return v.sympified_expression

        t = sympy.Dummy('t')

        times = {
            t: 0.5,
            't0': 0.3,
            't1': 0.7,
            't2': 1.3,
        }

        entries = [TableEntry(0, 0, None), TableEntry(1, 0, 'hold')]
        self.assertEqual(
            ExpressionScalar(0),
            TableEntry._sequence_as_expression(
                entries, get_sympy, t, pre_value=None,
                post_value=None).sympified_expression.subs(times))

        entries = [TableEntry(0, 1, None), TableEntry(1, 1, 'hold')]
        self.assertEqual(
            ExpressionScalar(1),
            TableEntry._sequence_as_expression(
                entries, get_sympy, t, pre_value=None,
                post_value=None).sympified_expression.subs(times))

        entries = [TableEntry(0, 0, None), TableEntry(1, 1, 'linear')]
        self.assertEqual(
            ExpressionScalar(.5),
            TableEntry._sequence_as_expression(
                entries, get_sympy, t, pre_value=None,
                post_value=None).sympified_expression.subs(times))

        entries = [
            TableEntry('t0', 'a', 'linear'),
            TableEntry('t1', 'b', 'linear'),
            TableEntry('t2', 'c', 'hold')
        ]
        self.assertEqual(
            ExpressionScalar('(a+b)*.5'),
            TableEntry._sequence_as_expression(
                entries, get_sympy, t, pre_value=None,
                post_value=None).sympified_expression.subs(times))
    def test_integral(self):
        template = DummyPulseTemplate(duration='t1',
                                      defined_channels={'X', 'Y'},
                                      parameter_names={'a', 'b'},
                                      measurement_names={'M'},
                                      integrals={
                                          'X': ExpressionScalar('a'),
                                          'Y': ExpressionScalar(4)
                                      })
        overwritten_channels = {'Y': 'c', 'Z': 'a'}
        pccpt = ParallelConstantChannelPulseTemplate(template,
                                                     overwritten_channels)

        expected_integral = {
            'X': ExpressionScalar('a'),
            'Y': ExpressionScalar('c*t1'),
            'Z': ExpressionScalar('a*t1')
        }
        self.assertEqual(expected_integral, pccpt.integral)
Пример #28
0
    def test_evaluate_with_exact_rationals(self):
        expr = ExpressionScalar('1 / 3')
        self.assertEqual(TimeType.from_fraction(1, 3),
                         expr.evaluate_with_exact_rationals({}))

        expr = ExpressionScalar('a * (1 / 3)')
        self.assertEqual(TimeType.from_fraction(2, 3),
                         expr.evaluate_with_exact_rationals({'a': 2}))

        expr = ExpressionScalar('dot(a, b) * (1 / 3)')
        self.assertEqual(
            TimeType.from_fraction(10, 3),
            expr.evaluate_with_exact_rationals({
                'a': [2, 2],
                'b': [1, 4]
            }))
Пример #29
0
    def test_non_numeric_evaluation(self):
        expression = ExpressionScalar('a*b')
        call_arguments = dict()

        expected = "The result of evaluate_numeric is of type {} " \
                   "which is not a number".format(float)
        self.assertEqual(str(NonNumericEvaluation(expression, 1., call_arguments)), expected)

        expected = "The result of evaluate_numeric is of type {} " \
                   "which is not a number".format(np.zeros(1).dtype)
        self.assertEqual(str(NonNumericEvaluation(expression, np.zeros(1), call_arguments)), expected)
Пример #30
0
    def integral(self) -> Dict[ChannelID, ExpressionScalar]:
        expressions = dict()
        for channel, channel_entries in self._entries.items():

            expr = 0
            for first_entry, second_entry in zip(channel_entries[:-1],
                                                 channel_entries[1:]):
                substitutions = {
                    't0': ExpressionScalar(first_entry.t).sympified_expression,
                    'v0': ExpressionScalar(first_entry.v).sympified_expression,
                    't1':
                    ExpressionScalar(second_entry.t).sympified_expression,
                    'v1': ExpressionScalar(second_entry.v).sympified_expression
                }

                expr += first_entry.interp.integral.sympified_expression.subs(
                    substitutions)
            expressions[channel] = ExpressionScalar(expr)

        return expressions