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
16 changes: 4 additions & 12 deletions src/raven_toolbox/analysis/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,10 @@ def random_sampling(
Seed for reproducible chains and draws.
thinning:
``achr`` and ``chrr``: Markov-chain steps between recorded samples (default 100).
The default is calibrated for small models (~200 to 500 reactions). On genome-scale
models (>2000 reactions) lag-1 autocorrelation remains high even at thinning=100
(measured: 0.926 on yeast-GEM with 4102 reactions), giving about 12 effective
samples from 300 stored samples (ESS ≈ n × (1−ρ)/(1+ρ)). Independent chains at
these default settings also fail to agree with each other: on
yeast-GEM, 67.5% of reactions fail the Gelman-Rubin R-hat>1.1 convergence
threshold across 4 independent chains (96.5% fail the stricter R-hat>1.01).
Default-settings genome-scale output is therefore unconverged for most
reactions. Options for genome-scale analyses are increasing thinning
substantially (≥1000), increasing n_samples to compensate, using
``method='chrr'`` (raven-toolbox's rounding-based alternative to ACHR), or
assessing sample quality with an ESS or R-hat diagnostic (see the
On genome-scale models (>2000 reactions) consecutive samples remain strongly
correlated at the default, and independent chains can disagree. Options for
genome-scale analyses are increasing thinning substantially (≥1000), increasing
n_samples, or assessing sample quality with an ESS or R-hat diagnostic (see the
`sampling convergence calibration study
<https://github.com/CompMetEng/raven-docs/blob/main/docs/parameter-tuning/studies/sampling-convergence-calibration.md>`_
on raven-docs).
Expand Down
88 changes: 29 additions & 59 deletions src/raven_toolbox/init/ftinit.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,8 @@ def _reaction_big_m(lb: float, ub: float, cap: float, force_on: float) -> float:

# A resolve_ties tie-break phase is adopted whether it proves or times out (see
# _resolve_ties), so it is given a fraction of the primary solve's own budget rather than
# the full amount again: a phase that would not converge within the full budget has been
# observed (on genome-scale Human-GEM) to still not converge, only slower; a phase that
# does converge does so far inside either budget (a pure integer count/id-rank objective
# with a 0.4 absolute gap). Not independently tuned — see the ftINIT reproducibility study
# on raven-docs for the experiment that would calibrate this properly instead of halving
# on general principle.
# the full amount again: a phase that does converge does so far inside either budget (a
# pure integer count/id-rank objective with a 0.4 absolute gap). Not tuned.
_TIE_BREAK_TIME_FRACTION = 0.5


Expand Down Expand Up @@ -223,15 +219,12 @@ def run_ftinit(
prove_abs_gap : float or None
When set, proves the solve to this fixed absolute objective gap (on Gurobi: ``MIPGap``
0 and ``MIPGapAbs`` this value); ``mip_gap`` and ``mip_gap_abs`` do not apply then. The
default None leaves the gap to ``mip_gap`` and ``mip_gap_abs``. In the four-seed sweep
(seeds 1234, 7, 1 and 2; ``resolve_ties=True``; no gap-fill; Human-GEM v2.0.0-38, one
cell line) the default escalation returned a step-1 objective 4.0 to 12.0 below the
proven optimum without a warning, while every value from 2.0 to 0.05 reached the
optimum for all four seeds and gave the same reaction sets. Every step solve (the 48
primary solves) ended with status ``optimal``; the flux phases ``phase2c-minflux`` (3
of 4 seeds) and ``phase2d-direction`` (4 of 4 seeds) reached the time limit and were
adopted as unproven incumbents. The docstring of :func:`raven_toolbox.init.ftinit`
gives the measured run times.
default None leaves the gap to ``mip_gap`` and ``mip_gap_abs``. The default escalation
can stop at an objective below the proven optimum without a warning. The flux phases
``phase2c-minflux`` and ``phase2d-direction`` can reach the time limit, in which case
the incumbent is adopted as an unproven tie-break. The docstring of
:func:`raven_toolbox.init.ftinit` links the study that measures the effect of this
setting.
resolve_ties : bool
Opt-in; the default False gives RAVEN's result. When True, the degeneracy of the MILP
is resolved deterministically. After the score optimum is found, a lexicographic
Expand Down Expand Up @@ -282,11 +275,10 @@ def run_ftinit(
Gurobi's ``Threads`` (default 1, RAVEN's value). More threads can shorten the solve, and
with more than one thread two runs of the same input can return different reaction
sets, because multi-threaded Gurobi chooses between equal optima non-deterministically.
The studies on raven-docs ran with one thread. The number of threads has no measured
effect on the spread between different seeds, so it does not replace ``resolve_ties``;
see the `ftINIT reproducibility study
The number of threads does not select between equal optima in a controlled way, so it
does not replace ``resolve_ties``. The `ftINIT reproducibility study
<https://github.com/CompMetEng/raven-docs/blob/main/docs/parameter-tuning/studies/ftinit-determinism.md>`_
on raven-docs. It is applied on Gurobi only.
on raven-docs measures the spread between seeds. It is applied on Gurobi only.
feas_tol : float
Gurobi's ``FeasibilityTol``. The default is 1e-9 (RAVEN's value and Gurobi's minimum;
Gurobi's own default is 1e-6). See the note on tolerances below.
Expand All @@ -305,8 +297,7 @@ def run_ftinit(
``feas_tol``, ``opt_tol``, ``int_feas_tol`` and ``presolve`` are RAVEN parity settings:
they determine which optimal vertex the solver returns for the degenerate MILP and how
binaries round at the 0.5 on/off cut. Changing them changes the optimum returned and the
run time. The studies on raven-docs ran at the defaults; the effect of other values on the
run time and on the extracted model has not been benchmarked.
run time.

The private parameter ``_pin_fluxes`` (default True) is set by
:func:`raven_toolbox.init.ftinit`: it is False in the last step, whose fluxes no later
Expand Down Expand Up @@ -635,9 +626,7 @@ def _resolve_ties(opt, prob, obj_expr, indicators, primary, time_limit, rank_key

Many reaction subsets reach the same score optimum of the ftINIT MILP, and the solver
returns one of them. The choice is reproducible for a fixed solver build and seed, and can
change with the Gurobi version, the platform or the seed. In the determinism study
(Human-GEM v2.0.0-38, one cell line) two seeds gave kept-reaction sets that differ by 110
reactions and 17 predicted essential genes.
change with the Gurobi version, the platform or the seed.

The function runs a lexicographic phase 2 that holds the score objective at its optimum
with a floor constraint: first it minimises the count of kept removable reactions (the
Expand All @@ -655,14 +644,11 @@ def _resolve_ties(opt, prob, obj_expr, indicators, primary, time_limit, rank_key
distribution, which the staged schedule reads for the forced directions and the
``ess_force`` clamp of the next step, is pinned afterwards by :func:`_min_abs_flux`.

Caveat, measured on genome-scale Human-GEM (both phases prove in milliseconds at toy or
unit-test scale): the phases can exhaust ``time_limit``, in which case the incumbent
adopted is an unproven tie-break. It reduces the run-to-run spread relative to no
tie-break at all, and it does not guarantee a unique result. A warning is issued when this
happens; see the `ftINIT reproducibility
study
Caveat: the phases can exhaust ``time_limit``, in which case the incumbent adopted is an
unproven tie-break. It does not guarantee a unique result. A warning is issued when this
happens. The `ftINIT reproducibility study
<https://github.com/CompMetEng/raven-docs/blob/main/docs/parameter-tuning/studies/ftinit-determinism.md>`_
on raven-docs.
on raven-docs measures the spread between seeds with and without the tie-break.

Returns ``True`` if phase 2 produced a usable solution (the caller then reads the
resolved "on" set and fluxes), ``False`` if it did not converge to an incumbent (the
Expand Down Expand Up @@ -1158,21 +1144,12 @@ def ftinit(
relative-gap escalation with a single solve per step proven to this fixed absolute
gap, so the kept-set objective is optimal at any scale and not an arbitrary within-gap
incumbent. It changes which optimum is returned and not its score; the alternative
optima are equally consistent with the expression data. The sweep ran on Human-GEM
v2.0.0-38 with one cell line, four seeds (1234, 7, 1 and 2), ``resolve_ties=True``,
no gap-fill and ``time_limit`` 1800 s. The default escalation returned a step-1
objective 4.0 to 12.0 below the proven optimum; with seeds 1234 and 7 alone it ended
7.0 and 12.0 below, and 4.0 is seed 2. Every value from 2.0 to 0.05 reached the
optimum for all four seeds and gave the same reaction sets, so 1.0 lies in the range
of equal results; 5.0 stopped 2.0 below the optimum for one seed. Every step solve
(the 48 primary solves) ended with status ``optimal``; the flux phases
``phase2c-minflux`` (3 of 4 seeds) and ``phase2d-direction`` (4 of 4 seeds) reached
the time limit and were adopted as unproven incumbents. The mean build time was about
5770 s at 0.05 against 5640 s at 1.0. The study recommends 1.0 together with
``resolve_ties`` when the seed-to-seed swing of ``resolve_ties`` alone (41 reactions,
1 gene here) is too large and the run time is acceptable. The full-pipeline runs of
the calibration study used ``time_limit`` 600 s per step and the determinism builds
1800 s.
optima are equally consistent with the expression data. A larger value stops the
solve at a larger distance from the proven optimum. The flux phases of ``resolve_ties``
can reach ``time_limit`` and are then adopted as unproven incumbents. The `ftINIT
reproducibility study
<https://github.com/CompMetEng/raven-docs/blob/main/docs/parameter-tuning/studies/ftinit-determinism.md>`_
on raven-docs sweeps this setting and reports the run times.
resolve_ties : bool
Opt-in; the default False gives RAVEN's behaviour. It reduces the arbitrariness of the
tie-break in the degenerate MILP and gives a more parsimonious and more reproducible
Expand Down Expand Up @@ -1206,20 +1183,13 @@ def ftinit(

Notes
-----
The studies on raven-docs ran at the default tolerances, ``presolve`` and one thread (see
:func:`run_ftinit`). The stability of the extraction under small input changes is a
separate property that neither ``seed`` nor ``threads`` determines; see the `ftINIT
reproducibility study
The stability of the extraction under small input changes is a separate property that
neither ``seed`` nor ``threads`` determines. The `ftINIT reproducibility study
<https://github.com/CompMetEng/raven-docs/blob/main/docs/parameter-tuning/studies/ftinit-determinism.md>`_
on raven-docs. Measured there on Human-GEM v2.0.0-38 with one cell line (seeds 1234 and 7,
``time_limit`` 1800 s): the default escalation differs between the seeds by 110 reactions
and 17 predicted essential genes. ``resolve_ties`` alone gives identical reaction sets for
repeated builds at a fixed seed and differs between the seeds by 41 reactions and 1 gene,
at about 3.6 times the run time (about 14 min against 4 min). ``resolve_ties`` with
``prove_abs_gap=1.0`` differs by 1 reaction and 0 genes, at about 26 times the baseline
run time (about 100 min). The tie-break phases of ``resolve_ties`` can exhaust
``time_limit`` at genome scale; the spread is then reduced and not eliminated, and a
warning is issued.
on raven-docs measures the spread between seeds and the run time for the default
escalation, for ``resolve_ties`` and for ``resolve_ties`` with ``prove_abs_gap``. The
tie-break phases of ``resolve_ties`` can exhaust ``time_limit``; the result is then an
unproven tie-break, not a unique optimum, and a warning is issued.

When models are compared before and after a curation, an edit applied to the template
(followed by a new extraction) and the same edit applied to the extracted model are
Expand Down
7 changes: 4 additions & 3 deletions src/raven_toolbox/init/prep.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,10 @@ def prep_init_model(
larger merged model that may reach a different extraction optimum.
scale : bool
Keyword-only; default ``True``. When ``False``, the merged model's stoichiometry is
not rescaled. In the INIT parameter calibration study on raven-docs (Human-GEM, one
cell line), the full ftINIT pipeline without scaling was feasible at ``big_m`` 1000
and took 157 s against 83 s with scaling, and it was infeasible at ``big_m`` 100.
not rescaled. Without scaling, a small ``big_m`` can make the MILP infeasible. The
`INIT parameter calibration study
<https://github.com/CompMetEng/raven-docs/blob/main/docs/parameter-tuning/studies/init-param-calibration.md>`_
on raven-docs compares the pipeline with and without scaling.
verbose : bool
Keyword-only; default ``False``. Prints one line per phase plus per-task progress
during essential-reaction discovery.
Expand Down
8 changes: 2 additions & 6 deletions src/raven_toolbox/init/taskfill.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,8 @@

# A resolve_ties tie-break phase is adopted whether it proves or times out (see
# _resolve_ties_fill), so it is given a fraction of the primary fill's own budget rather
# than the full amount again: a phase that would not converge within the full budget has
# been observed (on genome-scale Human-GEM) to still not converge, only slower; a phase
# that does converge does so far inside either budget (a pure integer count/id-rank
# objective with a 0.4 absolute gap). Not independently tuned — see the ftINIT
# reproducibility study on raven-docs for the experiment that would calibrate this
# properly instead of halving on general principle.
# than the full amount again: a phase that does converge does so far inside either budget
# (a pure integer count/id-rank objective with a 0.4 absolute gap). Not tuned.
_TIE_BREAK_TIME_FRACTION = 0.5


Expand Down
12 changes: 5 additions & 7 deletions src/raven_toolbox/localization/certify.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,11 @@ def _prepare_scope(model, scores, reactions_to_relocate, *, transportable, base_
# --------------------------------------------------------------------------- master
def _pin_deterministic(prob, opt) -> None:
"""Pin solver parameters so a degenerate placement objective gives the same solution on every
run and on every machine. In a benchmark of the yeast master (identical model, one parameter
varied at a time), three settings changed which co-optimal placement Gurobi returned: thread
count, seed and presolve level. The MIP gap changed the result only when loosened above ~1e-2,
which also gives non-optimal solutions, and no tolerance changed it. The function sets one
thread, a fixed seed, presolve level 2 (the optimizeProb default of the MATLAB port), a MIP gap
of 0 (exact optimum) and an integrality tolerance of 1e-9. Only the Gurobi backend is
configured; other backends keep their defaults."""
run and on every machine. The objective is degenerate, so thread count, seed and presolve level
can change which co-optimal placement Gurobi returns. The function sets one thread, a fixed
seed, presolve level 2 (the optimizeProb default of the MATLAB port), a MIP gap of 0 (exact
optimum) and an integrality tolerance of 1e-9. Only the Gurobi backend is configured; other
backends keep their defaults."""
if "gurobi" not in getattr(prob, "__name__", ""):
return
try:
Expand Down
10 changes: 4 additions & 6 deletions src/raven_toolbox/localization/scores.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,16 +193,15 @@ def load_deeploc(path: str | Path, *,
labels). A label absent from the map is dropped with its column (see the module docstring).
min_confidence : float
Drops genes whose top compartment probability (before per-gene normalisation) is below it
(default ``0.0``, which keeps every gene). In the yeast-GEM benchmark of the confidence
study, the share of calls that other evidence corroborates rises with the raw probability.
(default ``0.0``, which keeps every gene).
membrane_split : mapping of str to str or None
For example ``{"m": "mm"}`` (default ``None``, no split). It moves the probability of an
organelle to its membrane sub-compartment when the protein is membrane-associated
(``1 - P(Soluble) >= membrane_threshold``, using DeepLoc's ``Soluble`` column); otherwise
it stays in the lumen. Keys and values are the compartment ids of the model (after
``compartment_map``). A key that is not a compartment of the table is skipped. Raises
:class:`ValueError` when the file has no ``Soluble`` column. The evidence supports only the
mitochondrial split (``m``/``mm``; matrix versus membrane AUC ~0.93). DeepLoc does not
mitochondrial split (``m``/``mm``). DeepLoc does not
separate the ER lumen from the membrane, so a split of ``er`` has no support.
membrane_threshold : float
Value of ``1 - P(Soluble)`` from which a protein counts as membrane-associated (default
Expand All @@ -214,9 +213,8 @@ def load_deeploc(path: str | Path, *,
normalise : bool
If True (default), rescale the best compartment of every gene to 1.0. This follows the
RAVEN ``parseScores`` convention and keeps the scales of several sources comparable. False
keeps DeepLoc's raw probabilities. The raw probabilities are calibrated (a 0.97 call is
more reliable than a 0.40 one), so a downstream assignment can weight confident genes more
heavily.
keeps DeepLoc's raw probabilities, so a downstream assignment can weight confident genes
more heavily.
"""
raw = pd.read_csv(path)
wide = _wide_mapped(raw, id_column=None, compartment_map=compartment_map, source=str(path))
Expand Down
9 changes: 4 additions & 5 deletions src/raven_toolbox/localization/triage.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
``uncertainty`` in ``[0, 1]`` blended from the signals that apply, and the list is ranked by it. The
signals that fire differ per gene:

* **low confidence**: the raw top probability of the predictor is low (in the yeast-GEM
benchmark, the share of calls that other evidence corroborates rises with the raw
probability). This signal carries the largest default weight (0.35) of the signals in the
* **low confidence**: the raw top probability of the predictor is low. This signal carries the largest default weight (0.35) of the signals in the
blended ``uncertainty``. Needs ``scores.raw_confidence``
(``load_deeploc(keep_raw_confidence=True)``) or an explicit ``raw_confidence=``, because
normalisation hides the raw probability.
Expand All @@ -28,7 +26,8 @@

See the `DeepLoc yeast-GEM benchmark
<https://github.com/CompMetEng/raven-gecko-parity/blob/develop/docs/localization/deeploc_yeast_benchmark.md>`_
on raven-gecko-parity for the source of the thresholds.
on raven-gecko-parity compares the raw predictor probability with other evidence for the
yeast-GEM calls and gives the bins and thresholds.
"""
from __future__ import annotations

Expand Down Expand Up @@ -61,7 +60,7 @@


def confidence_bin(p: float) -> str:
"""Calibration bin of a raw confidence, with the bins of the benchmark's corroboration rates."""
"""Bin of a raw confidence, with the bins of the benchmark's corroboration table."""
for lo, hi in ((0.0, 0.5), (0.5, 0.7), (0.7, 0.9)):
if lo <= p < hi:
return f"[{lo:.1f},{hi:.1f})"
Expand Down
Loading
Loading