diff --git a/Cargo.toml b/Cargo.toml index 654af06e4..8854a4c1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ tracing-subscriber = { version = "0.3.19", features = [ "time", ] } faer = "0.24.0" -pharmsol = { version = "=0.28.8" } +pharmsol = { version = "=0.29.0" } anyhow = "1.0.100" rayon = "1.10.0" rand = "0.10.1" @@ -37,10 +37,7 @@ rand = "0.10.1" default = [] json = [] exa = [] -dsl-core = ["pharmsol/dsl-core"] -dsl-jit = ["pharmsol/dsl-jit"] -dsl-aot = ["pharmsol/dsl-aot"] -dsl-aot-load = ["pharmsol/dsl-aot-load"] +dsl = ["pharmsol/dsl"] [profile.release] codegen-units = 1 @@ -59,8 +56,13 @@ name = "bimodal_ke" harness = false # The BestDose example defines its model from a DSL text string, which requires -# a runtime DSL backend. Build/run it with: `--features dsl-jit`. +# a runtime DSL backend. Build/run it with: `--features dsl`. [[example]] name = "bestdose" path = "examples/bestdose/main.rs" -required-features = ["dsl-jit"] +required-features = ["dsl"] + +[[example]] +name = "bimodal_ke_backend_compare" +path = "examples/bimodal_ke_backend_compare.rs" +required-features = ["dsl"] diff --git a/examples/bestdose/main.rs b/examples/bestdose/main.rs index 82a682b31..ed1ac12e2 100644 --- a/examples/bestdose/main.rs +++ b/examples/bestdose/main.rs @@ -1,7 +1,5 @@ use anyhow::Result; -use pharmsol::dsl::{ - compile_module_source_to_runtime, CompiledRuntimeModel, RuntimeCompilationTarget, -}; +use pharmsol::dsl::{compile_module_source_to_runtime, CompiledRuntimeModel}; use pharmsol::Equation; use pmcore::bestdose::{BestDoseOptions, BestDoseProblem, DoseRange, Target}; use pmcore::prelude::*; @@ -34,7 +32,6 @@ fn main() -> Result<()> { let eq = match compile_module_source_to_runtime( MODEL_SOURCE, Some("bestdose_one_compartment"), - RuntimeCompilationTarget::Jit, |_, _| {}, ) .map_err(|e| anyhow::anyhow!("failed to compile DSL model: {e}"))? diff --git a/examples/bimodal_ke_backend_compare.rs b/examples/bimodal_ke_backend_compare.rs index 81cf95807..0a5488aae 100644 --- a/examples/bimodal_ke_backend_compare.rs +++ b/examples/bimodal_ke_backend_compare.rs @@ -1,46 +1,12 @@ use std::time::{Duration, Instant}; use anyhow::{anyhow, Result}; +use pharmsol::dsl::{compile_module_source_to_runtime, CompiledRuntimeModel, RuntimeOdeModel}; use pharmsol::Cache; use pmcore::prelude::*; -#[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" -))] -use anyhow::{bail, Context}; -#[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" -))] -use pharmsol::dsl::{self, CompiledRuntimeModel, RuntimeBackend, RuntimeCompilationTarget}; -#[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" -))] -use std::fs; -#[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" -))] -use std::path::PathBuf; -#[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" -))] -use std::time::{SystemTime, UNIX_EPOCH}; - const DATA_PATH: &str = "examples/bimodal_ke/bimodal_ke.csv"; -#[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" -))] + const BIMODAL_KE_DSL: &str = r#" name = bimodal_ke kind = ode @@ -66,18 +32,7 @@ struct ComparisonResult { } fn main() -> Result<()> { - let mut results = Vec::new(); - results.push(run_legacy()?); - results.push(run_macro()?); - - #[cfg(feature = "dsl-jit")] - results.push(run_runtime_jit()?); - - #[cfg(all(feature = "dsl-aot", feature = "dsl-aot-load"))] - results.push(run_runtime_native_aot()?); - - #[cfg(feature = "dsl-wasm")] - results.push(run_runtime_wasm()?); + let results = vec![run_legacy()?, run_macro()?, run_dsl()?]; print_summary(&results)?; @@ -137,62 +92,16 @@ fn macro_equation() -> equation::ODE { .with_solver(OdeSolver::ExplicitRk(ExplicitRkTableau::Tsit45)) } -#[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" -))] -fn artifact_root(name: &str) -> Result { - let stamp = SystemTime::now() - .duration_since(UNIX_EPOCH) - .context("system clock is before unix epoch")? - .as_millis(); - let path = std::env::current_dir()? - .join("target") - .join("bimodal_ke_backend_compare") - .join(format!("{name}-{stamp}-{}", std::process::id())); - fs::create_dir_all(&path)?; - Ok(path) -} - -#[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" -))] -fn compile_runtime_ode( - label: &'static str, - expected_backend: RuntimeBackend, - target: RuntimeCompilationTarget, -) -> Result<(pharmsol::dsl::RuntimeOdeModel, Duration)> { - let started = Instant::now(); - let compiled = dsl::compile_module_source_to_runtime( - BIMODAL_KE_DSL, - Some("bimodal_ke"), - target, - |_, _| {}, - )?; - let compile_time = started.elapsed(); +fn dsl_equation() -> Result { + let compiled = compile_module_source_to_runtime(BIMODAL_KE_DSL, Some("bimodal_ke"), |_, _| {}) + .map_err(|e| anyhow!("failed to compile DSL model: {e}"))?; - let model = match compiled { - CompiledRuntimeModel::Ode(model) => model + match compiled { + CompiledRuntimeModel::Ode(model) => Ok(model .enable_cache() - .with_solver(OdeSolver::ExplicitRk(ExplicitRkTableau::Tsit45)), - CompiledRuntimeModel::Analytical(_) => { - bail!("{label} compiled bimodal_ke as analytical instead of ode") - } - CompiledRuntimeModel::Sde(_) => bail!("{label} compiled bimodal_ke as sde instead of ode"), - }; - - if model.backend() != expected_backend { - bail!( - "{label} compiled to {:?}, expected {:?}", - model.backend(), - expected_backend - ); + .with_solver(OdeSolver::ExplicitRk(ExplicitRkTableau::Tsit45))), + other => Err(anyhow!("expected an ODE model, got {:?}", other.kind())), } - - Ok((model, compile_time)) } fn run_case( @@ -214,15 +123,6 @@ fn run_case( - label: &'static str, - compile_time: Duration, - fit_time: Duration, - result: &NonParametricResult, -) -> Result { Ok(ComparisonResult { label, compile_time, @@ -235,7 +135,7 @@ fn summarize_result( fn run_legacy() -> Result { let started = Instant::now(); let equation = legacy_equation(); - run_case("legacy-handwritten", started.elapsed(), equation) + run_case("handwritten", started.elapsed(), equation) } fn run_macro() -> Result { @@ -244,55 +144,21 @@ fn run_macro() -> Result { run_case("macro-ode", started.elapsed(), equation) } -#[cfg(feature = "dsl-jit")] -fn run_runtime_jit() -> Result { - let (equation, compile_time) = compile_runtime_ode( - "dsl-jit", - RuntimeBackend::Jit, - RuntimeCompilationTarget::Jit, - )?; - run_case("dsl-jit", compile_time, equation) -} - -#[cfg(all(feature = "dsl-aot", feature = "dsl-aot-load"))] -fn run_runtime_native_aot() -> Result { - let root = artifact_root("native-aot")?; - let (equation, compile_time) = compile_runtime_ode( - "dsl-native-aot", - RuntimeBackend::NativeAot, - RuntimeCompilationTarget::NativeAot( - dsl::NativeAotCompileOptions::new(root.join("build")) - .with_output(root.join("bimodal_ke_runtime_aot.pkm")), - ), - )?; - run_case("dsl-native-aot", compile_time, equation) -} - -#[cfg(feature = "dsl-wasm")] -fn run_runtime_wasm() -> Result { - let (equation, compile_time) = compile_runtime_ode( - "dsl-wasm", - RuntimeBackend::Wasm, - RuntimeCompilationTarget::Wasm, - )?; - run_case("dsl-wasm", compile_time, equation) +fn run_dsl() -> Result { + let started = Instant::now(); + let equation = dsl_equation()?; + run_case("dsl-runtime", started.elapsed(), equation) } fn print_summary(results: &[ComparisonResult]) -> Result<()> { let baseline = results .iter() - .find(|result| result.label == "legacy-handwritten") - .ok_or_else(|| anyhow!("missing legacy-handwritten baseline"))?; + .find(|result| result.label == "handwritten") + .ok_or_else(|| anyhow!("missing handwritten baseline"))?; println!("bimodal_ke NPAG backend comparison"); println!("dataset: {DATA_PATH}"); println!("cache: on"); - #[cfg(not(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - feature = "dsl-wasm" - )))] - println!("runtime DSL backends skipped; enable dsl-jit, dsl-aot+dsl-aot-load, or dsl-wasm to include them"); println!(); println!( "{:<18} {:>12} {:>12} {:>12} {:>14} {:>14}", diff --git a/src/model/mod.rs b/src/model/mod.rs index 861d16f1c..9467057ec 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -139,11 +139,7 @@ impl_metadata_opt!(ODE, Analytical, SDE); macro_rules! impl_metadata_some { ($($t:ty),+) => { $( - #[cfg(any( - feature = "dsl-jit", - all(feature = "dsl-aot", feature = "dsl-aot-load"), - all(feature = "dsl-wasm", not(all(target_arch = "wasm32", target_os = "unknown"))) - ))] + #[cfg(feature = "dsl")] impl EquationMetadataSource for $t { fn equation_metadata(&self) -> Option<&ValidatedModelMetadata> { Some(self.metadata()) diff --git a/tests/onecomp.rs b/tests/onecomp.rs index 4520ab4b9..c63509b52 100644 --- a/tests/onecomp.rs +++ b/tests/onecomp.rs @@ -131,7 +131,7 @@ fn test_one_compartment_npod() -> Result<()> { .fit_with(NonParametricAlgorithm::npod())?; // Check the results - assert_eq!(result.cycles(), 12); + assert_eq!(result.cycles(), 11); assert!(result.objf() - 565.7749 < 0.01); Ok(())