Tutorials › Quantitative Systems Pharmacology (QSP) › Cross-Implementation Checks for Independent Code

Verification, Validation and Independent Validation · Tutorial 756 of 799

Cross-Implementation Checks for Independent Code

Learn how to design and interpret cross-implementation checks that reveal coding or configuration discrepancies without mistaking agreement for validation.

Advanced 12 min read

What You'll Learn

  • Specify the assumptions needed for a meaningful comparison of two implementations.
  • Map states with different units or representations onto common quantities before comparing them.
  • Apply absolute-plus-relative tolerances and interpret the resulting discrepancies.
  • Check shared inputs, numerical settings, time points, and dosing-event conventions.
  • Distinguish cross-implementation evidence from analytical verification, regression testing, and model validation.

Why Compare Independent Implementations?

When two separately coded versions of a mechanistic model receive the same inputs, their outputs should agree closely if they implement the same equations correctly and solve them adequately. A disagreement can reveal a coding error, a unit conversion problem, inconsistent event handling, or a numerical configuration that needs investigation. Agreement is useful evidence that the implementation is reproducible across code paths; it does not establish that the model’s equations describe biology correctly.

A cross-implementation check is informative only when the comparison is controlled. The implementations must represent the same model, receive equivalent inputs, and report comparable quantities at aligned times. Their numerical settings must be documented, and any difference in state representation must be resolved before comparing outputs. The discrepancy criterion should be chosen before looking at the results.

Definition: A cross-implementation check compares outputs from independently coded versions of the same specified mechanistic model under shared, equivalent inputs. Before comparison, each implementation’s states and outputs are mapped to common quantities and units. The check assesses implementation agreement under the tested conditions; it does not by itself verify either implementation against a known solution or validate the model against observations.

Conditions for a Meaningful Comparison

Write the model state reported by implementation A as \(x_A(t)\), and the state reported by implementation B as \(x_B(t)\). The same symbol need not mean the same stored quantity in both codes. For example, one implementation might store drug amount and another might store drug concentration. Define a mapping from each implementation’s reported state to a common comparison quantity, \(y_A(t)=g_A(x_A(t))\) and \(y_B(t)=g_B(x_B(t))\). Compare \(y_A\) with \(y_B\), not raw state vectors whose components may have different meanings or units.

Before running the comparison, document the conditions it assumes:

  • Same model specification. Both codes implement the same equations, parameter meanings, initial conditions, and boundary conditions. Equivalent equations written in different forms are acceptable, but the correspondence must be explicit.
  • Equivalent inputs. Parameter values, dose amounts, units, input functions, and intervention schedules agree after any necessary conversion.
  • Comparable numerical settings. Record the solver, tolerances, step-size controls, and interpolation choices. For a controlled first comparison, match these settings as closely as the solvers permit. Different solver algorithms can still be compared, but their settings and consequences must be examined rather than assumed equivalent.
  • Aligned outputs. Compare the same requested times and the same event convention, such as a value immediately before or immediately after a dose. If one code reports at different times, use a justified interpolation procedure or rerun it at the common times.
  • Valid mappings and tolerances. State transformations must preserve the intended quantity, and each component must have a prespecified discrepancy tolerance appropriate to its scale and units.

For stochastic models, matching a random-number seed may not make implementations comparable: the codes may consume random draws in different orders or use different random-number generators. The earlier material on statistical tests for stochastic QSP implementations addresses comparisons that account for simulation variability. The examples here focus on deterministic trajectories and outputs.

A Scale-Aware Discrepancy Rule

For mapped output component \(j\) at comparison time \(t_k\), denote the results by \(y_{A,j}(t_k)\) and \(y_{B,j}(t_k)\). A common prespecified rule combines an absolute tolerance \(a_j\) and a relative tolerance \(r_j\):

$$ \left|y_{A,j}(t_k)-y_{B,j}(t_k)\right| \leq a_j+r_j\max\!\left(\left|y_{A,j}(t_k)\right|,\left|y_{B,j}(t_k)\right|\right). $$

Here \(a_j\) has the units of component \(j\), while \(r_j\) is dimensionless. The absolute term gives a meaningful allowance near zero; the relative term scales the allowance when values are large. A comparison can also be summarized by the scaled discrepancy

$$ q_{j,k} = \frac{\left|y_{A,j}(t_k)-y_{B,j}(t_k)\right|} {a_j+r_j\max\!\left(\left|y_{A,j}(t_k)\right|,\left|y_{B,j}(t_k)\right|\right)}. $$

