Skip to content

Native .conf grammar for bounded/truncated normal_var, laplace_var (and log forms) #417

@wshlavacek

Description

@wshlavacek

Motivation

#411 (ADR-0020) added truncated priors on the unbounded-support families: the
FreeParameter constructor now accepts lb/ub and wraps the prior in a
TruncatedPrior with a two-sided reflecting box, and the PEtab v2 importer
maps a normal/laplace/log-* prior with finite bounds onto that capability.

But there is no native .conf syntax to declare a bounded normal yet. A user
writing a config can only get a truncated prior via the PEtab path; a native
normal_var is always unbounded. This issue adds the config surface so the two
adapters (native .conf and PEtab) reach the truncation capability equally.

Current state

parse.py partitions the prior keywords into two grammars off
has_bounded_support (ADR-0010):

  • bounded (uniform_var/loguniform_var): name lb ub plus the optional
    b/u reflecting-bounds flag (b_var_def_keys).
  • unbounded (normal_var/laplace_var + log forms): name p1 p2 (mean/sd or
    location/scale), no flag (var_def_keys).

A truncated normal needs two extra numbers (the box lb ub) on top of the
family's mean sd — a token shape neither grammar branch produces today. The
FreeParameter(..., lb=, ub=) plumbing and TruncatedPrior already exist
(#411); only the grammar + config._load_variables wiring are missing.

What's needed

  • Extend the grammar so an unbounded family can optionally take a box, e.g.
    normal_var = k__FREE mean sd lb ub (and the laplace_var / lognormal_var
    / loglaplace_var forms), routing lb/ub to the FreeParameter constructor.
  • Backward compatible: the 2-number form stays unbounded exactly as today; the
    4-number form is the new truncated form.
  • config._load_variables (config.py) passes the parsed lb/ub through to
    FreeParameter(..., lb=, ub=).

Design questions (for the implementer)

  • Token syntax. Append lb ub (4 numbers total), or reuse a flag like the
    Uniform b/u? The Uniform flag toggles whether a box reflects; here the box
    is two new values, so an appended lb ub reads more naturally. Decide and pin.
  • parse.py token lists. This touches the per-keyword token-count grammar that
    Migrate parse.py scalar/list token lists into the Pydantic schema (single coercion source) #402 flagged (the camelCase / token-list smell). Coordinate with that.
  • Golden config nets. The narrowing/golden-net tests (ADR-0013) may need
    regeneration if the parsed representation of these keywords changes; keep the
    diff to additions only.
  • One-sided. Still unsupported (ADR-0020 — the reflecting fold needs two finite
    bounds); the grammar should require both lb and ub when a box is given.

Scope & priority

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions