1use rayon::prelude::*;
4
5use super::compression::{
6 NcdComputeOptions, NcdVariant, OperationParallelism, try_compress_size_backend,
7 try_ncd_bytes_backend_with_options, try_ncd_matrix_bytes_backend_with_options,
8};
9use super::metrics::{
10 d_kl_bytes, js_div_bytes, nhd_bytes, try_conditional_entropy_bytes, try_cross_entropy_bytes,
11 try_mutual_information_bytes, try_ned_bytes, try_nte_bytes, tvd_bytes,
12};
13use super::types::CompressionBackend;
14use crate::error::{InfotheoryError, InfotheoryResult};
15use crate::spec::CompiledCompressionBackend;
16use rayon::ThreadPoolBuilder;
17
18#[inline(always)]
19fn try_read_path_pair(x: &str, y: &str) -> InfotheoryResult<(Vec<u8>, Vec<u8>)> {
20 let (bx, by) = rayon::join(
21 || std::fs::read(x).map_err(InfotheoryError::from),
22 || std::fs::read(y).map_err(InfotheoryError::from),
23 );
24 Ok((bx?, by?))
25}
26
27#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
29pub struct CompressionPathBatchOptions {
30 pub parallelism: OperationParallelism,
32}
33
34pub fn try_get_compressed_size_path_backend(
36 path: &str,
37 backend: &CompiledCompressionBackend,
38) -> InfotheoryResult<u64> {
39 let data = std::fs::read(path)?;
40 try_compress_size_backend(&data, backend)
41}
42
43#[inline(always)]
44pub fn try_get_bytes_from_paths(paths: &[&str]) -> InfotheoryResult<Vec<Vec<u8>>> {
46 paths
47 .par_iter()
48 .map(|path| std::fs::read(*path).map_err(InfotheoryError::from))
49 .collect()
50}
51
52pub fn try_get_compressed_sizes_from_paths_backend(
54 paths: &[&str],
55 backend: &CompiledCompressionBackend,
56) -> InfotheoryResult<Vec<u64>> {
57 try_get_compressed_sizes_from_paths_backend_with_options(
58 paths,
59 backend,
60 CompressionPathBatchOptions::default(),
61 )
62}
63
64pub fn try_get_compressed_sizes_from_paths_backend_with_options(
67 paths: &[&str],
68 backend: &CompiledCompressionBackend,
69 options: CompressionPathBatchOptions,
70) -> InfotheoryResult<Vec<u64>> {
71 match options.parallelism {
72 OperationParallelism::Serial => paths
73 .iter()
74 .map(|path| try_get_compressed_size_path_backend(path, backend))
75 .collect(),
76 OperationParallelism::Auto => paths
77 .par_iter()
78 .map(|path| try_get_compressed_size_path_backend(path, backend))
79 .collect(),
80 OperationParallelism::Threads(threads) => {
81 if threads <= 1 {
82 return paths
83 .iter()
84 .map(|path| try_get_compressed_size_path_backend(path, backend))
85 .collect();
86 }
87 let pool = ThreadPoolBuilder::new()
88 .num_threads(threads)
89 .build()
90 .map_err(|err| {
91 InfotheoryError::runtime(format!("failed to build rayon pool: {err}"))
92 })?;
93 pool.install(|| {
94 paths
95 .par_iter()
96 .map(|path| try_get_compressed_size_path_backend(path, backend))
97 .collect()
98 })
99 }
100 }
101}
102
103pub fn try_ncd_paths_backend(
105 x: &str,
106 y: &str,
107 backend: &CompressionBackend,
108 variant: NcdVariant,
109) -> InfotheoryResult<f64> {
110 let (bx, by) = rayon::join(
111 || std::fs::read(x).map_err(InfotheoryError::from),
112 || std::fs::read(y).map_err(InfotheoryError::from),
113 );
114 let compiled = backend
115 .compile()
116 .map_err(|err| InfotheoryError::invalid_backend_config(err.to_string()))?;
117 try_ncd_bytes_backend_with_options(&bx?, &by?, &compiled, variant, NcdComputeOptions::default())
118}
119
120#[inline(always)]
121pub fn try_ncd_paths_compiled_backend(
123 x: &str,
124 y: &str,
125 backend: &CompiledCompressionBackend,
126 variant: NcdVariant,
127) -> InfotheoryResult<f64> {
128 try_ncd_paths_compiled_backend_with_options(
129 x,
130 y,
131 backend,
132 variant,
133 NcdComputeOptions::default(),
134 )
135}
136
137pub fn try_ncd_paths_compiled_backend_with_options(
140 x: &str,
141 y: &str,
142 backend: &CompiledCompressionBackend,
143 variant: NcdVariant,
144 options: NcdComputeOptions,
145) -> InfotheoryResult<f64> {
146 let (bx, by) = rayon::join(
147 || std::fs::read(x).map_err(InfotheoryError::from),
148 || std::fs::read(y).map_err(InfotheoryError::from),
149 );
150 try_ncd_bytes_backend_with_options(&bx?, &by?, backend, variant, options)
151}
152
153pub fn try_ncd_matrix_paths_backend(
155 paths: &[&str],
156 backend: &CompiledCompressionBackend,
157 variant: NcdVariant,
158) -> InfotheoryResult<Vec<f64>> {
159 try_ncd_matrix_paths_backend_with_options(paths, backend, variant, NcdComputeOptions::default())
160}
161
162pub fn try_ncd_matrix_paths_backend_with_options(
166 paths: &[&str],
167 backend: &CompiledCompressionBackend,
168 variant: NcdVariant,
169 options: NcdComputeOptions,
170) -> InfotheoryResult<Vec<f64>> {
171 let datas = try_get_bytes_from_paths(paths)?;
172 try_ncd_matrix_bytes_backend_with_options(&datas, backend, variant, options)
173}
174
175pub fn try_ned_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
177 let (bx, by) = try_read_path_pair(x, y)?;
178 try_ned_bytes(&bx, &by)
179}
180
181pub fn try_nte_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
183 let (bx, by) = try_read_path_pair(x, y)?;
184 try_nte_bytes(&bx, &by)
185}
186
187pub fn try_tvd_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
189 let (bx, by) = try_read_path_pair(x, y)?;
190 Ok(tvd_bytes(&bx, &by))
191}
192
193pub fn try_nhd_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
195 let (bx, by) = try_read_path_pair(x, y)?;
196 Ok(nhd_bytes(&bx, &by))
197}
198
199pub fn try_mutual_information_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
201 let (bx, by) = try_read_path_pair(x, y)?;
202 try_mutual_information_bytes(&bx, &by)
203}
204
205pub fn try_conditional_entropy_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
207 let (bx, by) = try_read_path_pair(x, y)?;
208 try_conditional_entropy_bytes(&bx, &by)
209}
210
211pub fn try_cross_entropy_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
213 let (bx, by) = try_read_path_pair(x, y)?;
214 try_cross_entropy_bytes(&bx, &by)
215}
216
217pub fn try_kl_divergence_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
219 let (bx, by) = try_read_path_pair(x, y)?;
220 Ok(d_kl_bytes(&bx, &by))
221}
222
223pub fn try_js_divergence_paths(x: &str, y: &str) -> InfotheoryResult<f64> {
225 let (bx, by) = try_read_path_pair(x, y)?;
226 Ok(js_div_bytes(&bx, &by))
227}