Skip to content

Commit

Permalink
Hierarchical: fix no error if inner observable parameter in noise for…
Browse files Browse the repository at this point in the history
…mula & viceversa (#1504)

* Search for observable inner pars in noise formulas & vice-versa

* Fix if statements

* Fix different censoring_types are allowed
  • Loading branch information
Doresic authored Nov 12, 2024
1 parent 9a69f3c commit 80a7b8d
Showing 1 changed file with 82 additions and 53 deletions.
135 changes: 82 additions & 53 deletions pypesto/hierarchical/petab.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,63 +76,63 @@ def validate_hierarchical_petab_problem(petab_problem: petab.Problem) -> None:
petab_problem:
The PEtab problem.
"""
if PARAMETER_TYPE not in petab_problem.parameter_df:
# not a hierarchical optimization problem
return

# ensure we only have linear parameter scale
inner_parameter_table = petab_problem.parameter_df[
petab_problem.parameter_df[PARAMETER_TYPE].isin(
[
InnerParameterType.OFFSET,
InnerParameterType.SIGMA,
InnerParameterType.SCALING,
]
)
]
if (
petab.PARAMETER_SCALE in inner_parameter_table
and not (
inner_parameter_table[petab.PARAMETER_SCALE].isna()
| (inner_parameter_table[petab.PARAMETER_SCALE] == petab.LIN)
| (
inner_parameter_table[PARAMETER_TYPE]
!= InnerParameterType.SIGMA
if PARAMETER_TYPE in petab_problem.parameter_df:
# ensure we only have linear parameter scale
inner_parameter_table = petab_problem.parameter_df[
petab_problem.parameter_df[PARAMETER_TYPE].isin(
[
InnerParameterType.OFFSET,
InnerParameterType.SIGMA,
InnerParameterType.SCALING,
]
)
).all()
):
sub_df = inner_parameter_table.loc[
:, [PARAMETER_TYPE, petab.PARAMETER_SCALE]
]
raise NotImplementedError(
"LOG and LOG10 parameter scale of inner parameters is not supported "
"for sigma parameters. Inner parameter table:\n"
f"{sub_df}"
)
elif (
petab.PARAMETER_SCALE in inner_parameter_table
and not (
inner_parameter_table[petab.PARAMETER_SCALE].isna()
| (inner_parameter_table[petab.PARAMETER_SCALE] == petab.LIN)
).all()
):
sub_df = inner_parameter_table.loc[
:, [PARAMETER_TYPE, petab.PARAMETER_SCALE]
]
warnings.warn(
f"LOG and LOG10 parameter scale of inner parameters is used only "
f"for their visualization, and does not affect their optimization. "
f"Inner parameter table:\n{sub_df}",
stacklevel=1,
)
if (
petab.PARAMETER_SCALE in inner_parameter_table
and not (
inner_parameter_table[petab.PARAMETER_SCALE].isna()
| (inner_parameter_table[petab.PARAMETER_SCALE] == petab.LIN)
| (
inner_parameter_table[PARAMETER_TYPE]
!= InnerParameterType.SIGMA
)
).all()
):
sub_df = inner_parameter_table.loc[
:, [PARAMETER_TYPE, petab.PARAMETER_SCALE]
]
raise NotImplementedError(
"LOG and LOG10 parameter scale of inner parameters is not supported "
"for sigma parameters. Inner parameter table:\n"
f"{sub_df}"
)
elif (
petab.PARAMETER_SCALE in inner_parameter_table
and not (
inner_parameter_table[petab.PARAMETER_SCALE].isna()
| (inner_parameter_table[petab.PARAMETER_SCALE] == petab.LIN)
).all()
):
sub_df = inner_parameter_table.loc[
:, [PARAMETER_TYPE, petab.PARAMETER_SCALE]
]
warnings.warn(
f"LOG and LOG10 parameter scale of inner parameters is used only "
f"for their visualization, and does not affect their optimization. "
f"Inner parameter table:\n{sub_df}",
stacklevel=1,
)

inner_parameter_df = validate_measurement_formulae(
petab_problem=petab_problem
)
inner_parameter_df = validate_measurement_formulae(
petab_problem=petab_problem
)

validate_inner_parameter_pairings(inner_parameter_df=inner_parameter_df)
validate_inner_parameter_pairings(
inner_parameter_df=inner_parameter_df
)

validate_observable_data_types(petab_problem=petab_problem)
if MEASUREMENT_TYPE in petab_problem.measurement_df:
validate_observable_data_types(petab_problem=petab_problem)


def validate_inner_parameter_pairings(
Expand Down Expand Up @@ -477,6 +477,18 @@ def _get_symbolic_formula_from_measurement(
observable_id=observable_id,
override_type=formula_type,
)
# Search for placeholders in the formula that are not allowed to be
# overridden by inner parameters -- noise inner parameters should not
# be in observable formulas, and vice versa.
disallowed_formula_type = (
"noise" if formula_type == "observable" else "observable"
)
disallowed_formula_placeholders = get_formula_placeholders(
formula_string=formula_string,
observable_id=observable_id,
override_type=disallowed_formula_type,
)

if formula_placeholders:
overrides = measurement[formula_type + "Parameters"]
overrides = (
Expand All @@ -487,6 +499,20 @@ def _get_symbolic_formula_from_measurement(
subs = dict(zip(formula_placeholders, overrides))
symbolic_formula = symbolic_formula.subs(subs)

if disallowed_formula_placeholders:
disallowed_overrides = measurement[
disallowed_formula_type + "Parameters"
]
disallowed_overrides = (
disallowed_overrides.split(PARAMETER_SEPARATOR)
if isinstance(disallowed_overrides, str)
else [disallowed_overrides]
)
disallowed_subs = dict(
zip(disallowed_formula_placeholders, disallowed_overrides)
)
symbolic_formula = symbolic_formula.subs(disallowed_subs)

symbolic_formula_inner_parameters = {
sp.Symbol(inner_parameter_id): inner_parameter_type
for inner_parameter_id, inner_parameter_type in inner_parameters.items()
Expand Down Expand Up @@ -614,7 +640,10 @@ def validate_observable_data_types(petab_problem: petab.Problem) -> None:
other_data_type,
other_observables,
) in observables_by_data_type.items():
if data_type == other_data_type:
if data_type == other_data_type or (
data_type in CENSORING_TYPES
and other_data_type in CENSORING_TYPES
):
continue
if observables & other_observables:
raise ValueError(
Expand Down

0 comments on commit 80a7b8d

Please sign in to comment.