Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serveral refactorings in glotaran.Parameter #910

Merged
merged 18 commits into from
Nov 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ad18248
Added Parameter to and from dict methods.
joernweissenborn Nov 20, 2021
0064f88
Moved markdown related parameter group tests to test_parameter_group_…
joernweissenborn Nov 20, 2021
4cc77d2
Refactored parameter tests.
joernweissenborn Nov 20, 2021
a76ad61
Added parameter to and from dictonionary list.
joernweissenborn Nov 20, 2021
02f5a9e
Added more extensive test for paramater csv.
joernweissenborn Nov 20, 2021
f6f5026
Added `as_optimized` to parameter(group) as dict and dataframe functi…
joernweissenborn Nov 21, 2021
95aac8c
Fixed deprecation test.
joernweissenborn Nov 21, 2021
ef65e56
Added `Parameter.markdown`
joernweissenborn Nov 21, 2021
5e2d1e2
Update glotaran/parameter/parameter_group.py
joernweissenborn Nov 21, 2021
0d10f4b
♻️ Refactored by Sourcery (less if nesting)
Nov 21, 2021
36123af
🩹 Fixed renamed method get_group_for_parameter_by_label only in def
s-weigand Nov 21, 2021
bed48e8
🧹 Removed redunent int since mypy sees int as subclass of float
s-weigand Nov 21, 2021
9d5ea14
♻️ Changed stderr type from 'float|None' to float and default to np.nan
s-weigand Nov 21, 2021
9402e55
🩹🧪 Fixed tests due to changed rendering
s-weigand Nov 21, 2021
5172afa
👌 Improved typing where dict and list were used w/o types
s-weigand Nov 21, 2021
053e356
🧹👌 Fixed up left over tying issues in parameters
s-weigand Nov 21, 2021
6c418bb
🧹 Fixed typo
s-weigand Nov 21, 2021
4168edd
🧹 Apply minor naming suggestions from code review
s-weigand Nov 21, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@
from glotaran.examples.sequential import parameter


def test_parameter_group_to_csv(tmp_path: Path):
def test_parameter_group_to_csv_no_stderr(tmp_path: Path):
"""``ParameterGroup.to_csv`` raises deprecation warning and saves file."""
parameter_path = tmp_path / "test_parameter.csv"
deprecation_warning_on_call_test_helper(
parameter.to_csv, args=[parameter_path.as_posix()], raise_exception=True
)
expected = dedent(
"""\
label,value,minimum,maximum,vary,non-negative,expression
j.1,1.0,-inf,inf,False,False,None
j.0,0.0,-inf,inf,False,False,None
kinetic.1,0.5,-inf,inf,True,False,None
kinetic.2,0.3,-inf,inf,True,False,None
kinetic.3,0.1,-inf,inf,True,False,None
irf.center,0.3,-inf,inf,True,False,None
irf.width,0.1,-inf,inf,True,False,None
label,value,expression,minimum,maximum,non-negative,vary,standard-error
j.1,1.0,None,-inf,inf,False,False,None
j.0,0.0,None,-inf,inf,False,False,None
kinetic.1,0.5,None,-inf,inf,False,True,None
kinetic.2,0.3,None,-inf,inf,False,True,None
kinetic.3,0.1,None,-inf,inf,False,True,None
irf.center,0.3,None,-inf,inf,False,True,None
irf.width,0.1,None,-inf,inf,False,True,None
"""
)

Expand Down
10 changes: 5 additions & 5 deletions glotaran/model/test/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,9 +514,9 @@ def test_model_markdown():
* **k1**:
* *Label*: k1
* *Matrix*:
* *('s2', 's1')*: rates.1: **5.01000e-01** *(StdErr: 0e+00)*
* *('s3', 's2')*: rates.2: **2.02000e-02** *(StdErr: 0e+00)*
* *('s3', 's3')*: rates.3: **1.05000e-03** *(StdErr: 0e+00)*
* *('s2', 's1')*: rates.1: **5.01000e-01** *(StdErr: nan)*
* *('s3', 's2')*: rates.2: **2.02000e-02** *(StdErr: nan)*
* *('s3', 's3')*: rates.3: **1.05000e-03** *(StdErr: nan)*


## Initial Concentration
Expand All @@ -532,8 +532,8 @@ def test_model_markdown():
* **irf1** (multi-gaussian):
* *Label*: irf1
* *Type*: multi-gaussian
* *Center*: [irf.center: **1.30000e+00** *(StdErr: 0e+00)*]
* *Width*: [irf.width: **7.80000e+00** *(StdErr: 0e+00)*]
* *Center*: [irf.center: **1.30000e+00** *(StdErr: nan)*]
* *Width*: [irf.width: **7.80000e+00** *(StdErr: nan)*]
* *Normalize*: True
* *Backsweep*: False

Expand Down
123 changes: 111 additions & 12 deletions glotaran/parameter/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import numpy as np
from numpy.typing._array_like import _SupportsArray

from glotaran.utils.ipython import MarkdownStr
from glotaran.utils.sanitize import sanitize_parameter_list

