diff --git a/src/common/aka_iterators.hh b/src/common/aka_iterators.hh index deaeda701..e5a41ca92 100644 --- a/src/common/aka_iterators.hh +++ b/src/common/aka_iterators.hh @@ -1,321 +1,326 @@ /** * @file aka_iterators.hh * * @author Nicolas Richart * * @date creation Wed Jul 19 2017 * * @brief iterator interfaces * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_error.hh" /* -------------------------------------------------------------------------- */ -#include -#include #include #include +#include +#include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_ITERATORS_HH__ #define __AKANTU_AKA_ITERATORS_HH__ namespace akantu { namespace tuple { /* ------------------------------------------------------------------------ */ namespace details { template struct Foreach { template static inline decltype(auto) transform_forward(F && func, Tuple && tuple) { return std::tuple_cat( Foreach::transform_forward(std::forward(func), std::forward(tuple)), std::forward_as_tuple(std::forward(func)( std::get(std::forward(tuple))))); } template static inline decltype(auto) transform(F && func, Tuple && tuple) { return std::tuple_cat( Foreach::transform(std::forward(func), std::forward(tuple)), std::make_tuple(std::forward(func)( std::get(std::forward(tuple))))); } template static inline void foreach (F && func, Tuple && tuple) { Foreach::foreach (std::forward(func), std::forward(tuple)); std::forward(func)(std::get(std::forward(tuple))); } template static inline bool equal(Tuple && a, Tuple && b) { if (not(std::get(std::forward(a)) == std::get(std::forward(b)))) return false; return Foreach::equal(std::forward(a), std::forward(b)); } }; /* ------------------------------------------------------------------------ */ template <> struct Foreach<1> { template static inline decltype(auto) transform_forward(F && func, Tuple && tuple) { return std::forward_as_tuple( std::forward(func)(std::get<0>(std::forward(tuple)))); } template static inline decltype(auto) transform(F && func, Tuple && tuple) { return std::make_tuple( std::forward(func)(std::get<0>(std::forward(tuple)))); } template static inline void foreach (F && func, Tuple && tuple) { std::forward(func)(std::get<0>(std::forward(tuple))); } template static inline bool equal(Tuple && a, Tuple && b) { return std::get<0>(std::forward(a)) == std::get<0>(std::forward(b)); } }; } // namespace details /* ------------------------------------------------------------------------ */ template bool are_equal(Tuple && a, Tuple && b) { return details::Foreach>::value>::equal( std::forward(a), std::forward(b)); } template void foreach (F && func, Tuple && tuple) { details::Foreach>::value>::foreach ( std::forward(func), std::forward(tuple)); } template decltype(auto) transform_forward(F && func, Tuple && tuple) { return details::Foreach>::value>:: transform_forward(std::forward(func), std::forward(tuple)); } template decltype(auto) transform(F && func, Tuple && tuple) { return details::Foreach>::value>:: transform(std::forward(func), std::forward(tuple)); } } // namespace tuple namespace iterators { namespace details { struct dereference_iterator { - template - decltype(auto) operator()(Iter & it) const { + template decltype(auto) operator()(Iter & it) const { return std::forward(*it); } }; struct increment_iterator { template void operator()(Iter & it) const { ++it; } }; struct begin_container { template decltype(auto) operator()(Container && cont) const { return std::forward(cont).begin(); } }; struct end_container { template decltype(auto) operator()(Container && cont) const { return std::forward(cont).end(); } }; } // namespace details /* ------------------------------------------------------------------------ */ template class ZipIterator { private: using tuple_t = std::tuple; + public: explicit ZipIterator(tuple_t iterators) : iterators(std::move(iterators)) {} decltype(auto) operator*() { return tuple::transform_forward(details::dereference_iterator(), iterators); } ZipIterator & operator++() { tuple::foreach (details::increment_iterator(), iterators); return *this; } bool operator==(const ZipIterator & other) const { return tuple::are_equal(iterators, other.iterators); } bool operator!=(const ZipIterator & other) const { return not operator==(other); } private: tuple_t iterators; }; } // namespace iterators /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ template decltype(auto) zip_iterator(std::tuple && iterators_tuple) { - auto zip = iterators::ZipIterator(std::forward(iterators_tuple)); + auto zip = iterators::ZipIterator( + std::forward(iterators_tuple)); return zip; } /* -------------------------------------------------------------------------- */ namespace containers { template class ZipContainer { using containers_t = std::tuple; public: explicit ZipContainer(Containers &&... containers) : containers(std::forward(containers)...) {} decltype(auto) begin() const { return zip_iterator( tuple::transform(iterators::details::begin_container(), std::forward(containers))); } decltype(auto) end() const { return zip_iterator( tuple::transform(iterators::details::end_container(), std::forward(containers))); } decltype(auto) begin() { return zip_iterator( tuple::transform(iterators::details::begin_container(), std::forward(containers))); } decltype(auto) end() { return zip_iterator( tuple::transform(iterators::details::end_container(), std::forward(containers))); } private: containers_t containers; }; } // namespace containers /* -------------------------------------------------------------------------- */ template decltype(auto) zip(Containers &&... conts) { - return containers::ZipContainer(std::forward(conts)...); + return containers::ZipContainer( + std::forward(conts)...); } /* -------------------------------------------------------------------------- */ /* Arange */ /* -------------------------------------------------------------------------- */ namespace iterators { template class ArangeIterator { public: using value_type = T; - using pointer = T*; - using reference = T&; + using pointer = T *; + using reference = T &; using iterator_category = std::input_iterator_tag; constexpr ArangeIterator(T value, T step) : value(value), step(step) {} constexpr ArangeIterator(const ArangeIterator &) = default; constexpr ArangeIterator & operator++() { value += step; return *this; } constexpr const T & operator*() const { return value; } constexpr bool operator==(const ArangeIterator & other) const { return (value == other.value) and (step == other.step); } constexpr bool operator!=(const ArangeIterator & other) const { return not operator==(other); } private: T value{0}; const T step{1}; }; } // namespace iterators namespace containers { template class ArangeContainer { public: using iterator = iterators::ArangeIterator; constexpr ArangeContainer(T start, T stop, T step = 1) - : start(start), stop((stop - start)% step == 0 ? stop : start + (1 + (stop -start)/step)*step), step(step) {} + : start(start), stop((stop - start) % step == 0 + ? stop + : start + (1 + (stop - start) / step) * step), + step(step) {} explicit constexpr ArangeContainer(T stop) : ArangeContainer(0, stop, 1) {} constexpr T operator[](size_t i) { T val = start + i * step; assert(val < stop && "i is out of range"); return val; } constexpr size_t size() { return (stop - start) / step; } constexpr iterator begin() { return iterator(start, step); } constexpr iterator end() { return iterator(stop, step); } private: const T start{0}, stop{0}, step{1}; }; } // namespace containers -template -inline decltype(auto) arange(T stop) { +template inline decltype(auto) arange(T stop) { return containers::ArangeContainer(stop); } -template +template inline constexpr decltype(auto) arange(T start, T stop, T step = 1) { return containers::ArangeContainer(start, stop, step); } -template -inline constexpr decltype(auto) enumerate(Container && container, size_t start_ = 0) { +template +inline constexpr decltype(auto) enumerate(Container && container, + size_t start_ = 0) { auto stop = std::forward(container).size(); decltype(stop) start = start_; return zip(arange(start, stop), std::forward(container)); } } // namespace akantu #endif /* __AKANTU_AKA_ITERATORS_HH__ */ diff --git a/src/common/aka_math.hh b/src/common/aka_math.hh index 18409e62b..3a38dfd1a 100644 --- a/src/common/aka_math.hh +++ b/src/common/aka_math.hh @@ -1,291 +1,292 @@ /** * @file aka_math.hh * * @author Ramin Aghababaei * @author Guillaume Anciaux * @author Marion Estelle Chambart * @author David Simon Kammer * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Leonardo Snozzi * @author Peter Spijker * @author Marco Vocialta * * @date creation: Wed Aug 04 2010 * @date last modification: Fri May 15 2015 * * @brief mathematical operations * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_MATH_H__ #define __AKANTU_AKA_MATH_H__ /* -------------------------------------------------------------------------- */ #include #include "aka_common.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template class Array; class Math { /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Matrix algebra */ /* ------------------------------------------------------------------------ */ /// @f$ y = A*x @f$ static void matrix_vector(UInt m, UInt n, const Array & A, const Array & x, Array & y, Real alpha = 1.); /// @f$ y = A*x @f$ static inline void matrix_vector(UInt m, UInt n, Real * A, Real * x, Real * y, Real alpha = 1.); /// @f$ y = A^t*x @f$ static inline void matrixt_vector(UInt m, UInt n, Real * A, Real * x, Real * y, Real alpha = 1.); /// @f$ C = A*B @f$ static void matrix_matrix(UInt m, UInt n, UInt k, const Array & A, const Array & B, Array & C, Real alpha = 1.); /// @f$ C = A*B^t @f$ static void matrix_matrixt(UInt m, UInt n, UInt k, const Array & A, const Array & B, Array & C, Real alpha = 1.); /// @f$ C = A*B @f$ static inline void matrix_matrix(UInt m, UInt n, UInt k, Real * A, Real * B, Real * C, Real alpha = 1.); /// @f$ C = A^t*B @f$ static inline void matrixt_matrix(UInt m, UInt n, UInt k, Real * A, Real * B, Real * C, Real alpha = 1.); /// @f$ C = A*B^t @f$ static inline void matrix_matrixt(UInt m, UInt n, UInt k, Real * A, Real * B, Real * C, Real alpha = 1.); /// @f$ C = A^t*B^t @f$ static inline void matrixt_matrixt(UInt m, UInt n, UInt k, Real * A, Real * B, Real * C, Real alpha = 1.); template static inline void matMul(UInt m, UInt n, UInt k, Real alpha, Real * A, Real * B, Real beta, Real * C); template static inline void matVectMul(UInt m, UInt n, Real alpha, Real * A, Real * x, Real beta, Real * y); static inline void aXplusY(UInt n, Real alpha, Real * x, Real * y); static inline void matrix33_eigenvalues(Real * A, Real * Adiag); static inline void matrix22_eigenvalues(Real * A, Real * Adiag); template static inline void eigenvalues(Real * A, Real * d); /// solve @f$ A x = \Lambda x @f$ and return d and V such as @f$ A V[i:] = /// d[i] V[i:]@f$ template static void matrixEig(UInt n, T * A, T * d, T * V = nullptr); /// determinent of a 2x2 matrix static inline Real det2(const Real * mat); /// determinent of a 3x3 matrix static inline Real det3(const Real * mat); /// determinent of a nxn matrix template static inline Real det(const Real * mat); /// determinent of a nxn matrix template static inline T det(UInt n, const T * mat); /// inverse a nxn matrix template static inline void inv(const Real * mat, Real * inv); /// inverse a nxn matrix template static inline void inv(UInt n, const T * mat, T * inv); /// inverse a 3x3 matrix static inline void inv3(const Real * mat, Real * inv); /// inverse a 2x2 matrix static inline void inv2(const Real * mat, Real * inv); /// solve A x = b using a LU factorization template static inline void solve(UInt n, const T * A, T * x, const T * b); /// return the double dot product between 2 tensors in 2d static inline Real matrixDoubleDot22(Real * A, Real * B); /// return the double dot product between 2 tensors in 3d static inline Real matrixDoubleDot33(Real * A, Real * B); /// extension of the double dot product to two 2nd order tensor in dimension n static inline Real matrixDoubleDot(UInt n, Real * A, Real * B); /* ------------------------------------------------------------------------ */ /* Array algebra */ /* ------------------------------------------------------------------------ */ /// vector cross product static inline void vectorProduct3(const Real * v1, const Real * v2, Real * res); /// normalize a vector static inline void normalize2(Real * v); /// normalize a vector static inline void normalize3(Real * v); /// return norm of a 2-vector static inline Real norm2(const Real * v); /// return norm of a 3-vector static inline Real norm3(const Real * v); /// return norm of a vector static inline Real norm(UInt n, const Real * v); /// return the dot product between 2 vectors in 2d static inline Real vectorDot2(const Real * v1, const Real * v2); /// return the dot product between 2 vectors in 3d static inline Real vectorDot3(const Real * v1, const Real * v2); /// return the dot product between 2 vectors static inline Real vectorDot(Real * v1, Real * v2, UInt n); /* ------------------------------------------------------------------------ */ /* Geometry */ /* ------------------------------------------------------------------------ */ /// compute normal a normal to a vector static inline void normal2(const Real * v1, Real * res); /// compute normal a normal to a vector static inline void normal3(const Real * v1, const Real * v2, Real * res); /// compute the tangents to an array of normal vectors static void compute_tangents(const Array & normals, Array & tangents); /// distance in 2D between x and y static inline Real distance_2d(const Real * x, const Real * y); /// distance in 3D between x and y static inline Real distance_3d(const Real * x, const Real * y); /// radius of the in-circle of a triangle static inline Real triangle_inradius(const Real * coord1, const Real * coord2, const Real * coord3); /// radius of the in-circle of a tetrahedron static inline Real tetrahedron_inradius(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4); /// volume of a tetrahedron static inline Real tetrahedron_volume(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4); /// compute the barycenter of n points static inline void barycenter(const Real * coord, UInt nb_points, UInt spatial_dimension, Real * barycenter); /// vector between x and y static inline void vector_2d(const Real * x, const Real * y, Real * vec); /// vector pointing from x to y in 3 spatial dimension static inline void vector_3d(const Real * x, const Real * y, Real * vec); /// test if two scalar are equal within a given tolerance static inline bool are_float_equal(Real x, Real y); /// test if two vectors are equal within a given tolerance static inline bool are_vector_equal(UInt n, Real * x, Real * y); #ifdef isnan #error \ "You probably included which is incompatible with aka_math please use\ or add a \"#undef isnan\" before akantu includes" #endif /// test if a real is a NaN static inline bool isnan(Real x); /// test if the line x and y intersects each other static inline bool intersects(Real x_min, Real x_max, Real y_min, Real y_max); /// test if a is in the range [x_min, x_max] static inline bool is_in_range(Real a, Real x_min, Real x_max); static inline Real getTolerance() { return tolerance; }; static inline void setTolerance(Real tol) { tolerance = tol; }; template static inline T pow(T x); /// reduce all the values of an array, the summation is done in place and the /// array is modified static Real reduce(Array & array); class NewtonRaphson { public: NewtonRaphson(Real tolerance, Real max_iteration) : tolerance(tolerance), max_iteration(max_iteration) {} template Real solve(const Functor & funct, Real x_0); private: Real tolerance; Real max_iteration; }; struct NewtonRaphsonFunctor { - NewtonRaphsonFunctor(std::string name) : name(std::move(name)) {} + explicit NewtonRaphsonFunctor(std::string name) : name(std::move(name)) {} + virtual ~NewtonRaphsonFunctor() = default; virtual Real f(Real x) const = 0; virtual Real f_prime(Real x) const = 0; std::string name; }; private: /// tolerance for functions that need one static Real tolerance; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "aka_math_tmpl.hh" } // akantu #endif /* __AKANTU_AKA_MATH_H__ */ diff --git a/src/common/aka_math_tmpl.hh b/src/common/aka_math_tmpl.hh index ebf148bfb..89c38aae4 100644 --- a/src/common/aka_math_tmpl.hh +++ b/src/common/aka_math_tmpl.hh @@ -1,786 +1,784 @@ /** * @file aka_math_tmpl.hh * * @author Ramin Aghababaei * @author Guillaume Anciaux * @author Alejandro M. Aragón * @author David Simon Kammer * @author Daniel Pino Muñoz * @author Mathilde Radiguet * @author Nicolas Richart * @author Leonardo Snozzi * @author Peter Spijker * @author Marco Vocialta * * @date creation: Wed Aug 04 2010 * @date last modification: Wed Oct 21 2015 * * @brief Implementation of the inline functions of the math toolkit * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ } // akantu #include #include #include #include "aka_blas_lapack.hh" namespace akantu { /* -------------------------------------------------------------------------- */ inline void Math::matrix_vector(UInt im, UInt in, Real * A, Real * x, Real * y, Real alpha) { #ifdef AKANTU_USE_BLAS /// y = alpha*op(A)*x + beta*y char tran_A = 'N'; int incx = 1; int incy = 1; double beta = 0.; int m = im; int n = in; aka_gemv(&tran_A, &m, &n, &alpha, A, &m, x, &incx, &beta, y, &incy); #else memset(y, 0, im * sizeof(Real)); for (UInt i = 0; i < im; ++i) { for (UInt j = 0; j < in; ++j) { y[i] += A[i + j * im] * x[j]; } y[i] *= alpha; } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrixt_vector(UInt im, UInt in, Real * A, Real * x, Real * y, Real alpha) { #ifdef AKANTU_USE_BLAS /// y = alpha*op(A)*x + beta*y char tran_A = 'T'; int incx = 1; int incy = 1; double beta = 0.; int m = im; int n = in; aka_gemv(&tran_A, &m, &n, &alpha, A, &m, x, &incx, &beta, y, &incy); #else memset(y, 0, in * sizeof(Real)); for (UInt i = 0; i < im; ++i) { for (UInt j = 0; j < in; ++j) { y[j] += A[j * im + i] * x[i]; } y[i] *= alpha; } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrix_matrix(UInt im, UInt in, UInt ik, Real * A, Real * B, Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'N'; char trans_b = 'N'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &m, B, &k, &beta, C, &m); #else memset(C, 0, im * in * sizeof(Real)); for (UInt j = 0; j < in; ++j) { UInt _jb = j * ik; UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { for (UInt l = 0; l < ik; ++l) { UInt _la = l * im; C[i + _jc] += A[i + _la] * B[l + _jb]; } C[i + _jc] *= alpha; } } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrixt_matrix(UInt im, UInt in, UInt ik, Real * A, Real * B, Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'T'; char trans_b = 'N'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &k, B, &k, &beta, C, &m); #else memset(C, 0, im * in * sizeof(Real)); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; UInt _jb = j * ik; for (UInt i = 0; i < im; ++i) { UInt _ia = i * ik; for (UInt l = 0; l < ik; ++l) { C[i + _jc] += A[l + _ia] * B[l + _jb]; } C[i + _jc] *= alpha; } } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrix_matrixt(UInt im, UInt in, UInt ik, Real * A, Real * B, Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'N'; char trans_b = 'T'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &m, B, &n, &beta, C, &m); #else memset(C, 0, im * in * sizeof(Real)); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { for (UInt l = 0; l < ik; ++l) { UInt _la = l * im; UInt _lb = l * in; C[i + _jc] += A[i + _la] * B[j + _lb]; } C[i + _jc] *= alpha; } } #endif } /* -------------------------------------------------------------------------- */ inline void Math::matrixt_matrixt(UInt im, UInt in, UInt ik, Real * A, Real * B, Real * C, Real alpha) { #ifdef AKANTU_USE_BLAS /// C := alpha*op(A)*op(B) + beta*C char trans_a = 'T'; char trans_b = 'T'; double beta = 0.; int m = im, n = in, k = ik; aka_gemm(&trans_a, &trans_b, &m, &n, &k, &alpha, A, &k, B, &n, &beta, C, &m); #else memset(C, 0, im * in * sizeof(Real)); for (UInt j = 0; j < in; ++j) { UInt _jc = j * im; for (UInt i = 0; i < im; ++i) { UInt _ia = i * ik; for (UInt l = 0; l < ik; ++l) { UInt _lb = l * in; C[i + _jc] += A[l + _ia] * B[j + _lb]; } C[i + _jc] *= alpha; } } #endif } /* -------------------------------------------------------------------------- */ inline void Math::aXplusY(UInt n, Real alpha, Real * x, Real * y) { #ifdef AKANTU_USE_BLAS /// y := alpha x + y int incx = 1, incy = 1; aka_axpy(&n, &alpha, x, &incx, y, &incy); #else for (UInt i = 0; i < n; ++i) *(y++) += alpha * *(x++); #endif } /* -------------------------------------------------------------------------- */ inline Real Math::vectorDot(Real * v1, Real * v2, UInt in) { #ifdef AKANTU_USE_BLAS /// d := v1 . v2 int incx = 1, incy = 1, n = in; Real d = aka_dot(&n, v1, &incx, v2, &incy); #else Real d = 0; for (UInt i = 0; i < in; ++i) { d += v1[i] * v2[i]; } #endif return d; } /* -------------------------------------------------------------------------- */ template inline void Math::matMul(UInt m, UInt n, UInt k, Real alpha, Real * A, Real * B, __attribute__((unused)) Real beta, Real * C) { if (tr_A) { if (tr_B) matrixt_matrixt(m, n, k, A, B, C, alpha); else matrixt_matrix(m, n, k, A, B, C, alpha); } else { if (tr_B) matrix_matrixt(m, n, k, A, B, C, alpha); else matrix_matrix(m, n, k, A, B, C, alpha); } } /* -------------------------------------------------------------------------- */ template inline void Math::matVectMul(UInt m, UInt n, Real alpha, Real * A, Real * x, __attribute__((unused)) Real beta, Real * y) { if (tr_A) { matrixt_vector(m, n, A, x, y, alpha); } else { matrix_vector(m, n, A, x, y, alpha); } } /* -------------------------------------------------------------------------- */ template inline void Math::matrixEig(UInt n, T * A, T * d, T * V) { // Matrix A is row major, so the lapack function in fortran will process // A^t. Asking for the left eigenvectors of A^t will give the transposed right // eigenvectors of A so in the C++ code the right eigenvectors. char jobvl; if (V != nullptr) jobvl = 'V'; // compute left eigenvectors else jobvl = 'N'; // compute left eigenvectors char jobvr('N'); // compute right eigenvectors auto * di = new T[n]; // imaginary part of the eigenvalues int info; int N = n; T wkopt; int lwork = -1; // query and allocate the optimal workspace aka_geev(&jobvl, &jobvr, &N, A, &N, d, di, V, &N, nullptr, &N, &wkopt, &lwork, &info); lwork = int(wkopt); auto * work = new T[lwork]; // solve the eigenproblem aka_geev(&jobvl, &jobvr, &N, A, &N, d, di, V, &N, nullptr, &N, work, &lwork, &info); AKANTU_DEBUG_ASSERT( info == 0, "Problem computing eigenvalues/vectors. DGEEV exited with the value " << info); delete[] work; delete[] di; // I hope for you that there was no complex eigenvalues !!! } /* -------------------------------------------------------------------------- */ inline void Math::matrix22_eigenvalues(Real * A, Real * Adiag) { /// d = determinant of Matrix A Real d = det2(A); /// b = trace of Matrix A Real b = A[0] + A[3]; Real c = sqrt(b * b - 4 * d); Adiag[0] = .5 * (b + c); Adiag[1] = .5 * (b - c); } /* -------------------------------------------------------------------------- */ inline void Math::matrix33_eigenvalues(Real * A, Real * Adiag) { matrixEig(3, A, Adiag); } /* -------------------------------------------------------------------------- */ template inline void Math::eigenvalues(Real * A, Real * d) { if (dim == 1) { d[0] = A[0]; } else if (dim == 2) { matrix22_eigenvalues(A, d); } // else if(dim == 3) { matrix33_eigenvalues(A, d); } else matrixEig(dim, A, d); } /* -------------------------------------------------------------------------- */ inline Real Math::det2(const Real * mat) { return mat[0] * mat[3] - mat[1] * mat[2]; } /* -------------------------------------------------------------------------- */ inline Real Math::det3(const Real * mat) { return mat[0] * (mat[4] * mat[8] - mat[7] * mat[5]) - mat[3] * (mat[1] * mat[8] - mat[7] * mat[2]) + mat[6] * (mat[1] * mat[5] - mat[4] * mat[2]); } /* -------------------------------------------------------------------------- */ template inline Real Math::det(const Real * mat) { if (n == 1) return *mat; else if (n == 2) return det2(mat); else if (n == 3) return det3(mat); else return det(n, mat); } /* -------------------------------------------------------------------------- */ template inline T Math::det(UInt n, const T * A) { int N = n; int info; auto * ipiv = new int[N + 1]; auto * LU = new T[N * N]; std::copy(A, A + N * N, LU); // LU factorization of A aka_getrf(&N, &N, LU, &N, ipiv, &info); if (info > 0) { AKANTU_DEBUG_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); } // det(A) = det(L) * det(U) = 1 * det(U) = product_i U_{ii} T det = 1.; for (int i = 0; i < N; ++i) det *= (2 * (ipiv[i] == i) - 1) * LU[i * n + i]; delete[] ipiv; delete[] LU; return det; } /* -------------------------------------------------------------------------- */ inline void Math::normal2(const Real * vec, Real * normal) { normal[0] = vec[1]; normal[1] = -vec[0]; Math::normalize2(normal); } /* -------------------------------------------------------------------------- */ inline void Math::normal3(const Real * vec1, const Real * vec2, Real * normal) { Math::vectorProduct3(vec1, vec2, normal); Math::normalize3(normal); } /* -------------------------------------------------------------------------- */ inline void Math::normalize2(Real * vec) { Real norm = Math::norm2(vec); vec[0] /= norm; vec[1] /= norm; } /* -------------------------------------------------------------------------- */ inline void Math::normalize3(Real * vec) { Real norm = Math::norm3(vec); vec[0] /= norm; vec[1] /= norm; vec[2] /= norm; } /* -------------------------------------------------------------------------- */ inline Real Math::norm2(const Real * vec) { return sqrt(vec[0] * vec[0] + vec[1] * vec[1]); } /* -------------------------------------------------------------------------- */ inline Real Math::norm3(const Real * vec) { return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]); } /* -------------------------------------------------------------------------- */ inline Real Math::norm(UInt n, const Real * vec) { Real norm = 0.; for (UInt i = 0; i < n; ++i) { norm += vec[i] * vec[i]; } return sqrt(norm); } /* -------------------------------------------------------------------------- */ inline void Math::inv2(const Real * mat, Real * inv) { Real det_mat = det2(mat); inv[0] = mat[3] / det_mat; inv[1] = -mat[1] / det_mat; inv[2] = -mat[2] / det_mat; inv[3] = mat[0] / det_mat; } /* -------------------------------------------------------------------------- */ inline void Math::inv3(const Real * mat, Real * inv) { Real det_mat = det3(mat); inv[0] = (mat[4] * mat[8] - mat[7] * mat[5]) / det_mat; inv[1] = (mat[2] * mat[7] - mat[8] * mat[1]) / det_mat; inv[2] = (mat[1] * mat[5] - mat[4] * mat[2]) / det_mat; inv[3] = (mat[5] * mat[6] - mat[8] * mat[3]) / det_mat; inv[4] = (mat[0] * mat[8] - mat[6] * mat[2]) / det_mat; inv[5] = (mat[2] * mat[3] - mat[5] * mat[0]) / det_mat; inv[6] = (mat[3] * mat[7] - mat[6] * mat[4]) / det_mat; inv[7] = (mat[1] * mat[6] - mat[7] * mat[0]) / det_mat; inv[8] = (mat[0] * mat[4] - mat[3] * mat[1]) / det_mat; } /* -------------------------------------------------------------------------- */ template inline void Math::inv(const Real * A, Real * Ainv) { if (n == 1) *Ainv = 1. / *A; else if (n == 2) inv2(A, Ainv); else if (n == 3) inv3(A, Ainv); else inv(n, A, Ainv); } /* -------------------------------------------------------------------------- */ template inline void Math::inv(UInt n, const T * A, T * invA) { int N = n; int info; auto * ipiv = new int[N + 1]; int lwork = N * N; auto * work = new T[lwork]; std::copy(A, A + n * n, invA); aka_getrf(&N, &N, invA, &N, ipiv, &info); if (info > 0) { AKANTU_DEBUG_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); } aka_getri(&N, invA, &N, ipiv, work, &lwork, &info); if (info != 0) { AKANTU_DEBUG_ERROR("Cannot invert the matrix (info: " << info << " )"); } delete[] ipiv; delete[] work; } /* -------------------------------------------------------------------------- */ template inline void Math::solve(UInt n, const T * A, T * x, const T * b) { int N = n; int info; auto * ipiv = new int[N]; auto * lu_A = new T[N * N]; std::copy(A, A + N * N, lu_A); aka_getrf(&N, &N, lu_A, &N, ipiv, &info); if (info > 0) { AKANTU_DEBUG_ERROR("Singular matrix - cannot factorize it (info: " << info << " )"); - exit(EXIT_FAILURE); } char trans = 'N'; int nrhs = 1; std::copy(b, b + N, x); aka_getrs(&trans, &N, &nrhs, lu_A, &N, ipiv, x, &N, &info); if (info != 0) { AKANTU_DEBUG_ERROR("Cannot solve the system (info: " << info << " )"); - exit(EXIT_FAILURE); } delete[] ipiv; delete[] lu_A; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ inline Real Math::matrixDoubleDot22(Real * A, Real * B) { Real d; d = A[0] * B[0] + A[1] * B[1] + A[2] * B[2] + A[3] * B[3]; return d; } /* -------------------------------------------------------------------------- */ inline Real Math::matrixDoubleDot33(Real * A, Real * B) { Real d; d = A[0] * B[0] + A[1] * B[1] + A[2] * B[2] + A[3] * B[3] + A[4] * B[4] + A[5] * B[5] + A[6] * B[6] + A[7] * B[7] + A[8] * B[8]; return d; } /* -------------------------------------------------------------------------- */ inline Real Math::matrixDoubleDot(UInt n, Real * A, Real * B) { Real d = 0.; for (UInt i = 0; i < n; ++i) { for (UInt j = 0; j < n; ++j) { d += A[i * n + j] * B[i * n + j]; } } return d; } /* -------------------------------------------------------------------------- */ inline void Math::vectorProduct3(const Real * v1, const Real * v2, Real * res) { res[0] = v1[1] * v2[2] - v1[2] * v2[1]; res[1] = v1[2] * v2[0] - v1[0] * v2[2]; res[2] = v1[0] * v2[1] - v1[1] * v2[0]; } /* -------------------------------------------------------------------------- */ inline Real Math::vectorDot2(const Real * v1, const Real * v2) { return (v1[0] * v2[0] + v1[1] * v2[1]); } /* -------------------------------------------------------------------------- */ inline Real Math::vectorDot3(const Real * v1, const Real * v2) { return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]); } /* -------------------------------------------------------------------------- */ inline Real Math::distance_2d(const Real * x, const Real * y) { return sqrt((y[0] - x[0]) * (y[0] - x[0]) + (y[1] - x[1]) * (y[1] - x[1])); } /* -------------------------------------------------------------------------- */ inline Real Math::triangle_inradius(const Real * coord1, const Real * coord2, const Real * coord3) { /** * @f{eqnarray*}{ * r &=& A / s \\ * A &=& 1/4 * \sqrt{(a + b + c) * (a - b + c) * (a + b - c) (-a + b + c)} \\ * s &=& \frac{a + b + c}{2} * @f} */ Real a, b, c; a = distance_2d(coord1, coord2); b = distance_2d(coord2, coord3); c = distance_2d(coord1, coord3); Real s; s = (a + b + c) * 0.5; return sqrt((s - a) * (s - b) * (s - c) / s); } /* -------------------------------------------------------------------------- */ inline Real Math::distance_3d(const Real * x, const Real * y) { return sqrt((y[0] - x[0]) * (y[0] - x[0]) + (y[1] - x[1]) * (y[1] - x[1]) + (y[2] - x[2]) * (y[2] - x[2])); } /* -------------------------------------------------------------------------- */ inline Real Math::tetrahedron_volume(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4) { Real xx[9], vol; xx[0] = coord2[0]; xx[1] = coord2[1]; xx[2] = coord2[2]; xx[3] = coord3[0]; xx[4] = coord3[1]; xx[5] = coord3[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; vol = det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord3[0]; xx[4] = coord3[1]; xx[5] = coord3[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; vol -= det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord2[0]; xx[4] = coord2[1]; xx[5] = coord2[2]; xx[6] = coord4[0]; xx[7] = coord4[1]; xx[8] = coord4[2]; vol += det3(xx); xx[0] = coord1[0]; xx[1] = coord1[1]; xx[2] = coord1[2]; xx[3] = coord2[0]; xx[4] = coord2[1]; xx[5] = coord2[2]; xx[6] = coord3[0]; xx[7] = coord3[1]; xx[8] = coord3[2]; vol -= det3(xx); vol /= 6; return vol; } /* -------------------------------------------------------------------------- */ inline Real Math::tetrahedron_inradius(const Real * coord1, const Real * coord2, const Real * coord3, const Real * coord4) { Real l12, l13, l14, l23, l24, l34; l12 = distance_3d(coord1, coord2); l13 = distance_3d(coord1, coord3); l14 = distance_3d(coord1, coord4); l23 = distance_3d(coord2, coord3); l24 = distance_3d(coord2, coord4); l34 = distance_3d(coord3, coord4); Real s1, s2, s3, s4; s1 = (l12 + l23 + l13) * 0.5; s1 = sqrt(s1 * (s1 - l12) * (s1 - l23) * (s1 - l13)); s2 = (l12 + l24 + l14) * 0.5; s2 = sqrt(s2 * (s2 - l12) * (s2 - l24) * (s2 - l14)); s3 = (l23 + l34 + l24) * 0.5; s3 = sqrt(s3 * (s3 - l23) * (s3 - l34) * (s3 - l24)); s4 = (l13 + l34 + l14) * 0.5; s4 = sqrt(s4 * (s4 - l13) * (s4 - l34) * (s4 - l14)); Real volume = Math::tetrahedron_volume(coord1, coord2, coord3, coord4); return 3 * volume / (s1 + s2 + s3 + s4); } /* -------------------------------------------------------------------------- */ inline void Math::barycenter(const Real * coord, UInt nb_points, UInt spatial_dimension, Real * barycenter) { memset(barycenter, 0, spatial_dimension * sizeof(Real)); for (UInt n = 0; n < nb_points; ++n) { UInt offset = n * spatial_dimension; for (UInt i = 0; i < spatial_dimension; ++i) { barycenter[i] += coord[offset + i] / (Real)nb_points; } } } /* -------------------------------------------------------------------------- */ inline void Math::vector_2d(const Real * x, const Real * y, Real * res) { res[0] = y[0] - x[0]; res[1] = y[1] - x[1]; } /* -------------------------------------------------------------------------- */ inline void Math::vector_3d(const Real * x, const Real * y, Real * res) { res[0] = y[0] - x[0]; res[1] = y[1] - x[1]; res[2] = y[2] - x[2]; } /* -------------------------------------------------------------------------- */ /// Combined absolute and relative tolerance test proposed in /// Real-time collision detection by C. Ericson (2004) inline bool Math::are_float_equal(const Real x, const Real y) { Real abs_max = std::max(std::abs(x), std::abs(y)); abs_max = std::max(abs_max, Real(1.)); return std::abs(x - y) <= (tolerance * abs_max); } /* -------------------------------------------------------------------------- */ inline bool Math::isnan(Real x) { #if defined(__INTEL_COMPILER) #pragma warning(push) #pragma warning(disable : 1572) #endif // defined(__INTEL_COMPILER) // x = x return false means x = quiet_NaN return !(x == x); #if defined(__INTEL_COMPILER) #pragma warning(pop) #endif // defined(__INTEL_COMPILER) } /* -------------------------------------------------------------------------- */ inline bool Math::are_vector_equal(UInt n, Real * x, Real * y) { bool test = true; for (UInt i = 0; i < n; ++i) { test &= are_float_equal(x[i], y[i]); } return test; } /* -------------------------------------------------------------------------- */ inline bool Math::intersects(Real x_min, Real x_max, Real y_min, Real y_max) { return !((x_max <= y_min) || (x_min >= y_max)); } /* -------------------------------------------------------------------------- */ inline bool Math::is_in_range(Real a, Real x_min, Real x_max) { return ((a >= x_min) && (a <= x_max)); } /* -------------------------------------------------------------------------- */ template inline T Math::pow(T x) { return (pow

