6#ifndef THEORETICA_IO_CSV_H
7#define THEORETICA_IO_CSV_H
33 inline std::vector<std::string>
parse_csv(
const std::string& line,
char delimiter =
',') {
35 std::vector<std::string> fields;
39 for (
size_t i = 0; i < line.length(); ++i) {
45 }
else if (c == delimiter && !quoted) {
46 fields.emplace_back(field);
48 }
else if(!std::isspace(c) || quoted) {
53 fields.emplace_back(field);
63 inline std::string
quote_csv(
const std::string& str) {
65 bool has_whitespace =
false;
68 if (std::isspace(c)) {
69 has_whitespace =
true;
74 if (str.find(
',') != std::string::npos || has_whitespace)
75 return "\"" + str +
"\"";
86 template<
typename Type,
unsigned int N>
88 const std::string& filename,
const vec<Type, N>& v,
unsigned int precision = 8) {
90 std::ofstream file (filename);
91 if (!file.is_open()) {
96 for (
size_t i = 0; i < v.
size(); ++i)
97 file << std::setprecision(precision) << v[i] << std::endl;
106 template<
typename Type,
unsigned int N>
108 const std::string& filename,
const std::string& header,
111 std::ofstream file (filename);
112 if (!file.is_open()) {
118 file <<
"\"" << header <<
"\"" << std::endl;
119 for (
size_t i = 0; i < v.
size(); ++i)
120 file << std::setprecision(precision) << v[i] << std::endl;
131 template<
typename Type,
unsigned int N, enable_real<Type> = true>
134 std::ifstream file (filename);
137 if (!file.is_open()) {
143 if (!std::getline(file, line))
149 std::vector<real> col;
156 std::replace(line.begin(), line.end(),
',',
'.');
157 first = std::stod(line);
158 col.emplace_back(first);
159 }
catch (
const std::invalid_argument& e) {
161 }
catch(
const std::out_of_range& e) {
167 while (std::getline(file, line)) {
170 std::replace(line.begin(), line.end(),
',',
'.');
173 real val = std::stod(line);
174 col.emplace_back(val);
175 }
catch (
const std::exception& e) {
176 col.emplace_back(
nan());
181 if (v.
size() > col.size()) {
183 for (
size_t i = 0; i < col.size(); i++)
186 for (
size_t i = col.size(); i < v.
size(); i++)
205 template<
typename Type,
unsigned int N, enable_real<Type> = true>
207 const std::string& filename,
const std::string& col_name,
210 std::ifstream file (filename);
213 if (!file.is_open()) {
220 if (!std::getline(file, line))
224 std::vector<std::string> headers =
parse_csv(line);
226 for (
size_t i = 0; i < headers.size(); ++i) {
228 if (headers[i] == col_name) {
235 if (col_index == -1) {
242 for (
size_t i = 0; i < v.
size(); ++i)
249 std::vector<real> data;
250 std::vector<std::string> cells;
252 while (std::getline(file, line)) {
256 if (
size_t(col_index) < cells.size()) {
258 std::string cell = cells[col_index];
259 std::replace(cell.begin(), cell.end(),
',',
'.');
262 const real val = std::stod(cell);
263 data.emplace_back(val);
264 }
catch (
const std::exception& e) {
265 data.emplace_back(
nan());
268 data.emplace_back(
nan());
273 size_t actual_size = data.size();
276 while (actual_size > 0 &&
is_nan(data[actual_size - 1]))
280 if (v.
size() < actual_size) {
284 if (v.
size() < actual_size) {
291 for (
size_t i = 0; i < actual_size; i++)
294 for (
size_t i = actual_size; i < v.
size(); i++)
303 template<
typename Type,
unsigned int N,
unsigned int M>
306 const std::string& delimiter =
", ",
unsigned int precision = 8) {
308 std::ofstream file (filename);
310 if (!file.is_open()) {
315 for (
size_t i = 0; i < A.
rows(); i++) {
316 for (
size_t j = 0; j < A.
cols(); j++) {
318 file << std::setprecision(precision) << A(i, j);
320 if (j != A.cols() - 1)
335 template<
unsigned int N,
unsigned int K>
338 std::ifstream file (filename);
341 if (!file.is_open()) {
346 std::vector<std::vector<real>> rows;
349 if (!std::getline(file, line))
352 std::vector<std::string> first_row =
parse_csv(line);
355 bool has_header =
false;
357 for (
const auto& cell : first_row) {
368 std::vector<real> row;
370 for (
auto cell : first_row) {
372 std::replace(cell.begin(), cell.end(),
',',
'.');
375 row.emplace_back(std::stod(cell));
376 }
catch (
const std::exception& e) {
377 row.emplace_back(
nan());
382 rows.emplace_back(row);
386 while (std::getline(file, line)) {
392 std::vector<std::string> cells =
parse_csv(line);
393 std::vector<real> row;
395 for (
auto cell : cells) {
397 std::replace(cell.begin(), cell.end(),
',',
'.');
400 row.emplace_back(std::stod(cell));
401 }
catch (
const std::exception& e) {
402 row.emplace_back(
nan());
407 rows.emplace_back(row);
411 A.
resize(rows.size(), rows[0].size());
413 if (A.
rows() < rows[0].size() || A.
cols() < rows.size()) {
420 for (
size_t i = 0; i <
min(rows.size(), A.
rows()); ++i) {
422 for (
size_t j = 0; j <
min(rows[i].size(), A.
cols()); ++j)
423 A(i, j) = rows[i][j];
426 for (
size_t j = rows[i].size(); j < A.
cols(); ++j)
431 for (
size_t i = rows.size(); i < A.
rows(); ++i)
432 for (
size_t j = 0; j < A.
cols(); ++j)
444 template<
typename Vector>
447 size_t interleave = 1,
const std::string& delimiter =
", ",
size_t precision = 8) {
449 std::ofstream file (filename);
451 if (!file.is_open()) {
456 if(solution.
t.
size() != solution.
x.size()) {
461 for (
size_t i = 0; i < solution.
t.
size(); ++i) {
463 file << std::setprecision(precision) << solution.
t[i];
465 for (
size_t j = 0; j < solution.
x[i].size(); ++j) {
467 if (j % interleave == 0)
468 file << delimiter << std::setprecision(precision) << solution.
x[i][j];
481 template<
typename Vector>
484 std::ifstream file (filename);
487 if (!file.is_open()) {
493 std::vector<Vector> x;
494 std::vector<std::string> cells;
498 if (std::getline(file, line)) {
502 bool has_header =
false;
503 for (
const auto& cell : cells) {
515 val = std::stod(cells[0]);
516 }
catch (
const std::exception& e) {
521 state.resize(cells.size() - 1);
522 if (state.size() + 1 != cells.size()) {
527 for (
size_t j = 1; j < cells.size(); ++j) {
530 val = std::stod(cells[j]);
531 }
catch (
const std::exception& e) {
537 x.emplace_back(state);
541 while (std::getline(file, line)) {
551 if (state.size() == 0)
552 state.resize(cells.size() - 1);
555 t.emplace_back(std::stod(cells[0]));
556 }
catch (
const std::exception& e) {
557 t.emplace_back(
nan());
560 if (state.size() + 1 != cells.size()) {
565 for (
size_t j = 1; j < cells.size(); ++j) {
568 state[j - 1] = std::stod(cells[j]);
569 }
catch (
const std::exception& e) {
570 state[j - 1] =
nan();
574 x.emplace_back(state);
580 solution.
x.resize(x.size());
581 for (
size_t i = 0; i < solution.
x.size(); i++)
582 solution.
x[i] = x[i];
591 const std::string& filename,
const data_table& table,
592 const std::string& delimiter =
", ",
unsigned int precision = 8) {
594 std::ofstream file (filename);
596 if (!file.is_open()) {
602 for (
const std::string& name : table.
header()) {
612 size_t max_rows = table.
rows();
613 for (
size_t i = 0; i < max_rows; ++i) {
616 for (
const auto& col : table.
data()) {
622 file << std::setprecision(precision) << col[i];
641 std::ifstream file (filename);
644 if (!file.is_open()) {
650 if (!std::getline(file, line))
653 std::vector<std::string> first_row =
parse_csv(line);
655 if (first_row.empty())
658 std::vector<std::string> column_names;
659 size_t num_cols = first_row.size();
660 std::vector<vec<real>> columns (num_cols);
663 bool has_header =
false;
665 for (
const auto& cell : first_row) {
676 for (
size_t j = 0; j < first_row.size(); ++j) {
678 std::string cell = first_row[j];
679 std::replace(cell.begin(), cell.end(),
',',
'.');
682 columns[j].append(std::stod(cell));
683 }
catch (
const std::exception& e) {
684 columns[j].append(
nan());
689 for (
size_t j = 0; j < num_cols; ++j) {
690 column_names.emplace_back(
"col" + std::to_string(j));
695 for (
const auto& name : first_row)
701 while (std::getline(file, line)) {
706 std::vector<std::string> cells =
parse_csv(line);
708 for (
size_t j = 0; j < num_cols; ++j) {
710 if (j < cells.size()) {
711 std::string cell = cells[j];
712 std::replace(cell.begin(), cell.end(),
',',
'.');
715 real val = std::stod(cell);
716 columns[j].append(val);
717 }
catch (
const std::exception& e) {
718 columns[j].append(
nan());
721 columns[j].append(
nan());
726 for (
size_t j = 0; j < num_cols; ++j)
727 table.
insert(column_names[j], columns[j]);
744 const std::string& filename,
const histogram& hist,
745 bool normalized =
false,
bool lower_extreme =
false,
746 const std::string& delimiter =
", ",
unsigned int precision = 8) {
748 std::ofstream file (filename);
749 if (!file.is_open()) {
754 const auto bin_counts = hist.
bins();
757 if (!bin_counts.size()) {
762 const real bin_dx = (hist.
range()[1] - hist.
range()[0]) / bin_counts.size();
763 real norm_factor = normalized ? hist.
number() * bin_dx : 1.0;
768 real bin_value = lower_extreme ? hist.
range()[0] : (hist.
range()[0] + 0.5 * bin_dx);
771 file <<
"bins, counts, number, average, tss, min, max" << std::endl;
772 if (!bin_counts.size())
775 file << std::setprecision(precision) << bin_value << delimiter;
776 file << std::setprecision(precision) << (bin_counts[0] / norm_factor) << delimiter;
777 file << hist.
number() << delimiter;
778 file << hist.
mean() << delimiter;
779 file << hist.
tss() << delimiter;
780 file << hist.
min() << delimiter;
781 file << hist.
max() << std::endl;
783 for (
size_t i = 1; i < bin_counts.size(); i++) {
786 file << std::setprecision(precision) << bin_value << delimiter;
787 file << std::setprecision(precision) << (bin_counts[i] / norm_factor) << std::endl;
798 inline void read_csv(
const std::string& filename,
histogram& hist,
bool lower_extreme =
false) {
800 std::ifstream file (filename);
801 if (!file.is_open()) {
807 std::vector<std::string> cells;
810 std::getline(file, line);
813 int bin_index = -1, count_index = -1, number_index = -1, average_index = -1;
814 int tss_index = -1, min_index = -1, max_index = -1;
817 for (
size_t i = 0; i < cells.size(); i++) {
819 if (cells[i] ==
"bins") bin_index = i;
820 else if (cells[i] ==
"counts") count_index = i;
821 else if (cells[i] ==
"number") number_index = i;
822 else if (cells[i] ==
"average") average_index = i;
823 else if (cells[i] ==
"tss") tss_index = i;
824 else if (cells[i] ==
"min") min_index = i;
825 else if (cells[i] ==
"max") max_index = i;
828 if (bin_index == -1 || count_index == -1 || number_index == -1 ||
829 average_index == -1 || tss_index == -1 || min_index == -1 || max_index == -1) {
836 int min_size = bin_index;
837 if (min_size < count_index) min_size = count_index;
838 if (min_size < number_index) min_size = number_index;
839 if (min_size < average_index) min_size = average_index;
840 if (min_size < tss_index) min_size = tss_index;
841 if (min_size < min_index) min_size = min_index;
842 if (min_size < max_index) min_size = max_index;
846 std::getline(file, line);
849 if (cells.size() <
size_t(min_size)) {
856 real run_average, run_tss, value_min, value_max;
860 counts = {std::stod(cells[count_index])};
861 bins = {std::stod(cells[bin_index])};
863 N = std::stod(cells[number_index]);
864 run_average = std::stod(cells[average_index]);
865 run_tss = std::stod(cells[tss_index]);
866 value_min = std::stod(cells[min_index]);
867 value_max = std::stod(cells[max_index]);
869 }
catch (
const std::invalid_argument& e) {
874 int bins_max_index = (bin_index > count_index ? bin_index : count_index) + 1;
877 while (std::getline(file, line)) {
881 if (cells.size() <
size_t(bins_max_index)) {
887 counts.append(cells[count_index] !=
"" ? std::stod(cells[count_index]) :
nan());
888 bins.append(cells[bin_index] !=
"" ? std::stod(cells[bin_index]) :
nan());
889 }
catch (
const std::exception& e) {
899 bool is_normalized =
false;
900 for (
size_t i = 0; i < counts.
size(); i++) {
903 if (counts[i] !=
floor(counts[i])) {
904 is_normalized =
true;
909 std::vector<unsigned int> bin_counts (counts.
size());
910 for (
size_t i = 0; i < counts.
size(); i++) {
911 bin_counts[i] = (
unsigned int) (is_normalized ? (counts[i] * N) : counts[i]);
914 const real bin_dx = bins.
size() > 1 ? (bins[1] - bins[0]) : 0;
915 range_min = lower_extreme ? bins[0] : (bins[0] - 0.5 * bin_dx);
916 range_max = lower_extreme ? bins[bins.
size() - 1] + bin_dx : bins[bins.
size() - 1] + 0.5 * bin_dx;
919 for (
size_t i = 1; i < bins.
size(); i++) {
920 if (
abs((bins[i] - bins[i - 1]) - bin_dx) > 1e-6) {
927 bin_counts,
vec2({range_min, range_max}),
928 N, run_average, run_tss,
943 template<
typename Type>
944 inline Type
read_csv(
const std::string& filename) {
A data structure for holding labeled columns of data, where each column is a vector of real numbers.
Definition data_table.h:26
std::vector< std::string > header() const
Get a list of the column names in the data table.
Definition data_table.h:145
std::vector< vec< real > > & data()
Get the columns of the data table as a simple vector of column vectors, without the column names or i...
Definition data_table.h:162
data_table & insert(const std::string &name, const vec< real > &data)
Insert a new column into the data table with the given name and data.
Definition data_table.h:390
size_t rows() const
Get the (maximum) number of rows in the data table.
Definition data_table.h:95
Histogram class with running statistics, can be constructed from the parameters of the bins or from a...
Definition histogram.h:28
void rebuild(const std::vector< unsigned int > &bin_counts, const vec2 &range, size_t N, real run_average, real run_tss, real value_min, real value_max)
Rebuild the histogram from its parameters, including the bin counts and the running statistics (used ...
Definition histogram.h:233
real min() const
Get the smallest data point of the histogram.
Definition histogram.h:209
real max() const
Get the biggest data point of the histogram.
Definition histogram.h:201
vec2 range() const
Get the histogram range as a vector of two elements, containing the lower and upper extremes.
Definition histogram.h:158
real tss() const
Get the total sum of squares (TSS) computed using Welford's one-pass method.
Definition histogram.h:226
unsigned int number() const
Get the number of data points inside the histogram.
Definition histogram.h:170
real mean() const
Get the mean value of the histogram data.
Definition histogram.h:217
std::vector< unsigned int > bins() const
Get a vector containing the bin counts of each bin.
Definition histogram.h:181
A generic matrix with a fixed number of rows and columns.
Definition mat.h:136
TH_CONSTEXPR unsigned int rows() const
Returns the number of rows in the matrix.
Definition mat.h:641
TH_CONSTEXPR unsigned int cols() const
Returns the number of columns in the matrix.
Definition mat.h:648
mat< Type, N, K > resize(unsigned int n, unsigned int k)
Compatibility function to allow for allocation or resizing of dynamic matrices.
Definition mat.h:730
A statically allocated N-dimensional vector with elements of the given type.
Definition vec.h:92
void resize(size_t n) const
Compatibility function to allow for allocation or resizing of dynamic vectors.
Definition vec.h:459
TH_CONSTEXPR unsigned int size() const
Returns the size of the vector (N).
Definition vec.h:449
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compilation op...
Definition error.h:219
Data table structure for holding labeled columns of data.
Error handling for IO operations.
Matrix class and operations.
Vector1 & vec_copy(Vector1 &dest, const Vector2 &src)
Copy a vector by overwriting another.
Definition algebra.h:241
Matrix & mat_error(Matrix &m)
Overwrite the given matrix with the error matrix with NaN values on the diagonal and zeroes everywher...
Definition algebra.h:40
Vector & vec_error(Vector &v)
Overwrite the given vector with the error vector with NaN values.
Definition algebra.h:58
Input and output module.
Definition csv.h:23
bool is_number(const std::string &str)
Check if a given string could be correctly interpreted as a number.
Definition strings.h:20
std::string trim(const std::string &str)
Remove all leading and trailing whitespace from a string, returning the resulting string.
Definition strings.h:40
@ FileNotFound
File or directory not found.
Definition error.h:31
@ FormatError
The file format is invalid or the data is corrupted.
Definition error.h:43
@ ReadError
Error occurred while reading from the file or stream.
Definition error.h:37
std::string quote_csv(const std::string &str)
Given a string entry, sanitize it for printing to a CSV file.
Definition csv.h:63
std::vector< std::string > parse_csv(const std::string &line, char delimiter=',')
Parse a CSV line handling quoted fields.
Definition csv.h:33
void read_csv(const std::string &filename, vec< Type, N > &v)
Read a vector from a file in the CSV format.
Definition csv.h:132
void write_csv(const std::string &filename, const vec< Type, N > &v, unsigned int precision=8)
Write a vector to file in the CSV format.
Definition csv.h:87
std::string unquote(const std::string &str)
Remove leading and trailing double quotes from a string, if both are present.
Definition strings.h:58
Main namespace of the library which contains all functions and objects.
Definition algebra.h:27
auto min(const Vector &X)
Finds the minimum value inside a dataset.
Definition dataset.h:347
bool is_nan(const T &x)
Check whether a generic variable is (equivalent to) a NaN number.
Definition error.h:90
dual2 abs(dual2 x)
Compute the absolute value of a second order dual number.
Definition dual2_functions.h:242
double real
A real number, defined as a floating point type.
Definition constants.h:207
TH_CONSTEXPR real nan()
Return a quiet NaN number in floating point representation.
Definition error.h:74
@ OutOfRange
Result out of range.
Definition error.h:29
constexpr real MACH_EPSILON
Machine epsilon for the real type.
Definition constants.h:216
vec< real, 2 > vec2
A 2-dimensional vector with real elements.
Definition algebra_types.h:39
TH_CONSTEXPR int floor(real x)
Compute the floor of x, as the maximum integer number that is smaller than x.
Definition real_analysis.h:271
Numerical methods for ordinary differential equations.
String manipulation functions.
Data structure holding the numerical solution of a discretized ODE, where the vector represents the ...
Definition ode.h:24
vec< real > t
A vector of the time values (independent variable).
Definition ode.h:27
vec< Vector > x
A vector of the phase space values (solution).
Definition ode.h:30
Vector class and operations.