Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ReleaseNotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
- Make ExpressionScalar hashable
- Fix bug that prevented evaluation of expressions containing some special functions (`erfc`, `factorial`, etc.)

- Parameters:
- `ConstantParameter` now accepts a `Expression` without free variables as value (given as `Expression` or string)

## 0.2 ##

- General:
Expand Down
19 changes: 12 additions & 7 deletions qupulse/pulses/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import numpy

from qupulse.serialization import AnonymousSerializable
from qupulse.expressions import Expression
from qupulse.expressions import Expression, ExpressionVariableMissingException
from qupulse.utils.types import HashableNumpyArray, DocStringABCMeta

__all__ = ["Parameter", "ConstantParameter",
Expand Down Expand Up @@ -49,7 +49,7 @@ def requires_stop(self) -> bool:

@abstractmethod
def __hash__(self) -> int:
pass
"""Returns a hash value of the parameter. Must be implemented."""

def __eq__(self, other) -> bool:
return type(self) is type(other) and hash(self) == hash(other)
Expand All @@ -58,17 +58,22 @@ def __eq__(self, other) -> bool:
class ConstantParameter(Parameter):
"""A pulse parameter with a constant value."""

def __init__(self, value: Union[Real, numpy.ndarray]) -> None:
def __init__(self, value: Union[Real, numpy.ndarray, Expression, str, sympy.Expr]) -> None:
"""Create a ConstantParameter instance.

Args:
value (Real): The value of the parameter
"""
super().__init__()
if isinstance(value, Real):
self._value = value
else:
self._value = numpy.array(value).view(HashableNumpyArray)
try:
if isinstance(value, Real):
self._value = value
elif isinstance(value, (str, Expression, sympy.Expr)):
self._value = Expression(value).evaluate_numeric()
else:
self._value = numpy.array(value).view(HashableNumpyArray)
except ExpressionVariableMissingException:
raise RuntimeError("Expressions passed into ConstantParameter may not have free variables.")

def get_value(self) -> Union[Real, numpy.ndarray]:
return self._value
Expand Down
2 changes: 0 additions & 2 deletions tests/pulses/bug_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ def test_plotting_two_channel_function_pulse_after_two_channel_table_pulse_crash

_ = plot(sequence_template, parameters=sequence_parameters, sample_rate=100, show=False)

@unittest.expectedFailure
def test_plot_with_parameter_value_being_expression_string(self) -> None:
"""This is currently not supported but probably should be?"""
sine_measurements = [('M', 't_duration/2', 't_duration')]
sine = FunctionPulseTemplate('a*sin(omega*t)', 't_duration', measurements=sine_measurements)
sine_channel_mapping = dict(default='sin_channel')
Expand Down
24 changes: 23 additions & 1 deletion tests/pulses/parameters_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,26 @@ def test_repr(self) -> None:
constant_parameter = ConstantParameter(0.2)
self.assertEqual("<ConstantParameter 0.2>", repr(constant_parameter))

def test_expression_value(self) -> None:
expression_str = "exp(4)*sin(pi/2)"
expression_obj = Expression(expression_str)
expression_val = expression_obj.evaluate_numeric()
param = ConstantParameter(expression_str)
self.assertEqual(expression_val, param.get_value())
param = ConstantParameter(expression_obj)
self.assertEqual(expression_val, param.get_value())

def test_invalid_expression_value(self) -> None:
expression_obj = Expression("sin(pi/2*t)")
with self.assertRaises(RuntimeError):
ConstantParameter(expression_obj)

def test_numpy_value(self) -> None:
import numpy as np
arr = np.array([6, 7, 8])
param = ConstantParameter(arr)
np.array_equal(arr, param.get_value())


class MappedParameterTest(unittest.TestCase):

Expand Down Expand Up @@ -87,10 +107,12 @@ def test_no_relation(self):
ParameterConstraint('a*b')
ParameterConstraint('1 < 2')

def test_str(self):
def test_str_and_serialization(self):
self.assertEqual(str(ParameterConstraint('a < b')), 'a < b')
self.assertEqual(ParameterConstraint('a < b').get_serialization_data(), 'a < b')

self.assertEqual(str(ParameterConstraint('a==b')), 'a==b')
self.assertEqual(ParameterConstraint('a==b').get_serialization_data(), 'a==b')


class ParameterNotProvidedExceptionTests(unittest.TestCase):
Expand Down
8 changes: 4 additions & 4 deletions tests/pulses/pulse_template_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,12 @@ class PulseTemplateTest(unittest.TestCase):

def test_create_program(self) -> None:
template = PulseTemplateStub(defined_channels={'A'}, parameter_names={'foo'})
parameters = {'foo': ConstantParameter(2.126), 'bar': -26.2, 'hugo': '2*x+b', 'append_a_child': '1'}
parameters = {'foo': ConstantParameter(2.126), 'bar': -26.2, 'hugo': 'exp(sin(pi/2))', 'append_a_child': '1'}
measurement_mapping = {'M': 'N'}
channel_mapping = {'A': 'B'}

expected_parameters = {'foo': ConstantParameter(2.126), 'bar': ConstantParameter(-26.2),
'hugo': ConstantParameter('2*x+b'), 'append_a_child': ConstantParameter('1')}
'hugo': ConstantParameter('exp(sin(pi/2))'), 'append_a_child': ConstantParameter('1')}
to_single_waveform = {'voll', 'toggo'}
global_transformation = TransformationStub()

Expand Down Expand Up @@ -308,11 +308,11 @@ def test_create_program_channel_mapping(self):

def test_create_program_none(self) -> None:
template = PulseTemplateStub(defined_channels={'A'}, parameter_names={'foo'})
parameters = {'foo': ConstantParameter(2.126), 'bar': -26.2, 'hugo': '2*x+b'}
parameters = {'foo': ConstantParameter(2.126), 'bar': -26.2, 'hugo': 'exp(sin(pi/2))'}
measurement_mapping = {'M': 'N'}
channel_mapping = {'A': 'B'}
expected_parameters = {'foo': ConstantParameter(2.126), 'bar': ConstantParameter(-26.2),
'hugo': ConstantParameter('2*x+b')}
'hugo': ConstantParameter('exp(sin(pi/2))')}
expected_internal_kwargs = dict(parameters=expected_parameters,
measurement_mapping=measurement_mapping,
channel_mapping=channel_mapping,
Expand Down