(x) * x); } template <> inline UInt Math::pow<0, UInt>(__attribute__((unused)) UInt x) { return (1); } template <> inline Real Math::pow<0, Real>(__attribute__((unused)) Real x) { return (1.); } /* -------------------------------------------------------------------------- */ template Real Math::NewtonRaphson::solve(const Functor & funct, Real x_0) { Real x = x_0; Real f_x = funct.f(x); UInt iter = 0; while (std::abs(f_x) > this->tolerance && iter < this->max_iteration) { x -= f_x / funct.f_prime(x); f_x = funct.f(x); iter++; } AKANTU_DEBUG_ASSERT(iter < this->max_iteration, "Newton Raphson (" << funct.name << ") solve did not converge in " << this->max_iteration << " iterations (tolerance: " << this->tolerance << ")"); return x; } diff --git a/src/io/parser/cppargparse/cppargparse.cc b/src/io/parser/cppargparse/cppargparse.cc index fb83e174f..70c2d9a08 100644 --- a/src/io/parser/cppargparse/cppargparse.cc +++ b/src/io/parser/cppargparse/cppargparse.cc @@ -1,526 +1,528 @@ /** * @file cppargparse.cc * * @author Nicolas Richart * * @date creation: Thu Apr 03 2014 * @date last modification: Wed Nov 11 2015 * * @brief implementation of the ArgumentParser * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "cppargparse.hh" #include #include #include #include #include #include #include #include #include #include #include #include namespace cppargparse { /* -------------------------------------------------------------------------- */ static inline std::string to_upper(const std::string & str) { std::string lstr = str; std::transform(lstr.begin(), lstr.end(), lstr.begin(), (int (*)(int))std::toupper); return lstr; } /* -------------------------------------------------------------------------- */ /* ArgumentParser */ /* -------------------------------------------------------------------------- */ ArgumentParser::ArgumentParser() : external_exit(NULL), prank(0), psize(1) { this->addArgument("-h;--help", "show this help message and exit", 0, _boolean, false, true); } /* -------------------------------------------------------------------------- */ ArgumentParser::~ArgumentParser() { for (_Arguments::iterator it = arguments.begin(); it != arguments.end(); ++it) { delete it->second; } } /* -------------------------------------------------------------------------- */ void ArgumentParser::setParallelContext(int prank, int psize) { this->prank = prank; this->psize = psize; } /* -------------------------------------------------------------------------- */ void ArgumentParser::_exit(const std::string & msg, int status) { if (prank == 0) { if (msg != "") { std::cerr << msg << std::endl; std::cerr << std::endl; } this->print_help(std::cerr); } if (external_exit) (*external_exit)(status); else { exit(status); } } /* -------------------------------------------------------------------------- */ const ArgumentParser::Argument & ArgumentParser:: operator[](const std::string & name) const { Arguments::const_iterator it = success_parsed.find(name); if (it != success_parsed.end()) { return *(it->second); } else { throw std::range_error("No argument named \'" + name + "\' was found in the parsed argument," + " make sur to specify it \'required\'" + " or to give it a default value"); } } /* -------------------------------------------------------------------------- */ bool ArgumentParser::has(const std::string & name) const { return (success_parsed.find(name) != success_parsed.end()); } /* -------------------------------------------------------------------------- */ void ArgumentParser::addArgument(const std::string & name_or_flag, const std::string & help, int nargs, ArgumentType type) { _addArgument(name_or_flag, help, nargs, type); } /* -------------------------------------------------------------------------- */ ArgumentParser::_Argument & ArgumentParser::_addArgument(const std::string & name, const std::string & help, int nargs, ArgumentType type) { - _Argument * arg = NULL; + _Argument * arg = nullptr; switch (type) { case _string: { arg = new ArgumentStorage(); break; } case _float: { arg = new ArgumentStorage(); break; } case _integer: { arg = new ArgumentStorage(); break; } case _boolean: { arg = new ArgumentStorage(); break; } } arg->help = help; arg->nargs = nargs; arg->type = type; std::stringstream sstr(name); std::string item; std::vector tmp_keys; while (std::getline(sstr, item, ';')) { tmp_keys.push_back(item); } int long_key = -1; int short_key = -1; bool problem = (tmp_keys.size() > 2) || (name == ""); for (std::vector::iterator it = tmp_keys.begin(); it != tmp_keys.end(); ++it) { if (it->find("--") == 0) { problem |= (long_key != -1); long_key = it - tmp_keys.begin(); } else if (it->find("-") == 0) { problem |= (long_key != -1); short_key = it - tmp_keys.begin(); } } problem |= ((tmp_keys.size() == 2) && (long_key == -1 || short_key == -1)); if (problem) { + delete arg; throw std::invalid_argument("Synthax of name or flags is not correct. " "Possible synthax are \'-f\', \'-f;--foo\', " "\'--foo\', \'bar\'"); } if (long_key != -1) { arg->name = tmp_keys[long_key]; arg->name.erase(0, 2); } else if (short_key != -1) { arg->name = tmp_keys[short_key]; arg->name.erase(0, 1); } else { arg->name = tmp_keys[0]; pos_args.push_back(arg); arg->required = (nargs != _one_if_possible); arg->is_positional = true; } arguments[arg->name] = arg; if (!arg->is_positional) { if (short_key != -1) { std::string key = tmp_keys[short_key]; key_args[key] = arg; arg->keys.push_back(key); } if (long_key != -1) { std::string key = tmp_keys[long_key]; key_args[key] = arg; arg->keys.push_back(key); } } return *arg; } #if not HAVE_STRDUP static char * strdup(const char * str) { size_t len = strlen(str); char *x = (char *)malloc(len+1); /* 1 for the null terminator */ if(!x) return NULL; /* malloc could not allocate memory */ memcpy(x,str,len+1); /* copy the string into the new buffer */ return x; } #endif /* -------------------------------------------------------------------------- */ void ArgumentParser::parse(int & argc, char **& argv, int flags, bool parse_help) { bool stop_in_not_parsed = flags & _stop_on_not_parsed; bool remove_parsed = flags & _remove_parsed; std::vector argvs; for (int i = 0; i < argc; ++i) { argvs.push_back(std::string(argv[i])); } unsigned int current_position = 0; if (this->program_name == "" && argc > 0) { std::string prog = argvs[current_position]; const char * c_prog = prog.c_str(); char * c_prog_tmp = strdup(c_prog); std::string base_prog(basename(c_prog_tmp)); this->program_name = base_prog; std::free(c_prog_tmp); } std::queue<_Argument *> positional_queue; for (PositionalArgument::iterator it = pos_args.begin(); it != pos_args.end(); ++it) positional_queue.push(*it); std::vector argvs_to_remove; ++current_position; // consume argv[0] while (current_position < argvs.size()) { std::string arg = argvs[current_position]; ++current_position; ArgumentKeyMap::iterator key_it = key_args.find(arg); bool is_positional = false; _Argument * argument_ptr = NULL; if (key_it == key_args.end()) { if (positional_queue.empty()) { if (stop_in_not_parsed) this->_exit("Argument " + arg + " not recognized", EXIT_FAILURE); continue; } else { argument_ptr = positional_queue.front(); is_positional = true; --current_position; } } else { argument_ptr = key_it->second; } if (remove_parsed && !is_positional && argument_ptr->name != "help") { argvs_to_remove.push_back(current_position - 1); } _Argument & argument = *argument_ptr; unsigned int min_nb_val = 0, max_nb_val = 0; switch (argument.nargs) { case _one_if_possible: max_nb_val = 1; break; // "?" case _at_least_one: min_nb_val = 1; // "+" + [[gnu::fallthrough]]; case _any: max_nb_val = argc - current_position; break; // "*" default: min_nb_val = max_nb_val = argument.nargs; // "N" } std::vector values; unsigned int arg_consumed = 0; if (max_nb_val <= (argc - current_position)) { for (; arg_consumed < max_nb_val; ++arg_consumed) { std::string v = argvs[current_position]; ++current_position; bool is_key = key_args.find(v) != key_args.end(); bool is_good_type = checkType(argument.type, v); if (!is_key && is_good_type) { values.push_back(v); if (remove_parsed) argvs_to_remove.push_back(current_position - 1); } else { // unconsume not parsed argument for optional - if (!is_positional || (is_positional && is_key)) + if (!is_positional || is_key) --current_position; break; } } } if (arg_consumed < min_nb_val) { if (!is_positional) { this->_exit("Not enought values for the argument " + argument.name + " where provided", EXIT_FAILURE); } else { if (stop_in_not_parsed) this->_exit("Argument " + arg + " not recognized", EXIT_FAILURE); } } else { if (is_positional) positional_queue.pop(); if (!argument.parsed) { success_parsed[argument.name] = &argument; argument.parsed = true; if ((argument.nargs == _one_if_possible || argument.nargs == 0) && arg_consumed == 0) { if (argument.has_const) argument.setToConst(); else if (argument.has_default) argument.setToDefault(); } else { argument.setValues(values); } } else { this->_exit("Argument " + argument.name + " already present in the list of argument", EXIT_FAILURE); } } } for (_Arguments::iterator ait = arguments.begin(); ait != arguments.end(); ++ait) { _Argument & argument = *(ait->second); if (!argument.parsed) { if (argument.has_default) { argument.setToDefault(); success_parsed[argument.name] = &argument; } if (argument.required) { this->_exit("Argument " + argument.name + " required but not given!", EXIT_FAILURE); } } } // removing the parsed argument if remove_parsed is true if (argvs_to_remove.size()) { std::vector::const_iterator next_to_remove = argvs_to_remove.begin(); for (int i = 0, c = 0; i < argc; ++i) { if (next_to_remove == argvs_to_remove.end() || i != *next_to_remove) { argv[c] = argv[i]; ++c; } else { if (next_to_remove != argvs_to_remove.end()) ++next_to_remove; } } argc -= argvs_to_remove.size(); } this->argc = &argc; this->argv = &argv; if (this->arguments["help"]->parsed && parse_help) { this->_exit(); } } /* -------------------------------------------------------------------------- */ bool ArgumentParser::checkType(ArgumentType type, const std::string & value) const { std::stringstream sstr(value); switch (type) { case _string: { std::string s; sstr >> s; break; } case _float: { double d; sstr >> d; break; } case _integer: { int i; sstr >> i; break; } case _boolean: { bool b; sstr >> b; break; } } return (sstr.fail() == false); } /* -------------------------------------------------------------------------- */ void ArgumentParser::printself(std::ostream & stream) const { for (Arguments::const_iterator it = success_parsed.begin(); it != success_parsed.end(); ++it) { const Argument & argument = *(it->second); argument.printself(stream); stream << std::endl; } } /* -------------------------------------------------------------------------- */ void ArgumentParser::print_usage(std::ostream & stream) const { stream << "Usage: " << this->program_name; - std::stringstream sstr_opt; // print shorten usage for (_Arguments::const_iterator it = arguments.begin(); it != arguments.end(); ++it) { const _Argument & argument = *(it->second); if (!argument.is_positional) { if (!argument.required) stream << " ["; stream << argument.keys[0]; this->print_usage_nargs(stream, argument); if (!argument.required) stream << "]"; } } for (PositionalArgument::const_iterator it = pos_args.begin(); it != pos_args.end(); ++it) { const _Argument & argument = **it; this->print_usage_nargs(stream, argument); } stream << std::endl; } /* -------------------------------------------------------------------------- */ void ArgumentParser::print_usage_nargs(std::ostream & stream, const _Argument & argument) const { std::string u_name = to_upper(argument.name); switch (argument.nargs) { case _one_if_possible: stream << " [" << u_name << "]"; break; case _at_least_one: stream << " " << u_name; + [[gnu::fallthrough]]; case _any: stream << " [" << u_name << " ...]"; break; default: for (int i = 0; i < argument.nargs; ++i) { stream << " " << u_name; } } } void ArgumentParser::print_help(std::ostream & stream) const { this->print_usage(stream); if (!pos_args.empty()) { stream << std::endl; stream << "positional arguments:" << std::endl; for (PositionalArgument::const_iterator it = pos_args.begin(); it != pos_args.end(); ++it) { const _Argument & argument = **it; this->print_help_argument(stream, argument); } } if (!key_args.empty()) { stream << std::endl; stream << "optional arguments:" << std::endl; for (_Arguments::const_iterator it = arguments.begin(); it != arguments.end(); ++it) { const _Argument & argument = *(it->second); if (!argument.is_positional) { this->print_help_argument(stream, argument); } } } } void ArgumentParser::print_help_argument(std::ostream & stream, const _Argument & argument) const { std::string key(""); if (argument.is_positional) key = argument.name; else { std::stringstream sstr; for (unsigned int i = 0; i < argument.keys.size(); ++i) { if (i != 0) sstr << ", "; sstr << argument.keys[i]; this->print_usage_nargs(sstr, argument); } key = sstr.str(); } stream << " " << std::left << std::setw(15) << key << " " << argument.help; argument.printDefault(stream); stream << std::endl; } }