SHOGUN  v3.0.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Math.h
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 3 of the License, or
5  * (at your option) any later version.
6  *
7  * Written (W) 2013 Thoralf Klein
8  * Written (W) 2013 Soumyajit De
9  * Written (W) 2012 Fernando Jose Iglesias Garcia
10  * Written (W) 2011 Siddharth Kherada
11  * Written (W) 2011 Justin Patera
12  * Written (W) 2011 Alesis Novik
13  * Written (W) 2011-2013 Heiko Strathmann
14  * Written (W) 1999-2009 Soeren Sonnenburg
15  * Written (W) 1999-2008 Gunnar Raetsch
16  * Written (W) 2007 Konrad Rieck
17  * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
18  */
19 
20 #ifndef __MATHEMATICS_H_
21 #define __MATHEMATICS_H_
22 
23 #include <shogun/base/SGObject.h>
24 #include <shogun/lib/common.h>
25 #include <shogun/io/SGIO.h>
26 #include <shogun/base/Parallel.h>
28 
29 #ifndef _USE_MATH_DEFINES
30 #define _USE_MATH_DEFINES
31 #endif
32 
33 #include <math.h>
34 #include <stdio.h>
35 #include <float.h>
36 #include <sys/types.h>
37 #ifndef _WIN32
38 #include <sys/time.h>
39 #include <unistd.h>
40 #endif
41 #include <time.h>
42 
43 #ifdef HAVE_PTHREAD
44 #include <pthread.h>
45 #endif
46 
47 #ifdef SUNOS
48 #include <ieeefp.h>
49 #endif
50 
52 #ifdef log2
53 #define cygwin_log2 log2
54 #undef log2
55 #endif
56 
57 #ifndef M_PI
58 #define M_PI 3.14159265358979323846
59 #endif
60 
61 #ifdef _WIN32
62 #ifndef isnan
63 #define isnan _isnan
64 #endif
65 
66 #ifndef isfinite
67 #define isfinite _isfinite
68 #endif
69 #endif //_WIN32
70 
71 #ifndef NAN
72 #include <stdlib.h>
73 #define NAN (strtod("NAN",NULL))
74 #endif
75 
76 /* Size of RNG seed */
77 #define RNG_SEED_SIZE 256
78 
79 /* Maximum stack size */
80 #define RADIX_STACK_SIZE 512
81 
82 /* Stack macros */
83 #define radix_push(a, n, i) sp->sa = a, sp->sn = n, (sp++)->si = i
84 #define radix_pop(a, n, i) a = (--sp)->sa, n = sp->sn, i = sp->si
85 
86 #ifndef DOXYGEN_SHOULD_SKIP_THIS
87 
88 template <class T> struct radix_stack_t
89 {
91  T *sa;
93  size_t sn;
95  uint16_t si;
96 };
97 
99 
101 template <class T1, class T2> struct thread_qsort
102 {
104  T1* output;
106  T2* index;
108  uint32_t size;
109 
111  int32_t* qsort_threads;
113  int32_t sort_limit;
115  int32_t num_threads;
116 };
117 #endif // DOXYGEN_SHOULD_SKIP_THIS
118 
119 #define COMPLEX128_ERROR_ONEARG(function) \
120 static inline complex128_t function(complex128_t a) \
121 { \
122  SG_SERROR("CMath::%s():: Not supported for complex128_t\n",\
123  #function);\
124  return complex128_t(0.0, 0.0); \
125 }
126 
127 #define COMPLEX128_STDMATH(function) \
128 static inline complex128_t function(complex128_t a) \
129 { \
130  return std::function(a); \
131 }
132 
133 namespace shogun
134 {
136  extern CRandom* sg_rand;
137  class CSGObject;
140 class CMath : public CSGObject
141 {
142  public:
146 
147  CMath();
148 
150  virtual ~CMath();
152 
156 
158  //
159  template <class T>
160  static inline T min(T a, T b)
161  {
162  return (a<=b) ? a : b;
163  }
164 
166  template <class T>
167  static inline T max(T a, T b)
168  {
169  return (a>=b) ? a : b;
170  }
171 
173  template <class T>
174  static inline T clamp(T value, T lb, T ub)
175  {
176  if (value<=lb)
177  return lb;
178  else if (value>=ub)
179  return ub;
180  else
181  return value;
182  }
183 
185  template <class T>
186  static inline T abs(T a)
187  {
188  // can't be a>=0?(a):(-a), because compiler complains about
189  // 'comparison always true' when T is unsigned
190  if (a==0)
191  return 0;
192  else if (a>0)
193  return a;
194  else
195  return -a;
196  }
197 
199  static inline float64_t abs(complex128_t a)
200  {
201  float64_t a_real=a.real();
202  float64_t a_imag=a.imag();
203  return (CMath::sqrt(a_real*a_real+a_imag*a_imag));
204  }
206 
209 
210  static inline float64_t round(float64_t d)
211  {
212  return ::floor(d+0.5);
213  }
214 
215  static inline float64_t floor(float64_t d)
216  {
217  return ::floor(d);
218  }
219 
220  static inline float64_t ceil(float64_t d)
221  {
222  return ::ceil(d);
223  }
224 
226  template <class T>
227  static inline T sign(T a)
228  {
229  if (a==0)
230  return 0;
231  else return (a<0) ? (-1) : (+1);
232  }
233 
235  template <class T>
236  static inline void swap(T &a,T &b)
237  {
238  /* register for fast swaps */
239  register T c=a;
240  a=b;
241  b=c;
242  }
243 
245  template <class T>
246  static inline T sq(T x)
247  {
248  return x*x;
249  }
250 
252  static inline float32_t sqrt(float32_t x)
253  {
254  return ::sqrtf(x);
255  }
256 
258  static inline float64_t sqrt(float64_t x)
259  {
260  return ::sqrt(x);
261  }
262 
264  static inline floatmax_t sqrt(floatmax_t x)
265  {
266  //fall back to double precision sqrt if sqrtl is not
267  //available
268 #ifdef HAVE_SQRTL
269  return ::sqrtl(x);
270 #else
271  return ::sqrt(x);
272 #endif
273  }
274 
277 
278 
279  static inline float32_t invsqrt(float32_t x)
280  {
281  union float_to_int
282  {
283  float32_t f;
284  int32_t i;
285  };
286 
287  float_to_int tmp;
288  tmp.f=x;
289 
290  float32_t xhalf = 0.5f * x;
291  // store floating-point bits in integer tmp.i
292  // and do initial guess for Newton's method
293  tmp.i = 0x5f3759d5 - (tmp.i >> 1);
294  x = tmp.f; // convert new bits into float
295  x = x*(1.5f - xhalf*x*x); // One round of Newton's method
296  return x;
297  }
298 
300  static inline floatmax_t powl(floatmax_t x, floatmax_t n)
301  {
302  //fall back to double precision pow if powl is not
303  //available
304 #ifdef HAVE_POWL
305  return ::powl((long double) x, (long double) n);
306 #else
307  return ::pow((double) x, (double) n);
308 #endif
309  }
310 
311  static inline int32_t pow(bool x, int32_t n)
312  {
313  return 0;
314  }
315 
316  static inline int32_t pow(int32_t x, int32_t n)
317  {
318  ASSERT(n>=0)
319  int32_t result=1;
320  while (n--)
321  result*=x;
322 
323  return result;
324  }
325 
326  static inline float64_t pow(float64_t x, int32_t n)
327  {
328  if (n>=0)
329  {
330  float64_t result=1;
331  while (n--)
332  result*=x;
333 
334  return result;
335  }
336  else
337  return ::pow((double)x, (double)n);
338  }
339 
340  static inline float64_t pow(float64_t x, float64_t n)
341  {
342  return ::pow((double) x, (double) n);
343  }
344 
346  static inline complex128_t pow(complex128_t x, int32_t n)
347  {
348  return std::pow(x, n);
349  }
350 
352  {
353  return std::pow(x, n);
354  }
355 
357  {
358  return std::pow(x, n);
359  }
360 
362  {
363  return std::pow(x, n);
364  }
365 
366  static inline float64_t exp(float64_t x)
367  {
368  return ::exp((double) x);
369  }
370 
373 
374 
375  static inline float64_t tan(float64_t x)
376  {
377  return ::tan((double) x);
378  }
379 
382 
383 
384  static inline float64_t atan(float64_t x)
385  {
386  return ::atan((double) x);
387  }
388 
391 
392 
393  static inline float64_t atan2(float64_t x, float64_t y)
394  {
395  return ::atan2((double) x, (double) y);
396  }
397 
400 
401 
402  static inline float64_t tanh(float64_t x)
403  {
404  return ::tanh((double) x);
405  }
406 
409 
410  static inline float64_t log10(float64_t v)
411  {
412  return ::log(v)/::log(10.0);
413  }
414 
417 
418  static inline float64_t log2(float64_t v)
419  {
420 #ifdef HAVE_LOG2
421  return ::log2(v);
422 #else
423  return ::log(v)/::log(2.0);
424 #endif //HAVE_LOG2
425  }
426 
427  static inline float64_t log(float64_t v)
428  {
429  return ::log(v);
430  }
431 
434 
435  static inline index_t floor_log(index_t n)
436  {
437  index_t i;
438  for (i = 0; n != 0; i++)
439  n >>= 1;
440 
441  return i;
442  }
443 
444  static inline float64_t sin(float64_t x)
445  {
446  return ::sin(x);
447  }
448 
451 
452  static inline float64_t asin(float64_t x)
453  {
454  return ::asin(x);
455  }
456 
459 
460  static inline float64_t sinh(float64_t x)
461  {
462  return ::sinh(x);
463  }
464 
467 
468  static inline float64_t cos(float64_t x)
469  {
470  return ::cos(x);
471  }
472 
475 
476  static inline float64_t acos(float64_t x)
477  {
478  return ::acos(x);
479  }
480 
483 
484  static inline float64_t cosh(float64_t x)
485  {
486  return ::cosh(x);
487  }
488 
491 
492  static float64_t area_under_curve(float64_t* xy, int32_t len, bool reversed)
493  {
494  ASSERT(len>0 && xy)
495 
496  float64_t area = 0.0;
497 
498  if (!reversed)
499  {
500  for (int i=1; i<len; i++)
501  area += 0.5*(xy[2*i]-xy[2*(i-1)])*(xy[2*i+1]+xy[2*(i-1)+1]);
502  }
503  else
504  {
505  for (int i=1; i<len; i++)
506  area += 0.5*(xy[2*i+1]-xy[2*(i-1)+1])*(xy[2*i]+xy[2*(i-1)]);
507  }
508 
509  return area;
510  }
511 
512  static inline int64_t factorial(int32_t n)
513  {
514  int64_t res=1;
515  for (int i=2; i<=n; i++)
516  res*=i ;
517  return res ;
518  }
519 
520  static void init_random(uint32_t initseed=0)
521  {
522  if (initseed==0)
523  {
524  struct timeval tv;
525  gettimeofday(&tv, NULL);
526  seed=(uint32_t) (4223517*getpid()*tv.tv_sec*tv.tv_usec);
527  }
528  else
529  seed=initseed;
530 
532  }
533 
534  static inline uint64_t random()
535  {
536  return sg_rand->random_64();
537  }
538 
539  static inline uint64_t random(uint64_t min_value, uint64_t max_value)
540  {
541  return sg_rand->random(min_value, max_value);
542  }
543 
544  static inline int64_t random(int64_t min_value, int64_t max_value)
545  {
546  return sg_rand->random(min_value, max_value);
547  }
548 
549  static inline uint32_t random(uint32_t min_value, uint32_t max_value)
550  {
551  return sg_rand->random(min_value, max_value);
552  }
553 
554  static inline int32_t random(int32_t min_value, int32_t max_value)
555  {
556  return sg_rand->random(min_value, max_value);
557  }
558 
559  static inline float32_t random(float32_t min_value, float32_t max_value)
560  {
561  return sg_rand->random(min_value, max_value);
562  }
563 
564  static inline float64_t random(float64_t min_value, float64_t max_value)
565  {
566  return sg_rand->random(min_value, max_value);
567  }
568 
569  static inline floatmax_t random(floatmax_t min_value, floatmax_t max_value)
570  {
571  return sg_rand->random(min_value, max_value);
572  }
573 
577  static inline float32_t normal_random(float32_t mean, float32_t std_dev)
578  {
579  // sets up variables & makes sure rand_s.range == (0,1)
580  float32_t ret;
581  float32_t rand_u;
582  float32_t rand_v;
583  float32_t rand_s;
584  do
585  {
586  rand_u = CMath::random(-1.0, 1.0);
587  rand_v = CMath::random(-1.0, 1.0);
588  rand_s = rand_u*rand_u + rand_v*rand_v;
589  } while ((rand_s == 0) || (rand_s >= 1));
590 
591  // the meat & potatos, and then the mean & standard deviation shifting...
592  ret = rand_u*sqrt(-2.0*log(rand_s)/rand_s);
593  ret = std_dev*ret + mean;
594  return ret;
595  }
596 
600  static inline float64_t normal_random(float64_t mean, float64_t std_dev)
601  {
602  float64_t ret;
603  float64_t rand_u;
604  float64_t rand_v;
605  float64_t rand_s;
606  do
607  {
608  rand_u = CMath::random(-1.0, 1.0);
609  rand_v = CMath::random(-1.0, 1.0);
610  rand_s = rand_u*rand_u + rand_v*rand_v;
611  } while ((rand_s == 0) || (rand_s >= 1));
612 
613  ret = rand_u*sqrt(-2.0*log(rand_s)/rand_s);
614  ret = std_dev*ret + mean;
615  return ret;
616  }
617 
620  static inline float32_t randn_float()
621  {
622  return normal_random(0.0, 1.0);
623  }
624 
627  static inline float64_t randn_double()
628  {
629  return normal_random(0.0, 1.0);
630  }
631 
632  template <class T>
633  static int32_t get_num_nonzero(T* vec, int32_t len)
634  {
635  int32_t nnz = 0;
636  for (index_t i=0; i<len; ++i)
637  nnz += vec[i] != 0;
638 
639  return nnz;
640  }
641 
642  static int32_t get_num_nonzero(complex128_t* vec, int32_t len)
643  {
644  int32_t nnz=0;
645  for (index_t i=0; i<len; ++i)
646  nnz+=vec[i]!=0.0;
647  return nnz;
648  }
649 
650  static inline int64_t nchoosek(int32_t n, int32_t k)
651  {
652  int64_t res=1;
653 
654  for (int32_t i=n-k+1; i<=n; i++)
655  res*=i;
656 
657  return res/factorial(k);
658  }
659 
667  static void linspace(float64_t* output, float64_t start, float64_t end, int32_t n = 100);
668 
675  template <class T>
676  static T log_sum_exp(SGVector<T> values)
677  {
678  REQUIRE(values.vector, "Values are empty");
679 
680  /* find minimum element index */
681  index_t min_index=0;
682  T X0=values[0];
683  if (values.vlen>1)
684  {
685  for (index_t i=1; i<values.vlen; ++i)
686  {
687  if (values[i]<X0)
688  {
689  X0=values[i];
690  min_index=i;
691  }
692  }
693  }
694 
695  /* remove element from vector copy and compute log sum exp */
696  SGVector<T> values_without_X0(values.vlen-1);
697  index_t from_idx=0;
698  index_t to_idx=0;
699  for (from_idx=0; from_idx<values.vlen; ++from_idx)
700  {
701  if (from_idx!=min_index)
702  {
703  values_without_X0[to_idx]=exp(values[from_idx]-X0);
704  to_idx++;
705  }
706  }
707 
708  return X0+log(SGVector<T>::sum(values_without_X0)+1);
709  }
710 
717  template <class T>
718  static T log_mean_exp(SGVector<T> values)
719  {
720  return log_sum_exp(values) - log(values.vlen);
721  }
722 
726  static void sort(int32_t *a, int32_t cols, int32_t sort_col=0);
727  static void sort(float64_t *a, int32_t*idx, int32_t N);
728 
731  template <class T>
732  static void qsort(T* output, int32_t size)
733  {
734  if (size<=1)
735  return;
736 
737  if (size==2)
738  {
739  if (output[0] > output [1])
740  CMath::swap(output[0],output[1]);
741  return;
742  }
743  //T split=output[random(0,size-1)];
744  T split=output[size/2];
745 
746  int32_t left=0;
747  int32_t right=size-1;
748 
749  while (left<=right)
750  {
751  while (output[left] < split)
752  left++;
753  while (output[right] > split)
754  right--;
755 
756  if (left<=right)
757  {
758  CMath::swap(output[left],output[right]);
759  left++;
760  right--;
761  }
762  }
763 
764  if (right+1> 1)
765  qsort(output,right+1);
766 
767  if (size-left> 1)
768  qsort(&output[left],size-left);
769  }
770 
773  template <class T>
774  static void insertion_sort(T* output, int32_t size)
775  {
776  for (int32_t i=0; i<size-1; i++)
777  {
778  int32_t j=i-1;
779  T value=output[i];
780  while (j >= 0 && output[j] > value)
781  {
782  output[j+1] = output[j];
783  j--;
784  }
785  output[j+1]=value;
786  }
787  }
788 
790  template <class T>
791  inline static void radix_sort(T* array, int32_t size)
792  {
793  radix_sort_helper(array,size,0);
794  }
795 
796  /*
797  * Inline function to extract the byte at position p (from left)
798  * of an 64 bit integer. The function is somewhat identical to
799  * accessing an array of characters via [].
800  */
801  template <class T>
802  static inline uint8_t byte(T word, uint16_t p)
803  {
804  return (word >> (sizeof(T)-p-1) * 8) & 0xff;
805  }
806 
808  static inline uint8_t byte(complex128_t word, uint16_t p)
809  {
810  SG_SERROR("CMath::byte():: Not supported for complex128_t\n");
811  return uint8_t(0);
812  }
813 
814  template <class T>
815  static void radix_sort_helper(T* array, int32_t size, uint16_t i)
816  {
817  static size_t count[256], nc, cmin;
818  T *ak;
819  uint8_t c=0;
820  radix_stack_t<T> s[RADIX_STACK_SIZE], *sp, *olds, *bigs;
821  T *an, *aj, *pile[256];
822  size_t *cp, cmax;
823 
824  /* Push initial array to stack */
825  sp = s;
826  radix_push(array, size, i);
827 
828  /* Loop until all digits have been sorted */
829  while (sp>s) {
830  radix_pop(array, size, i);
831  an = array + size;
832 
833  /* Make character histogram */
834  if (nc == 0) {
835  cmin = 0xff;
836  for (ak = array; ak < an; ak++) {
837  c = byte(*ak, i);
838  count[c]++;
839  if (count[c] == 1) {
840  /* Determine smallest character */
841  if (c < cmin)
842  cmin = c;
843  nc++;
844  }
845  }
846 
847  /* Sort recursively if stack size too small */
848  if (sp + nc > s + RADIX_STACK_SIZE) {
849  radix_sort_helper(array, size, i);
850  continue;
851  }
852  }
853 
854  /*
855  * Set pile[]; push incompletely sorted bins onto stack.
856  * pile[] = pointers to last out-of-place element in bins.
857  * Before permuting: pile[c-1] + count[c] = pile[c];
858  * during deal: pile[c] counts down to pile[c-1].
859  */
860  olds = bigs = sp;
861  cmax = 2;
862  ak = array;
863  pile[0xff] = an;
864  for (cp = count + cmin; nc > 0; cp++) {
865  /* Find next non-empty pile */
866  while (*cp == 0)
867  cp++;
868  /* Pile with several entries */
869  if (*cp > 1) {
870  /* Determine biggest pile */
871  if (*cp > cmax) {
872  cmax = *cp;
873  bigs = sp;
874  }
875 
876  if (i < sizeof(T)-1)
877  radix_push(ak, *cp, (uint16_t) (i + 1));
878  }
879  pile[cp - count] = ak += *cp;
880  nc--;
881  }
882 
883  /* Play it safe -- biggest bin last. */
884  swap(*olds, *bigs);
885 
886  /*
887  * Permute misplacements home. Already home: everything
888  * before aj, and in pile[c], items from pile[c] on.
889  * Inner loop:
890  * r = next element to put in place;
891  * ak = pile[r[i]] = location to put the next element.
892  * aj = bottom of 1st disordered bin.
893  * Outer loop:
894  * Once the 1st disordered bin is done, ie. aj >= ak,
895  * aj<-aj + count[c] connects the bins in array linked list;
896  * reset count[c].
897  */
898  aj = array;
899  while (aj<an)
900  {
901  T r;
902 
903  for (r = *aj; aj < (ak = --pile[c = byte(r, i)]);)
904  swap(*ak, r);
905 
906  *aj = r;
907  aj += count[c];
908  count[c] = 0;
909  }
910  }
911  }
912 
914  static void radix_sort_helper(complex128_t* array, int32_t size, uint16_t i)
915  {
916  SG_SERROR("CMath::radix_sort_helper():: Not supported for complex128_t\n");
917  }
918 
928  template <class T>
929  static void qsort(T** vector, index_t length)
930  {
931  if (length<=1)
932  return;
933 
934  if (length==2)
935  {
936  if (*vector[0]>*vector[1])
937  swap(vector[0],vector[1]);
938  return;
939  }
940  T* split=vector[length/2];
941 
942  int32_t left=0;
943  int32_t right=length-1;
944 
945  while (left<=right)
946  {
947  while (*vector[left]<*split)
948  ++left;
949  while (*vector[right]>*split)
950  --right;
951 
952  if (left<=right)
953  {
954  swap(vector[left],vector[right]);
955  ++left;
956  --right;
957  }
958  }
959 
960  if (right+1>1)
961  qsort(vector,right+1);
962 
963  if (length-left>1)
964  qsort(&vector[left],length-left);
965  }
966 
968  static void qsort(complex128_t** vector, index_t length)
969  {
970  SG_SERROR("CMath::qsort():: Not supported for complex128_t\n");
971  }
972 
974  template <class T> static void display_bits(T word, int32_t width=8*sizeof(T))
975  {
976  ASSERT(width>=0)
977  for (int i=0; i<width; i++)
978  {
979  T mask = ((T) 1)<<(sizeof(T)*8-1);
980  while (mask)
981  {
982  if (mask & word)
983  SG_SPRINT("1")
984  else
985  SG_SPRINT("0")
986 
987  mask>>=1;
988  }
989  }
990  }
991 
993  static void display_bits(complex128_t word,
994  int32_t width=8*sizeof(complex128_t))
995  {
996  SG_SERROR("CMath::display_bits():: Not supported for complex128_t\n");
997  }
998 
1004  template <class T1,class T2>
1005  static void qsort_index(T1* output, T2* index, uint32_t size);
1006 
1008  template <class T>
1009  static void qsort_index(complex128_t* output, T* index, uint32_t size)
1010  {
1011  SG_SERROR("CMath::qsort_index():: Not supported for complex128_t\n");
1012  }
1013 
1019  template <class T1,class T2>
1020  static void qsort_backward_index(
1021  T1* output, T2* index, int32_t size);
1022 
1024  template <class T>
1026  complex128_t* output, T* index, uint32_t size)
1027  {
1028  SG_SERROR("CMath::qsort_backword_index():: \
1029  Not supported for complex128_t\n");
1030  }
1031 
1039  template <class T1,class T2>
1040  inline static void parallel_qsort_index(T1* output, T2* index, uint32_t size, int32_t n_threads, int32_t limit=262144)
1041  {
1042  int32_t n=0;
1043  thread_qsort<T1,T2> t;
1044  t.output=output;
1045  t.index=index;
1046  t.size=size;
1047  t.qsort_threads=&n;
1048  t.sort_limit=limit;
1049  t.num_threads=n_threads;
1050  parallel_qsort_index<T1,T2>(&t);
1051  }
1052 
1054  template <class T>
1055  inline static void parallel_qsort_index(complex128_t* output, T* index,
1056  uint32_t size, int32_t n_threads, int32_t limit=0)
1057  {
1058  SG_SERROR("CMath::parallel_qsort_index():: Not supported for complex128_t\n");
1059  }
1060 
1061 
1062  template <class T1,class T2>
1063  static void* parallel_qsort_index(void* p);
1064 
1065 
1066  /* finds the smallest element in output and puts that element as the
1067  first element */
1068  template <class T>
1069  static void min(float64_t* output, T* index, int32_t size);
1070 
1072  static void min(float64_t* output, complex128_t* index, int32_t size)
1073  {
1074  SG_SERROR("CMath::min():: Not supported for complex128_t\n");
1075  }
1076 
1077  /* finds the n smallest elements in output and puts these elements as the
1078  first n elements */
1079  template <class T>
1080  static void nmin(
1081  float64_t* output, T* index, int32_t size, int32_t n);
1082 
1084  static void nmin(float64_t* output, complex128_t* index,
1085  int32_t size, int32_t n)
1086  {
1087  SG_SERROR("CMath::nmin():: Not supported for complex128_t\n");
1088  }
1089 
1090 
1091 
1092  /* finds an element in a sorted array via binary search
1093  * returns -1 if not found */
1094  template <class T>
1095  static int32_t binary_search_helper(T* output, int32_t size, T elem)
1096  {
1097  int32_t start=0;
1098  int32_t end=size-1;
1099 
1100  if (size<1)
1101  return 0;
1102 
1103  while (start<end)
1104  {
1105  int32_t middle=(start+end)/2;
1106 
1107  if (output[middle]>elem)
1108  end=middle-1;
1109  else if (output[middle]<elem)
1110  start=middle+1;
1111  else
1112  return middle;
1113  }
1114 
1115  return start;
1116  }
1117 
1119  static int32_t binary_search_helper(complex128_t* output, int32_t size, complex128_t elem)
1120  {
1121  SG_SERROR("CMath::binary_search_helper():: Not supported for complex128_t\n");
1122  return int32_t(0);
1123  }
1124 
1125  /* finds an element in a sorted array via binary search
1126  * * returns -1 if not found */
1127  template <class T>
1128  static inline int32_t binary_search(T* output, int32_t size, T elem)
1129  {
1130  int32_t ind = binary_search_helper(output, size, elem);
1131  if (ind >= 0 && output[ind] == elem)
1132  return ind;
1133  return -1;
1134  }
1135 
1137  static inline int32_t binary_search(complex128_t* output, int32_t size, complex128_t elem)
1138  {
1139  SG_SERROR("CMath::binary_search():: Not supported for complex128_t\n");
1140  return int32_t(-1);
1141  }
1142 
1143 
1144  /* Finds an element in a sorted array of pointers via binary search
1145  * Every element is dereferenced once before being compared
1146  *
1147  * @param array array of pointers to search in (assumed being sorted)
1148  * @param length length of array
1149  * @param elem pointer to element to search for
1150  * @return index of elem, -1 if not found */
1151  template<class T>
1152  static inline int32_t binary_search(T** vector, index_t length,
1153  T* elem)
1154  {
1155  int32_t start=0;
1156  int32_t end=length-1;
1157 
1158  if (length<1)
1159  return -1;
1160 
1161  while (start<end)
1162  {
1163  int32_t middle=(start+end)/2;
1164 
1165  if (*vector[middle]>*elem)
1166  end=middle-1;
1167  else if (*vector[middle]<*elem)
1168  start=middle+1;
1169  else
1170  {
1171  start=middle;
1172  break;
1173  }
1174  }
1175 
1176  if (start>=0&&*vector[start]==*elem)
1177  return start;
1178 
1179  return -1;
1180  }
1181 
1183  static inline int32_t binary_search(complex128_t** vector, index_t length, complex128_t* elem)
1184  {
1185  SG_SERROR("CMath::binary_search():: Not supported for complex128_t\n");
1186  return int32_t(-1);
1187  }
1188 
1189  template <class T>
1191  T* output, int32_t size, T elem)
1192  {
1193  int32_t ind = binary_search_helper(output, size, elem);
1194 
1195  if (output[ind]<=elem)
1196  return ind;
1197  if (ind>0 && output[ind-1] <= elem)
1198  return ind-1;
1199  return -1;
1200  }
1201 
1204  int32_t size, complex128_t elem)
1205  {
1206  SG_SERROR("CMath::binary_search_max_lower_equal():: \
1207  Not supported for complex128_t\n");
1208  return int32_t(-1);
1209  }
1210 
1213  static float64_t Align(
1214  char * seq1, char* seq2, int32_t l1, int32_t l2, float64_t gapCost);
1215 
1216 
1218 
1221  {
1222  return c.real();
1223  }
1224 
1227  {
1228  return c.imag();
1229  }
1230 
1232  inline static uint32_t get_seed()
1233  {
1234  return CMath::seed;
1235  }
1236 
1238  inline static uint32_t get_log_range()
1239  {
1240  return CMath::LOGRANGE;
1241  }
1242 
1243 #ifdef USE_LOGCACHE
1244 
1245  inline static uint32_t get_log_accuracy()
1246  {
1247  return CMath::LOGACCURACY;
1248  }
1249 #endif
1250 
1252  inline static int is_finite(double f)
1253  {
1254 #if defined(isfinite) && !defined(SUNOS)
1255  return isfinite(f);
1256 #else
1257  return finite(f);
1258 #endif
1259  }
1260 
1262  static int is_infinity(double f);
1263 
1265  static int is_nan(double f);
1266 
1277 #ifdef USE_LOGCACHE
1278  static inline float64_t logarithmic_sum(float64_t p, float64_t q)
1279  {
1280  float64_t diff;
1281 
1282  if (!CMath::is_finite(p))
1283  return q;
1284 
1285  if (!CMath::is_finite(q))
1286  {
1287  SG_SWARNING("INVALID second operand to logsum(%f,%f) expect undefined results\n", p, q)
1288  return NAN;
1289  }
1290  diff = p - q;
1291  if (diff > 0)
1292  return diff > LOGRANGE? p : p + logtable[(int)(diff * LOGACCURACY)];
1293  return -diff > LOGRANGE? q : q + logtable[(int)(-diff * LOGACCURACY)];
1294  }
1295 
1297  static void init_log_table();
1298 
1300  static int32_t determine_logrange();
1301 
1303  static int32_t determine_logaccuracy(int32_t range);
1304 #else
1306  float64_t p, float64_t q)
1307  {
1308  float64_t diff;
1309 
1310  if (!CMath::is_finite(p))
1311  return q;
1312  if (!CMath::is_finite(q))
1313  return p;
1314  diff = p - q;
1315  if (diff > 0)
1316  return diff > LOGRANGE? p : p + log(1 + exp(-diff));
1317  return -diff > LOGRANGE? q : q + log(1 + exp(diff));
1318  }
1319 #endif
1320 #ifdef USE_LOGSUMARRAY
1321 
1326  static inline float64_t logarithmic_sum_array(
1327  float64_t *p, int32_t len)
1328  {
1329  if (len<=2)
1330  {
1331  if (len==2)
1332  return logarithmic_sum(p[0],p[1]) ;
1333  if (len==1)
1334  return p[0];
1335  return -INFTY ;
1336  }
1337  else
1338  {
1339  register float64_t *pp=p ;
1340  if (len%2==1) pp++ ;
1341  for (register int32_t j=0; j < len>>1; j++)
1342  pp[j]=logarithmic_sum(pp[j<<1], pp[1+(j<<1)]) ;
1343  }
1344  return logarithmic_sum_array(p,len%2 + (len>>1)) ;
1345  }
1346 #endif //USE_LOGSUMARRAY
1347 
1348 
1350  virtual const char* get_name() const { return "Math"; }
1351  public:
1354 
1355  static const float64_t INFTY;
1356  static const float64_t ALMOST_INFTY;
1357 
1360 
1362  static const float64_t PI;
1363 
1366 
1367  /* largest and smallest possible float64_t */
1370 
1371  protected:
1373  static int32_t LOGRANGE;
1374 
1376  static uint32_t seed;
1377 
1378 #ifdef USE_LOGCACHE
1379 
1381  static int32_t LOGACCURACY;
1383 
1384  static float64_t* logtable;
1385 #endif
1386 };
1387 
1388 //implementations of template functions
1389 template <class T1,class T2>
1391  {
1392  struct thread_qsort<T1,T2>* ps=(thread_qsort<T1,T2>*) p;
1393  T1* output=ps->output;
1394  T2* index=ps->index;
1395  int32_t size=ps->size;
1396  int32_t* qsort_threads=ps->qsort_threads;
1397  int32_t sort_limit=ps->sort_limit;
1398  int32_t num_threads=ps->num_threads;
1399 
1400  if (size<2)
1401  {
1402  return NULL;
1403  }
1404 
1405  if (size==2)
1406  {
1407  if (output[0] > output [1])
1408  {
1409  swap(output[0], output[1]);
1410  swap(index[0], index[1]);
1411  }
1412  return NULL;
1413  }
1414  //T1 split=output[random(0,size-1)];
1415  T1 split=output[size/2];
1416 
1417  int32_t left=0;
1418  int32_t right=size-1;
1419 
1420  while (left<=right)
1421  {
1422  while (output[left] < split)
1423  left++;
1424  while (output[right] > split)
1425  right--;
1426 
1427  if (left<=right)
1428  {
1429  swap(output[left], output[right]);
1430  swap(index[left], index[right]);
1431  left++;
1432  right--;
1433  }
1434  }
1435  bool lthread_start=false;
1436  bool rthread_start=false;
1437  pthread_t lthread;
1438  pthread_t rthread;
1439  struct thread_qsort<T1,T2> t1;
1440  struct thread_qsort<T1,T2> t2;
1441 
1442  if (right+1> 1 && (right+1< sort_limit || *qsort_threads >= num_threads-1))
1443  qsort_index(output,index,right+1);
1444  else if (right+1> 1)
1445  {
1446  (*qsort_threads)++;
1447  lthread_start=true;
1448  t1.output=output;
1449  t1.index=index;
1450  t1.size=right+1;
1451  t1.qsort_threads=qsort_threads;
1452  t1.sort_limit=sort_limit;
1453  t1.num_threads=num_threads;
1454  if (pthread_create(&lthread, NULL, parallel_qsort_index<T1,T2>, &t1) != 0)
1455  {
1456  lthread_start=false;
1457  (*qsort_threads)--;
1458  qsort_index(output,index,right+1);
1459  }
1460  }
1461 
1462 
1463  if (size-left> 1 && (size-left< sort_limit || *qsort_threads >= num_threads-1))
1464  qsort_index(&output[left],&index[left], size-left);
1465  else if (size-left> 1)
1466  {
1467  (*qsort_threads)++;
1468  rthread_start=true;
1469  t2.output=&output[left];
1470  t2.index=&index[left];
1471  t2.size=size-left;
1472  t2.qsort_threads=qsort_threads;
1473  t2.sort_limit=sort_limit;
1474  t2.num_threads=num_threads;
1475  if (pthread_create(&rthread, NULL, parallel_qsort_index<T1,T2>, &t2) != 0)
1476  {
1477  rthread_start=false;
1478  (*qsort_threads)--;
1479  qsort_index(&output[left],&index[left], size-left);
1480  }
1481  }
1482 
1483  if (lthread_start)
1484  {
1485  pthread_join(lthread, NULL);
1486  (*qsort_threads)--;
1487  }
1488 
1489  if (rthread_start)
1490  {
1491  pthread_join(rthread, NULL);
1492  (*qsort_threads)--;
1493  }
1494 
1495  return NULL;
1496  }
1497 
1498  template <class T1,class T2>
1499 void CMath::qsort_index(T1* output, T2* index, uint32_t size)
1500 {
1501  if (size<=1)
1502  return;
1503 
1504  if (size==2)
1505  {
1506  if (output[0] > output [1])
1507  {
1508  swap(output[0],output[1]);
1509  swap(index[0],index[1]);
1510  }
1511  return;
1512  }
1513  //T1 split=output[random(0,size-1)];
1514  T1 split=output[size/2];
1515 
1516  int32_t left=0;
1517  int32_t right=size-1;
1518 
1519  while (left<=right)
1520  {
1521  while (output[left] < split)
1522  left++;
1523  while (output[right] > split)
1524  right--;
1525 
1526  if (left<=right)
1527  {
1528  swap(output[left],output[right]);
1529  swap(index[left],index[right]);
1530  left++;
1531  right--;
1532  }
1533  }
1534 
1535  if (right+1> 1)
1536  qsort_index(output,index,right+1);
1537 
1538  if (size-left> 1)
1539  qsort_index(&output[left],&index[left], size-left);
1540 }
1541 
1542  template <class T1,class T2>
1543 void CMath::qsort_backward_index(T1* output, T2* index, int32_t size)
1544 {
1545  if (size<=1)
1546  return;
1547 
1548  if (size==2)
1549  {
1550  if (output[0] < output [1])
1551  {
1552  swap(output[0],output[1]);
1553  swap(index[0],index[1]);
1554  }
1555  return;
1556  }
1557 
1558  //T1 split=output[random(0,size-1)];
1559  T1 split=output[size/2];
1560 
1561  int32_t left=0;
1562  int32_t right=size-1;
1563 
1564  while (left<=right)
1565  {
1566  while (output[left] > split)
1567  left++;
1568  while (output[right] < split)
1569  right--;
1570 
1571  if (left<=right)
1572  {
1573  swap(output[left],output[right]);
1574  swap(index[left],index[right]);
1575  left++;
1576  right--;
1577  }
1578  }
1579 
1580  if (right+1> 1)
1581  qsort_backward_index(output,index,right+1);
1582 
1583  if (size-left> 1)
1584  qsort_backward_index(&output[left],&index[left], size-left);
1585 }
1586 
1587  template <class T>
1588 void CMath::nmin(float64_t* output, T* index, int32_t size, int32_t n)
1589 {
1590  if (6*n*size<13*size*CMath::log(size))
1591  for (int32_t i=0; i<n; i++)
1592  min(&output[i], &index[i], size-i) ;
1593  else
1594  qsort_index(output, index, size) ;
1595 }
1596 
1597 /* move the smallest entry in the array to the beginning */
1598  template <class T>
1599 void CMath::min(float64_t* output, T* index, int32_t size)
1600 {
1601  if (size<=1)
1602  return;
1603  float64_t min_elem=output[0];
1604  int32_t min_index=0;
1605  for (int32_t i=1; i<size; i++)
1606  {
1607  if (output[i]<min_elem)
1608  {
1609  min_index=i;
1610  min_elem=output[i];
1611  }
1612  }
1613  swap(output[0], output[min_index]);
1614  swap(index[0], index[min_index]);
1615 }
1616 
1617 #define COMPLEX128_ERROR_ONEARG_T(function) \
1618 template <> \
1619 inline complex128_t CMath::function<complex128_t>(complex128_t a) \
1620 { \
1621  SG_SERROR("CMath::%s():: Not supported for complex128_t\n",\
1622  #function);\
1623  return complex128_t(0.0, 0.0); \
1624 }
1625 
1626 #define COMPLEX128_ERROR_TWOARGS_T(function) \
1627 template <> \
1628 inline complex128_t CMath::function<complex128_t>(complex128_t a, complex128_t b) \
1629 { \
1630  SG_SERROR("CMath::%s():: Not supported for complex128_t\n",\
1631  #function);\
1632  return complex128_t(0.0, 0.0); \
1633 }
1634 
1635 #define COMPLEX128_ERROR_THREEARGS_T(function) \
1636 template <> \
1637 inline complex128_t CMath::function<complex128_t>(complex128_t a, complex128_t b, complex128_t c) \
1638 { \
1639  SG_SERROR("CMath::%s():: Not supported for complex128_t\n",\
1640  #function);\
1641  return complex128_t(0.0, 0.0); \
1642 }
1643 
1644 #define COMPLEX128_ERROR_SORT_T(function) \
1645 template <> \
1646 inline void CMath::function<complex128_t>(complex128_t* output, int32_t b) \
1647 { \
1648  SG_SERROR("CMath::%s():: Not supported for complex128_t\n",\
1649  #function);\
1650 }
1651 
1654 
1655 
1657 
1660 
1662 // COMPLEX128_ERROR_ONEARG_T(sign)
1663 
1666 
1669 
1672 
1673 }
1674 #undef COMPLEX128_ERROR_ONEARG
1675 #undef COMPLEX128_ERROR_ONEARG_T
1676 #undef COMPLEX128_ERROR_TWOARGS_T
1677 #undef COMPLEX128_ERROR_THREEARGS_T
1678 #undef COMPLEX128_STDMATH
1679 #undef COMPLEX128_ERROR_SORT_T
1680 #endif

SHOGUN Machine Learning Toolbox - Documentation