Skip to content

refactor: Remove likelihood calculation - #291

Open
Siel wants to merge 13 commits into
mainfrom
feature/likelihood-extraction
Open

refactor: Remove likelihood calculation#291
Siel wants to merge 13 commits into
mainfrom
feature/likelihood-extraction

Conversation

@Siel

@Siel Siel commented Jul 15, 2026

Copy link
Copy Markdown
Member

No description provided.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Projectpharmsol
Branchfeature/likelihood-extraction
Testbedmhovd-pgx

🚨 3 Alerts

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
native/predictions/1cpt-12h-po/analytical/macro/coldLatency
microseconds (µs)
📈 plot
🚷 threshold
🚨 alert (🔔)
1.96 µs
(+12.14%)Baseline: 1.75 µs
1.90 µs
(103.42%)

native/predictions/2cpt-120h-q12h/ode/handwritten/hotLatency
nanoseconds (ns)
📈 plot
🚷 threshold
🚨 alert (🔔)
627.53 ns
(+21.11%)Baseline: 518.14 ns
602.75 ns
(104.11%)

native/predictions/2cpt-120h-q12h/ode/macro/hotLatency
nanoseconds (ns)
📈 plot
🚷 threshold
🚨 alert (🔔)
606.39 ns
(+17.44%)Baseline: 516.34 ns
603.66 ns
(100.45%)

Click to view all benchmark results
BenchmarkLatencyBenchmark Result
nanoseconds (ns)
(Result Δ%)
Upper Boundary
nanoseconds (ns)
(Limit %)
dsl/compile/1cpt-12h-po/analytical/dsl-jit📈 view plot
🚷 view threshold
47,034.00 ns
(-8.22%)Baseline: 51,244.59 ns
68,209.46 ns
(68.96%)
dsl/compile/1cpt-12h-po/ode/dsl-jit📈 view plot
🚷 view threshold
83,851.00 ns
(-3.51%)Baseline: 86,903.69 ns
100,809.07 ns
(83.18%)
dsl/compile/2cpt-120h-q12h/analytical/dsl-jit📈 view plot
🚷 view threshold
48,215.00 ns
(-5.40%)Baseline: 50,964.88 ns
67,386.24 ns
(71.55%)
dsl/compile/2cpt-120h-q12h/ode/dsl-jit📈 view plot
🚷 view threshold
101,420.00 ns
(-4.96%)Baseline: 106,716.84 ns
140,558.95 ns
(72.15%)
dsl/predictions/1cpt-12h-po/analytical/dsl-jit/cold📈 view plot
🚷 view threshold
2,270.30 ns
(-0.73%)Baseline: 2,287.06 ns
2,490.71 ns
(91.15%)
dsl/predictions/1cpt-12h-po/analytical/dsl-jit/hot📈 view plot
🚷 view threshold
332.41 ns
(-85.74%)Baseline: 2,331.49 ns
2,528.50 ns
(13.15%)
dsl/predictions/1cpt-12h-po/ode/dsl-jit/cold📈 view plot
🚷 view threshold
24,139.00 ns
(-0.14%)Baseline: 24,172.00 ns
25,009.91 ns
(96.52%)
dsl/predictions/1cpt-12h-po/ode/dsl-jit/hot📈 view plot
🚷 view threshold
332.60 ns
(-70.31%)Baseline: 1,120.24 ns
11,828.16 ns
(2.81%)
dsl/predictions/2cpt-120h-q12h/analytical/dsl-jit/cold📈 view plot
🚷 view threshold
4,133.20 ns
(-4.72%)Baseline: 4,338.03 ns
4,695.41 ns
(88.03%)
dsl/predictions/2cpt-120h-q12h/analytical/dsl-jit/hot📈 view plot
🚷 view threshold
559.01 ns
(-86.97%)Baseline: 4,291.05 ns
4,669.26 ns
(11.97%)
dsl/predictions/2cpt-120h-q12h/ode/dsl-jit/cold📈 view plot
🚷 view threshold
90,660.00 ns
(-1.63%)Baseline: 92,158.34 ns
94,574.78 ns
(95.86%)
dsl/predictions/2cpt-120h-q12h/ode/dsl-jit/hot📈 view plot
🚷 view threshold
571.19 ns
(-83.32%)Baseline: 3,424.75 ns
44,555.36 ns
(1.28%)
native/predictions/1cpt-12h-po/analytical/handwritten/cold📈 view plot
🚷 view threshold
1,911.30 ns
(+7.55%)Baseline: 1,777.11 ns
1,911.91 ns
(99.97%)
native/predictions/1cpt-12h-po/analytical/handwritten/hot📈 view plot
🚷 view threshold
296.05 ns
(-83.36%)Baseline: 1,778.97 ns
1,909.71 ns
(15.50%)
native/predictions/1cpt-12h-po/analytical/macro/cold📈 view plot
🚷 view threshold
🚨 view alert (🔔)
1,961.40 ns
(+12.14%)Baseline: 1,749.12 ns
1,896.48 ns
(103.42%)

