Skip to content

Commit

Permalink
rust: Read ops as ref
Browse files Browse the repository at this point in the history
  • Loading branch information
felixhekhorn committed Aug 19, 2024
1 parent b3c3682 commit 19dcd27
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 92 deletions.
4 changes: 0 additions & 4 deletions crates/dekoder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ version.workspace = true
[package.metadata.docs.rs]
rustdoc-args = ["--html-in-header", "doc-header.html"]

[lib]
name = "ekors"
crate-type = ["cdylib"]

[dependencies]
tar = "0.4.41"
hashbrown = "0.14"
Expand Down
31 changes: 21 additions & 10 deletions crates/dekoder/src/inventory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,18 @@ pub(crate) trait ValueT {
// File suffix (instead of header suffix)
const FILE_SUFFIX: &'static str;
/// Load from file.
fn load_from_path(p: PathBuf) -> Self;
fn load_from_path(&mut self, p: PathBuf);
}

/// Assets manager.
pub(crate) struct Inventory<K: HeaderT, V: ValueT> {
pub(crate) struct Inventory<K: HeaderT> {
/// Working directory
pub(crate) path: PathBuf,
/// Available keys
pub(crate) keys: HashMap<OsString, K>,
/// Available values (in memory)
pub(crate) values: HashMap<OsString, V>,
}

impl<K: HeaderT, V: ValueT> Inventory<K, V> {
impl<K: HeaderT> Inventory<K> {
/// Load all available entries.
pub fn load_keys(&mut self) {
for entry in glob(self.path.join(&HEADER_EXT).to_str().unwrap())
Expand All @@ -50,14 +48,27 @@ impl<K: HeaderT, V: ValueT> Inventory<K, V> {
);
}
}

/// List available keys.
pub fn keys(&self) -> Vec<&K> {
let mut ks = Vec::new();
for k in self.keys.values() {
ks.push(k);
}
ks
}

/// Check if `k` is available (with given precision).
pub fn get(&mut self, k: &K, ulps: i64) -> Option<V> {
pub fn has(&self, k: &K, ulps: i64) -> bool {
self.keys.iter().find(|it| (it.1).eq(&k, ulps)).is_some()
}

/// Load `k` from disk.
pub fn load<V: ValueT>(&mut self, k: &K, ulps: i64, v: &mut V) {
let k = self.keys.iter().find(|it| (it.1).eq(&k, ulps));
let k = k?;
let k = k.unwrap();
let path = self.path.join(k.0).with_extension(V::FILE_SUFFIX);
let v = V::load_from_path(path);
// self.values.insert(k.0.clone(), &v);
Some(v)
v.load_from_path(path);
}
}

Expand Down
97 changes: 25 additions & 72 deletions crates/dekoder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ mod inventory;
/// A reference point in the evolution atlas.
pub struct EvolutionPoint {
/// Evolution scale.
scale: f64,
pub scale: f64,
/// Number of flavors
nf: i64,
pub nf: i64,
}

impl inventory::HeaderT for EvolutionPoint {
Expand All @@ -35,6 +35,7 @@ impl inventory::HeaderT for EvolutionPoint {
nf: yml["nf"].as_i64().unwrap(),
}
}

/// Comparator.
fn eq(&self, other: &Self, ulps: i64) -> bool {
self.nf == other.nf && approx_eq!(f64, self.scale, other.scale, ulps = ulps)
Expand All @@ -43,18 +44,27 @@ impl inventory::HeaderT for EvolutionPoint {

/// 4D evolution operator.
pub struct Operator {
ar: Array4<f64>,
pub ar: Array4<f64>,
}

impl inventory::ValueT for Operator {
const FILE_SUFFIX: &'static str = "npz.lz4";
fn load_from_path(p: PathBuf) -> Self {
fn load_from_path(&mut self, p: PathBuf) {
let mut reader = BufReader::new(FrameDecoder::new(BufReader::new(File::open(p).unwrap())));
let mut buffer = Vec::new();
std::io::copy(&mut reader, &mut buffer).unwrap();
let mut npz = NpzReader::new(Cursor::new(buffer)).unwrap();
let operator: Array4<f64> = npz.by_name("operator.npy").unwrap();
Self { ar: operator }
self.ar = operator
}
}

impl Operator {
/// Empty initializer.
pub fn zeros() -> Self {
Self {
ar: Array4::zeros((0, 0, 0, 0)),
}
}
}

Expand All @@ -67,7 +77,7 @@ pub struct EKO {
/// allow content modifications?
read_only: bool,
/// final operators
operators: inventory::Inventory<EvolutionPoint, Operator>,
operators: inventory::Inventory<EvolutionPoint>,
}

/// Operators directory.
Expand Down Expand Up @@ -165,7 +175,6 @@ impl EKO {
let mut operators = inventory::Inventory {
path: path.join(DIR_OPERATORS),
keys: HashMap::new(),
values: HashMap::new(),
};
operators.load_keys();
Self {
Expand All @@ -176,74 +185,18 @@ impl EKO {
}
}

/// Check if the operator at the evolution point `ep` is available.
pub fn get_operator(&mut self, ep: &EvolutionPoint, ulps: i64) -> Option<Operator> {
self.operators.get(ep, ulps)
/// List available evolution points.
pub fn available_operators(&self) -> Vec<&EvolutionPoint> {
self.operators.keys()
}
}

mod test {
#[test]
fn save_as_other() {
use super::EKO;
use std::fs::{remove_dir_all, remove_file};
use std::path::PathBuf;
let base: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect();
let src = base.join("data").join("v0.15.tar");
assert!(src.try_exists().is_ok_and(|x| x));
let dst = base.join("target").join("v0.15");
// get rid of previous runs if needed
let dst_exists = dst.try_exists().is_ok_and(|x| x);
if dst_exists {
let _ = remove_dir_all(dst.to_owned());
}
// open
let mut eko = EKO::edit(src.to_owned(), dst.to_owned());
let dst_exists = dst.try_exists().is_ok_and(|x| x);
assert!(dst_exists);
// set a different output
let tarb = base.join("target").join("v0.15b.tar");
let tarb_exists = tarb.try_exists().is_ok_and(|x| x);
if tarb_exists {
let _ = remove_file(tarb.to_owned());
}
eko.set_tar_path(tarb.to_owned());
// close
let res = eko.close(true);
assert!(res.is_ok());
assert!(tarb.try_exists().is_ok_and(|x| x));
let dst_exists = dst.try_exists().is_ok_and(|x| x);
assert!(!dst_exists);
// clean up
if dst_exists {
let _ = remove_dir_all(dst.to_str().unwrap());
}
/// Check if the operator at the evolution point `ep` is available.
pub fn has_operator(&self, ep: &EvolutionPoint, ulps: i64) -> bool {
self.operators.has(ep, ulps)
}

#[test]
fn has_operator() {
use super::{EvolutionPoint, EKO};
use std::fs::remove_dir_all;
use std::path::PathBuf;
let base: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect();
let src = base.join("data").join("v0.15.tar");
assert!(src.try_exists().is_ok_and(|x| x));
let dst = base.join("target").join("v0.15");
// get rid of previous runs if needed
let dst_exists = dst.try_exists().is_ok_and(|x| x);
if dst_exists {
let _ = remove_dir_all(dst.to_owned());
}
// open
let mut eko = EKO::read(src.to_owned(), dst.to_owned());
assert!(eko
.get_operator(
&EvolutionPoint {
scale: 10000.,
nf: 4
},
64
)
.is_some());
/// Load the operator at the evolution point `ep` from disk.
pub fn load_operator(&mut self, ep: &EvolutionPoint, ulps: i64, op: &mut Operator) {
self.operators.load(ep, ulps, op);
}
}
6 changes: 0 additions & 6 deletions crates/dekoder/tests/load.rs

This file was deleted.

87 changes: 87 additions & 0 deletions crates/dekoder/tests/test_load.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use dekoder::{EvolutionPoint, Operator, EKO};
use std::fs::{remove_dir_all, remove_file};
use std::path::PathBuf;

#[test]
fn save_as_other() {
let base: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect();
let src = base.join("data").join("v0.15.tar");
assert!(src.try_exists().is_ok_and(|x| x));
let dst = base.join("target").join("v0.15a");
// get rid of previous runs if needed
let dst_exists = dst.try_exists().is_ok_and(|x| x);
if dst_exists {
remove_dir_all(dst.to_owned()).unwrap();
}
// open
let mut eko = EKO::edit(src.to_owned(), dst.to_owned());
let dst_exists = dst.try_exists().is_ok_and(|x| x);
assert!(dst_exists);
// set a different output
let tarb = base.join("target").join("v0.15b.tar");
let tarb_exists = tarb.try_exists().is_ok_and(|x| x);
if tarb_exists {
remove_file(tarb.to_owned()).unwrap();
}
eko.set_tar_path(tarb.to_owned());
// close
eko.close(true).unwrap();
let tarb_exists = tarb.try_exists().is_ok_and(|x| x);
assert!(tarb_exists);
let dst_exists = dst.try_exists().is_ok_and(|x| x);
assert!(!dst_exists);
// clean up
if tarb_exists {
remove_file(tarb.to_owned()).unwrap();
}
if dst_exists {
remove_dir_all(dst.to_str().unwrap()).unwrap();
}
}

#[test]
fn has_operator() {
let base: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect();
let src = base.join("data").join("v0.15.tar");
assert!(src.try_exists().is_ok_and(|x| x));
let dst = base.join("target").join("v0.15b");
// get rid of previous runs if needed
let dst_exists = dst.try_exists().is_ok_and(|x| x);
if dst_exists {
remove_dir_all(dst.to_owned()).unwrap();
}
// open
let eko = EKO::read(src.to_owned(), dst.to_owned());
// check there is only one:
assert!(eko.available_operators().len() == 1);
// ask for one
let ep = EvolutionPoint {
scale: 10000.,
nf: 4,
};
assert!(eko.has_operator(&ep, 64));
eko.close(false).unwrap();
}

#[test]
fn load_operator() {
let base: PathBuf = [env!("CARGO_MANIFEST_DIR"), "tests"].iter().collect();
let src = base.join("data").join("v0.15.tar");
assert!(src.try_exists().is_ok_and(|x| x));
let dst = base.join("target").join("v0.15c");
// get rid of previous runs if needed
let dst_exists = dst.try_exists().is_ok_and(|x| x);
if dst_exists {
remove_dir_all(dst.to_owned()).unwrap();
}
// open
let mut eko = EKO::read(src.to_owned(), dst.to_owned());
let ep = EvolutionPoint {
scale: 10000.,
nf: 4,
};
let mut op = Operator::zeros();
eko.load_operator(&ep, 64, &mut op);
assert!(op.ar.dim().0 > 0);
eko.close(false).unwrap();
}

0 comments on commit 19dcd27

Please sign in to comment.