Provided the denominator is positive, the component passes at that time when \(q_{j,k}\leq 1\). A trajectory-level rule might require this condition at every prespecified time for every monitored component. The rule should identify which components and times are tested; reporting only an average discrepancy can conceal a localized failure.

Why the Tolerance Has Two Parts

The rule follows directly from combining an absolute error allowance with an allowance proportional to the scale of the result. Let \(\Delta_{j,k}=|y_{A,j}(t_k)-y_{B,j}(t_k)|\), and let \(M_{j,k}=\max(|y_{A,j}(t_k)|,|y_{B,j}(t_k)|)\). If the allowed discrepancy is the sum of a baseline allowance \(a_j\) and a scale-dependent allowance \(r_jM_{j,k}\), then passing means \(\Delta_{j,k}\leq a_j+r_jM_{j,k}\). Dividing by that positive allowance gives \(q_{j,k}\leq1\). Near zero, the relative contribution is small, so \(a_j\) prevents an unrealistically strict requirement based solely on relative error. At larger magnitudes, \(r_jM_{j,k}\) allows the criterion to reflect scale.

This tolerance is an acceptance rule for comparing outputs, not a solver setting and not a universal guarantee of accuracy. The numerical solver’s internal error controls should be sufficiently tight for the check’s purpose, but a solver tolerance does not automatically determine a scientifically appropriate \(a_j\) or \(r_j\). Prespecify comparison tolerances using the output’s units, scale, and intended computational use.

Worked Example: Mapping Amount to Concentration

Hypothetical data. At one time point, implementation A reports drug amount \(8.000\) mg in a compartment of volume \(2.00\) L. Implementation B reports concentration \(3.998\) mg/L. The common comparison quantity is amount, and the prespecified tolerances are \(a=0.010\) mg and \(r=0.001\).

Convert B’s concentration to amount using the shared compartment volume:

$$ y_A=8.000\ \mathrm{mg}, \qquad y_B=(3.998\ \mathrm{mg/L})(2.00\ \mathrm{L})=7.996\ \mathrm{mg}. $$

The absolute discrepancy is \(0.004\) mg. The allowed discrepancy is

$$ 0.010+0.001\max(8.000,7.996) =0.010+0.008 =0.018\ \mathrm{mg}. $$

Because \(0.004\leq0.018\) mg, this comparison passes. The result is meaningful because both values were mapped to amount in the same units. Comparing \(8.000\) mg directly with \(3.998\) mg/L would be dimensionally invalid.

Worked Example: Checking Outputs at Different Scales

Hypothetical data. At a selected time, the two implementations report drug concentration and cytokine concentration. Use \(a_{\mathrm{drug}}=0.01\) mg/L and \(r_{\mathrm{drug}}=0.02\) for drug, and \(a_{\mathrm{cytokine}}=0.0001\) ng/mL and \(r_{\mathrm{cytokine}}=0.02\) for cytokine.

For drug, A reports \(50.0\) mg/L and B reports \(50.6\) mg/L. The discrepancy is \(0.6\) mg/L, while the allowance is

$$ 0.01+0.02\max(50.0,50.6) =0.01+1.012 =1.022\ \mathrm{mg/L}. $$

The drug comparison passes because \(0.6\leq1.022\) mg/L. For cytokine, A reports \(0.0100\) ng/mL and B reports \(0.0104\) ng/mL. Its discrepancy is \(0.0004\) ng/mL, and its allowance is

$$ 0.0001+0.02\max(0.0100,0.0104) =0.0001+0.000208 =0.000308\ \mathrm{ng/mL}. $$

The cytokine comparison fails because \(0.0004>0.000308\) ng/mL. Thus, a large-scale output can pass while a smaller-scale output fails. Each decision uses the tolerances defined for that component, with units carried through the calculation.

Aligning Events and Comparison Times

Discontinuous inputs require particular care. At a bolus dose, the state may jump; a reported value at the event time must therefore be identified as pre-dose or post-dose. The two implementations must use the same convention. A mismatch can produce a large discrepancy even when both codes implement the intended dose correctly.

Worked Example: A Bolus at a Shared Event Time

Hypothetical data. A one-compartment model receives a \(100\) mg bolus at \(t=2\) h into a \(10\) L compartment. After the dose, concentration declines by first-order elimination with \(k=0.20\ \mathrm{h}^{-1}\). Both implementations are asked for the post-dose concentration at \(t=2.5\) h. With no drug before the dose, the expected calculation is