native/predictions/1cpt-12h-po/analytical/macro/hot📈 view plot
🚷 view threshold
281.14 ns
(-84.13%)Baseline: 1,771.23 ns
1,903.75 ns
(14.77%)
native/predictions/1cpt-12h-po/ode/handwritten/cold📈 view plot
🚷 view threshold
22,355.00 ns
(+0.81%)Baseline: 22,176.16 ns
22,970.17 ns
(97.32%)
native/predictions/1cpt-12h-po/ode/handwritten/hot📈 view plot
🚷 view threshold
274.23 ns
(+1.58%)Baseline: 269.97 ns
386.96 ns
(70.87%)
native/predictions/1cpt-12h-po/ode/macro/cold📈 view plot
🚷 view threshold
22,104.00 ns
(-0.22%)Baseline: 22,152.38 ns
22,644.96 ns
(97.61%)
native/predictions/1cpt-12h-po/ode/macro/hot📈 view plot
🚷 view threshold
353.58 ns
(+4.34%)Baseline: 338.86 ns
424.35 ns
(83.32%)
native/predictions/2cpt-120h-q12h/analytical/handwritten/cold📈 view plot
🚷 view threshold
4,160.40 ns
(+5.95%)Baseline: 3,926.63 ns
4,255.18 ns
(97.77%)
native/predictions/2cpt-120h-q12h/analytical/handwritten/hot📈 view plot
🚷 view threshold
612.43 ns
(-84.44%)Baseline: 3,934.75 ns
4,223.54 ns
(14.50%)
native/predictions/2cpt-120h-q12h/analytical/macro/cold📈 view plot
🚷 view threshold
4,063.50 ns
(+5.08%)Baseline: 3,867.05 ns
4,149.47 ns
(97.93%)
native/predictions/2cpt-120h-q12h/analytical/macro/hot📈 view plot
🚷 view threshold
604.52 ns
(-84.37%)Baseline: 3,867.16 ns
4,131.61 ns
(14.63%)
native/predictions/2cpt-120h-q12h/ode/handwritten/cold📈 view plot
🚷 view threshold
58,842.00 ns
(-30.86%)Baseline: 85,101.19 ns
87,569.64 ns
(67.19%)
native/predictions/2cpt-120h-q12h/ode/handwritten/hot📈 view plot
🚷 view threshold
🚨 view alert (🔔)
627.53 ns
(+21.11%)Baseline: 518.14 ns
602.75 ns
(104.11%)

native/predictions/2cpt-120h-q12h/ode/macro/cold📈 view plot
🚷 view threshold
59,550.00 ns
(-30.38%)Baseline: 85,541.78 ns
87,598.18 ns
(67.98%)
native/predictions/2cpt-120h-q12h/ode/macro/hot📈 view plot
🚷 view threshold
🚨 view alert (🔔)
606.39 ns
(+17.44%)Baseline: 516.34 ns
603.66 ns
(100.45%)

sde/simulation/session-retain📈 view plot
🚷 view threshold
881,040.00 ns
sde/simulation/session-select-ancestors📈 view plot
🚷 view threshold
902,300.00 ns
sde/simulation/standard-prediction📈 view plot
🚷 view threshold
616,460.00 ns
🐰 View full continuous benchmarking report in Bencher

Comment thread .github/workflows/build.yml Outdated
Comment thread src/simulator/cache.rs
}

