def __init__(self, parameters: Dict[str, float], expression: Expression,
                 duration_expression: Expression) -> None:
        """Creates a new FunctionWaveform instance.

        Args:
            parameters (Dict(str -> float)): A mapping of parameter names to parameter values.
            expression (Expression): The function represented by this FunctionWaveform
                as a mathematical expression where 't' denotes the time variable and other variables
                are filled with values from the parameters mapping.
            duration_expression (Expression): A mathematical expression which reliably
                computes the duration of this FunctionPulseTemplate.
        """
        super().__init__()
        self.__expression = expression
        self.__parameters = parameters
        self.__duration = duration_expression.evaluate(**self.__parameters)
class FunctionPulseTemplate(PulseTemplate):
    """Defines a pulse via a time-domain expression.

    FunctionPulseTemplate stores the expression and its external parameters. The user must provide
    two things: one expression that calculates the length of the pulse from the external parameters
    and the time-domain pulse shape itself as a expression. The external parameters are derived from
    the expressions themselves.
    Like other PulseTemplates the FunctionPulseTemplate can be declared to be a measurement pulse.

    The independent variable in the expression is called 't' and is given in units of nano-seconds.
    """

    def __init__(self, expression: str, duration_expression: str, measurement: bool=False) -> None:
        super().__init__()
        self.__expression = Expression(expression)
        self.__duration_expression = Expression(duration_expression)
        self.__is_measurement_pulse = measurement # type: bool
        self.__parameter_names = set(self.__duration_expression.variables() + self.__expression.variables()) - set(['t'])

    @property
    def parameter_names(self) -> Set[str]:
        """Return the set of names of declared parameters."""
        return self.__parameter_names

    @property
    def parameter_declarations(self) -> Set[ParameterDeclaration]:
        """Return a set of all parameter declaration objects of this TablePulseTemplate."""
        return set()

    def get_pulse_length(self, parameters) -> float:
        """Return the length of this pulse for the given parameters."""
        missing = self.__parameter_names - set(parameters.keys())
        for m in missing:
            raise ParameterNotProvidedException(m)
        return self.__duration_expression.evaluate(**parameters)

    def get_measurement_windows(self, parameters: Optional[Dict[str, Parameter]] = {}) -> List[MeasurementWindow]:
        """Return all measurement windows defined in this PulseTemplate.
       
        A ExpressionPulseTemplate specifies either no measurement windows or exactly one that spans its entire duration,
        depending on whether the measurement_pulse flag was given during construction.
        """
        if not self.__is_measurement_pulse:
            return
        else:
            return [(0, self.get_pulse_length(parameters))]

    @property
    def is_interruptable(self) -> bool:
        """Return true, if this PulseTemplate contains points at which it can halt if interrupted."""
        return False
        
    def build_sequence(self,
                       sequencer: Sequencer,
                       parameters: Dict[str, Parameter],
                       conditions: Dict[str, 'Condition'],
                       instruction_block: InstructionBlock) -> None:
        waveform = FunctionWaveform(parameters, self.__expression, self.__duration_expression)
        instruction_block.add_instruction_exec(waveform)

    def requires_stop(self, parameters: Dict[str, Parameter], conditions: Dict[str, 'Condition']) -> bool:
        return any(parameters[name].requires_stop for name in parameters.keys() if (name in self.parameter_names) and not isinstance(parameters[name], numbers.Number))

    def get_serialization_data(self, serializer: Serializer) -> None:
        root = dict()
        root['type'] = 'FunctionPulseTemplate'
        root['parameter_names'] = self.__parameter_names
        root['duration_expression'] = self.__duration_expression.string
        root['expression'] = self.__expression.string
        root['measurement'] = self.__is_measurement_pulse
        return root

    @staticmethod
    def deserialize(serializer: 'Serializer', **kwargs) -> 'Serializable':
        return FunctionPulseTemplate(kwargs['expression'], kwargs['duration_expression'], kwargs['Measurement'])
 def test_evaluate(self) -> None:
     e = Expression('a * b + c')
     params = {'a': 2, 'b': 1.5, 'c': -7}
     self.assertEqual(2 * 1.5 - 7, e.evaluate(**params))
 def test_evaluate_variable_missing(self) -> None:
     e = Expression('a * b + c')
     params = {'b': 1.5}
     with self.assertRaises(ExpressionVariableMissingException):
         e.evaluate(**params)
