Teh first one
[mldemos:kalians-mldemos.git] / _AlgorithmsPlugins / KernelMethods / dlib / matrix / matrix_math_functions.h
1 // Copyright (C) 2006  Davis E. King (davis@dlib.net)\r
2 // License: Boost Software License   See LICENSE.txt for the full license.\r
3 #ifndef DLIB_MATRIx_MATH_FUNCTIONS\r
4 #define DLIB_MATRIx_MATH_FUNCTIONS \r
5 \r
6 #include "matrix_math_functions_abstract.h"\r
7 #include "matrix_op.h"\r
8 #include "matrix_utilities.h"\r
9 #include "matrix.h"\r
10 #include "../algs.h"\r
11 #include <cmath>\r
12 #include <complex>\r
13 #include <limits>\r
14 \r
15 \r
16 namespace dlib\r
17 {\r
18 \r
19 // ----------------------------------------------------------------------------------------\r
20 \r
21     DLIB_DEFINE_FUNCTION_M(op_sqrt, sqrt, std::sqrt ,7);\r
22     DLIB_DEFINE_FUNCTION_M(op_log, log, std::log ,7);\r
23     DLIB_DEFINE_FUNCTION_M(op_log10, log10, std::log10 ,7);\r
24     DLIB_DEFINE_FUNCTION_M(op_exp, exp, std::exp ,7);\r
25 \r
26     DLIB_DEFINE_FUNCTION_M(op_conj, conj, std::conj ,2);\r
27 \r
28     DLIB_DEFINE_FUNCTION_M(op_ceil, ceil, std::ceil ,7);\r
29     DLIB_DEFINE_FUNCTION_M(op_floor, floor, std::floor ,7);\r
30 \r
31     DLIB_DEFINE_FUNCTION_M(op_sin, sin, std::sin ,7);\r
32     DLIB_DEFINE_FUNCTION_M(op_cos, cos, std::cos ,7);\r
33     DLIB_DEFINE_FUNCTION_M(op_tan, tan, std::tan ,7);\r
34     DLIB_DEFINE_FUNCTION_M(op_sinh, sinh, std::sinh ,7);\r
35     DLIB_DEFINE_FUNCTION_M(op_cosh, cosh, std::cosh ,7);\r
36     DLIB_DEFINE_FUNCTION_M(op_tanh, tanh, std::tanh ,7);\r
37     DLIB_DEFINE_FUNCTION_M(op_asin, asin, std::asin ,7);\r
38     DLIB_DEFINE_FUNCTION_M(op_acos, acos, std::acos ,7);\r
39     DLIB_DEFINE_FUNCTION_M(op_atan, atan, std::atan ,7);\r
40 \r
41 // ----------------------------------------------------------------------------------------\r
42 \r
43     namespace impl\r
44     {\r
45         template <typename type>\r
46         inline type sigmoid (const type& val)\r
47         {\r
48             return static_cast<type>(1/(1 + std::exp(-val)));\r
49         }\r
50 \r
51         template <typename type, typename S>\r
52         inline type round_zeros_eps (const type& val, const S& eps)\r
53         {\r
54             // you can only round matrices that contain built in scalar types like double, long, float, etc.\r
55             COMPILE_TIME_ASSERT(is_built_in_scalar_type<type>::value);\r
56 \r
57             if (val >= eps || val <= -eps)\r
58                 return val;\r
59             else\r
60                 return 0;\r
61         }\r
62 \r
63         template <typename type>\r
64         inline type round_zeros (const type& val)\r
65         {\r
66             // you can only round matrices that contain built in scalar types like double, long, float, etc.\r
67             COMPILE_TIME_ASSERT(is_built_in_scalar_type<type>::value);\r
68 \r
69             const type eps = 10*std::numeric_limits<type>::epsilon();\r
70             if (val >= eps || val <= -eps)\r
71                 return val;\r
72             else\r
73                 return 0;\r
74         }\r
75 \r
76         template <typename type>\r
77         inline type squared (const type& val)\r
78         {\r
79             return val*val;\r
80         }\r
81 \r
82         template <typename type>\r
83         type cubed (const type& val)\r
84         {\r
85             return val*val*val;\r
86         }\r
87 \r
88         template <typename type, typename S>\r
89         inline type pow1 (const type& val, const S& s)\r
90         {\r
91             // you can only call pow() on matrices that contain floats, doubles or long doubles.\r
92             COMPILE_TIME_ASSERT((\r
93                     is_same_type<type,float>::value == true || \r
94                     is_same_type<type,double>::value == true || \r
95                     is_same_type<type,long double>::value == true \r
96             ));\r
97 \r
98             return std::pow(val,static_cast<type>(s));\r
99         }\r
100 \r
101         template <typename type, typename S>\r
102         inline type pow2 (const S& s, const type& val)\r
103         {\r
104             // you can only call pow() on matrices that contain floats, doubles or long doubles.\r
105             COMPILE_TIME_ASSERT((\r
106                     is_same_type<type,float>::value == true || \r
107                     is_same_type<type,double>::value == true || \r
108                     is_same_type<type,long double>::value == true \r
109             ));\r
110 \r
111             return std::pow(static_cast<type>(s),val);\r
112         }\r
113 \r
114         template <typename type>\r
115         inline type reciprocal (const type& val)\r
116         {\r
117             // you can only compute reciprocal matrices that contain floats, doubles or long doubles.\r
118             COMPILE_TIME_ASSERT((\r
119                     is_same_type<type,float>::value == true || \r
120                     is_same_type<type,double>::value == true || \r
121                     is_same_type<type,long double>::value == true  ||\r
122                     is_same_type<type,std::complex<float> >::value == true || \r
123                     is_same_type<type,std::complex<double> >::value == true || \r
124                     is_same_type<type,std::complex<long double> >::value == true \r
125             ));\r
126 \r
127             if (val != static_cast<type>(0))\r
128                 return static_cast<type>((type)1.0/val);\r
129             else\r
130                 return 0;\r
131         }\r
132 \r
133         template <typename type>\r
134         inline type reciprocal_max (const type& val)\r
135         {\r
136             // you can only compute reciprocal_max matrices that contain floats, doubles or long doubles.\r
137             COMPILE_TIME_ASSERT((\r
138                     is_same_type<type,float>::value == true || \r
139                     is_same_type<type,double>::value == true || \r
140                     is_same_type<type,long double>::value == true \r
141             ));\r
142 \r
143             if (val != static_cast<type>(0))\r
144                 return static_cast<type>((type)1.0/val);\r
145             else\r
146                 return std::numeric_limits<type>::max();\r
147         }\r
148 \r
149     }\r
150 \r
151     DLIB_DEFINE_FUNCTION_M(op_sigmoid, sigmoid, impl::sigmoid, 7);\r
152     DLIB_DEFINE_FUNCTION_MS(op_round_zeros, round_zeros, impl::round_zeros_eps, 7);\r
153     DLIB_DEFINE_FUNCTION_M(op_round_zeros2, round_zeros, impl::round_zeros, 7);\r
154     DLIB_DEFINE_FUNCTION_M(op_cubed, cubed, impl::cubed, 7);\r
155     DLIB_DEFINE_FUNCTION_M(op_squared, squared, impl::squared, 6);\r
156     DLIB_DEFINE_FUNCTION_MS(op_pow1, pow, impl::pow1, 7);\r
157     DLIB_DEFINE_FUNCTION_SM(op_pow2, pow, impl::pow2, 7);\r
158     DLIB_DEFINE_FUNCTION_M(op_reciprocal, reciprocal, impl::reciprocal, 6);\r
159     DLIB_DEFINE_FUNCTION_M(op_reciprocal_max, reciprocal_max, impl::reciprocal_max, 6);\r
160 \r
161 // ----------------------------------------------------------------------------------------\r
162 \r
163     template <typename M, typename enabled = void>\r
164     struct op_round : basic_op_m<M> \r
165     {\r
166         op_round( const M& m_) : basic_op_m<M>(m_){}\r
167 \r
168         const static long cost = M::cost+7;\r
169         typedef typename M::type type;\r
170         typedef const typename M::type const_ret_type;\r
171         const_ret_type apply (long r, long c) const\r
172         { \r
173             return static_cast<type>(std::floor(this->m(r,c)+0.5)); \r
174         }\r
175     };\r
176 \r
177     template <typename M>\r
178     struct op_round<M,typename enable_if_c<std::numeric_limits<typename M::type>::is_integer>::type > \r
179     : basic_op_m<M>\r
180     {\r
181         op_round( const M& m_) : basic_op_m<M>(m_){}\r
182 \r
183         const static long cost = M::cost;\r
184         typedef typename M::type type;\r
185         typedef typename M::const_ret_type const_ret_type;\r
186         const_ret_type apply (long r, long c) const\r
187         { \r
188             return this->m(r,c);\r
189         }\r
190     };\r
191 \r
192     template <\r
193         typename EXP\r
194         >\r
195     const matrix_op<op_round<EXP> > round (\r
196         const matrix_exp<EXP>& m\r
197     )\r
198     {\r
199         // you can only round matrices that contain built in scalar types like double, long, float, etc.\r
200         COMPILE_TIME_ASSERT(is_built_in_scalar_type<typename EXP::type>::value);\r
201 \r
202         typedef op_round<EXP> op;\r
203         return matrix_op<op>(op(m.ref()));\r
204     }\r
205 \r
206 // ----------------------------------------------------------------------------------------\r
207 \r
208     template <typename M>\r
209     struct op_normalize : basic_op_m<M> \r
210     {\r
211         typedef typename M::type type;\r
212 \r
213         op_normalize( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}\r
214 \r
215         const type s;\r
216 \r
217         const static long cost = M::cost+5;\r
218         typedef const typename M::type const_ret_type;\r
219         const_ret_type apply (long r, long c) const\r
220         { \r
221             return this->m(r,c)*s;\r
222         }\r
223     };\r
224 \r
225     template <\r
226         typename EXP\r
227         >\r
228     const matrix_op<op_normalize<EXP> > normalize (\r
229         const matrix_exp<EXP>& m\r
230     )\r
231     {\r
232         // you can only compute normalized matrices that contain floats, doubles or long doubles.\r
233         COMPILE_TIME_ASSERT((\r
234                 is_same_type<typename EXP::type,float>::value == true || \r
235                 is_same_type<typename EXP::type,double>::value == true || \r
236                 is_same_type<typename EXP::type,long double>::value == true \r
237         ));\r
238 \r
239 \r
240         typedef op_normalize<EXP> op;\r
241         typename EXP::type temp = std::sqrt(sum(squared(m)));\r
242         if (temp != 0.0)\r
243             temp = 1.0/temp;\r
244 \r
245         return matrix_op<op>(op(m.ref(),temp));\r
246     }\r
247 \r
248 // ----------------------------------------------------------------------------------------\r
249 \r
250     template <typename M, typename return_type = typename M::type>\r
251     struct op_abs : basic_op_m<M>\r
252     {\r
253         op_abs( const M& m_) : basic_op_m<M>(m_){}\r
254 \r
255         const static long cost = M::cost+7;\r
256         typedef typename M::type type;\r
257         typedef const typename M::type const_ret_type;\r
258         const_ret_type apply ( long r, long c) const\r
259         { \r
260             return static_cast<type>(std::abs(this->m(r,c))); \r
261         }\r
262     };\r
263 \r
264     template <typename M, typename T>\r
265     struct op_abs<M, std::complex<T> > : basic_op_m<M>\r
266     {\r
267         op_abs( const M& m_) : basic_op_m<M>(m_){}\r
268 \r
269         const static long cost = M::cost;\r
270         typedef T type;\r
271         typedef const T const_ret_type;\r
272         const_ret_type apply ( long r, long c) const\r
273         { \r
274             return static_cast<type>(std::abs(this->m(r,c))); \r
275         }\r
276     };\r
277 \r
278     template <\r
279         typename EXP\r
280         >\r
281     const matrix_op<op_abs<EXP> > abs (\r
282         const matrix_exp<EXP>& m\r
283     )\r
284     {\r
285         typedef op_abs<EXP> op;\r
286         return matrix_op<op>(op(m.ref()));\r
287     }\r
288 \r
289 // ----------------------------------------------------------------------------------------\r
290 \r
291     template <typename M>\r
292     struct op_complex_matrix : basic_op_m<M>\r
293     {\r
294         op_complex_matrix( const M& m_) : basic_op_m<M>(m_){}\r
295 \r
296         const static long cost = M::cost+1;\r
297         typedef std::complex<typename M::type> type;\r
298         typedef const std::complex<typename M::type> const_ret_type;\r
299         const_ret_type apply ( long r, long c) const\r
300         { \r
301             return type(this->m(r,c));\r
302         }\r
303     };\r
304 \r
305     template <\r
306         typename EXP\r
307         >\r
308     const matrix_op<op_complex_matrix<EXP> > complex_matrix (\r
309         const matrix_exp<EXP>& m\r
310     )\r
311     {\r
312         typedef op_complex_matrix<EXP> op;\r
313         return matrix_op<op>(op(m.ref()));\r
314     }\r
315 \r
316 // ----------------------------------------------------------------------------------------\r
317 \r
318     template <typename M1, typename M2>\r
319     struct op_complex_matrix2 : basic_op_mm<M1,M2>\r
320     {\r
321         op_complex_matrix2( const M1& m1_, const M2& m2_) : basic_op_mm<M1,M2>(m1_,m2_){}\r
322 \r
323         const static long cost = M1::cost+M2::cost+1;\r
324         typedef std::complex<typename M1::type> type;\r
325         typedef const std::complex<typename M1::type> const_ret_type;\r
326 \r
327         const_ret_type apply ( long r, long c) const\r
328         { return type(this->m1(r,c), this->m2(r,c)); }\r
329     };\r
330 \r
331     template <\r
332         typename EXP1,\r
333         typename EXP2\r
334         >\r
335     const matrix_op<op_complex_matrix2<EXP1,EXP2> > complex_matrix (\r
336         const matrix_exp<EXP1>& real_part,\r
337         const matrix_exp<EXP2>& imag_part \r
338     )\r
339     {\r
340         COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));\r
341         COMPILE_TIME_ASSERT(EXP1::NR == EXP2::NR || EXP1::NR == 0 || EXP2::NR == 0);\r
342         COMPILE_TIME_ASSERT(EXP1::NC == EXP2::NC || EXP1::NC == 0 || EXP2::NC == 0);\r
343 \r
344         DLIB_ASSERT(real_part.nr() == imag_part.nr() &&\r
345                real_part.nc() == imag_part.nc(), \r
346             "\tconst matrix_exp::type complex_matrix(real_part, imag_part)"\r
347             << "\n\tYou can only make a complex matrix from two equally sized matrices"\r
348             << "\n\treal_part.nr(): " << real_part.nr()\r
349             << "\n\treal_part.nc(): " << real_part.nc() \r
350             << "\n\timag_part.nr(): " << imag_part.nr()\r
351             << "\n\timag_part.nc(): " << imag_part.nc() \r
352             );\r
353 \r
354         typedef op_complex_matrix2<EXP1,EXP2> op;\r
355         return matrix_op<op>(op(real_part.ref(),imag_part.ref()));\r
356     }\r
357 \r
358 // ----------------------------------------------------------------------------------------\r
359 \r
360     template <typename M>\r
361     struct op_norm : basic_op_m<M>\r
362     {\r
363         op_norm( const M& m_) : basic_op_m<M>(m_){}\r
364 \r
365         const static long cost = M::cost+6;\r
366         typedef typename M::type::value_type type;\r
367         typedef const typename M::type::value_type const_ret_type;\r
368         const_ret_type apply ( long r, long c) const\r
369         { return std::norm(this->m(r,c)); }\r
370     };\r
371 \r
372     template <\r
373         typename EXP\r
374         >\r
375     const matrix_op<op_norm<EXP> > norm (\r
376         const matrix_exp<EXP>& m\r
377     )\r
378     {\r
379         typedef op_norm<EXP> op;\r
380         return matrix_op<op>(op(m.ref()));\r
381     }\r
382 \r
383 // ----------------------------------------------------------------------------------------\r
384 \r
385     template <typename M>\r
386     struct op_real : basic_op_m<M>\r
387     {\r
388         op_real( const M& m_) : basic_op_m<M>(m_){}\r
389 \r
390         const static long cost = M::cost;\r
391         typedef typename M::type::value_type type;\r
392         typedef const typename M::type::value_type const_ret_type;\r
393         const_ret_type apply ( long r, long c) const\r
394         { return std::real(this->m(r,c)); }\r
395     };\r
396 \r
397     template <\r
398         typename EXP\r
399         >\r
400     const matrix_op<op_real<EXP> > real (\r
401         const matrix_exp<EXP>& m\r
402     )\r
403     {\r
404         typedef op_real<EXP> op;\r
405         return matrix_op<op>(op(m.ref()));\r
406     }\r
407 \r
408 // ----------------------------------------------------------------------------------------\r
409 \r
410     template <typename M>\r
411     struct op_imag : basic_op_m<M>\r
412     {\r
413         op_imag( const M& m_) : basic_op_m<M>(m_){}\r
414 \r
415         const static long cost = M::cost;\r
416         typedef typename M::type::value_type type;\r
417         typedef const typename M::type::value_type const_ret_type;\r
418         const_ret_type apply (long r, long c) const\r
419         { return std::imag(this->m(r,c)); }\r
420     };\r
421 \r
422     template <\r
423         typename EXP\r
424         >\r
425     const matrix_op<op_imag<EXP> > imag (\r
426         const matrix_exp<EXP>& m\r
427     )\r
428     {\r
429         typedef op_imag<EXP> op;\r
430         return matrix_op<op>(op(m.ref()));\r
431     }\r
432 \r
433 // ----------------------------------------------------------------------------------------\r
434 \r
435 }\r
436 \r
437 #endif // DLIB_MATRIx_MATH_FUNCTIONS\r
438 \r