/// Create an empty cache with the same capacity but no shared entries.
pub(crate) fn detached(&self) -> Self {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we rename to e.g. reset?
With documentation comment

/// Reset the cache
///
/// Creates a new, unique cache that is not shared with caches from potentially linked equations

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I would keep detached: this method returns a new empty cache that breaks Arc sharing, whereas reset suggests mutating the existing cache. invalidate_all() already provides the clear-in-place operation. empty_detached would also be accurate if we want a more explicit name.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Sounds good

Comment thread src/data/event.rs Outdated
Comment thread src/data/event.rs Outdated
Comment thread src/data/event.rs Outdated
Comment on lines 97 to +104

/// Calculate the log-likelihood of the predictions given an error model.
///
/// This is numerically more stable than computing the likelihood and taking its log,
/// especially for extreme values or many observations.
///
/// # Parameters
/// - `error_models`: The error models for computing observation variance
///
/// # Returns
/// The sum of log-likelihoods for all predictions
fn log_likelihood(&self, error_models: &AssayErrorModels) -> Result<f64, PharmsolError>;
/// Visit each effective prediction without requiring callers to own a `Vec`.
fn for_each_prediction(&self, mut f: impl FnMut(&Prediction)) {
let predictions = self.get_predictions();
for prediction in &predictions {
f(prediction);
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this preferred over implementing a mutable iterator?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Perhaps at least do both

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I prefer keeping for_each_prediction on the generic trait. SubjectPredictions can borrow stored points, but the SDE Array2<Prediction> implementation synthesizes effective mean predictions, so a generic mutable iterator cannot represent both consistently. A concrete mutable accessor on SubjectPredictions can be added later if a real mutation use case appears.

Comment thread src/simulator/prediction/point.rs Outdated
Comment on lines +15 to +17
pub struct SubjectPredictions {
predictions: Vec<Prediction>,
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I know we have had this structure for some time, but I am a little torn about it.
My biggest gripe is that it is disconnected from the data and subject from and for which it was generated.
Would it make sense to have predictions as part of the data?
Or as part of the Observation? I don't know.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I would keep predictions separate from Data and Observation: they depend on the model, parameters, and potentially RNG state, and multiple prediction sets may correspond to the same source data. SubjectPredictions now carries the subject ID and parallel occasion metadata, preserving provenance without mutating the input dataset.

Comment thread src/lib.rs Outdated
Comment on lines +21 to +22
//! metadata, and NCA. Estimation crates own scoring, objectives, priors,
//! algorithms, diagnostics, covariance, and fit semantics.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
//! metadata, and NCA. Estimation crates own scoring, objectives, priors,
//! algorithms, diagnostics, covariance, and fit semantics.
//! metadata, and NCA.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It seems like the documentation is leaking prompt details

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed with simplifying this. I removed the exhaustive ownership list and replaced it with a concise scope statement: pharmsol provides model execution and prediction generation, while scoring and estimation are handled downstream.

Comment thread CHANGELOG.md Outdated
Comment on lines +9 to +33

## [0.28.1](https://github.com/LAPKB/pharmsol/compare/pharmsol-v0.28.0...pharmsol-v0.28.1) - 2026-07-13
### Added

### Fixed
- Add a caller-controlled, simulation-neutral SDE particle session that pauses
at observation boundaries and can resume with retained or replaced states.
- Add focused Criterion coverage for standard SDE prediction and particle-session
retain/select paths.

### Removed

- Remove equation-level and prediction-container observation evaluation APIs;
downstream fitting crates now generate predictions with pharmsol and evaluate
observations themselves.
- Remove residual-distribution declarations, estimator caches, and parameter
optimization helpers from pharmsol's public API.

### Changed

- Fix data expansion ([#282](https://github.com/LAPKB/pharmsol/pull/282))
- Relocate the existing data-only `ErrorPoly` DTO while preserving its public
path and unchanged C0-C3 transport through observations and predictions.
As before, incomplete C0-C3 rows do not create an `ErrorPoly` value.
- Keep analytical, ODE, and SDE execution focused exclusively on simulation and
prediction generation, including simulation-only examples and benchmarks.
- Run the source-scoped simulation ownership check in CI, including untracked
source files during local use.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

PRs should not modify CHANGELOG directly

@mhovd mhovd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

See comments

@mhovd mhovd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

See comments

@mhovd mhovd changed the title Likelihood extraction refactor: Remove likelihood calculation Jul 21, 2026
@Siel
Siel force-pushed the feature/likelihood-extraction branch from 0b1ab2d to 027fd4d Compare July 21, 2026 21:05
@mhovd

mhovd commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator
  • Add subject ID to the predictions
  • Make sure to expand subjects with outeq from model metadata, then we can remove State from Prediction.
  • Remove progress artifacts and references

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