-
Notifications
You must be signed in to change notification settings - Fork 1
Feat/zero index #200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/normalized-row-api
Are you sure you want to change the base?
Feat/zero index #200
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -47,7 +47,7 @@ use std::collections::HashMap; | |||||||||||||||||||||
| /// # Fields | ||||||||||||||||||||||
| /// | ||||||||||||||||||||||
| /// All fields use Pmetrics conventions: | ||||||||||||||||||||||
| /// - `input` and `outeq` are **1-indexed** (will be converted to 0-indexed internally) | ||||||||||||||||||||||
| /// - `input` and `outeq` are **1-indexed** (kept as-is, user must size arrays accordingly) | ||||||||||||||||||||||
|
||||||||||||||||||||||
| /// - `input` and `outeq` are **1-indexed** (kept as-is, user must size arrays accordingly) | |
| /// - `input` and `outeq` are **1-indexed** (for compatibility with Pmetrics; internal code handles any necessary index translation) |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing the saturating_sub(1) conversion breaks array indexing throughout the codebase. The outeq value is used directly as an array index in multiple places (e.g., y[observation.outeq()] in src/simulator/equation/analytical/mod.rs:192 and src/simulator/equation/ode/mod.rs:324). With 1-indexed values, this will access the wrong array element or cause out-of-bounds errors. Array indices in Rust are 0-based, so internal representation must remain 0-indexed even if external formats use 1-indexing.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing the saturating_sub(1) conversion breaks array indexing for input compartments. The input value is used directly as an array index (e.g., bolus_v[bolus.input()] in src/simulator/equation/ode/mod.rs:274 and self[input] += amount in the State trait implementation). With 1-indexed values, this will access the wrong compartment or cause out-of-bounds panics.
| let input = self.input.ok_or_else(|| PmetricsError::MissingBolusInput { | |
| id: self.id.clone(), | |
| time: self.time, | |
| })?; // Keep 1-indexed as provided by Pmetrics | |
| let input_raw = self.input.ok_or_else(|| PmetricsError::MissingBolusInput { | |
| id: self.id.clone(), | |
| time: self.time, | |
| })?; // Pmetrics input is 1-indexed in the source data | |
| // Convert to 0-based index for internal use (e.g., array indexing) | |
| let input = input_raw.saturating_sub(1); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -315,7 +315,7 @@ impl Data { | |
| let value = obs | ||
| .value() | ||
| .map_or_else(|| ".".to_string(), |v| v.to_string()); | ||
| let outeq = (obs.outeq() + 1).to_string(); | ||
| let outeq = obs.outeq().to_string(); | ||
| let censor = match obs.censoring() { | ||
| Censor::None => "0".to_string(), | ||
| Censor::BLOQ => "1".to_string(), | ||
|
|
@@ -372,7 +372,7 @@ impl Data { | |
| &inf.amount().to_string(), | ||
| &".".to_string(), | ||
| &".".to_string(), | ||
| &(inf.input() + 1).to_string(), | ||
| &inf.input().to_string(), | ||
| &".".to_string(), | ||
| &".".to_string(), | ||
| &".".to_string(), | ||
|
|
@@ -393,7 +393,7 @@ impl Data { | |
| &bol.amount().to_string(), | ||
| &".".to_string(), | ||
| &".".to_string(), | ||
| &(bol.input() + 1).to_string(), | ||
| &bol.input().to_string(), | ||
| &".".to_string(), | ||
| &".".to_string(), | ||
| &".".to_string(), | ||
|
|
@@ -466,8 +466,8 @@ mod tests { | |
| #[test] | ||
| fn write_pmetrics_preserves_infusion_input() { | ||
| let subject = Subject::builder("writer") | ||
| .infusion(0.0, 200.0, 2, 1.0) | ||
| .observation(1.0, 0.0, 0) | ||
| .infusion(0.0, 200.0, 3, 1.0) // input=3 (1-indexed) | ||
| .observation(1.0, 0.0, 1) // outeq=1 (1-indexed) | ||
|
Comment on lines
+469
to
+470
|
||
| .build(); | ||
| let data = Data::new(vec![subject]); | ||
|
|
||
|
|
@@ -485,7 +485,7 @@ mod tests { | |
| .find(|record| record.get(3) != Some("0")) | ||
| .expect("infusion row missing"); | ||
|
|
||
| assert_eq!(infusion_row.get(7), Some("3")); | ||
| assert_eq!(infusion_row.get(7), Some("3")); // Written as-is (1-indexed) | ||
| } | ||
|
|
||
| #[test] | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation inconsistency is problematic. Line 135 says '(1-indexed)' but lines 90, 105, 120, 174, 191, and 213 in this same file only say 'compartment number' without specifying indexing. Lines 233 and 135 mention '(1-indexed)' but the others don't. This inconsistency will confuse users about whether the values are 0-indexed or 1-indexed.