Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error selection #81

Merged
merged 5 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions brro-compressor/src/compressor/fft.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bincode::{Decode, Encode};
use std::{collections::BinaryHeap, cmp::Ordering};
use rustfft::{FftPlanner, num_complex::Complex};
use crate::utils::error::error_smape;
use crate::utils::error::calculate_error;

use super::BinConfig;
use log::{error, debug, warn, info, trace};
Expand Down Expand Up @@ -230,7 +230,7 @@ impl FFT {
let out_data: Vec<f64> = idata.iter()
.map(|&f| self.round(f.re/len_f32, 2))
.collect();
current_err = error_smape(data, &out_data);
current_err = calculate_error(data, &out_data);
trace!("Current Err: {}", current_err);
// Max iterations is 18 (We start at 10%, we can go to 95% and 1% at a time)
match iterations {
Expand Down Expand Up @@ -411,7 +411,7 @@ mod tests {
let frame_size = vector1.len();
let compressed_data = fft_allowed_error(&vector1, 0.01);
let out = FFT::decompress(&compressed_data).to_data(frame_size);
let e = error_smape(&vector1, &out);
let e = calculate_error(&vector1, &out);
assert!(e <= 0.01);
}

Expand Down
52 changes: 28 additions & 24 deletions brro-compressor/src/compressor/polynomial.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::utils::{DECIMAL_PRECISION, error::error_smape, round_and_limit_f64};
use crate::utils::{DECIMAL_PRECISION, error::calculate_error, round_and_limit_f64};

use super::BinConfig;
use bincode::{Decode, Encode};
Expand Down Expand Up @@ -35,13 +35,13 @@ pub struct Polynomial {
/// The minimum numeric value of the points in the frame
pub min_value: f32,
pub min_position: usize,
/// To reduce error, is it worth it?
pub residuals: Vec<(i32, i64)>,
/// What is the base step between points
pub point_step: u8,
}

impl Polynomial {
pub fn new(sample_count: usize, min: f64, max: f64, ptype: PolynomialType) -> Self {
println!("Polynomial compressor: min:{} max:{}, idw: {:?}", min, max, ptype);
debug!("Polynomial compressor: min:{} max:{}, Type: {:?}", min, max, ptype);
Polynomial {
id: ptype,
data_points: Vec::with_capacity(sample_count),
Expand All @@ -51,7 +51,8 @@ impl Polynomial {
min_value: min as f32,
min_position: 0,
max_position: 0,
residuals: Vec::with_capacity(sample_count),
// Minimum step is always 1
point_step: 1,
}
}

Expand Down Expand Up @@ -93,7 +94,7 @@ impl Polynomial {
};
trace!("Calculated Values: {:?}", out_data);
trace!("Data Values: {:?}", data);
current_err = error_smape(data, &out_data);
current_err = calculate_error(data, &out_data);
trace!("Current Err: {}", current_err);
// Max iterations is 18 (We start at 10%, we can go to 95% and 1% at a time)
match iterations {
Expand All @@ -118,14 +119,17 @@ impl Polynomial {
let data_len = data.len();
// Instead of calculation, we use the provided count
let point_count = points;
// Step size
let step = (data_len/point_count).max(1);
// I can calculate the positions from here
let mut points: Vec<f64> = (0..data_len).step_by(data_len/point_count).map(|f| f as f64).collect();
points.push((data_len-1) as f64);
let mut points: Vec<f64> = (0..data_len).step_by(step).map(|f| f as f64).collect();
// Pushing the last value if needed
if points[points.len()-1] != data_len as f64 -1. { points.push(data_len as f64 - 1.); }
cjrolo marked this conversation as resolved.
Show resolved Hide resolved
// I need to extract the values for those points
let mut values: Vec<f64> = points.iter().map(|&f| data[f as usize]).collect();

debug!("Points: {:?}", points);
debug!("Values: {:?}", values);
debug!("Compressed Hinted Points: {:?}", points);
debug!("Compressed Hinted Values: {:?}", values);

// I need to insert MIN and MAX only if they don't belong to the values already.
let mut prev_pos = points[0];
Expand All @@ -143,6 +147,7 @@ impl Polynomial {
}

self.data_points = values;
self.point_step = step as u8;
}

// --- MANDATORY METHODS ---
Expand All @@ -163,6 +168,7 @@ impl Polynomial {
bincode::encode_to_vec(self, config).unwrap()
}

// --- END OF MANDATORY METHODS ---
/// Since IDW and Polynomial are the same code everywhere, this function prepares the data
/// to be used by one of the polynomial decompression methods
/*
Expand All @@ -185,14 +191,12 @@ impl Polynomial {
Walk `X` and check every element if `min_position` is between current point and previous point, if so, insert it there. Continue, do it the same for `max_position`.
*/
fn get_positions(&self, frame_size: usize) -> Vec<usize> {
// How many points I should have
let point_count = if 3 >= (frame_size/100) { 3 } else { frame_size/100 };
// Build the point array with the saved step
let mut points: Vec<usize> = (0..frame_size).step_by(self.point_step as usize).collect();
if points[points.len()-1] != frame_size-1 { points.push(frame_size-1); }
cjrolo marked this conversation as resolved.
Show resolved Hide resolved
// If they differ, it means I added either max and/or min
let point_dif = self.data_points.len() - point_count;
let point_dif = self.data_points.len() - points.len();
// I can calculate the positions from here
let mut points: Vec<usize> = (0..frame_size).step_by(frame_size/point_count).collect();
// Also we always use the last point
points.push(frame_size-1);
debug!("Points diff: {}", point_dif);
if point_dif > 0 {
let mut prev_pos = points[0];
Expand All @@ -207,7 +211,7 @@ impl Polynomial {
prev_pos = position_value;
}
}
debug!("{} {}", points.len(), self.data_points.len());
trace!("{} {}", points.len(), self.data_points.len());
debug!("Points: {:?}", points);
debug!("Out Values: {:?}", self.data_points);
points
Expand Down Expand Up @@ -307,7 +311,7 @@ mod tests {
#[test]
fn test_polynomial() {
let vector1 = vec![1.0, 0.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 5.0];
assert_eq!(polynomial(&vector1, PolynomialType::Polynomial), [0, 5, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 8, 64, 0, 0, 0, 0, 0, 0, 20, 64, 0, 0, 160, 64, 11, 0, 0, 0, 0, 1, 0]);
assert_eq!(polynomial(&vector1, PolynomialType::Polynomial), [0, 5, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 8, 64, 0, 0, 0, 0, 0, 0, 20, 64, 0, 0, 160, 64, 11, 0, 0, 0, 0, 1, 4]);
}

#[test]
Expand All @@ -332,16 +336,16 @@ mod tests {
fn test_to_allowed_error() {
let vector1 = vec![1.0, 1.0, 1.0, 1.0, 2.0, 3.0, 5.0, 1.0, 2.0, 7.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 5.0];
let frame_size = vector1.len();
let compressed_data = polynomial_allowed_error(&vector1, 0.02, PolynomialType::Polynomial);
let compressed_data = polynomial_allowed_error(&vector1, 0.5, PolynomialType::Polynomial);
let out = Polynomial::decompress(&compressed_data).to_data(frame_size);
let e = error_smape(&vector1, &out);
assert!(e <= 0.02);
let e = calculate_error(&vector1, &out);
assert!(e <= 0.5);
}

#[test]
fn test_idw() {
let vector1 = vec![1.0, 0.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 3.0, 1.0, 1.0, 5.0];
assert_eq!(polynomial(&vector1, PolynomialType::Idw), [1, 5, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 8, 64, 0, 0, 0, 0, 0, 0, 20, 64, 0, 0, 160, 64, 11, 0, 0, 0, 0, 1, 0]);
assert_eq!(polynomial(&vector1, PolynomialType::Idw), [1, 5, 0, 0, 0, 0, 0, 0, 240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 8, 64, 0, 0, 0, 0, 0, 0, 20, 64, 0, 0, 160, 64, 11, 0, 0, 0, 0, 1, 4]);
}

#[test]
Expand All @@ -368,7 +372,7 @@ mod tests {
let frame_size = vector1.len();
let compressed_data = polynomial_allowed_error(&vector1, 0.02, PolynomialType::Idw);
let out = Polynomial::decompress(&compressed_data).to_data(frame_size);
let e = error_smape(&vector1, &out);
assert!(e <= 0.02);
let e = calculate_error(&vector1, &out);
assert!(e <= 0.5);
}
}
37 changes: 36 additions & 1 deletion brro-compressor/src/utils/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
use std::cmp;

#[derive(Default, Debug, Clone)]
pub enum ErrorMethod {
Mse,
Nmse,
Mae,
#[default]
Mape,
Smape,
}

impl ErrorMethod {
pub fn error(self, original: &[f64], generated: &[f64]) -> f64 {
match self {
ErrorMethod::Mse => error_mse(original, generated),
ErrorMethod::Nmse => error_nmsqe(original, generated),
ErrorMethod::Mae => error_mae(original, generated),
ErrorMethod::Mape => error_mape(original, generated),
ErrorMethod::Smape => error_smape(original, generated)
}
}
}

/// This function calculates the error between 2 arrays of f64. The results are from 0 to ..
/// Being 0, no error, 1 - 100% error and so on.
/// This uses the default function to calculte it.
pub fn calculate_error(original: &[f64], generated: &[f64]) -> f64 {
ErrorMethod::error(ErrorMethod::default(), original, generated)
}

/// This function calculates the error between 2 arrays of f64. The results are from 0 to ..
/// Being 0, no error, 1 - 100% error and so on.
/// This uses the provided method to calculte it.
pub fn calculate_error_method(original: &[f64], generated: &[f64], method: ErrorMethod) -> f64 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why use this over just method.error(original, generated)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows to force a specific method if needed. My guess will end as dead code. But I do see some advantages looking ahead. (Mostly for benchmarks).

ErrorMethod::error(method, original, generated)
}
/// Calculates the mean squared error between two vectors.
///
/// # Arguments
Expand All @@ -10,7 +45,7 @@ use std::cmp;
/// # Returns
///
/// The mean squared error, or an error message if the vector lengths are different.
pub fn error_mse(vec1: &[f64], vec2: &Vec<f64>) -> f64 {
pub fn error_mse(vec1: &[f64], vec2: &[f64]) -> f64 {
if vec1.len() != vec2.len() { panic!("Can't compute error! Arrays with different lenghts.")}

let min_length = cmp::min(vec1.len(), vec2.len());
Expand Down
30 changes: 30 additions & 0 deletions plot_comparison.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash
filename=$2
error=$1

cp ../../wbro-july/$filename.wbro tmp.wbro

target/debug/brro-compressor --compressor fft --error $error --verbose tmp.wbro > ../../comparison-$filename.m
target/debug/brro-compressor -u --verbose tmp.bro >> ../../comparison-$filename.m

sed -i -e 's/Output/output_fft/g' ../../comparison-$filename.m

cp ../../wbro-july/$filename.wbro tmp.wbro

target/debug/brro-compressor --compressor idw --error $error --verbose tmp.wbro > /dev/null
target/debug/brro-compressor -u --verbose tmp.bro >> ../../comparison-$filename.m

sed -i -e 's/Output/output_idw/g' ../../comparison-$filename.m

cp ../../wbro-july/$filename.wbro tmp.wbro

target/debug/brro-compressor --compressor polynomial --error $error --verbose tmp.wbro > /dev/null
target/debug/brro-compressor -u --verbose tmp.bro >> ../../comparison-$filename.m

sed -i -e 's/Output/output_poly/g' ../../comparison-$filename.m

echo "plot(Input,'b', output_fft,'r', output_idw, 'g', output_poly, 'k')" >> ../../comparison-$filename.m
echo "print -dpng $filename.png" >> ../../comparison-$filename.m

rm tmp.wbro
rm tmp.bro
14 changes: 9 additions & 5 deletions plot_data.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#!/bin/bash
filename=$1
target/debug/brro-compressor --compressor fft --error 1 --verbose ../../wbro-july/$filename.wbro > ../../$filename.m
target/debug/brro-compressor -u --verbose ../../wbro-july/$filename.bro >> ../../$filename.m
echo "plot(Input,'b', Output,'r')" >> ../../$filename.m
echo "print -dpng $filename.png" >> ../../$filename.m
filename=$2
compressor=$1
cp ../../wbro-july/$filename.wbro tmp.wbro
target/debug/brro-compressor --compressor $compressor --error 1 --verbose tmp.wbro > ../../$filename-$compressor.m
target/debug/brro-compressor -u --verbose tmp.bro >> ../../$filename-$compressor.m
echo "plot(Input,'b', Output,'r')" >> ../../$filename-$compressor.m
echo "print -dpng $filename.png" >> ../../$filename-$compressor.m
rm tmp.wbro
rm tmp.bro