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)