17#ifndef __math_math_h__
18#define __math_math_h__
39 constexpr double e = 2.71828182845904523536;
40 constexpr double pi = 3.14159265358979323846;
43 constexpr double sqrt2 = 1.41421356237309504880;
53 template <
typename T>
inline constexpr T
pow2 (
const T& v) {
return v*v; }
54 template <
typename T>
inline constexpr T
pow3 (
const T& v) {
return pow2 (v) *v; }
55 template <
typename T>
inline constexpr T
pow4 (
const T& v) {
return pow2 (
pow2 (v)); }
56 template <
typename T>
inline constexpr T
pow5 (
const T& v) {
return pow4 (v) *v; }
57 template <
typename T>
inline constexpr T
pow6 (
const T& v) {
return pow2 (
pow3 (v)); }
58 template <
typename T>
inline constexpr T
pow7 (
const T& v) {
return pow6 (v) *v; }
59 template <
typename T>
inline constexpr T
pow8 (
const T& v) {
return pow2 (
pow4 (v)); }
60 template <
typename T>
inline constexpr T
pow9 (
const T& v) {
return pow8 (v) *v; }
61 template <
typename T>
inline constexpr T
pow10 (
const T& v) {
return pow8 (v) *
pow2 (v); }
64 template <
typename I,
typename T>
inline constexpr I
round (
const T x)
throw ()
75 template <
typename I,
typename T>
inline constexpr I
floor (
const T x)
throw ()
86 template <
typename I,
typename T>
inline constexpr I
ceil (
const T x)
throw ()
97 template<
typename Derived>
98 inline bool is_finite(
const Eigen::MatrixBase<Derived>& x)
100 return ( (x - x).array() == (x - x).array()).all();
104 template<
typename Derived>
105 inline bool is_nan(
const Eigen::MatrixBase<Derived>& x)
107 return ((x.array() == x.array())).all();
112 template <
class Cont>
114 typedef char yes[1], no[2];
115 template<
typename C>
static yes& test(
typename Cont::Scalar);
116 template<
typename C>
static no& test(...);
118 static const bool value =
sizeof(test<Cont>(0)) ==
sizeof(yes);
122 template <
class Cont,
typename ReturnType =
int>
127 template <
class Cont>
130 using type =
typename Cont::Scalar;
135 template <
class MatrixType>
138 DEBUG (
"saving " +
str(M.rows()) +
"x" +
str(M.cols()) +
" matrix to file \"" + filename +
"\"...");
141 Eigen::IOFormat fmt (Eigen::FullPrecision, Eigen::DontAlignCols, std::string (1,
Path::delimiter (filename)),
"\n",
"",
"",
"",
"");
142 out << M.format (fmt);
147 template <
class ValueType = default_type>
150 std::ifstream stream (filename, std::ios_base::in | std::ios_base::binary);
152 throw Exception (
"Unable to open numerical data text file \"" + filename +
"\": " + strerror(errno));
154 std::string sbuf, cbuf;
157 while (
getline (stream, sbuf)) {
158 hash = sbuf.find_first_of (
'#');
159 if (comments and hash != std::string::npos) {
160 cbuf =
strip (sbuf.substr (hash));
162 comments->push_back (cbuf.substr(1));
165 sbuf =
strip (sbuf.substr (0, hash));
169 const auto elements =
MR::split (sbuf,
" ,;\t",
true);
172 for (
const auto& entry : elements)
173 V.back().push_back (to<ValueType> (entry));
175 e.push_back (
"Cannot load row " +
str(V.size()) +
" of file \"" + filename +
"\" as delimited numerical matrix data:");
181 if (V.back().size() != V[0].size())
182 throw Exception (
"uneven rows in matrix file \"" + filename +
"\" " +
183 "(first row: " +
str(V[0].size()) +
" columns; row " +
str(V.size()) +
": " +
str(V.back().size()) +
" columns)");
189 throw Exception (
"no data in matrix file \"" + filename +
"\"");
195 template <
class ValueType = default_type>
196 Eigen::Matrix<ValueType, Eigen::Dynamic, Eigen::Dynamic>
load_matrix (
const std::string& filename)
198 DEBUG (
"loading matrix file \"" + filename +
"\"...");
201 Eigen::Matrix<ValueType, Eigen::Dynamic, Eigen::Dynamic> M (V.size(), V[0].size());
202 for (ssize_t i = 0; i < M.rows(); i++)
203 for (ssize_t j = 0; j < M.cols(); j++)
206 DEBUG (
"found " +
str(M.rows()) +
"x" +
str(M.cols()) +
" matrix in file \"" + filename +
"\"");
211 template <
class ValueType = default_type>
212 Eigen::Matrix<ValueType, Eigen::Dynamic, Eigen::Dynamic>
parse_matrix (
const std::string& spec)
214 Eigen::Matrix<ValueType, Eigen::Dynamic, Eigen::Dynamic> M;
216 for (
size_t row = 0; row < lines.size(); ++row) {
219 M.resize (lines.size(), values.size());
220 else if (M.cols() != ssize_t (values.size()))
221 throw Exception (
"error converting string to matrix - uneven number of entries per row");
222 for (
size_t col = 0; col < values.size(); ++col)
223 M(row, col) = values[col];
229 template <
class VectorType>
232 DEBUG (
"loading transform file \"" + filename +
"\"...");
238 throw Exception (
"transform in file " + filename +
" is empty");
240 if (V[0].size() != 4)
241 throw Exception (
"transform in file " + filename +
" is invalid: does not contain 4 columns.");
243 if (V.size() != 3 && V.size() != 4)
244 throw Exception (
"transform in file " + filename +
" is invalid: must contain either 3 or 4 rows.");
247 for (ssize_t i = 0; i < 3; i++)
248 for (ssize_t j = 0; j < 4; j++)
251 if (centre.size() == 3) {
252 const std::string key =
" centre: ";
253 const std::string key_legacy =
"centre ";
258 for (
auto & line : comments) {
259 if (strncmp(line.c_str(), key.c_str(), key.size()) == 0)
260 elements =
split (
strip (line.substr (key.size())),
" ,;\t",
true);
261 else if (strncmp(line.c_str(), key_legacy.c_str(), key_legacy.size()) == 0)
262 elements =
split (
strip (line.substr (key_legacy.size())),
" ,;\t",
true);
263 if (elements.size()) {
264 if (elements.size() != 3)
265 throw Exception (
"could not parse centre in transformation file " + filename +
": " +
strip (line.substr (key.size())));
267 centre[0] = to<default_type> (elements[0]);
268 centre[1] = to<default_type> (elements[1]);
269 centre[2] = to<default_type> (elements[2]);
271 throw Exception (
"File \"" + filename +
"\" contains non-numerical data in centre: " +
strip (line.substr (key.size())));
290 DEBUG (
"saving transform to file \"" + filename +
"\"...");
294 Eigen::IOFormat fmt (Eigen::FullPrecision, Eigen::DontAlignCols, std::string (1, d),
"\n",
"",
"",
"",
"");
295 out << M.matrix().format (fmt);
296 out <<
"\n0" << d <<
"0" << d <<
"0" << d <<
"1\n";
299 template <
class Derived>
302 if (centre.rows() != 3 or centre.cols() != 1)
303 throw Exception (
"save_transform() requires 3x1 vector as centre");
305 Eigen::IOFormat centrefmt(Eigen::FullPrecision, Eigen::DontAlignCols,
" ",
"\n",
"",
"",
"",
"\n");
306 std::ostringstream os;
307 os<<centre.transpose().format(centrefmt);
308 local_keyvals.insert(std::pair<std::string, std::string>(
"centre", os.str()));
309 save_transform(M, filename, local_keyvals, add_to_command_history);
313 template <
class VectorType>
316 DEBUG (
"saving vector of size " +
str(V.size()) +
" to file \"" + filename +
"\"...");
320 for (
decltype(V.size()) i = 0; i < V.size() - 1; i++)
321 out <<
str(V[i], 10) << d;
322 out <<
str(V[V.size() - 1], 10) <<
"\n";
326 template <
class ValueType = default_type>
327 Eigen::Matrix<ValueType, Eigen::Dynamic, 1>
load_vector (
const std::string& filename)
329 auto vec = load_matrix<ValueType> (filename);
333 throw Exception (
"file \"" + filename +
"\" contains matrix, not vector");
open output files for writing, checking for pre-existing file if necessary
typename Cont::Scalar type
Get the underlying scalar value type for both std:: containers and Eigen.
typename Cont::value_type type
convenience functions for SFINAE on std:: / Eigen containers
constexpr T pow6(const T &v)
constexpr T pow5(const T &v)
constexpr T pow8(const T &v)
bool is_nan(const Eigen::MatrixBase< Derived > &x)
check if all elements of an Eigen MatrixBase object are a number
constexpr T pow7(const T &v)
constexpr T pow2(const T &v)
constexpr I ceil(const T x)
template function with cast to different type
constexpr T pow3(const T &v)
constexpr T pow10(const T &v)
constexpr I floor(const T x)
template function with cast to different type
constexpr T pow4(const T &v)
constexpr T pow9(const T &v)
bool is_finite(const Eigen::MatrixBase< Derived > &x)
check if all elements of an Eigen MatrixBase object are finite
constexpr I round(const T x)
void write(File::OFStream &out, const KeyValues &keyvals, const std::string &prefix, const bool add_to_command_history=true)
MR::default_type value_type
char delimiter(const std::string &filename)
std::map< std::string, std::string > KeyValues
used in various places for storing key-value pairs
transform_type load_transform(const std::string &filename, VectorType ¢re)
read matrix data from filename into an Eigen::Tranform class
vector< vector< ValueType > > load_matrix_2D_vector(const std::string &filename, vector< std::string > *comments=nullptr)
read matrix data into a 2D vector filename
Eigen::Matrix< ValueType, Eigen::Dynamic, Eigen::Dynamic > load_matrix(const std::string &filename)
read matrix data into an Eigen::Matrix filename
vector< default_type > parse_floats(const std::string &spec)
std::istream & getline(std::istream &stream, std::string &string)
read a line from the stream
void save_transform(const transform_type &M, const std::string &filename, const KeyValues &keyvals=KeyValues(), const bool add_to_command_history=true)
write the transform M to file
std::string strip(const std::string &string, const std::string &ws={" \0\t\r\n", 5}, bool left=true, bool right=true)
std::string str(const T &value, int precision=0)
Eigen::Transform< default_type, 3, Eigen::AffineCompact > transform_type
the type for the affine transform of an image:
Eigen::Matrix< ValueType, Eigen::Dynamic, 1 > load_vector(const std::string &filename)
read the vector data from filename
vector< std::string > split_lines(const std::string &string, bool ignore_empty_fields=true, size_t num=std::numeric_limits< size_t >::max())
vector< std::string > split(const std::string &string, const char *delimiters=" \t\n", bool ignore_empty_fields=false, size_t num=std::numeric_limits< size_t >::max())
constexpr default_type NaN
Eigen::Matrix< ValueType, Eigen::Dynamic, Eigen::Dynamic > parse_matrix(const std::string &spec)
read matrix data from a text string spec
void save_matrix(const MatrixType &M, const std::string &filename, const KeyValues &keyvals=KeyValues(), const bool add_to_command_history=true)
write the matrix M to file
void save_vector(const VectorType &V, const std::string &filename, const KeyValues &keyvals=KeyValues(), const bool add_to_command_history=true)
write the vector V to file