Skip to content

Add petab.v2.reparametrize_log - #560

Open
dweindl wants to merge 1 commit into
PEtab-dev:mainfrom
dweindl:reparametrize-log
Open

dweindl wants to merge 1 commit into
PEtab-dev:mainfrom
dweindl:reparametrize-log

Conversation

@dweindl

@dweindl dweindl commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

PEtab v2 has no parameterScale. To estimate a parameter <id> on log scale, or to specify a prior for log10(<id>), the v2 spec recommends replacing <id> by a new parameter log10_<id> with <id> = 10^log10_<id>.

This adds petab.v2.reparametrize_log(problem, parameter_ids, ...), which does this for the given parameters on a copy of the problem and returns the copy and the mapping of old to new parameter IDs:

  • parameter table: log-transformed bounds (dropped for non-estimated parameters) and nominal value; priors from the priors argument, or derived from log-normal, log-laplace and log-uniform priors on <id> (other priors on <id> raise)
  • SBML model: new parameter log10_<id> and initial assignment <id> = 10^log10_<id> (replacing any existing one; <id> stays constant=true)
  • observable/noise formulas and condition target values: <id> → 10^log10_<id>
  • measurement overrides: replaced by the new IDs, numeric overrides are log-transformed, and the placeholder ph is replaced by 10^ph in the formulas

A lower bound of 0 becomes -inf, following PEtab-dev/PEtab#682. If other parameters have priors, such a parameter needs an explicit prior, since the default uniform(lb, ub) would be improper; otherwise, a ValueError is raised.

Base e (log_<id>) is supported as well. The procedure follows the one described in the proposed v1→v2 migration guide (PEtab-dev/PEtab#680).

Split off from #539, which uses this in petab1to2(reparametrize=...) to preserve v1 parameter-scale priors.

🤖 Generated with Claude Code

@dweindl dweindl self-assigned this Oct 19, 2026
@codecov-commenter

codecov-commenter commented Oct 19, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.77108% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.81%. Comparing base (e654711) to head (7fc047b).

Files with missing lines Patch % Lines
petab/v2/reparametrize.py 93.42% 5 Missing and 5 partials ⚠️
petab/v2/models/_sbml_utils.py 81.81% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #560      +/-   ##
==========================================
+ Coverage   78.44%   78.81%   +0.36%     
==========================================
  Files          68       69       +1     
  Lines        7876     8037     +161     
  Branches     1406     1445      +39     
==========================================
+ Hits         6178     6334     +156     
- Misses       1214     1215       +1     
- Partials      484      488       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dweindl
dweindl force-pushed the reparametrize-log branch 2 times, most recently from 74b7276 to e74ee3b Compare October 19, 2026 15:26
@dweindl
dweindl marked this pull request as ready for review October 20, 2026 06:22
@dweindl
dweindl requested a review from a team as a code owner October 20, 2026 06:22
@dweindl
dweindl force-pushed the reparametrize-log branch 4 times, most recently from e1d0f09 to 2c303c3 Compare October 20, 2026 14:56

@dilpath dilpath left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment on lines +206 to +213
problem["scaling"].nominal_value = None
problem["offset1"].nominal_value = 0
problem["offset2"].lb = -1
problem["offset2"].ub = 10
with pytest.warns(UserWarning, match="no positive nominal value"):
problem, _ = reparametrize_log(
problem, ["scaling", "offset1", "offset2"]
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this warning for offset1? If so, then maybe it's fine if the spec allows -inf for log10_offset1 nominal value.

Comment on lines +236 to +242
@pytest.mark.parametrize("prior", [C.UNIFORM, C.NORMAL, C.GAMMA])
def test_reparametrize_log_inexpressible_prior(prior):
problem = _problem()
problem["scaling"].prior_distribution = prior
problem["scaling"].prior_parameters = [1, 2]
with pytest.raises(ValueError, match="cannot be expressed"):
reparametrize_log(problem, ["scaling"])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring? Is the issue that we can't implement the same "uniform" distribution after log-scaling the parameter?

Comment thread petab/v2/reparametrize.py
Comment on lines +112 to +114
ln_b = math.log(10)
# not `math.log(x) / ln_b`, which is inexact for powers of 10
log_b = math.log10

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ln and log are the same for me -- maybe log_factor for ln_b/log_function for log_b?

Comment thread petab/v2/reparametrize.py
Comment on lines +132 to +135
if problem.extensions.sciml is not None:
raise NotImplementedError(
"Reparametrization of PEtab SciML problems is not supported."
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NotImplementedError if any kind of extension is required in the problem config?

Comment thread petab/v2/reparametrize.py
Comment on lines +159 to +162
if model.sbml_model.getParameter(p) is None:
raise NotImplementedError(
f"Model entity `{p}' is not an SBML parameter."
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine as is. Although I guess this error should also occur elsewhere/earlier in the package in general, that a parameter in the parameter table must be a parameter in the model.

Comment thread petab/v2/reparametrize.py
Comment on lines +196 to +198
elif p in priors or par.prior_distribution is None or not par.estimate:
# priors of non-estimated parameters are irrelevant
prior_distribution, prior_parameters = None, []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: not par.estimate: is it necessary to drop the pre-existing prior instead of converting it? Seems more like a NotImplementedError

Comment thread petab/v2/reparametrize.py
)

if par.estimate:
lb = log_b(par.lb) if par.lb > 0 else -math.inf

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we could define somewhere, some log and log10 functions like

def log10(x):
    return math.log10(x) if x != 0 else -math.inf

Comment thread petab/v2/reparametrize.py
set_initial_assignment(
model,
parameter_id,
b_expr ** sp.Symbol(new_id),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

petab_symbol? Probably irrelevant.

Comment thread petab/v2/reparametrize.py
b_expr: sp.Expr,
log_b,
) -> None:
"""Log-transform placeholders overridden by reparametrized parameters."""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Describe here any potential issues? e.g. that placeholders need to be overridden by either no reparametrized parameters, or only reparametrized parameters with the same base.

PEtab v2 has no `parameterScale`. To estimate a parameter `p` on log
scale (and to specify priors for `log10(p)`), `p` has to be replaced by
a new parameter `log10_p` with `p = 10^log10_p`.

`reparametrize_log` does this for a given set of parameters on a copy
of the problem and returns the copy and the mapping of old to new IDs:

* parameter table: log-transformed bounds and nominal values (a lower
  bound of 0 becomes -inf); priors given explicitly, or derived from
  `log-normal`, `log-laplace` and `log-uniform` priors
* SBML model: new parameter `log10_p` and initial assignment
  `p = 10^log10_p`
* observable/noise formulas and condition table target values:
  `p` -> `10^log10_p`
* measurement table overrides: `p` -> `log10_p`, numeric overrides are
  log-transformed, and the placeholder `ph` -> `10^ph` in the formulas

Base e is supported as well.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants