def test_undefined_comparison(self): valued = Expression(2) unknown = Expression('a') self.assertIsNone(unknown < 0) self.assertIsNone(unknown > 0) self.assertIsNone(unknown >= 0) self.assertIsNone(unknown <= 0) self.assertFalse(unknown == 0) self.assertIsNone(0 < unknown) self.assertIsNone(0 > unknown) self.assertIsNone(0 <= unknown) self.assertIsNone(0 >= unknown) self.assertFalse(0 == unknown) self.assertIsNone(unknown < valued) self.assertIsNone(unknown > valued) self.assertIsNone(unknown >= valued) self.assertIsNone(unknown <= valued) self.assertFalse(unknown == valued) valued, unknown = unknown, valued self.assertIsNone(unknown < valued) self.assertIsNone(unknown > valued) self.assertIsNone(unknown >= valued) self.assertIsNone(unknown <= valued) self.assertFalse(unknown == valued) valued, unknown = unknown, valued self.assertFalse(unknown == valued)
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'])
def test_symbolic_math(self): a = Expression('a') b = Expression('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))
def test_build_waveform(self) -> None: wf = self.fpt.build_waveform(self.args) self.assertIsNotNone(wf) self.assertIsInstance(wf, FunctionWaveform) expected_waveform = FunctionWaveform(dict(a=3, y=1), Expression(self.f), Expression(self.duration)) self.assertEqual(expected_waveform, wf)
def test_sample(self) -> None: f = Expression("(t+1)**b") length = Expression("c**b") par = {"b": 2, "c": 10} fw = FunctionWaveform(par, f, length) a = np.arange(4) expected_result = [[1, 4, 9, 16]] result = fw.sample(a) self.assertTrue(np.all(result == expected_result))
def test_parameter_names_and_declarations_expression_input(self) -> None: template = FunctionPulseTemplate(Expression("3 * foo + bar * t"), Expression("5 * hugo")) expected_parameter_names = {'foo', 'bar', 'hugo'} self.assertEqual(expected_parameter_names, template.parameter_names) self.assertEqual( {ParameterDeclaration(name) for name in expected_parameter_names}, template.parameter_declarations)
def test_equality(self) -> None: wf1a = FunctionWaveform(Expression('2*t'), 3, channel='A') wf1b = FunctionWaveform(Expression('2*t'), 3, channel='A') wf3 = FunctionWaveform(Expression('2*t+2'), 3, channel='A') wf4 = FunctionWaveform(Expression('2*t'), 4, channel='A') self.assertEqual(wf1a, wf1a) self.assertEqual(wf1a, wf1b) self.assertNotEqual(wf1a, wf3) self.assertNotEqual(wf1a, wf4)
def test_get_serialization_data(self) -> None: expected_data = dict(measurements=self.measurements, entries=self.entries, parameter_constraints=[ str(Expression('ilse>2')), str(Expression('k>foo')) ]) data = self.template.get_serialization_data(self.serializer) self.assertEqual(expected_data, data)
def test_known_interpolation_strategies(self): strategies = [("linear", LinearInterpolationStrategy()), ("hold", HoldInterpolationStrategy()), ("jump", JumpInterpolationStrategy())] for strat_name, strat_val in strategies: entry = TableEntry('a', Expression('b'), strat_name) self.assertEqual(entry.t, Expression('a')) self.assertEqual(entry.v, Expression('b')) self.assertEqual(entry.interp, strat_val)
def test_get_serialization_data(self) -> None: expected_data = dict(measurements=self.measurements, time_point_tuple_list=self.entries, channel_names=(0, 'A'), parameter_constraints=[ str(Expression('ilse>2')), str(Expression('k>foo')) ]) data = self.template.get_serialization_data(self.serializer) self.assertEqual(expected_data, data)
def test_add(self) -> None: map = PulseTemplateParameterMapping({'bar'}) dummy1 = DummyPulseTemplate(parameter_names={'foo', 'hugo'}) dummy2 = DummyPulseTemplate(parameter_names={'grr'}) map.add(dummy1, 'foo', '4*bar') map.add(dummy2, 'grr', Expression('bar ** 2')) map.add(dummy1, 'hugo', '3') map.add(dummy2, 'grr', Expression('sin(bar)')) self.assertEqual(dict(foo=Expression('4*bar'), hugo=Expression('3')), map.get_template_map(dummy1)) self.assertEqual(dict(grr=Expression('sin(bar)')), map.get_template_map(dummy2))
def test_map_parameters(self) -> None: map = PulseTemplateParameterMapping({'bar', 'barbar'}) dummy = DummyPulseTemplate(parameter_names={'foo', 'hugo'}) map.add(dummy, 'hugo', '4*bar') map.add(dummy, 'foo', Expression('barbar')) mapped = map.map_parameters( dummy, dict(bar=ConstantParameter(3), barbar=ConstantParameter(5))) self.assertEqual( dict(hugo=MappedParameter(Expression('4*bar'), dict(bar=ConstantParameter(3))), foo=MappedParameter(Expression('barbar'), dict(barbar=ConstantParameter(5)))), mapped)
def __init__(self, measurements: Optional[List[MeasurementDeclaration]]): if measurements is None: self._measurement_windows = [] else: self._measurement_windows = [ (name, begin if isinstance(begin, Expression) else Expression(begin), length if isinstance(length, Expression) else Expression(length)) for name, begin, length in measurements ] for _, _, length in self._measurement_windows: if (length < 0) is True: raise ValueError( 'Measurement window length may not be negative')
def test_deserialize(self) -> None: dummy1 = DummyPulseTemplate(parameter_names={'foo'}, num_channels=2) dummy2 = DummyPulseTemplate(parameter_names={}, num_channels=1) exp = Expression("bar - 35") data = dict(external_parameters=['bar'], subtemplates=[ dict(template=str(id(dummy1)), parameter_mappings=dict(foo=str(exp)), channel_mappings=[0, 2]), dict(template=str(id(dummy2)), parameter_mappings=dict(), channel_mappings=[1]) ]) serializer = DummySerializer(serialize_callback=lambda x: str(x) if isinstance(x, Expression) else str(id(x))) serializer.subelements[str(id(dummy1))] = dummy1 serializer.subelements[str(id(dummy2))] = dummy2 serializer.subelements[str(exp)] = exp template = MultiChannelPulseTemplate.deserialize(serializer, **data) self.assertEqual(set(data['external_parameters']), template.parameter_names) self.assertEqual({ParameterDeclaration('bar')}, template.parameter_declarations) recovered_data = template.get_serialization_data(serializer) self.assertEqual(data, recovered_data)
def test_equality(self) -> None: wf1a = FunctionWaveform(dict(a=2, b=1), Expression('a*t'), Expression('b')) wf1b = FunctionWaveform(dict(a=2, b=1), Expression('a*t'), Expression('b')) wf2 = FunctionWaveform(dict(a=3, b=1), Expression('a*t'), Expression('b')) wf3 = FunctionWaveform(dict(a=2, b=1), Expression('a*t+2'), Expression('b')) wf4 = FunctionWaveform(dict(a=2, c=2), Expression('a*t'), Expression('c')) self.assertEqual(wf1a, wf1a) self.assertEqual(wf1a, wf1b) self.assertNotEqual(wf1a, wf2) self.assertNotEqual(wf1a, wf3) self.assertNotEqual(wf1a, wf4)
def test_requires_stop_and_get_value(self) -> None: p = MappedParameter(Expression("foo + bar * hugo")) with self.assertRaises(ParameterNotProvidedException): p.requires_stop with self.assertRaises(ParameterNotProvidedException): p.get_value() foo = DummyParameter(-1.1) bar = DummyParameter(0.5) hugo = DummyParameter(5.2, requires_stop=True) ilse = DummyParameter(2356.4, requires_stop=True) p.dependencies = {'foo': foo, 'hugo': hugo, 'ilse': ilse} with self.assertRaises(ParameterNotProvidedException): p.requires_stop with self.assertRaises(ParameterNotProvidedException): p.get_value() p.dependencies = {'foo': foo, 'bar': bar, 'hugo': hugo} self.assertTrue(p.requires_stop) with self.assertRaises(Exception): p.get_value() hugo = DummyParameter(5.2, requires_stop=False) p.dependencies = {'foo': foo, 'bar': bar, 'hugo': hugo, 'ilse': ilse} self.assertFalse(p.requires_stop) self.assertEqual(1.5, p.get_value())
def test_map_parameters_not_provided(self) -> None: map = PulseTemplateParameterMapping({'bar', 'barbar'}) dummy = DummyPulseTemplate(parameter_names={'foo', 'hugo'}) map.add(dummy, 'hugo', '4*bar') map.add(dummy, 'foo', Expression('barbar')) with self.assertRaises(ParameterNotProvidedException): map.map_parameters(dummy, dict(bar=ConstantParameter(3)))
def test_time_is_0_on_instantiation(self): table = TablePulseTemplate({0: [('a', 1)]}) self.assertEqual(table.duration, Expression('a')) self.assertEqual(table.parameter_names, {'a'}) self.assertIsNone( table.build_waveform(parameters=dict(a=0), channel_mapping={0: 0}))
def test_get_most_simple_representation(self): cpl = Expression('1 + 1j').get_most_simple_representation() self.assertIsInstance(cpl, complex) self.assertEqual(cpl, 1 + 1j) integer = Expression('3').get_most_simple_representation() self.assertIsInstance(integer, int) self.assertEqual(integer, 3) flt = Expression('3.').get_most_simple_representation() self.assertIsInstance(flt, float) self.assertEqual(flt, 3.) st = Expression('a + b').get_most_simple_representation() self.assertIsInstance(st, str) self.assertEqual(st, 'a + b')
def add(self, template: PulseTemplate, parameter: str, mapping_expression: Union[str, Expression]): """Add a new mapping for a parameter of a pulse template. Args: template (PulseTemplate): The pulse template for which a parameter mapping will be added. parameter (str): The name of the parameter of the pulse template that will be mapped. mapping_expression (str or Expression): The mathematical expression that specifies the mapping from external parameters to the parameter of the pulse template. Raises: UnnecessaryMappingException, if parameter is not declared by template. MissingParameterDeclarationException, if mapping_expression requires a variable that is not a parameter in the external parameters of this PulseTemplateParameterMapping. """ if parameter not in template.parameter_names: raise UnnecessaryMappingException(template, parameter) if isinstance(mapping_expression, str): mapping_expression = Expression(mapping_expression) required_externals = set(mapping_expression.variables()) non_declared_externals = required_externals - self.__external_parameters if non_declared_externals: raise MissingParameterDeclarationException( template, non_declared_externals.pop()) template_map = self.__get_template_map(template) template_map[parameter] = mapping_expression self.__map[template] = template_map
def test_expression_variable_missing(self): variable = 's' expression = Expression('s*t') self.assertEqual( str(ExpressionVariableMissingException(variable, expression)), "Could not evaluate <s*t>: A value for variable <s> is missing!")
def test_deserialize(self) -> None: basic_data = dict(duration_expression=str(self.s2), expression=str(self.s), measurement=False, identifier='hugo') serializer = DummySerializer(serialize_callback=lambda x: str(x)) serializer.subelements[str(self.s2)] = Expression(self.s2) serializer.subelements[str(self.s)] = Expression(self.s) template = FunctionPulseTemplate.deserialize(serializer, **basic_data) self.assertEqual('hugo', template.identifier) self.assertEqual({'a', 'b', 'c'}, template.parameter_names) self.assertEqual( {ParameterDeclaration(name) for name in {'a', 'b', 'c'}}, template.parameter_declarations) serialized_data = template.get_serialization_data(serializer) del basic_data['identifier'] self.assertEqual(basic_data, serialized_data)
def test_get_remaining_mappings(self) -> None: map = PulseTemplateParameterMapping({'bar', 'barbar'}) dummy = DummyPulseTemplate(parameter_names={'foo', 'hugo'}) self.assertEqual({'foo', 'hugo'}, map.get_remaining_mappings(dummy)) map.add(dummy, 'hugo', '4*bar') self.assertEqual({'foo'}, map.get_remaining_mappings(dummy)) map.add(dummy, 'foo', Expression('barbar')) self.assertEqual(set(), map.get_remaining_mappings(dummy))
def test_number_math(self): a = Expression('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))
def test_evaluate_numeric(self) -> None: e = Expression('a * b + c') params = {'a': 2, 'b': 1.5, 'c': -7} self.assertEqual(2 * 1.5 - 7, e.evaluate_numeric(**params)) with self.assertRaises(NonNumericEvaluation): params['a'] = sympify('h') e.evaluate_numeric(**params)
def test_get_serialization_data(self) -> None: exp = Expression("foo + bar * hugo") p = MappedParameter(exp) serializer = DummySerializer() data = p.get_serialization_data(serializer) self.assertEqual( dict(type=serializer.get_type_identifier(p), expression=str(id(exp))), data)
def test_evaluate_numpy(self): e = Expression('a * b + c') params = { 'a': 2 * np.ones(4), 'b': 1.5 * np.ones(4), 'c': -7 * np.ones(4) } np.testing.assert_equal((2 * 1.5 - 7) * np.ones(4), e.evaluate_numeric(**params))
def test_build_waveform(self) -> None: with self.assertRaises(ParameterConstraintViolation): self.fpt.build_waveform(self.invalid_par_vals, channel_mapping={'A': 'B'}) wf = self.fpt.build_waveform(self.valid_par_vals, channel_mapping={'A': 'B'}) self.assertIsNotNone(wf) self.assertIsInstance(wf, FunctionWaveform) expression = Expression(self.s).evaluate_symbolic(self.valid_par_vals) duration = Expression( self.s2).evaluate_numeric(c=self.valid_par_vals['c']) expected_waveform = FunctionWaveform(expression, duration=duration, channel='B') self.assertEqual(expected_waveform, wf)
def test_deserialize(self) -> None: basic_data = dict(duration_expression=str(self.s2), expression=self.s, channel='A', identifier='hugo', measurement_declarations=self.meas_list, parameter_constraints=self.constraints) serializer = DummySerializer( serialize_callback=lambda x: x.original_expression) serializer.subelements[self.s2] = Expression(self.s2) serializer.subelements[self.s] = Expression(self.s) template = FunctionPulseTemplate.deserialize(serializer, **basic_data) self.assertEqual('hugo', template.identifier) self.assertEqual({'a', 'b', 'c', 'x', 'z', 'j', 'u', 'd'}, template.parameter_names) self.assertEqual(template.measurement_declarations, self.meas_list) serialized_data = template.get_serialization_data(serializer) del basic_data['identifier'] self.assertEqual(basic_data, serialized_data)
def __init__(self, relation: Union[str, sympy.Expr]): super().__init__() if isinstance(relation, str) and '==' in relation: # The '==' operator is interpreted by sympy as exactly, however we need a symbolical evaluation self._expression = sympy.Eq(*sympy.sympify(relation.split('=='))) else: self._expression = sympy.sympify(relation) if not isinstance(self._expression, sympy.boolalg.Boolean): raise ValueError('Constraint is not boolean') self._expression = Expression(self._expression)