if TYPE_CHECKING:
Expand Down Expand Up @@ -42,11 +43,12 @@ def __init__(
self,
label: str = None,
full_label: str = None,
expression: str = None,
maximum: int | float = np.inf,
minimum: int | float = -np.inf,
expression: str | None = None,
maximum: float = np.inf,
minimum: float = -np.inf,
non_negative: bool = False,
value: float | int = np.nan,
standard_error: float = np.nan,
value: float = np.nan,
vary: bool = True,
):
"""Optimization Parameter supporting numpy array operations.
Expand All @@ -58,15 +60,17 @@ def __init__(
full_label : str
The label of the parameter with its path in a parameter group prepended.
, by default None
expression : str
expression : str | None
Expression to calculate the parameters value from,
e.g. if used in relation to another parameter. , by default None
maximum : int
maximum : float
Upper boundary for the parameter to be varied to., by default np.inf
minimum : int
minimum : float
Lower boundary for the parameter to be varied to., by default -np.inf
non_negative : bool
Whether the parameter should always be bigger than zero., by default False
standard_error: float
The standard error of the parameter. , by default ``np.nan``
value : float
Value of the parameter, by default np.nan
vary : bool
Expand All @@ -79,7 +83,7 @@ def __init__(
self.maximum = maximum
self.minimum = minimum
self.non_negative = non_negative
self.standard_error = 0.0
self.standard_error = standard_error
self.value = value
self.vary = vary

Expand Down Expand Up @@ -144,6 +148,57 @@ def from_list_or_value(
param._set_options_from_dict(options)
return param

@classmethod
def from_dict(cls, parameter_dict: dict[str, Any]) -> Parameter:
"""Create a :class:`Parameter` from a dictionary.

Expects a dictionary created by :method:`Parameter.as_dict`.

Parameters
----------
parameter_dict : dict[str, Any]
The source dictionary.

Returns
-------
Parameter
The created :class:`Parameter`
"""
parameter_dict = {k.replace("-", "_"): v for k, v in parameter_dict.items()}
parameter_dict["full_label"] = parameter_dict["label"]
parameter_dict["label"] = parameter_dict["label"].split(".")[-1]
return cls(**parameter_dict)

def as_dict(self, as_optimized: bool = True) -> dict[str, Any]:
"""Create a dictionary containing the parameter properties.

Note:
-----
Intended for internal use.

Parameters
----------
as_optimized : bool
Whether to include properties which are the result of optimization.

Returns
-------
dict[str, Any]
The created dictionary.
"""
parameter_dict = {
"label": self.full_label,
"value": self.value,
"expression": self.expression,
"minimum": self.minimum,
"maximum": self.maximum,
"non-negative": self.non_negative,
"vary": self.vary,
}
if as_optimized:
parameter_dict["standard-error"] = self.standard_error
return parameter_dict

def set_from_group(self, group: ParameterGroup):
"""Set all values of the parameter to the values of the corresponding parameter in the group.

Expand All @@ -165,12 +220,12 @@ def set_from_group(self, group: ParameterGroup):
self.value = p.value
self.vary = p.vary

def _set_options_from_dict(self, options: dict):
def _set_options_from_dict(self, options: dict[str, Any]):
"""Set the parameter's options from a dictionary.

Parameters
----------
options : dict
options : dict[str, Any]
A dictionary containing parameter options.
"""
if Keys.EXPR in options:
Expand Down Expand Up @@ -220,7 +275,7 @@ def full_label(self, full_label: str):

@property
def non_negative(self) -> bool:
r"""Indicate if the parameter is non-negativ.
r"""Indicate if the parameter is non-negative.

If true, the parameter will be transformed with :math:`p' = \log{p}` and
:math:`p = \exp{p'}`.
Expand All @@ -232,7 +287,7 @@ def non_negative(self) -> bool:
Returns
-------
bool
Whether the parameter is non-negativ.
Whether the parameter is non-negative.
"""
return self._non_negative if self.expression is None else False

Expand Down Expand Up @@ -409,6 +464,50 @@ def set_value_from_optimization(self, value: float):
"""
self.value = np.exp(value) if self.non_negative else value

def markdown(
self,
all_parameter: ParameterGroup | None = None,
initial_parameter: ParameterGroup | None = None,
) -> MarkdownStr:
"""Get a markdown representation of the parameter.

Parameters
----------
all_parameter : ParameterGroup | None
A parameter group containing the whole parameter set (used for expression lookup).
initial_parameter : ParameterGroup | None
The initial parameter.

Returns
-------
MarkdownStr
The parameter as markdown string.
"""
md = f"{self.full_label}"

value = f"{self.value:.2e}"
if self.vary:
if self.standard_error is not np.nan:
value += f"±{self.standard_error}"
if initial_parameter is not None:
initial_value = initial_parameter.get(self.full_label).value
value += f", initial: {initial_value:.2e}"
md += f"({value})"
elif self.expression is not None:
expression = self.expression
if all_parameter is not None:
for match in PARAMETER_EXPRESION_REGEX.findall(expression):
label = match[0]
parameter = all_parameter.get(label)
expression = expression.replace(
"$" + label, f"_{parameter.markdown(all_parameter=all_parameter)}_"
)
md += f"({value}={expression})"
else:
md += f"({value}, fixed)"

return MarkdownStr(md)

def __getstate__(self):
"""Get state for pickle."""
return (
Expand Down
Loading