#[doc(alias = "gsl_interp_accel")]
#[derive(Default, Debug, Clone)]
pub struct Accelerator {
pub(crate) cache: usize,
pub(crate) hits: usize,
pub(crate) misses: usize,
}
#[doc(alias = "gsl_interp_bsearch")]
fn bsearch(xarray: &[f64], x: f64, ilo: usize, ihi: usize) -> usize {
let mut ilo = ilo;
let mut ihi = ihi;
while ihi > ilo + 1 {
let i = ihi.midpoint(ilo);
if xarray[i] > x {
ihi = i;
} else {
ilo = i;
}
}
ilo
}
impl Accelerator {
#[must_use]
pub fn new() -> Self {
Accelerator {
cache: 0,
hits: 0,
misses: 0,
}
}
#[doc(alias = "gsl_interp_accel_find")]
pub(crate) fn find(&mut self, xarray: &[f64], x: f64) -> usize {
if x < xarray[self.cache] {
self.misses += 1;
self.cache = bsearch(xarray, x, 0, self.cache);
} else if x >= xarray[self.cache + 1] {
self.misses += 1;
self.cache = bsearch(xarray, x, self.cache, xarray.len() - 1);
} else {
self.hits += 1;
}
self.cache
}
#[doc(alias = "gsl_interp_accel_reset")]
pub fn reset(&mut self) {
self.cache = 0;
self.hits = 0;
self.misses = 0;
}
#[must_use]
pub fn hits(&self) -> usize {
self.hits
}
#[must_use]
pub fn misses(&self) -> usize {
self.misses
}
#[must_use]
pub fn cache(&self) -> usize {
self.cache
}
}
#[cfg(test)]
mod test {
use super::*;
fn setup_acc() -> Accelerator {
Accelerator::new()
}
fn setup_xarray() -> [f64; 5] {
[0.0, 1.0, 2.0, 3.0, 4.0]
}
#[test]
fn instantiation() {
let acc = Accelerator::default();
let _ = format!("{:?}", acc);
assert_eq!(acc.hits(), 0);
assert_eq!(acc.misses(), 0);
assert_eq!(acc.cache(), 0);
}
#[test]
fn reset() {
let mut acc = Accelerator::new();
acc.cache = 1;
acc.hits = 1;
acc.misses = 1;
acc.reset();
assert_eq!(acc.cache, 0);
assert_eq!(acc.hits, 0);
assert_eq!(acc.misses, 0);
}
#[test]
fn bsearch_interior_point() {
let (_, xarray) = (setup_acc(), setup_xarray());
let res = bsearch(&xarray, 1.5, 0, 4);
assert_eq!(res, 1);
}
#[test]
fn search_last_value() {
let (_, xarray) = (setup_acc(), setup_xarray());
let res = bsearch(&xarray, 4.0, 0, 4);
assert_eq!(res, 3);
}
#[test]
fn search_first_value() {
let (_, xarray) = (setup_acc(), setup_xarray());
let res = bsearch(&xarray, 0.0, 0, 4);
assert_eq!(res, 0);
}
#[test]
fn bsearch_boundary() {
let (_, xarray) = (setup_acc(), setup_xarray());
let res = bsearch(&xarray, 2.0, 0, 4);
assert_eq!(res, 2);
}
#[test]
fn bsearch_above_bounds() {
let (_, xarray) = (setup_acc(), setup_xarray());
let res = bsearch(&xarray, 10.0, 0, 4);
assert_eq!(res, 3);
}
#[test]
fn bsearch_below_bounds() {
let (_, xarray) = (setup_acc(), setup_xarray());
let res = bsearch(&xarray, -10.0, 0, 4);
assert_eq!(res, 0);
}
#[test]
fn accelerator() {
let xarray = setup_xarray();
let mut acc = setup_acc();
let mut k1 = 0;
let mut k2 = 0;
let mut t = false;
let r = [
-0.2, 0.0, 0.1, 0.7, 1.0, 1.3, 1.9, 2.0, 2.2, 2.7, 3.0, 3.1, 3.6, 4.0, 4.1, 4.9,
];
while (k1 < 16) & (k2 < 16) {
let x = if t { r[k1] } else { r[k2] };
t = !t;
if !t {
k1 = (k1 + 1) % 16;
if k1 == 0 {
k2 += 1;
}
}
let i = acc.find(&xarray, x);
let j = bsearch(&xarray, x, 0, 4);
assert_eq!(i, j);
}
}
}