Mercurial > hg > segmenter-vamp-plugin
diff armadillo-2.4.4/include/armadillo_bits/diskio_meat.hpp @ 0:8b6102e2a9b0
Armadillo Library
author | maxzanoni76 <max.zanoni@eecs.qmul.ac.uk> |
---|---|
date | Wed, 11 Apr 2012 09:27:06 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/armadillo-2.4.4/include/armadillo_bits/diskio_meat.hpp Wed Apr 11 09:27:06 2012 +0100 @@ -0,0 +1,3118 @@ +// Copyright (C) 2008-2011 NICTA (www.nicta.com.au) +// Copyright (C) 2008-2011 Conrad Sanderson +// Copyright (C) 2009-2010 Ian Cullinan +// +// This file is part of the Armadillo C++ library. +// It is provided without any warranty of fitness +// for any purpose. You can redistribute this file +// and/or modify it under the terms of the GNU +// Lesser General Public License (LGPL) as published +// by the Free Software Foundation, either version 3 +// of the License or (at your option) any later version. +// (see http://www.opensource.org/licenses for more info) + + +//! \addtogroup diskio +//! @{ + + +//! Generate the first line of the header used for saving matrices in text format. +//! Format: "ARMA_MAT_TXT_ABXYZ". +//! A is one of: I (for integral types) or F (for floating point types). +//! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). +//! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. +template<typename eT> +inline +std::string +diskio::gen_txt_header(const Mat<eT>& x) + { + arma_type_check(( is_supported_elem_type<eT>::value == false )); + + arma_ignore(x); + + if(is_u8<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_IU001"); + } + else + if(is_s8<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_IS001"); + } + else + if(is_u16<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_IU002"); + } + else + if(is_s16<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_IS002"); + } + else + if(is_u32<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_IU004"); + } + else + if(is_s32<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_IS004"); + } +#if defined(ARMA_64BIT_WORD) + else + if(is_u64<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_IU008"); + } + else + if(is_s64<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_IS008"); + } +#endif + else + if(is_float<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_FN004"); + } + else + if(is_double<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_FN008"); + } + else + if(is_complex_float<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_FC008"); + } + else + if(is_complex_double<eT>::value == true) + { + return std::string("ARMA_MAT_TXT_FC016"); + } + else + { + return std::string(); + } + + } + + + +//! Generate the first line of the header used for saving matrices in binary format. +//! Format: "ARMA_MAT_BIN_ABXYZ". +//! A is one of: I (for integral types) or F (for floating point types). +//! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). +//! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. +template<typename eT> +inline +std::string +diskio::gen_bin_header(const Mat<eT>& x) + { + arma_type_check(( is_supported_elem_type<eT>::value == false )); + + arma_ignore(x); + + if(is_u8<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_IU001"); + } + else + if(is_s8<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_IS001"); + } + else + if(is_u16<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_IU002"); + } + else + if(is_s16<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_IS002"); + } + else + if(is_u32<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_IU004"); + } + else + if(is_s32<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_IS004"); + } +#if defined(ARMA_64BIT_WORD) + else + if(is_u64<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_IU008"); + } + else + if(is_s64<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_IS008"); + } +#endif + else + if(is_float<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_FN004"); + } + else + if(is_double<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_FN008"); + } + else + if(is_complex_float<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_FC008"); + } + else + if(is_complex_double<eT>::value == true) + { + return std::string("ARMA_MAT_BIN_FC016"); + } + else + { + return std::string(); + } + + } + + + +//! Generate the first line of the header used for saving cubes in text format. +//! Format: "ARMA_CUB_TXT_ABXYZ". +//! A is one of: I (for integral types) or F (for floating point types). +//! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). +//! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. +template<typename eT> +inline +std::string +diskio::gen_txt_header(const Cube<eT>& x) + { + arma_type_check(( is_supported_elem_type<eT>::value == false )); + + arma_ignore(x); + + if(is_u8<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_IU001"); + } + else + if(is_s8<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_IS001"); + } + else + if(is_u16<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_IU002"); + } + else + if(is_s16<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_IS002"); + } + else + if(is_u32<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_IU004"); + } + else + if(is_s32<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_IS004"); + } +#if defined(ARMA_64BIT_WORD) + else + if(is_u64<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_IU008"); + } + else + if(is_s64<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_IS008"); + } +#endif + else + if(is_float<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_FN004"); + } + else + if(is_double<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_FN008"); + } + else + if(is_complex_float<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_FC008"); + } + else + if(is_complex_double<eT>::value == true) + { + return std::string("ARMA_CUB_TXT_FC016"); + } + else + { + return std::string(); + } + + } + + + +//! Generate the first line of the header used for saving cubes in binary format. +//! Format: "ARMA_CUB_BIN_ABXYZ". +//! A is one of: I (for integral types) or F (for floating point types). +//! B is one of: U (for unsigned types), S (for signed types), N (for not appliable) or C (for complex types). +//! XYZ specifies the width of each element in terms of bytes, e.g. "008" indicates eight bytes. +template<typename eT> +inline +std::string +diskio::gen_bin_header(const Cube<eT>& x) + { + arma_type_check(( is_supported_elem_type<eT>::value == false )); + + arma_ignore(x); + + if(is_u8<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_IU001"); + } + else + if(is_s8<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_IS001"); + } + else + if(is_u16<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_IU002"); + } + else + if(is_s16<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_IS002"); + } + else + if(is_u32<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_IU004"); + } + else + if(is_s32<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_IS004"); + } +#if defined(ARMA_64BIT_WORD) + else + if(is_u64<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_IU008"); + } + else + if(is_s64<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_IS008"); + } +#endif + else + if(is_float<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_FN004"); + } + else + if(is_double<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_FN008"); + } + else + if(is_complex_float<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_FC008"); + } + else + if(is_complex_double<eT>::value == true) + { + return std::string("ARMA_CUB_BIN_FC016"); + } + else + { + return std::string(); + } + + } + + + +inline +file_type +diskio::guess_file_type(std::istream& f) + { + arma_extra_debug_sigprint(); + + f.clear(); + const std::fstream::pos_type pos1 = f.tellg(); + + f.clear(); + f.seekg(0, ios::end); + + f.clear(); + const std::fstream::pos_type pos2 = f.tellg(); + + const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0; + + f.clear(); + f.seekg(pos1); + + podarray<unsigned char> data(N); + + unsigned char* ptr = data.memptr(); + + f.clear(); + f.read( reinterpret_cast<char*>(ptr), std::streamsize(N) ); + + const bool load_okay = f.good(); + + f.clear(); + f.seekg(pos1); + + bool has_binary = false; + bool has_comma = false; + + if(load_okay == true) + { + uword i = 0; + uword j = (N >= 2) ? 1 : 0; + + for(; j<N; i+=2, j+=2) + { + const unsigned char val_i = ptr[i]; + const unsigned char val_j = ptr[j]; + + // the range checking can be made more elaborate + if( ((val_i <= 8) || (val_i >= 123)) || ((val_j <= 8) || (val_j >= 123)) ) + { + has_binary = true; + break; + } + + if( (val_i == ',') || (val_j == ',') ) + { + has_comma = true; + break; + } + } + } + else + { + return file_type_unknown; + } + + if(has_binary) + { + return raw_binary; + } + + if(has_comma) + { + return csv_ascii; + } + + return raw_ascii; + } + + + +inline +char +diskio::conv_to_hex_char(const u8 x) + { + char out; + + switch(x) + { + case 0: out = '0'; break; + case 1: out = '1'; break; + case 2: out = '2'; break; + case 3: out = '3'; break; + case 4: out = '4'; break; + case 5: out = '5'; break; + case 6: out = '6'; break; + case 7: out = '7'; break; + case 8: out = '8'; break; + case 9: out = '9'; break; + case 10: out = 'a'; break; + case 11: out = 'b'; break; + case 12: out = 'c'; break; + case 13: out = 'd'; break; + case 14: out = 'e'; break; + case 15: out = 'f'; break; + default: out = '-'; break; + } + + return out; + } + + + +inline +void +diskio::conv_to_hex(char* out, const u8 x) + { + const u8 a = x / 16; + const u8 b = x - 16*a; + + out[0] = conv_to_hex_char(a); + out[1] = conv_to_hex_char(b); + } + + + +//! Append a quasi-random string to the given filename. +//! The rand() function is deliberately not used, +//! as rand() has an internal state that changes +//! from call to call. Such states should not be +//! modified in scientific applications, where the +//! results should be reproducable and not affected +//! by saving data. +inline +std::string +diskio::gen_tmp_name(const std::string& x) + { + const std::string* ptr_x = &x; + const u8* ptr_ptr_x = reinterpret_cast<const u8*>(&ptr_x); + + const char* extra = ".tmp_"; + const uword extra_size = 5; + + const uword tmp_size = 2*sizeof(u8*) + 2*2; + char tmp[tmp_size]; + + uword char_count = 0; + + for(uword i=0; i<sizeof(u8*); ++i) + { + conv_to_hex(&tmp[char_count], ptr_ptr_x[i]); + char_count += 2; + } + + const uword x_size = static_cast<uword>(x.size()); + u8 sum = 0; + + for(uword i=0; i<x_size; ++i) + { + sum += u8(x[i]); + } + + conv_to_hex(&tmp[char_count], sum); + char_count += 2; + + conv_to_hex(&tmp[char_count], u8(x_size)); + + + std::string out; + out.resize(x_size + extra_size + tmp_size); + + + for(uword i=0; i<x_size; ++i) + { + out[i] = x[i]; + } + + for(uword i=0; i<extra_size; ++i) + { + out[x_size + i] = extra[i]; + } + + for(uword i=0; i<tmp_size; ++i) + { + out[x_size + extra_size + i] = tmp[i]; + } + + return out; + } + + + +//! Safely rename a file. +//! Before renaming, test if we can write to the final file. +//! This should prevent: +//! (i) overwriting files that are write protected, +//! (ii) overwriting directories. +inline +bool +diskio::safe_rename(const std::string& old_name, const std::string& new_name) + { + std::fstream f(new_name.c_str(), std::fstream::out | std::fstream::app); + f.put(' '); + + bool save_okay = f.good(); + f.close(); + + if(save_okay == true) + { + std::remove(new_name.c_str()); + + const int mv_result = std::rename(old_name.c_str(), new_name.c_str()); + + save_okay = (mv_result == 0); + } + + return save_okay; + } + + + +//! Save a matrix as raw text (no header, human readable). +//! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements. +template<typename eT> +inline +bool +diskio::save_raw_ascii(const Mat<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::fstream f(tmp_name.c_str(), std::fstream::out); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_raw_ascii(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +//! Save a matrix as raw text (no header, human readable). +//! Matrices can be loaded in Matlab and Octave, as long as they don't have complex elements. +template<typename eT> +inline +bool +diskio::save_raw_ascii(const Mat<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + uword cell_width; + + // TODO: need sane values for complex numbers + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.setf(ios::scientific); + f.precision(10); + cell_width = 18; + } + + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + f.put(' '); + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.width(cell_width); + } + + f << x.at(row,col); + } + + f.put('\n'); + } + + return f.good(); + } + + + +//! Save a matrix as raw binary (no header) +template<typename eT> +inline +bool +diskio::save_raw_binary(const Mat<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f(tmp_name.c_str(), std::fstream::binary); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_raw_binary(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +template<typename eT> +inline +bool +diskio::save_raw_binary(const Mat<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + f.write( reinterpret_cast<const char*>(x.mem), std::streamsize(x.n_elem*sizeof(eT)) ); + + return f.good(); + } + + + +//! Save a matrix in text format (human readable), +//! with a header that indicates the matrix type as well as its dimensions +template<typename eT> +inline +bool +diskio::save_arma_ascii(const Mat<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f(tmp_name.c_str()); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_arma_ascii(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +//! Save a matrix in text format (human readable), +//! with a header that indicates the matrix type as well as its dimensions +template<typename eT> +inline +bool +diskio::save_arma_ascii(const Mat<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + const ios::fmtflags orig_flags = f.flags(); + + f << diskio::gen_txt_header(x) << '\n'; + f << x.n_rows << ' ' << x.n_cols << '\n'; + + uword cell_width; + + // TODO: need sane values for complex numbers + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.setf(ios::scientific); + f.precision(10); + cell_width = 18; + } + + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + f.put(' '); + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.width(cell_width); + } + + f << x.at(row,col); + } + + f.put('\n'); + } + + const bool save_okay = f.good(); + + f.flags(orig_flags); + + return save_okay; + } + + + +//! Save a matrix in CSV text format (human readable) +template<typename eT> +inline +bool +diskio::save_csv_ascii(const Mat<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f(tmp_name.c_str()); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_csv_ascii(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +//! Save a matrix in CSV text format (human readable) +template<typename eT> +inline +bool +diskio::save_csv_ascii(const Mat<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + const ios::fmtflags orig_flags = f.flags(); + + // TODO: need sane values for complex numbers + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.setf(ios::scientific); + f.precision(10); + } + + uword x_n_rows = x.n_rows; + uword x_n_cols = x.n_cols; + + for(uword row=0; row < x_n_rows; ++row) + { + for(uword col=0; col < x_n_cols; ++col) + { + f << x.at(row,col); + + if( col < (x_n_cols-1) ) + { + f.put(','); + } + } + + f.put('\n'); + } + + const bool save_okay = f.good(); + + f.flags(orig_flags); + + return save_okay; + } + + + +//! Save a matrix in binary format, +//! with a header that stores the matrix type as well as its dimensions +template<typename eT> +inline +bool +diskio::save_arma_binary(const Mat<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f(tmp_name.c_str(), std::fstream::binary); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_arma_binary(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +//! Save a matrix in binary format, +//! with a header that stores the matrix type as well as its dimensions +template<typename eT> +inline +bool +diskio::save_arma_binary(const Mat<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + f << diskio::gen_bin_header(x) << '\n'; + f << x.n_rows << ' ' << x.n_cols << '\n'; + + f.write( reinterpret_cast<const char*>(x.mem), std::streamsize(x.n_elem*sizeof(eT)) ); + + return f.good(); + } + + + +//! Save a matrix as a PGM greyscale image +template<typename eT> +inline +bool +diskio::save_pgm_binary(const Mat<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::fstream f(tmp_name.c_str(), std::fstream::out | std::fstream::binary); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_pgm_binary(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +// +// TODO: +// add functionality to save the image in a normalised format, +// i.e. scaled so that every value falls in the [0,255] range. + +//! Save a matrix as a PGM greyscale image +template<typename eT> +inline +bool +diskio::save_pgm_binary(const Mat<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + f << "P5" << '\n'; + f << x.n_cols << ' ' << x.n_rows << '\n'; + f << 255 << '\n'; + + const uword n_elem = x.n_rows * x.n_cols; + podarray<u8> tmp(n_elem); + + uword i = 0; + + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + tmp[i] = u8( x.at(row,col) ); // TODO: add round() ? + ++i; + } + } + + f.write(reinterpret_cast<const char*>(tmp.mem), std::streamsize(n_elem) ); + + return f.good(); + } + + + +//! Save a matrix as a PGM greyscale image +template<typename T> +inline +bool +diskio::save_pgm_binary(const Mat< std::complex<T> >& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const uchar_mat tmp = conv_to<uchar_mat>::from(x); + + return diskio::save_pgm_binary(tmp, final_name); + } + + + +//! Save a matrix as a PGM greyscale image +template<typename T> +inline +bool +diskio::save_pgm_binary(const Mat< std::complex<T> >& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + const uchar_mat tmp = conv_to<uchar_mat>::from(x); + + return diskio::save_pgm_binary(tmp, f); + } + + + +//! Load a matrix as raw text (no header, human readable). +//! Can read matrices saved as text in Matlab and Octave. +//! NOTE: this is much slower than reading a file with a header. +template<typename eT> +inline +bool +diskio::load_raw_ascii(Mat<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::fstream f; + f.open(name.c_str(), std::fstream::in); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_raw_ascii(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +//! Load a matrix as raw text (no header, human readable). +//! Can read matrices saved as text in Matlab and Octave. +//! NOTE: this is much slower than reading a file with a header. +template<typename eT> +inline +bool +diskio::load_raw_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + bool load_okay = f.good(); + + f.clear(); + const std::fstream::pos_type pos1 = f.tellg(); + + // + // work out the size + + uword f_n_rows = 0; + uword f_n_cols = 0; + + bool f_n_cols_found = false; + + std::string line_string; + std::string token; + + while( (f.good() == true) && (load_okay == true) ) + { + std::getline(f, line_string); + + if(line_string.size() == 0) + { + break; + } + + std::stringstream line_stream(line_string); + + uword line_n_cols = 0; + + while (line_stream >> token) + { + ++line_n_cols; + } + + if(f_n_cols_found == false) + { + f_n_cols = line_n_cols; + f_n_cols_found = true; + } + else + { + if(line_n_cols != f_n_cols) + { + err_msg = "inconsistent number of columns in "; + load_okay = false; + } + } + + ++f_n_rows; + } + + if(load_okay == true) + { + f.clear(); + f.seekg(pos1); + + x.set_size(f_n_rows, f_n_cols); + + eT val; + + for(uword row=0; (row < x.n_rows) && (load_okay == true); ++row) + { + for(uword col=0; (col < x.n_cols) && (load_okay == true); ++col) + { + f >> val; + + if(f.fail() == false) + { + x.at(row,col) = val; + } + else + { + load_okay = false; + err_msg = "couldn't interpret data in "; + //break; + } + } + } + } + + + // an empty file indicates an empty matrix + if( (f_n_cols_found == false) && (load_okay == true) ) + { + x.reset(); + } + + + return load_okay; + } + + + +//! Load a matrix in binary format (no header); +//! the matrix is assumed to have one column +template<typename eT> +inline +bool +diskio::load_raw_binary(Mat<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::ifstream f; + f.open(name.c_str(), std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_raw_binary(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +template<typename eT> +inline +bool +diskio::load_raw_binary(Mat<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + arma_ignore(err_msg); + + f.clear(); + const std::streampos pos1 = f.tellg(); + + f.clear(); + f.seekg(0, ios::end); + + f.clear(); + const std::streampos pos2 = f.tellg(); + + const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0; + + f.clear(); + //f.seekg(0, ios::beg); + f.seekg(pos1); + + x.set_size(N / sizeof(eT), 1); + + f.clear(); + f.read( reinterpret_cast<char *>(x.memptr()), std::streamsize(N) ); + + return f.good(); + } + + + +//! Load a matrix in text format (human readable), +//! with a header that indicates the matrix type as well as its dimensions +template<typename eT> +inline +bool +diskio::load_arma_ascii(Mat<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::ifstream f(name.c_str()); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_arma_ascii(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +//! Load a matrix in text format (human readable), +//! with a header that indicates the matrix type as well as its dimensions +template<typename eT> +inline +bool +diskio::load_arma_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + bool load_okay = true; + + std::string f_header; + uword f_n_rows; + uword f_n_cols; + + f >> f_header; + f >> f_n_rows; + f >> f_n_cols; + + if(f_header == diskio::gen_txt_header(x)) + { + x.set_size(f_n_rows, f_n_cols); + + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + f >> x.at(row,col); + } + } + + load_okay = f.good(); + } + else + { + load_okay = false; + err_msg = "incorrect header in "; + } + + return load_okay; + } + + + +//! Load a matrix in CSV text format (human readable) +template<typename eT> +inline +bool +diskio::load_csv_ascii(Mat<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::fstream f; + f.open(name.c_str(), std::fstream::in); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_csv_ascii(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +//! Load a matrix in CSV text format (human readable) +template<typename eT> +inline +bool +diskio::load_csv_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + bool load_okay = f.good(); + + f.clear(); + const std::fstream::pos_type pos1 = f.tellg(); + + // + // work out the size + + uword f_n_rows = 0; + uword f_n_cols = 0; + + std::string line_string; + std::string token; + + while( (f.good() == true) && (load_okay == true) ) + { + std::getline(f, line_string); + + if(line_string.size() == 0) + { + break; + } + + std::stringstream line_stream(line_string); + + uword line_n_cols = 0; + + while(line_stream.good() == true) + { + getline(line_stream, token, ','); + ++line_n_cols; + } + + if(f_n_cols < line_n_cols) + { + f_n_cols = line_n_cols; + } + + ++f_n_rows; + } + + f.clear(); + f.seekg(pos1); + + x.zeros(f_n_rows, f_n_cols); + + uword row = 0; + + while(f.good() == true) + { + std::getline(f, line_string); + + if(line_string.size() == 0) + { + break; + } + + std::stringstream line_stream(line_string); + + uword col = 0; + + while(line_stream.good() == true) + { + getline(line_stream, token, ','); + + eT val; + + std::stringstream ss(token); + + ss >> val; + + if(ss.fail() == false) + { + x.at(row,col) = val; + } + + ++col; + } + + ++row; + } + + return load_okay; + } + + + +//! Load a matrix in binary format, +//! with a header that indicates the matrix type as well as its dimensions +template<typename eT> +inline +bool +diskio::load_arma_binary(Mat<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::ifstream f; + f.open(name.c_str(), std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_arma_binary(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +template<typename eT> +inline +bool +diskio::load_arma_binary(Mat<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + bool load_okay = true; + + std::string f_header; + uword f_n_rows; + uword f_n_cols; + + f >> f_header; + f >> f_n_rows; + f >> f_n_cols; + + if(f_header == diskio::gen_bin_header(x)) + { + //f.seekg(1, ios::cur); // NOTE: this may not be portable, as on a Windows machine a newline could be two characters + f.get(); + + x.set_size(f_n_rows,f_n_cols); + f.read( reinterpret_cast<char *>(x.memptr()), std::streamsize(x.n_elem*sizeof(eT)) ); + + load_okay = f.good(); + } + else + { + load_okay = false; + err_msg = "incorrect header in "; + } + + return load_okay; + } + + + +inline +void +diskio::pnm_skip_comments(std::istream& f) + { + while( isspace(f.peek()) ) + { + while( isspace(f.peek()) ) + { + f.get(); + } + + if(f.peek() == '#') + { + while( (f.peek() != '\r') && (f.peek()!='\n') ) + { + f.get(); + } + } + } + } + + + +//! Load a PGM greyscale image as a matrix +template<typename eT> +inline +bool +diskio::load_pgm_binary(Mat<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::fstream f; + f.open(name.c_str(), std::fstream::in | std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_pgm_binary(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +//! Load a PGM greyscale image as a matrix +template<typename eT> +inline +bool +diskio::load_pgm_binary(Mat<eT>& x, std::istream& f, std::string& err_msg) + { + bool load_okay = true; + + std::string f_header; + f >> f_header; + + if(f_header == "P5") + { + uword f_n_rows = 0; + uword f_n_cols = 0; + int f_maxval = 0; + + diskio::pnm_skip_comments(f); + + f >> f_n_cols; + diskio::pnm_skip_comments(f); + + f >> f_n_rows; + diskio::pnm_skip_comments(f); + + f >> f_maxval; + f.get(); + + if( (f_maxval > 0) || (f_maxval <= 65535) ) + { + x.set_size(f_n_rows,f_n_cols); + + if(f_maxval <= 255) + { + const uword n_elem = f_n_cols*f_n_rows; + podarray<u8> tmp(n_elem); + + f.read( reinterpret_cast<char*>(tmp.memptr()), std::streamsize(n_elem) ); + + uword i = 0; + + //cout << "f_n_cols = " << f_n_cols << endl; + //cout << "f_n_rows = " << f_n_rows << endl; + + + for(uword row=0; row < f_n_rows; ++row) + { + for(uword col=0; col < f_n_cols; ++col) + { + x.at(row,col) = eT(tmp[i]); + ++i; + } + } + + } + else + { + const uword n_elem = f_n_cols*f_n_rows; + podarray<u16> tmp(n_elem); + + f.read( reinterpret_cast<char *>(tmp.memptr()), std::streamsize(n_elem*2) ); + + uword i = 0; + + for(uword row=0; row < f_n_rows; ++row) + { + for(uword col=0; col < f_n_cols; ++col) + { + x.at(row,col) = eT(tmp[i]); + ++i; + } + } + + } + + } + else + { + load_okay = false; + err_msg = "currently no code available to handle loading "; + } + + if(f.good() == false) + { + load_okay = false; + } + } + else + { + load_okay = false; + err_msg = "unsupported header in "; + } + + return load_okay; + } + + + +//! Load a PGM greyscale image as a matrix +template<typename T> +inline +bool +diskio::load_pgm_binary(Mat< std::complex<T> >& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + uchar_mat tmp; + const bool load_okay = diskio::load_pgm_binary(tmp, name, err_msg); + + x = conv_to< Mat< std::complex<T> > >::from(tmp); + + return load_okay; + } + + + +//! Load a PGM greyscale image as a matrix +template<typename T> +inline +bool +diskio::load_pgm_binary(Mat< std::complex<T> >& x, std::istream& is, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + uchar_mat tmp; + const bool load_okay = diskio::load_pgm_binary(tmp, is, err_msg); + + x = conv_to< Mat< std::complex<T> > >::from(tmp); + + return load_okay; + } + + + +//! Try to load a matrix by automatically determining its type +template<typename eT> +inline +bool +diskio::load_auto_detect(Mat<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::fstream f; + f.open(name.c_str(), std::fstream::in | std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_auto_detect(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +//! Try to load a matrix by automatically determining its type +template<typename eT> +inline +bool +diskio::load_auto_detect(Mat<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + static const std::string ARMA_MAT_TXT = "ARMA_MAT_TXT"; + static const std::string ARMA_MAT_BIN = "ARMA_MAT_BIN"; + static const std::string P5 = "P5"; + + podarray<char> raw_header(ARMA_MAT_TXT.length() + 1); + + std::streampos pos = f.tellg(); + + f.read( raw_header.memptr(), std::streamsize(ARMA_MAT_TXT.length()) ); + raw_header[ARMA_MAT_TXT.length()] = '\0'; + + f.clear(); + f.seekg(pos); + + const std::string header = raw_header.mem; + + if(ARMA_MAT_TXT == header.substr(0,ARMA_MAT_TXT.length())) + { + return load_arma_ascii(x, f, err_msg); + } + else + if(ARMA_MAT_BIN == header.substr(0,ARMA_MAT_BIN.length())) + { + return load_arma_binary(x, f, err_msg); + } + else + if(P5 == header.substr(0,P5.length())) + { + return load_pgm_binary(x, f, err_msg); + } + else + { + const file_type ft = guess_file_type(f); + + switch(ft) + { + case csv_ascii: + return load_csv_ascii(x, f, err_msg); + break; + + case raw_binary: + return load_raw_binary(x, f, err_msg); + break; + + case raw_ascii: + return load_raw_ascii(x, f, err_msg); + break; + + default: + err_msg = "unknown data in "; + return false; + } + } + + return false; + } + + + +// cubes + + + +//! Save a cube as raw text (no header, human readable). +template<typename eT> +inline +bool +diskio::save_raw_ascii(const Cube<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::fstream f(tmp_name.c_str(), std::fstream::out); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = save_raw_ascii(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +//! Save a cube as raw text (no header, human readable). +template<typename eT> +inline +bool +diskio::save_raw_ascii(const Cube<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + uword cell_width; + + // TODO: need sane values for complex numbers + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.setf(ios::scientific); + f.precision(10); + cell_width = 18; + } + + for(uword slice=0; slice < x.n_slices; ++slice) + { + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + f.put(' '); + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.width(cell_width); + } + + f << x.at(row,col,slice); + } + + f.put('\n'); + } + } + + return f.good(); + } + + + +//! Save a cube as raw binary (no header) +template<typename eT> +inline +bool +diskio::save_raw_binary(const Cube<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f(tmp_name.c_str(), std::fstream::binary); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_raw_binary(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +template<typename eT> +inline +bool +diskio::save_raw_binary(const Cube<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + f.write( reinterpret_cast<const char*>(x.mem), std::streamsize(x.n_elem*sizeof(eT)) ); + + return f.good(); + } + + + +//! Save a cube in text format (human readable), +//! with a header that indicates the cube type as well as its dimensions +template<typename eT> +inline +bool +diskio::save_arma_ascii(const Cube<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f(tmp_name.c_str()); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_arma_ascii(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +//! Save a cube in text format (human readable), +//! with a header that indicates the cube type as well as its dimensions +template<typename eT> +inline +bool +diskio::save_arma_ascii(const Cube<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + const ios::fmtflags orig_flags = f.flags(); + + f << diskio::gen_txt_header(x) << '\n'; + f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n'; + + uword cell_width; + + // TODO: need sane values for complex numbers + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.setf(ios::scientific); + f.precision(10); + cell_width = 18; + } + + for(uword slice=0; slice < x.n_slices; ++slice) + { + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + f.put(' '); + + if( (is_float<eT>::value == true) || (is_double<eT>::value == true) ) + { + f.width(cell_width); + } + + f << x.at(row,col,slice); + } + + f.put('\n'); + } + } + + const bool save_okay = f.good(); + + f.flags(orig_flags); + + return save_okay; + } + + + +//! Save a cube in binary format, +//! with a header that stores the cube type as well as its dimensions +template<typename eT> +inline +bool +diskio::save_arma_binary(const Cube<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f(tmp_name.c_str(), std::fstream::binary); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_arma_binary(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +//! Save a cube in binary format, +//! with a header that stores the cube type as well as its dimensions +template<typename eT> +inline +bool +diskio::save_arma_binary(const Cube<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + f << diskio::gen_bin_header(x) << '\n'; + f << x.n_rows << ' ' << x.n_cols << ' ' << x.n_slices << '\n'; + + f.write( reinterpret_cast<const char*>(x.mem), std::streamsize(x.n_elem*sizeof(eT)) ); + + return f.good(); + } + + + +//! Load a cube as raw text (no header, human readable). +//! NOTE: this is much slower than reading a file with a header. +template<typename eT> +inline +bool +diskio::load_raw_ascii(Cube<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + Mat<eT> tmp; + const bool load_okay = diskio::load_raw_ascii(tmp, name, err_msg); + + if(load_okay == true) + { + if(tmp.is_empty() == false) + { + x.set_size(tmp.n_rows, tmp.n_cols, 1); + + x.slice(0) = tmp; + } + else + { + x.reset(); + } + } + + return load_okay; + } + + + +//! Load a cube as raw text (no header, human readable). +//! NOTE: this is much slower than reading a file with a header. +template<typename eT> +inline +bool +diskio::load_raw_ascii(Cube<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + Mat<eT> tmp; + const bool load_okay = diskio::load_raw_ascii(tmp, f, err_msg); + + if(load_okay == true) + { + if(tmp.is_empty() == false) + { + x.set_size(tmp.n_rows, tmp.n_cols, 1); + + x.slice(0) = tmp; + } + else + { + x.reset(); + } + } + + return load_okay; + } + + + +//! Load a cube in binary format (no header); +//! the cube is assumed to have one slice with one column +template<typename eT> +inline +bool +diskio::load_raw_binary(Cube<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::ifstream f; + f.open(name.c_str(), std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_raw_binary(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +template<typename eT> +inline +bool +diskio::load_raw_binary(Cube<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + arma_ignore(err_msg); + + f.clear(); + const std::streampos pos1 = f.tellg(); + + f.clear(); + f.seekg(0, ios::end); + + f.clear(); + const std::streampos pos2 = f.tellg(); + + const uword N = ( (pos1 >= 0) && (pos2 >= 0) ) ? uword(pos2 - pos1) : 0; + + f.clear(); + //f.seekg(0, ios::beg); + f.seekg(pos1); + + x.set_size(N / sizeof(eT), 1, 1); + + f.clear(); + f.read( reinterpret_cast<char *>(x.memptr()), std::streamsize(N) ); + + return f.good(); + } + + + +//! Load a cube in text format (human readable), +//! with a header that indicates the cube type as well as its dimensions +template<typename eT> +inline +bool +diskio::load_arma_ascii(Cube<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::ifstream f(name.c_str()); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_arma_ascii(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +//! Load a cube in text format (human readable), +//! with a header that indicates the cube type as well as its dimensions +template<typename eT> +inline +bool +diskio::load_arma_ascii(Cube<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + bool load_okay = true; + + std::string f_header; + uword f_n_rows; + uword f_n_cols; + uword f_n_slices; + + f >> f_header; + f >> f_n_rows; + f >> f_n_cols; + f >> f_n_slices; + + if(f_header == diskio::gen_txt_header(x)) + { + x.set_size(f_n_rows, f_n_cols, f_n_slices); + + for(uword slice=0; slice < x.n_slices; ++slice) + { + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + f >> x.at(row,col,slice); + } + } + } + + load_okay = f.good(); + } + else + { + load_okay = false; + err_msg = "incorrect header in "; + } + + return load_okay; + } + + + +//! Load a cube in binary format, +//! with a header that indicates the cube type as well as its dimensions +template<typename eT> +inline +bool +diskio::load_arma_binary(Cube<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::ifstream f; + f.open(name.c_str(), std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_arma_binary(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +template<typename eT> +inline +bool +diskio::load_arma_binary(Cube<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + bool load_okay = true; + + std::string f_header; + uword f_n_rows; + uword f_n_cols; + uword f_n_slices; + + f >> f_header; + f >> f_n_rows; + f >> f_n_cols; + f >> f_n_slices; + + if(f_header == diskio::gen_bin_header(x)) + { + //f.seekg(1, ios::cur); // NOTE: this may not be portable, as on a Windows machine a newline could be two characters + f.get(); + + x.set_size(f_n_rows, f_n_cols, f_n_slices); + f.read( reinterpret_cast<char *>(x.memptr()), std::streamsize(x.n_elem*sizeof(eT)) ); + + load_okay = f.good(); + } + else + { + load_okay = false; + err_msg = "incorrect header in "; + } + + return load_okay; + } + + + +//! Try to load a cube by automatically determining its type +template<typename eT> +inline +bool +diskio::load_auto_detect(Cube<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::fstream f; + f.open(name.c_str(), std::fstream::in | std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_auto_detect(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +//! Try to load a cube by automatically determining its type +template<typename eT> +inline +bool +diskio::load_auto_detect(Cube<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + static const std::string ARMA_CUB_TXT = "ARMA_CUB_TXT"; + static const std::string ARMA_CUB_BIN = "ARMA_CUB_BIN"; + static const std::string P6 = "P6"; + + podarray<char> raw_header(ARMA_CUB_TXT.length() + 1); + + std::streampos pos = f.tellg(); + + f.read( raw_header.memptr(), std::streamsize(ARMA_CUB_TXT.length()) ); + raw_header[ARMA_CUB_TXT.length()] = '\0'; + + f.clear(); + f.seekg(pos); + + const std::string header = raw_header.mem; + + if(ARMA_CUB_TXT == header.substr(0, ARMA_CUB_TXT.length())) + { + return load_arma_ascii(x, f, err_msg); + } + else + if(ARMA_CUB_BIN == header.substr(0, ARMA_CUB_BIN.length())) + { + return load_arma_binary(x, f, err_msg); + } + else + if(P6 == header.substr(0, P6.length())) + { + return load_ppm_binary(x, f, err_msg); + } + else + { + const file_type ft = guess_file_type(f); + + switch(ft) + { + // case csv_ascii: + // return load_csv_ascii(x, f, err_msg); + // break; + + case raw_binary: + return load_raw_binary(x, f, err_msg); + break; + + case raw_ascii: + return load_raw_ascii(x, f, err_msg); + break; + + default: + err_msg = "unknown data in "; + return false; + } + } + + return false; + } + + + + + +// fields + + + +template<typename T1> +inline +bool +diskio::save_arma_binary(const field<T1>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f( tmp_name.c_str(), std::fstream::binary ); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_arma_binary(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +template<typename T1> +inline +bool +diskio::save_arma_binary(const field<T1>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + arma_type_check(( (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) )); + + f << "ARMA_FLD_BIN" << '\n'; + f << x.n_rows << '\n'; + f << x.n_cols << '\n'; + + bool save_okay = true; + + for(uword i=0; i<x.n_elem; ++i) + { + save_okay = diskio::save_arma_binary(x[i], f); + + if(save_okay == false) + { + break; + } + } + + return save_okay; + } + + + +template<typename T1> +inline +bool +diskio::load_arma_binary(field<T1>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::ifstream f( name.c_str(), std::fstream::binary ); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_arma_binary(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +template<typename T1> +inline +bool +diskio::load_arma_binary(field<T1>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + arma_type_check(( (is_Mat<T1>::value == false) && (is_Cube<T1>::value == false) )); + + bool load_okay = true; + + std::string f_type; + f >> f_type; + + if(f_type != "ARMA_FLD_BIN") + { + load_okay = false; + err_msg = "unsupported field type in "; + } + else + { + uword f_n_rows; + uword f_n_cols; + + f >> f_n_rows; + f >> f_n_cols; + + x.set_size(f_n_rows, f_n_cols); + + f.get(); + + for(uword i=0; i<x.n_elem; ++i) + { + load_okay = diskio::load_arma_binary(x[i], f, err_msg); + + if(load_okay == false) + { + break; + } + } + } + + return load_okay; + } + + + +inline +bool +diskio::save_std_string(const field<std::string>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f( tmp_name.c_str(), std::fstream::binary ); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_std_string(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +inline +bool +diskio::save_std_string(const field<std::string>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + for(uword row=0; row<x.n_rows; ++row) + for(uword col=0; col<x.n_cols; ++col) + { + f << x.at(row,col); + + if(col < x.n_cols-1) + { + f << ' '; + } + else + { + f << '\n'; + } + } + + return f.good(); + } + + + +inline +bool +diskio::load_std_string(field<std::string>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::ifstream f( name.c_str() ); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_std_string(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +inline +bool +diskio::load_std_string(field<std::string>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + bool load_okay = true; + + // + // work out the size + + uword f_n_rows = 0; + uword f_n_cols = 0; + + bool f_n_cols_found = false; + + std::string line_string; + std::string token; + + while( (f.good() == true) && (load_okay == true) ) + { + std::getline(f, line_string); + if(line_string.size() == 0) + break; + + std::stringstream line_stream(line_string); + + uword line_n_cols = 0; + while (line_stream >> token) + line_n_cols++; + + if(f_n_cols_found == false) + { + f_n_cols = line_n_cols; + f_n_cols_found = true; + } + else + { + if(line_n_cols != f_n_cols) + { + load_okay = false; + err_msg = "inconsistent number of columns in "; + } + } + + ++f_n_rows; + } + + if(load_okay == true) + { + f.clear(); + f.seekg(0, ios::beg); + //f.seekg(start); + + x.set_size(f_n_rows, f_n_cols); + + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + f >> x.at(row,col); + } + } + } + + if(f.good() == false) + { + load_okay = false; + } + + return load_okay; + } + + + +//! Try to load a field by automatically determining its type +template<typename T1> +inline +bool +diskio::load_auto_detect(field<T1>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::fstream f; + f.open(name.c_str(), std::fstream::in | std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_auto_detect(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +//! Try to load a field by automatically determining its type +template<typename T1> +inline +bool +diskio::load_auto_detect(field<T1>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + arma_type_check(( is_Mat<T1>::value == false )); + + static const std::string ARMA_FLD_BIN = "ARMA_FLD_BIN"; + static const std::string P6 = "P6"; + + podarray<char> raw_header(ARMA_FLD_BIN.length() + 1); + + std::streampos pos = f.tellg(); + + f.read( raw_header.memptr(), std::streamsize(ARMA_FLD_BIN.length()) ); + + f.clear(); + f.seekg(pos); + + raw_header[ARMA_FLD_BIN.length()] = '\0'; + + const std::string header = raw_header.mem; + + if(ARMA_FLD_BIN == header.substr(0, ARMA_FLD_BIN.length())) + { + return load_arma_binary(x, f, err_msg); + } + else + if(P6 == header.substr(0, P6.length())) + { + return load_ppm_binary(x, f, err_msg); + } + else + { + err_msg = "unsupported header in "; + return false; + } + } + + + +// +// handling of PPM images by cubes + + +template<typename eT> +inline +bool +diskio::load_ppm_binary(Cube<eT>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::fstream f; + f.open(name.c_str(), std::fstream::in | std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_ppm_binary(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +template<typename eT> +inline +bool +diskio::load_ppm_binary(Cube<eT>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + bool load_okay = true; + + std::string f_header; + f >> f_header; + + if(f_header == "P6") + { + uword f_n_rows = 0; + uword f_n_cols = 0; + int f_maxval = 0; + + diskio::pnm_skip_comments(f); + + f >> f_n_cols; + diskio::pnm_skip_comments(f); + + f >> f_n_rows; + diskio::pnm_skip_comments(f); + + f >> f_maxval; + f.get(); + + if( (f_maxval > 0) || (f_maxval <= 65535) ) + { + x.set_size(f_n_rows, f_n_cols, 3); + + if(f_maxval <= 255) + { + const uword n_elem = 3*f_n_cols*f_n_rows; + podarray<u8> tmp(n_elem); + + f.read( reinterpret_cast<char*>(tmp.memptr()), std::streamsize(n_elem) ); + + uword i = 0; + + //cout << "f_n_cols = " << f_n_cols << endl; + //cout << "f_n_rows = " << f_n_rows << endl; + + + for(uword row=0; row < f_n_rows; ++row) + { + for(uword col=0; col < f_n_cols; ++col) + { + x.at(row,col,0) = eT(tmp[i+0]); + x.at(row,col,1) = eT(tmp[i+1]); + x.at(row,col,2) = eT(tmp[i+2]); + i+=3; + } + + } + } + else + { + const uword n_elem = 3*f_n_cols*f_n_rows; + podarray<u16> tmp(n_elem); + + f.read( reinterpret_cast<char *>(tmp.memptr()), std::streamsize(2*n_elem) ); + + uword i = 0; + + for(uword row=0; row < f_n_rows; ++row) + { + for(uword col=0; col < f_n_cols; ++col) + { + x.at(row,col,0) = eT(tmp[i+0]); + x.at(row,col,1) = eT(tmp[i+1]); + x.at(row,col,2) = eT(tmp[i+2]); + i+=3; + } + + } + + } + + } + else + { + load_okay = false; + err_msg = "currently no code available to handle loading "; + } + + if(f.good() == false) + { + load_okay = false; + } + + } + else + { + load_okay = false; + err_msg = "unsupported header in "; + } + + return load_okay; + } + + + +template<typename eT> +inline +bool +diskio::save_ppm_binary(const Cube<eT>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + + std::ofstream f( tmp_name.c_str(), std::fstream::binary ); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_ppm_binary(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +template<typename eT> +inline +bool +diskio::save_ppm_binary(const Cube<eT>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + arma_debug_check( (x.n_slices != 3), "diskio::save_ppm_binary(): given cube must have exactly 3 slices" ); + + const uword n_elem = 3 * x.n_rows * x.n_cols; + podarray<u8> tmp(n_elem); + + uword i = 0; + for(uword row=0; row < x.n_rows; ++row) + { + for(uword col=0; col < x.n_cols; ++col) + { + tmp[i+0] = u8( access::tmp_real( x.at(row,col,0) ) ); + tmp[i+1] = u8( access::tmp_real( x.at(row,col,1) ) ); + tmp[i+2] = u8( access::tmp_real( x.at(row,col,2) ) ); + + i+=3; + } + } + + f << "P6" << '\n'; + f << x.n_cols << '\n'; + f << x.n_rows << '\n'; + f << 255 << '\n'; + + f.write( reinterpret_cast<const char*>(tmp.mem), std::streamsize(n_elem) ); + + return f.good(); + } + + + +// +// handling of PPM images by fields + + + +template<typename T1> +inline +bool +diskio::load_ppm_binary(field<T1>& x, const std::string& name, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + std::fstream f; + f.open(name.c_str(), std::fstream::in | std::fstream::binary); + + bool load_okay = f.is_open(); + + if(load_okay == true) + { + load_okay = diskio::load_ppm_binary(x, f, err_msg); + f.close(); + } + + return load_okay; + } + + + +template<typename T1> +inline +bool +diskio::load_ppm_binary(field<T1>& x, std::istream& f, std::string& err_msg) + { + arma_extra_debug_sigprint(); + + arma_type_check(( is_Mat<T1>::value == false )); + typedef typename T1::elem_type eT; + + bool load_okay = true; + + std::string f_header; + f >> f_header; + + if(f_header == "P6") + { + uword f_n_rows = 0; + uword f_n_cols = 0; + int f_maxval = 0; + + diskio::pnm_skip_comments(f); + + f >> f_n_cols; + diskio::pnm_skip_comments(f); + + f >> f_n_rows; + diskio::pnm_skip_comments(f); + + f >> f_maxval; + f.get(); + + if( (f_maxval > 0) || (f_maxval <= 65535) ) + { + x.set_size(3); + Mat<eT>& R = x(0); + Mat<eT>& G = x(1); + Mat<eT>& B = x(2); + + R.set_size(f_n_rows,f_n_cols); + G.set_size(f_n_rows,f_n_cols); + B.set_size(f_n_rows,f_n_cols); + + if(f_maxval <= 255) + { + const uword n_elem = 3*f_n_cols*f_n_rows; + podarray<u8> tmp(n_elem); + + f.read( reinterpret_cast<char*>(tmp.memptr()), std::streamsize(n_elem) ); + + uword i = 0; + + //cout << "f_n_cols = " << f_n_cols << endl; + //cout << "f_n_rows = " << f_n_rows << endl; + + + for(uword row=0; row < f_n_rows; ++row) + { + for(uword col=0; col < f_n_cols; ++col) + { + R.at(row,col) = eT(tmp[i+0]); + G.at(row,col) = eT(tmp[i+1]); + B.at(row,col) = eT(tmp[i+2]); + i+=3; + } + + } + } + else + { + const uword n_elem = 3*f_n_cols*f_n_rows; + podarray<u16> tmp(n_elem); + + f.read( reinterpret_cast<char *>(tmp.memptr()), std::streamsize(2*n_elem) ); + + uword i = 0; + + for(uword row=0; row < f_n_rows; ++row) + { + for(uword col=0; col < f_n_cols; ++col) + { + R.at(row,col) = eT(tmp[i+0]); + G.at(row,col) = eT(tmp[i+1]); + B.at(row,col) = eT(tmp[i+2]); + i+=3; + } + + } + + } + + } + else + { + load_okay = false; + err_msg = "currently no code available to handle loading "; + } + + if(f.good() == false) + { + load_okay = false; + } + + } + else + { + load_okay = false; + err_msg = "unsupported header in "; + } + + return load_okay; + } + + + +template<typename T1> +inline +bool +diskio::save_ppm_binary(const field<T1>& x, const std::string& final_name) + { + arma_extra_debug_sigprint(); + + const std::string tmp_name = diskio::gen_tmp_name(final_name); + std::ofstream f( tmp_name.c_str(), std::fstream::binary ); + + bool save_okay = f.is_open(); + + if(save_okay == true) + { + save_okay = diskio::save_ppm_binary(x, f); + + f.flush(); + f.close(); + + if(save_okay == true) + { + save_okay = diskio::safe_rename(tmp_name, final_name); + } + } + + return save_okay; + } + + + +template<typename T1> +inline +bool +diskio::save_ppm_binary(const field<T1>& x, std::ostream& f) + { + arma_extra_debug_sigprint(); + + arma_type_check(( is_Mat<T1>::value == false )); + + typedef typename T1::elem_type eT; + + arma_debug_check( (x.n_elem != 3), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" ); + + bool same_size = true; + for(uword i=1; i<3; ++i) + { + if( (x(0).n_rows != x(i).n_rows) || (x(0).n_cols != x(i).n_cols) ) + { + same_size = false; + break; + } + } + + arma_debug_check( (same_size != true), "diskio::save_ppm_binary(): given field must have exactly 3 matrices of equal size" ); + + const Mat<eT>& R = x(0); + const Mat<eT>& G = x(1); + const Mat<eT>& B = x(2); + + f << "P6" << '\n'; + f << R.n_cols << '\n'; + f << R.n_rows << '\n'; + f << 255 << '\n'; + + const uword n_elem = 3 * R.n_rows * R.n_cols; + podarray<u8> tmp(n_elem); + + uword i = 0; + for(uword row=0; row < R.n_rows; ++row) + { + for(uword col=0; col < R.n_cols; ++col) + { + tmp[i+0] = u8( access::tmp_real( R.at(row,col) ) ); + tmp[i+1] = u8( access::tmp_real( G.at(row,col) ) ); + tmp[i+2] = u8( access::tmp_real( B.at(row,col) ) ); + + i+=3; + } + } + + f.write( reinterpret_cast<const char*>(tmp.mem), std::streamsize(n_elem) ); + + return f.good(); + } + + + +//! @} +