pmcore/routines/output/
predictions.rs1use anyhow::{bail, Result};
2use pharmsol::{prelude::simulator::Prediction, Censor, Data, Predictions as PredTrait};
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 routines::output::{posterior::Posterior, weighted_median},
7 structs::{theta::Theta, weights::Weights},
8};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct NPPredictionRow {
17 id: String,
19 time: f64,
21 outeq: usize,
23 block: usize,
25 obs: Option<f64>,
27 cens: Censor,
29 pop_mean: f64,
31 pop_median: f64,
33 post_mean: f64,
35 post_median: f64,
37}
38
39impl NPPredictionRow {
40 pub fn id(&self) -> &str {
41 &self.id
42 }
43 pub fn time(&self) -> f64 {
44 self.time
45 }
46 pub fn outeq(&self) -> usize {
47 self.outeq
48 }
49 pub fn block(&self) -> usize {
50 self.block
51 }
52 pub fn obs(&self) -> Option<f64> {
53 self.obs
54 }
55 pub fn pop_mean(&self) -> f64 {
56 self.pop_mean
57 }
58 pub fn pop_median(&self) -> f64 {
59 self.pop_median
60 }
61 pub fn post_mean(&self) -> f64 {
62 self.post_mean
63 }
64 pub fn post_median(&self) -> f64 {
65 self.post_median
66 }
67
68 pub fn censoring(&self) -> Censor {
69 self.cens
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct NPPredictions {
75 predictions: Vec<NPPredictionRow>,
76}
77
78impl IntoIterator for NPPredictions {
79 type Item = NPPredictionRow;
80 type IntoIter = std::vec::IntoIter<NPPredictionRow>;
81
82 fn into_iter(self) -> Self::IntoIter {
83 self.predictions.into_iter()
84 }
85}
86
87impl Default for NPPredictions {
88 fn default() -> Self {
89 NPPredictions::new()
90 }
91}
92
93impl NPPredictions {
94 pub fn new() -> Self {
95 NPPredictions {
96 predictions: Vec::new(),
97 }
98 }
99
100 pub fn add(&mut self, row: NPPredictionRow) {
102 self.predictions.push(row);
103 }
104
105 pub fn predictions(&self) -> &[NPPredictionRow] {
107 &self.predictions
108 }
109
110 pub fn calculate(
123 equation: &impl pharmsol::prelude::simulator::Equation,
124 data: &Data,
125 theta: &Theta,
126 w: &Weights,
127 posterior: &Posterior,
128 idelta: f64,
129 tad: f64,
130 ) -> Result<Self> {
131 let mut container = NPPredictions::new();
133
134 let data = data.clone().expand(idelta, tad);
136 let subjects = data.subjects();
137
138 if subjects.len() != posterior.matrix().nrows() {
139 bail!("Number of subjects and number of posterior means do not match");
140 };
141
142 for subject in subjects.iter().enumerate() {
144 let (subject_index, subject) = subject;
145
146 let mut predictions: Vec<Vec<Prediction>> = Vec::new();
151
152 for spp in theta.matrix().row_iter() {
154 let spp_values = spp.iter().cloned().collect::<Vec<f64>>();
156 let pred = equation
157 .simulate_subject(subject, &spp_values, None)?
158 .0
159 .get_predictions();
160 predictions.push(pred);
161 }
162
163 if predictions.is_empty() {
164 continue; }
166
167 let mut pop_mean: Vec<f64> = vec![0.0; predictions.first().unwrap().len()];
169 for outer_pred in predictions.iter().enumerate() {
170 let (i, outer_pred) = outer_pred;
171 for inner_pred in outer_pred.iter().enumerate() {
172 let (j, pred) = inner_pred;
173 pop_mean[j] += pred.prediction() * w[i];
174 }
175 }
176
177 let mut pop_median: Vec<f64> = Vec::new();
179 for j in 0..predictions.first().unwrap().len() {
180 let mut values: Vec<f64> = Vec::new();
181 let mut weights: Vec<f64> = Vec::new();
182
183 for (i, outer_pred) in predictions.iter().enumerate() {
184 values.push(outer_pred[j].prediction());
185 weights.push(w[i]);
186 }
187
188 let median_val = weighted_median(&values, &weights);
189 pop_median.push(median_val);
190 }
191
192 let mut posterior_mean: Vec<f64> = vec![0.0; predictions.first().unwrap().len()];
194 for outer_pred in predictions.iter().enumerate() {
195 let (i, outer_pred) = outer_pred;
196 for inner_pred in outer_pred.iter().enumerate() {
197 let (j, pred) = inner_pred;
198 posterior_mean[j] += pred.prediction() * posterior.matrix()[(subject_index, i)];
199 }
200 }
201
202 let mut posterior_median: Vec<f64> = Vec::new();
204 for j in 0..predictions.first().unwrap().len() {
205 let mut values: Vec<f64> = Vec::new();
206 let mut weights: Vec<f64> = Vec::new();
207
208 for (i, outer_pred) in predictions.iter().enumerate() {
209 values.push(outer_pred[j].prediction());
210 weights.push(posterior.matrix()[(subject_index, i)]);
211 }
212
213 let median_val = weighted_median(&values, &weights);
214 posterior_median.push(median_val);
215 }
216
217 if let Some(first_spp_preds) = predictions.first() {
220 for (j, p) in first_spp_preds.iter().enumerate() {
221 let row = NPPredictionRow {
222 id: subject.id().clone(),
223 time: p.time(),
224 outeq: p.outeq(),
225 block: p.occasion(),
226 obs: p.observation(),
227 cens: p.censoring(),
228 pop_mean: pop_mean[j],
229 pop_median: pop_median[j],
230 post_mean: posterior_mean[j],
231 post_median: posterior_median[j],
232 };
233 container.add(row);
234 }
235 }
236 }
237
238 Ok(container)
239 }
240}