class FunctionPulseTemplate(AtomicPulseTemplate):
    """Defines a pulse via a time-domain expression.

    FunctionPulseTemplate stores the expression and its external parameters. The user must provide
    two things: one expression that calculates the length of the pulse from the external parameters
    and the time-domain pulse shape itself as a expression. The required external parameters are
    derived from the free variables in the expressions themselves.
    Like other PulseTemplates the FunctionPulseTemplate can be declared to be a measurement pulse.

    The independent variable for the time domain in the expression is expected to be called 't'.
    """
    def __init__(self,
                 expression: Union[str, Expression],
                 duration_expression: Union[str, Expression],
                 measurement: bool = False,
                 identifier: str = None) -> None:
        """Create a new FunctionPulseTemplate instance.

        Args:
            expression (str or Expression): The function represented by this FunctionPulseTemplate
                as a mathematical expression where 't' denotes the time variable and other variables
                will be parameters of the pulse.
            duration_expression (str or Expression): A mathematical expression which reliably
                computes the duration of an instantiation of this FunctionPulseTemplate from
                provided parameter values.
            measurement (bool): True, if this FunctionPulseTemplate shall define a measurement
                window. (optional, default = False)
            identifier (str): A unique identifier for use in serialization. (optional)
        """
        super().__init__(identifier)
        self.__expression = expression
        if not isinstance(self.__expression, Expression):
            self.__expression = Expression(self.__expression)
        self.__duration_expression = duration_expression
        if not isinstance(self.__duration_expression, Expression):
            self.__duration_expression = Expression(self.__duration_expression)
        self.__is_measurement_pulse = measurement  # type: bool
        self.__parameter_names = set(self.__duration_expression.variables() +
                                     self.__expression.variables()) - set(
                                         ['t'])

    @property
    def parameter_names(self) -> Set[str]:
        return self.__parameter_names

    @property
    def parameter_declarations(self) -> Set[ParameterDeclaration]:
        return {
            ParameterDeclaration(param_name)
            for param_name in self.parameter_names
        }

    def get_pulse_length(self, parameters: Dict[str, Parameter]) -> float:
        """Return the length of this pulse for the given parameters.

        OBSOLETE/FLAWED? Just used in by get_measurement_windows which days are counted.

        Args:
            parameters (Dict(str -> Parameter)): A mapping of parameter name to parameter objects.
        """
        missing_parameters = self.__parameter_names - set(parameters.keys())
        for missing_parameter in missing_parameters:
            raise ParameterNotProvidedException(missing_parameter)
        return self.__duration_expression.evaluate(
            **{
                parameter_name: parameter.get_value()
                for (parameter_name, parameter) in parameters.items()
            })

    def get_measurement_windows(self,
                                parameters: Optional[Dict[str, Parameter]]=None) \
            -> List[MeasurementWindow]:
        raise NotImplementedError()
        if not self.__is_measurement_pulse:
            return
        else:
            return [(0, self.get_pulse_length(parameters))]

    @property
    def is_interruptable(self) -> bool:
        return False

    @property
    def num_channels(self) -> int:
        return 1

    def build_waveform(self,
                       parameters: Dict[str, Parameter]) -> Optional[Waveform]:
        return FunctionWaveform(
            {
                parameter_name: parameter.get_value()
                for (parameter_name, parameter) in parameters.items()
            }, self.__expression, self.__duration_expression)

    def requires_stop(self, parameters: Dict[str, Parameter],
                      conditions: Dict[str, 'Condition']) -> bool:
        return any(parameters[name].requires_stop
                   for name in parameters.keys()
                   if (name in self.parameter_names))

    def get_serialization_data(self, serializer: Serializer) -> None:
        return dict(duration_expression=serializer.dictify(
            self.__duration_expression),
                    expression=serializer.dictify(self.__expression),
                    measurement=self.__is_measurement_pulse)

    @staticmethod
    def deserialize(
            serializer: 'Serializer',
            expression: str,
            duration_expression: str,
            measurement: bool,
            identifier: Optional[bool] = None) -> 'FunctionPulseTemplate':
        return FunctionPulseTemplate(
            serializer.deserialize(expression),
            serializer.deserialize(duration_expression),
            measurement,
            identifier=identifier)