/*
 * This file contains a C++ demonstration of ATC.
 */

#include <iostream>
#include <fstream>
#include <numeric>
#include <cmath>

#include "atc.hpp"

int main() {
	
	std::cout << "ATC version " << atc::version << std::endl;
	
	// Parameter set-up
	const std::string original_file = "../data/test_data_4x8x16x32.raw";
	const std::string compressed_file = "../data/tmp_compressed.atc";
	const std::string decompressed_file = "../data/tmp_decompressed.raw";
	std::vector<size_t> sizes = {4, 8, 16, 32};
	const double target_relative_error = 1e-3;
	atc::Options options;
	options.error_metric = atc::ErrorMetric::RelativeError;
	
	// Compression
	atc::Results compression_results = atc::compress(original_file, atc::DataType::float32, sizes, target_relative_error, compressed_file, options);
	
	// Decompression
	atc::decompress(compressed_file, decompressed_file);
	
	// Check results
	
	std::cout << "Compressed file size: " << compression_results.compressed_size << std::endl;
	std::cout << "Compression factor: " << compression_results.compression_factor << std::endl;
	size_t size = std::accumulate(sizes.begin(), sizes.end(), 1, [] (size_t x, size_t y) {return x*y;});
	
	// Get original data
	std::ifstream original_stream(original_file, std::ios::in | std::ios::binary);
	std::vector<float> original_data(size);
	original_stream.read(reinterpret_cast<char*>(original_data.data()), size*sizeof(float));
	
	// Get decompressed data
	std::ifstream decompressed_stream(decompressed_file, std::ios::in | std::ios::binary);
	std::vector<float> decompressed_data(size);
	decompressed_stream.read(reinterpret_cast<char*>(decompressed_data.data()), size*sizeof(float));
	
	// Compute relative error explicitly and compare to reported relative error
	double sq_norm = 0;
	double sse = 0;
	for (size_t i = 0; i < size; i++) {
		sq_norm += pow(original_data[i], 2);
		sse += pow(decompressed_data[i] - original_data[i], 2);
	}
	double relative_error = sqrt(sse/sq_norm);
	std::cout << "Target relative error: " << target_relative_error << std::endl;
	std::cout << "Actual relative error: " << relative_error << std::endl;
	
	return 0;
	
}