$$ C(2.5) = \frac{100\ \mathrm{mg}}{10\ \mathrm{L}} \exp[-(0.20\ \mathrm{h}^{-1})(0.5\ \mathrm{h})] = 10\exp(-0.1) \approx9.048\ \mathrm{mg/L}. $$

Suppose A reports \(9.048\) mg/L and B reports \(9.050\) mg/L. With \(a=0.005\) mg/L and \(r=0.001\), their discrepancy is \(0.002\) mg/L and the allowance is \(0.005+0.001(9.050)=0.01405\) mg/L, so this comparison passes. But if B mistakenly applies the dose at \(2.5\) h rather than \(2.0\) h, its post-dose value at the requested time would be \(10\) mg/L; the discrepancy from A would be \(0.952\) mg/L and would fail the same criterion. Checking event times and pre/post conventions helps identify the cause rather than treating the result as an unexplained solver difference.

A Practical Comparison Sequence

A disciplined sequence makes the evidence easier to reproduce and disagreements easier to diagnose. Keep the test conditions, mappings, and tolerances in the record alongside the output comparisons.

1
Freeze the specification.
Record equations, parameter values, initial conditions, inputs, units, and event schedules. Document how each implementation corresponds to that specification.
2
Align numerical and reporting settings.
Record solver settings and request common output times. Specify interpolation, event handling, and whether event-time values are pre-event or post-event.
3
Map and compare outputs.
Convert states to common quantities and units, apply prespecified component-wise tolerances, and retain discrepancies for each component and time.
4
Investigate and retest.
For a failure, trace inputs, units, state mappings, equations, events, and solver behavior. Correct a diagnosed issue and rerun the unchanged test conditions.

Useful diagnostics include plots of both trajectories, plots of their signed difference, and tables of the largest scaled discrepancies \(q_{j,k}\). A sudden difference near a dose suggests checking event alignment; a steadily growing difference may point to parameter, equation, or numerical discrepancies. These patterns guide investigation but do not identify a cause on their own. If the disagreement changes materially when numerical accuracy is tightened, solver convergence deserves further examination.

What Agreement Does—and Does Not—Show

Cross-implementation checks complement other verification approaches. An analytical reference solution can test a code against a known result in a case where such a solution exists. Invariant, limiting-case, and metamorphic tests examine properties or transformations expected of the model. Regression tests check whether a code change alters outputs from established cases. Independent implementations offer a different kind of evidence: agreement across separately coded paths for shared test cases. None of these checks alone establishes that the model is biologically adequate.

The word independent also needs care. If both implementations reuse the same equation-generation tool, parameter-processing module, or copied code, they may share the same defect. Record shared dependencies and avoid claiming independence beyond what the development process supports. Even genuinely separate implementations can agree because they share a mistaken interpretation of the specification.

A common mistake is to reason, “The two codes agree within tolerance, so the model is correct.” The comparison supports only the narrower conclusion that the mapped outputs agreed within the chosen tolerance under the tested conditions. It cannot show that the equations, assumptions, parameter values, or predictions are correct for a biological use. The opposite mistake is to compare raw states without checking units or meanings: numerical similarity between unlike quantities is not agreement.

Key takeaway: Make cross-implementation evidence interpretable by fixing shared inputs, aligning times and event conventions, mapping states to common units, and applying prespecified, scale-aware tolerances. Treat a pass as evidence of implementation agreement under those conditions—not as proof of model validity.

Check Your Understanding

Answer each question, then compare your reasoning with the brief solutions.

  1. One implementation reports \(12\) mg of drug and another reports \(4\) mg/L in a \(3\) L compartment. What must be done before comparing the outputs?
  2. Two mapped outputs are \(0.0200\) and \(0.0203\) ng/mL. With \(a=0.0001\) ng/mL and \(r=0.01\), does the comparison pass?
  3. Why should a bolus comparison specify whether event-time output is pre-dose or post-dose?
  4. State one conclusion that a passing cross-implementation check supports and one conclusion it does not support.

Solutions. (1) Convert the concentration to amount: \((4\ \mathrm{mg/L})(3\ \mathrm{L})=12\) mg, then compare in common units. (2) The discrepancy is \(0.0003\) ng/mL; the allowance is \(0.0001+0.01(0.0203)=0.000303\) ng/mL, so it passes because \(0.0003\leq0.000303\). (3) The state jumps at a bolus, so pre-dose and post-dose values differ; inconsistent conventions can create an apparent discrepancy. (4) A pass supports agreement of the mapped outputs under the tested conditions and tolerances. It does not establish that the model is biologically correct or valid for a particular use.

Clinical Biostats