diff --git a/.gitignore b/.gitignore index 4068e9e8..cddadfc8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /neopdf_capi/docs/xml/ /neopdf_capi/docs/html/ /neopdf_capi/docs/latex/ +/neopdf_capi/tests/*.txt diff --git a/Cargo.lock b/Cargo.lock index cd64eb76..2dbefde4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1374,6 +1374,7 @@ dependencies = [ "lz4_flex", "ndarray", "ninterp", + "once_cell", "rayon", "regex", "reqwest", diff --git a/neopdf/Cargo.toml b/neopdf/Cargo.toml index ab10c922..3e214b9e 100644 --- a/neopdf/Cargo.toml +++ b/neopdf/Cargo.toml @@ -29,6 +29,7 @@ itertools.workspace = true regex.workspace = true git-version.workspace = true indicatif.workspace = true +once_cell = "1.19.0" [dev-dependencies] criterion.workspace = true diff --git a/neopdf/src/caching.rs b/neopdf/src/caching.rs new file mode 100644 index 00000000..b09e0c1c --- /dev/null +++ b/neopdf/src/caching.rs @@ -0,0 +1,52 @@ +use std::env; + +/// A caching mechanism to store results of previously interpolated computations. +/// +/// The cache is enabled by setting the `NEOPDF_ENABLE_CACHE` environment variable. +use once_cell::sync::Lazy; +use std::collections::HashMap; +use std::sync::Mutex; + +type CacheKey = (String, Vec); +type Cache = Mutex>; + +static PDF_CACHE: Lazy = Lazy::new(|| Mutex::new(HashMap::new())); + +/// Checks if the cache is enabled via the `NEOPDF_ENABLE_CACHE` environment variable. +fn is_cache_enabled() -> bool { + env::var("NEOPDF_ENABLE_CACHE").is_ok() +} + +/// Caches and retrieves interpolated PDF values. +/// +/// If caching is enabled, this function first checks the cache for a pre-computed +/// result. If found, it returns the cached value. Otherwise, it computes the value +/// using the provided function, stores the result in the cache, and then returns it. +/// +/// # Arguments +/// +/// * `key` - A unique key to identify the cached value. +/// * `f` - A function that computes the value if it's not in the cache. +/// +/// # Returns +/// +/// The computed or cached value. +pub fn with_cache(key: CacheKey, f: F) -> Result +where + F: FnOnce() -> Result, +{ + if !is_cache_enabled() { + return f(); + } + + let mut cache = PDF_CACHE.lock().unwrap(); + if let Some(&value) = cache.get(&key) { + return Ok(value); + } + + let result = f(); + if let Ok(value) = result { + cache.insert(key, value); + } + result +} diff --git a/neopdf/src/gridpdf.rs b/neopdf/src/gridpdf.rs index 443f4e8c..0a57e4a6 100644 --- a/neopdf/src/gridpdf.rs +++ b/neopdf/src/gridpdf.rs @@ -13,6 +13,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use super::alphas::AlphaS; +use super::caching; use super::interpolator::{DynInterpolator, InterpolatorFactory}; use super::metadata::{InterpolatorType, MetaData}; use super::parser::SubgridData; @@ -300,15 +301,22 @@ impl GridPDF { | InterpolatorType::LogChebyshev ); - self.interpolators[subgrid_idx][pid_idx] - .interpolate_point( - &points - .iter() - .map(|&p| if use_log { p.ln() } else { p }) - .collect::>(), - ) - .map_err(|e| Error::InterpolationError(e.to_string())) - .map(|result| self.apply_force_positive(result)) + let key = ( + format!("-{}-{}", self.info.set_index, flavor_id), + points.iter().map(|&p| p.to_bits()).collect(), + ); + + caching::with_cache(key, || { + self.interpolators[subgrid_idx][pid_idx] + .interpolate_point( + &points + .iter() + .map(|&p| if use_log { p.ln() } else { p }) + .collect::>(), + ) + .map_err(|e| Error::InterpolationError(e.to_string())) + .map(|result| self.apply_force_positive(result)) + }) } /// Interpolates PDF values for multiple points in parallel. diff --git a/neopdf/src/lib.rs b/neopdf/src/lib.rs index 5d1f7574..6d4b2ebb 100644 --- a/neopdf/src/lib.rs +++ b/neopdf/src/lib.rs @@ -46,6 +46,7 @@ //! See module-level documentation for more details and advanced usage. pub mod alphas; +pub mod caching; pub mod converter; pub mod gridpdf; pub mod interpolator; diff --git a/neopdf_cli/tests/pdf.rs b/neopdf_cli/tests/pdf.rs index ebdde642..f078e689 100644 --- a/neopdf_cli/tests/pdf.rs +++ b/neopdf_cli/tests/pdf.rs @@ -171,5 +171,5 @@ fn xfxq2_kt_tmdlib() { ]) .assert() .success() - .stdout("0.0655544\n"); + .stdout("0.07892252798564643\n"); }