1 /*!
2  * \file include/NUMODIS/Math/Utilities.hxx
3  * \brief Contains basic mathematical functions and routines
4  *
5  * Note that:
6  * - Some functions are declared as INLINE functions for maximum
7  * efficiency. As a consequence, they are declared AND defined
8  * in the .hxx file.
9  * - Some functions have their BLAS or LAPACK equivalent, which
10  * are specifically designed to hanlde very large objects and are
11  * not efficient for small calculations. As a consequence, you
12  * should prefer the following functions for 3D calculations.
13  * \author Laurent Dupuy
14  * \date   9/06/2017
15  * \copyright Copyright (C) 2006-2018 CEA/DEN, EDF R&D. All rights
16  * reserved.
17  * This project is publicly released under either the GNU GPL Licence
18  * or the CECILL-A licence. A copy of thoses licences are delivered
19  * with the sources of TFEL. CEA or EDF may also distribute this
20  * project under specific licensing conditions.
21  */
22 
23 #ifndef NUMEODIS_UTILITIES_HXX
24 #define NUMEODIS_UTILITIES_HXX
25 
26 #include <cmath>
27 #include <vector>
28 #include <cstdlib>
29 #include <functional>
30 #include "NUMODIS/Config.hxx"
31 #include "NUMODIS/Vect3.hxx"
32 
33 namespace numodis
34 {
35 
36   namespace math
37   {
38 
39     // Greatest common divisor for rings (including unsigned integers)
40     template < typename RingType >
gcd_euclidean(RingType a,RingType b)41     RingType gcd_euclidean(RingType a,
42 			   RingType b)
43     {
44       constexpr const auto zero = static_cast<RingType>( 0 );
45       // Reduce by GCD-remainder property [GCD(a,b) == GCD(b,a MOD b)]
46       while ( true ) {
47 	if ( a == zero )
48 	  return b;
49 	b %= a;
50 
51 	if ( b == zero )
52 	  return a;
53 	a %= b;
54       }
55     } // end of gcd_euclidean
56 
57     //===============================================================
58     // GCD
59     //---------------------------------------------------------------
60     //! Compute the greatest common divisor of two positive integers
61     //---------------------------------------------------------------
62     /*!
63      * \param a first integer
64      * \param b second integer
65      * \return greatest common divisor
66      */
67     //===============================================================
68     template < typename IntegerType >
GCD(const IntegerType & a,const IntegerType & b)69     inline IntegerType GCD(const IntegerType&  a,
70 			   const IntegerType&  b)
71     {
72       // Avoid repeated construction
73       constexpr const auto zero = static_cast<IntegerType>( 0 );
74       const auto result = gcd_euclidean( a, b );
75       return ( result < zero ) ? static_cast<IntegerType>(-result) : result;
76     }
77 
78     TFELNUMODIS_VISIBILITY_EXPORT int GCD(const std::vector<int>& u);
79 
80     //===============================================================
81     // iCrossProduct
82     //---------------------------------------------------------------
83     //! Cross product of two vectors (3D): W = U x V
84     //---------------------------------------------------------------
85     /*!
86       \param U first vector (3D)
87       \param V second vector (3D)
88       \param W cross-product
89     */
90     //===============================================================
iCrossProduct(const std::vector<int> & U,const std::vector<int> & V,std::vector<int> & W)91     inline void iCrossProduct(const std::vector<int>& U,
92 			      const std::vector<int>& V,
93 			      std::vector<int>& W)
94     {
95       W[0]=U[1]*V[2]-U[2]*V[1];
96       W[1]=U[2]*V[0]-U[0]*V[2];
97       W[2]=U[0]*V[1]-U[1]*V[0];
98     }
99 
100 
101     //===============================================================
102     // iCrossProduct
103     //---------------------------------------------------------------
104     //! Cross product of two vectors (3D): W = U x V
105     //---------------------------------------------------------------
106     /*!
107       \param U first vector (3D)
108       \param V second vector (3D)
109       \param W cross-product
110     */
111     //===============================================================
iCrossProduct(const int U[],const int V[],int W[])112     inline void iCrossProduct(const int U[],
113 			      const int V[],
114 			      int W[])
115     {
116       W[0]=U[1]*V[2]-U[2]*V[1];
117       W[1]=U[2]*V[0]-U[0]*V[2];
118       W[2]=U[0]*V[1]-U[1]*V[0];
119     }
120 
121     //===============================================================
122     // iScalProduct
123     //---------------------------------------------------------------
124     //! Scalar product of two std::vector<int>: U.V
125     //---------------------------------------------------------------
126     /*
127       \param U first vector
128       \param V second vector
129     */
130     //===============================================================
iScalProduct(const std::vector<int> & U,const std::vector<int> & V)131     inline int iScalProduct(const std::vector<int>& U,
132 			    const std::vector<int>& V)
133     {
134       int sum=0;
135       for(unsigned i=0; i!= U.size(); i++)
136 	sum+=U[i]*V[i];
137       return sum;
138     }
139 
140     //===============================================================
141     // abs
142     //---------------------------------------------------------------
143     //! return the absolute value of a vector
144     //---------------------------------------------------------------
145     /*
146       \param U first vector
147       \param V second vector
148     */
149     //===============================================================
abs(const std::vector<int> & U)150     inline std::vector<int> abs(const std::vector<int>& U)
151     {
152 
153       std::vector<int> V(U);
154       for(unsigned i=0; i!=V.size(); i++)
155 	V[i]=std::abs(V[i]);
156 
157       return V;
158 
159     }
160 
161     //===============================================================
162     // dTripleProduct
163     //---------------------------------------------------------------
164     //! Triple product of three vectors: (UxV).W
165     //---------------------------------------------------------------
166     /*!
167       \param U first vector (3D)
168       \param V second vector (3D)
169       \param W third vector (3D)
170       \return triple product
171     */
172     //===============================================================
dTripleProduct(const Vect3 & U,const Vect3 & V,const Vect3 & W)173     inline double dTripleProduct(const Vect3& U,
174 				 const Vect3& V,
175 				 const Vect3& W)
176     {
177       return
178 	(U[1]*V[2]-U[2]*V[1])*W[0]+
179 	(U[2]*V[0]-U[0]*V[2])*W[1]+
180 	(U[0]*V[1]-U[1]*V[0])*W[2];
181     }
182 
183     //===============================================================
184     // dNorm
185     //---------------------------------------------------------------
186     //! Norm of a vector (3D)
187     //---------------------------------------------------------------
188     /*! \param X a vector                                          */
189     //===============================================================
dNorm(const Vect3 & X)190     inline double dNorm(const Vect3& X)
191     { return X.Norm(); }
192 
193     //===============================================================
194     // dNorm2
195     //---------------------------------------------------------------
196     //! Norm^2 of a vector (3D)
197     //---------------------------------------------------------------
198     /*! \param X a vector                                          */
199     //===============================================================
dNorm2(const Vect3 & X)200     inline double dNorm2(const Vect3& X)
201     { return X.SquareLength(); }
202 
203     //===============================================================
204     // dDistance
205     //---------------------------------------------------------------
206     //! Distance between two points (3D)
207     //---------------------------------------------------------------
208     /*!
209       \param X1 vector
210       \param X2 vector
211       \return distance between X1 and X2
212     */
213     //===============================================================
dDistance(const Vect3 & X1,const Vect3 & X2)214     inline double dDistance(const Vect3& X1,
215 			    const Vect3& X2)
216     {
217       Vect3 X(X1-X2);
218       return X.Norm();
219     }
220 
221     //===============================================================
222     // dCubeRoot
223     //---------------------------------------------------------------
224     //! Cube root of x.
225     //---------------------------------------------------------------
226     /*!
227       This function works even if x is negative.
228       \param x
229       \return Cube root of x
230     */
231     //===============================================================
dCubeRoot(const double x)232     inline double dCubeRoot(const double x)
233     { return (x >= 0.0 ? pow(x,1./3.) : -pow(-x,1./3.)); }
234 
235     //===============================================================
236     // dRound
237     //---------------------------------------------------------------
238     //! Returns the integer value closest to x
239     //---------------------------------------------------------------
240     /*!
241       There is no round function in the standard library. Some
242       compilers may include round though.
243       Examples:
244       x = -0.51 -> dRound = -1
245       x = -0.49 -> dRound =  0
246       x = 0.49 -> dRound = 0
247       x = 0.51 -> dRound = 1
248       \param x real number
249       \return the integer value closest to x
250     */
251     //===============================================================
dRound(const double x)252     inline int dRound(const double x)
253     {
254       return static_cast<int>(x > 0.0 ? x + 0.5 : x - 0.5);
255     }
256 
257     //===============================================================
258     // dInt
259     //---------------------------------------------------------------
260     //! Returns the smallest integer value less than x.
261     //---------------------------------------------------------------
262     /*!
263       Note that dInt is different from ceil!
264       Examples:
265       x = -0.51 -> dInt = -1
266       x = -0.49 -> dInt = -1
267       x =  0.49 -> dInt = 0
268       x =  0.51 -> dInt = 0
269       x = 1.01  -> dInt = 1
270       \param x real number
271       \return the smallest integer value less than x
272     */
273     //===============================================================
dInt(const double x)274     inline int dInt(const double x)
275     {
276       const auto ix = static_cast<int>(x);
277       return x >= 0.0 ? ix : -1+ix;
278     }
279 
280     //===============================================================
281     // Kronecker
282     //---------------------------------------------------------------
283     //! Returns the value of Kronecker (i,j)
284     //---------------------------------------------------------------
285     /*!
286       \param i an integer
287       \param j another integer
288       \return 1 if (i=j), 0 otherwise
289     */
290     //===============================================================
Kronecker(const unsigned i,const unsigned j)291     inline int Kronecker(const unsigned i,const unsigned j)
292     { return (i==j); }
293 
294     //===============================================================
295     // Abs<...>
296     //---------------------------------------------------------------
297     //! Calculate the absolute value
298     //===============================================================
299     template<class TYPE>
300     struct Abs: public std::unary_function<TYPE,void>
301     {
302 
303       //! defines the absolute value function of x
304       /*! \param x input value */
operator ()numodis::math::Abs305       void operator()(TYPE& x)
306       { x = (x>=0 ? x : -x); }
307 
308     };
309 
310     //===============================================================
311     // Sgn
312     //---------------------------------------------------------------
313     //! Return the sign of a number
314     //---------------------------------------------------------------
315     /*!
316       \param val input value
317       \return -1, 0 or 1
318     */
319     //===============================================================
Sgn(const T val)320     template<typename T> int Sgn(const T val)
321     { return (T(0) < val) - (val < T(0)); }
322 
323     //===============================================================
324     //                 NON-INLINE FUNCTIONS
325     //===============================================================
326 
327     double dUnitVector(const Vect3& U,
328 		       Vect3& V);
329 
330     double dUnitVector(Vect3& U);
331 
332     bool dCollinear(const Vect3& U,
333 		    const Vect3& V);
334 
335     bool dCollinear(const Vect3& U,
336 		    const Vect3& V,
337 		    Vect3& W);
338 
339     bool dOrthogonal(const Vect3& U,
340 		     const Vect3& V,
341 		     double* res);
342 
343     bool iCollinear(const std::vector<int>& U,
344 		    const std::vector<int>& V);
345 
346     bool iCollinear(const std::vector<int>& U,
347 		    const std::vector<int>& V,
348 		    int* pdirection);
349 
350     void iSortVector(std::vector<int>& U);
351 
352     void iSortVector3FirstValue(std::vector<int>& U);
353 
354     int Epsilon(const unsigned i,
355 		const unsigned j,
356 		const unsigned k);
357 
358   } // end namespace math
359 
360 } // end of namespace numodis
361 
362 #endif // NUMEODIS_UTILITIES_HXX
363