Module bestdose

Module bestdose 

Source
Expand description

§BestDose Algorithm

Bayesian dose optimization algorithm that finds optimal dosing regimens to achieve target drug concentrations or cumulative AUC (Area Under the Curve) values.

The BestDose algorithm combines Bayesian posterior estimation with dual optimization to balance patient-specific adaptation and population-level robustness.

§Quick Start

use pmcore::bestdose::{BestDosePosterior, Target, DoseRange};

// Stage 1: Compute posterior from patient history
let posterior = BestDosePosterior::compute(
    &population_theta,               // Population support points from NPAG
    &population_weights,             // Population probabilities
    Some(past_data),                 // Patient history (None = use prior)
    eq,                              // PK/PD model
    settings,                        // NPAG settings
)?;

// Stage 2 & 3: Optimize doses and get predictions
let result = posterior.optimize(
    target,                          // Future template with targets
    None,                            // time_offset (None = standard mode)
    DoseRange::new(0.0, 1000.0),     // Dose constraints (0-1000 mg)
    0.5,                             // bias_weight: 0=personalized, 1=population
    Target::Concentration,           // Target type
)?;

// Extract results
println!("Optimal dose: {:?} mg", result.doses());
println!("Final cost: {}", result.objf());
println!("Method: {}", result.optimization_method());

§Algorithm Overview (Three Stages)

┌─────────────────────────────────────────────────────────────────┐
│ STAGE 1: Posterior Density Calculation                         │
│                                                                 │
│  Prior (N points)                                              │
│      ↓                                                         │
│  Step 1.1: NPAGFULL11 - Bayesian Filtering                    │
│      Calculate P(data|θᵢ) for each support point              │
│      Apply Bayes rule: P(θᵢ|data) ∝ P(data|θᵢ) × P(θᵢ)       │
│      Filter: Keep points where P(θᵢ|data) > 1e-100 × max      │
│      ↓                                                         │
│  Filtered Posterior (M points, typically 5-50)                │
│      ↓                                                         │
│  Step 1.2: NPAGFULL - Local Refinement                        │
│      For each filtered point:                                 │
│          Run full NPAG optimization                           │
│          Find refined "daughter" point                        │
│      ↓                                                         │
│  Refined Posterior (M points with NPAGFULL11 weights)         │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ STAGE 2: Dual Optimization                                     │
│                                                                 │
│  Optimization 1: Posterior Weights (Patient-Specific)          │
│      Minimize Cost = (1-λ)×Variance + λ×Bias²                 │
│      Using NPAGFULL11 posterior weights                        │
│      ↓                                                         │
│  Result 1: (doses₁, cost₁)                                     │
│                                                                 │
│  Optimization 2: Uniform Weights (Population)                  │
│      Minimize Cost = (1-λ)×Variance + λ×Bias²                 │
│      Using uniform weights (1/M for all points)                │
│      ↓                                                         │
│  Result 2: (doses₂, cost₂)                                     │
│                                                                 │
│  Select Best: min(cost₁, cost₂)                                │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ STAGE 3: Final Predictions                                     │
│                                                                 │
│  Calculate predictions with optimal doses                       │
│  For AUC targets: Use dense time grid + trapezoidal rule      │
│    - AUCFromZero: Cumulative from time 0                       │
│    - AUCFromLastDose: Interval from last dose                  │
│  Return: Optimal doses, cost, predictions, method used         │
└─────────────────────────────────────────────────────────────────┘

§Mathematical Foundation

§Bayesian Posterior

The posterior density is calculated via Bayes’ rule:

P(θ | data) = P(data | θ) × P(θ) / P(data)

Where:

  • P(θ | data): Posterior (patient-specific parameters)
  • P(data | θ): Likelihood (from error model)
  • P(θ): Prior (from population)
  • P(data): Normalizing constant

§Cost Function

The optimization minimizes a hybrid cost function:

Cost = (1-λ) × Variance + λ × Bias²

