use std::fs::File;
use std::time::{Duration, Instant};
use serde::Serialize;
use crate::input::{Input, InputSet};
#[derive(Serialize, Clone)]
pub struct Point {
pub size: usize,
pub time: Duration,
}
#[derive(Serialize, Clone)]
pub struct Measurement {
pub algorithm_name: String,
pub measurement: Vec<Point>,
}
#[derive(Serialize, Clone)]
pub struct Measurements {
pub measurements: Vec<Measurement>,
pub relative_error: f32,
pub resolution: Duration,
}
fn get_resolution() -> Duration {
let start = Instant::now();
loop {
let end = start.elapsed();
if end != Duration::ZERO {
return end;
}
}
}
fn get_average_resolution() -> Duration {
let mut sum = Duration::ZERO;
for _ in 0..100 {
sum += get_resolution();
}
sum / 100
}
fn get_time<I, O, Alg>(f: Alg, input: &I, relative_error: f32, resolution: Duration) -> Duration
where
I: Input,
Alg: Fn(&I) -> O,
{
let mut n = 0;
let min_time_measurable = resolution * ((1.0 / relative_error) + 1.0) as u32;
let mut end: Duration;
let start = Instant::now();
loop {
(f)(input);
n += 1;
end = start.elapsed();
if end > min_time_measurable {
break;
}
}
end / n
}
fn get_time_mut<I, O, Alg>(f: Alg, input: &I, relative_error: f32, resolution: Duration) -> Duration
where
I: Input + Clone,
Alg: Fn(&mut I) -> O,
{
let mut n = 0;
let min_time_measurable = resolution * ((1.0 / relative_error) + 1.0) as u32;
let mut end: Duration;
let mut start = Instant::now();
loop {
let start_input_clone = Instant::now();
let input_cloned = &mut input.clone();
n += 1;
let end_input_clone = start_input_clone.elapsed();
(f)(input_cloned);
start += end_input_clone;
end = start.elapsed();
if end > min_time_measurable {
break;
}
}
end / n
}
fn get_time_same_length<I, O, Alg>(
f: &Alg,
inputs: &Vec<I>,
relative_error: f32,
resolution: Duration,
) -> Point
where
I: Input,
Alg: Fn(&I) -> O,
{
let mut total_time = Duration::ZERO;
let size = inputs[0].get_size();
for input in inputs {
let time = get_time(f, input, relative_error, resolution);
total_time += time;
}
Point {
size,
time: total_time,
}
}
fn get_time_same_length_mut<I, O, Alg>(
f: &Alg,
inputs: &Vec<I>,
relative_error: f32,
resolution: Duration,
) -> Point
where
I: Input + Clone,
Alg: Fn(&mut I) -> O,
{
let mut total_time = Duration::ZERO;
let size = inputs[0].get_size();
for input in inputs {
let time = get_time_mut(f, input, relative_error, resolution);
total_time += time;
}
Point {
size,
time: total_time,
}
}
fn get_times<I, O, Alg>(
f: &Alg,
f_name: &str,
inputs: &InputSet<I>,
relative_error: f32,
resolution: Duration,
) -> Measurement
where
I: Input,
Alg: Fn(&I) -> O,
{
let n = inputs.inputs.len();
let mut times = Vec::with_capacity(n);
for (_i, input) in inputs.inputs.iter().enumerate() {
let time = get_time_same_length(f, input, relative_error, resolution);
times.push(time);
#[cfg(feature = "debug")]
{
if _i % (n / 20) == 0 {
println!("{}%", _i * 100 / n);
}
}
}
Measurement {
algorithm_name: f_name.to_owned(), measurement: times,
}
}
fn get_times_mut<I, O, Alg>(
f: &Alg,
f_name: &str,
inputs: &InputSet<I>,
relative_error: f32,
resolution: Duration,
) -> Measurement
where
I: Input + Clone,
Alg: Fn(&mut I) -> O,
{
let n = inputs.inputs.len();
let mut times = Vec::with_capacity(n);
for (_i, input) in inputs.inputs.iter().enumerate() {
let time = get_time_same_length_mut(f, input, relative_error, resolution);
times.push(time);
#[cfg(feature = "debug")]
{
if _i % (n / 20) == 0 {
println!("{}%", _i * 100 / n);
}
}
}
Measurement {
algorithm_name: f_name.to_owned(), measurement: times,
}
}
pub fn measure<I, O, Alg>(
inputs: &InputSet<I>,
algorithms: &[(Alg, &str)],
relative_error: f32,
) -> Measurements
where
I: Input,
Alg: Fn(&I) -> O,
{
assert!(relative_error > 0.0, "Relative error must be positive");
let resolution = get_average_resolution();
let mut results = Vec::with_capacity(algorithms.len());
for (_i, algorithm) in algorithms.iter().enumerate() {
#[cfg(feature = "debug")]
println!(
"\n\nProcessing {} ({}/{})...\n",
algorithm.1, _i + 1,
algorithms.len()
);
let measurement = get_times(
&algorithm.0,
algorithm.1,
inputs,
relative_error,
resolution,
);
results.push(measurement);
}
Measurements {
measurements: results,
relative_error,
resolution,
}
}
pub fn measure_mut<I, O, Alg>(
inputs: &InputSet<I>,
algorithms: &[(Alg, &str)],
relative_error: f32,
) -> Measurements
where
I: Input + Clone,
Alg: Fn(&mut I) -> O,
{
assert!(relative_error > 0.0, "Relative error must be positive");
let resolution = get_average_resolution();
let mut results = Vec::with_capacity(algorithms.len());
for (_i, algorithm) in algorithms.iter().enumerate() {
#[cfg(feature = "debug")]
println!(
"\n\nProcessing {} ({}/{})...\n",
algorithm.1, _i + 1,
algorithms.len()
);
let measurement = get_times_mut(
&algorithm.0,
algorithm.1,
inputs,
relative_error,
resolution,
);
results.push(measurement);
}
Measurements {
measurements: results,
relative_error,
resolution,
}
}
impl Measurement {
pub fn max_time(&self) -> Duration {
self.measurement
.iter()
.max_by_key(|point| point.time)
.unwrap()
.time
}
pub fn min_time(&self) -> Duration {
self.measurement
.iter()
.min_by_key(|point| point.time)
.unwrap()
.time
}
pub fn max_length(&self) -> usize {
self.measurement
.iter()
.max_by_key(|point| point.size)
.unwrap()
.size
}
pub fn min_length(&self) -> usize {
self.measurement
.iter()
.min_by_key(|point| point.size)
.unwrap()
.size
}
pub fn linear_regression(&self) -> (f32, f32) {
let mut sum_x = 0.0;
let mut sum_y = 0.0;
let mut sum_xy = 0.0;
let mut sum_xx = 0.0;
let mut n = 0.0;
for point in &self.measurement {
let x = point.size as f32;
let y = point.time.as_micros() as f32;
sum_x += x;
sum_y += y;
sum_xy += x * y;
sum_xx += x * x;
n += 1.0;
}
let slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
let intercept = (sum_y - slope * sum_x) / n;
(slope, intercept)
}
pub fn log_log_scale(&self) -> Self {
let mut new_measurement = Measurement {
algorithm_name: self.algorithm_name.clone(),
measurement: Vec::with_capacity(self.measurement.len()),
};
for point in &self.measurement {
new_measurement.measurement.push(Point {
size: (point.size as f32).log2() as usize,
time: Duration::from_micros((point.time.as_micros() as f32).log2() as u64),
});
}
new_measurement
}
}
impl Measurements {
pub fn max_time(&self) -> Duration {
self.measurements
.iter()
.max_by_key(|measurement| measurement.max_time())
.unwrap()
.max_time()
}
pub fn min_time(&self) -> Duration {
self.measurements
.iter()
.min_by_key(|measurement| measurement.min_time())
.unwrap()
.min_time()
}
pub fn max_length(&self) -> usize {
self.measurements
.iter()
.max_by_key(|measurement| measurement.max_length())
.unwrap()
.max_length()
}
pub fn min_length(&self) -> usize {
self.measurements
.iter()
.min_by_key(|measurement| measurement.min_length())
.unwrap()
.min_length()
}
pub fn log_log_scale(&self) -> Self {
let mut new_measurements = Measurements {
measurements: Vec::with_capacity(self.measurements.len()),
relative_error: self.relative_error,
resolution: self.resolution,
};
for measurement in &self.measurements {
new_measurements
.measurements
.push(measurement.log_log_scale());
}
new_measurements
}
pub fn serialize_json(&self, filename: &str) {
let mut file = File::create(filename).unwrap();
serde_json::to_writer(&mut file, &self).unwrap();
}
}