Variance Term (Patient-Specific Performance):

Variance = Σᵢ P(θᵢ|data) × Σⱼ (target[j] - pred[i,j])²

Expected squared error using posterior weights.

Bias Term (Population-Level Performance):

Bias² = Σⱼ (target[j] - E[pred[j]])²
where E[pred[j]] = Σᵢ P(θᵢ) × pred[i,j]

Squared deviation from population mean prediction using prior weights.

Bias Weight Parameter (λ):

  • λ = 0.0: Fully personalized (minimize variance only)
  • λ = 0.5: Balanced hybrid approach
  • λ = 1.0: Population-based (minimize bias from population)

§Examples

§Single Dose Optimization

use pmcore::bestdose::{BestDosePosterior, Target, DoseRange};
use pharmsol::prelude::Subject;

// Define target: 5 mg/L at 24 hours
let target = Subject::builder("patient_001")
    .bolus(0.0, 0.0, 0)             // Dose placeholder (will be optimized)
    .observation(24.0, 5.0, 0)      // Target: 5 mg/L at 24h
    .build();

let posterior = BestDosePosterior::compute(
    &population_theta, &population_weights, Some(past), eq, settings,
)?;

let result = posterior.optimize(
    target, None,
    DoseRange::new(10.0, 500.0),    // 10-500 mg allowed
    0.3,                             // Slight population emphasis
    Target::Concentration,
)?;

println!("Optimal dose: {} mg", result.doses()[0]);

§Multiple Doses with AUC Target

use pmcore::bestdose::{BestDosePosterior, Target, DoseRange};
use pharmsol::prelude::Subject;

// Target: Achieve AUC₂₄ = 400 mg·h/L
let target = Subject::builder("patient_002")
    .bolus(0.0, 0.0, 0)             // Dose 1 placeholder (optimized)
    .bolus(12.0, 0.0, 0)            // Dose 2 placeholder (optimized)
    .observation(24.0, 400.0, 0)    // Target: AUC₂₄ = 400
    .build();

let posterior = BestDosePosterior::compute(
    &population_theta, &population_weights, Some(past), eq, settings,
)?;

let result = posterior.optimize(
    target, None,
    DoseRange::new(50.0, 300.0),
    0.0,                             // Full personalization
    Target::AUCFromZero,             // Cumulative AUC target!
)?;

println!("Dose 1: {} mg at t=0", result.doses()[0]);
println!("Dose 2: {} mg at t=12", result.doses()[1]);
if let Some(auc) = result.auc_predictions() {
    println!("Predicted AUC₂₄: {} mg·h/L", auc[0].1);
}

§Population-Only Optimization

// No patient history - use population prior directly
let posterior = BestDosePosterior::compute(
    &population_theta, &population_weights,
    None,                            // No past data → use prior
    eq, settings,
)?;

let result = posterior.optimize(
    target, None,
    DoseRange::new(0.0, 1000.0),
    1.0,                             // Full population weighting
    Target::Concentration,
)?;
// Returns population-typical dose

§Configuration

§Key Parameters

  • bias_weight (λ): Controls personalization level

    • 0.0: Minimize patient-specific variance (full personalization)
    • 1.0: Minimize deviation from population (robustness)
  • max_cycles: NPAGFULL refinement iterations

    • 0: Skip refinement (use filtered points directly)
    • 100-500: Typical range for refinement
  • doserange: Dose constraints

    • Set clinically appropriate bounds for your drug
  • target_type: Optimization target

    • Target::Concentration: Direct concentration targets
    • Target::AUCFromZero: Cumulative AUC from time 0
    • Target::AUCFromLastDose: Interval AUC from last dose

§See Also

Structs§

BestDosePosterior
The computed Bayesian posterior for a patient
BestDoseResult
Result from BestDose optimization
DoseRange
Allowable dose range constraints

Enums§

BestDoseStatus
Status of the BestDose optimization
OptimalMethod
Optimization method used in BestDose
Target
Target type for dose optimization