contrib/brl/bbas/bsta/bsta_von_mises.txx
Go to the documentation of this file.
00001 // This is brl/bbas/bsta/bsta_von_mises.txx
00002 #ifndef bsta_von_mises_txx_
00003 #define bsta_von_mises_txx_
00004 //:
00005 // \file
00006 // do not remove the following text
00007 // Approved for public release, distribution unlimited (DISTAR Case 14389)
00008 //
00009 
00010 #include "bsta_von_mises.h"
00011 #include <vcl_cassert.h>
00012 #include <vcl_limits.h>
00013 #include <vnl/vnl_math.h> // for pi
00014 
00015 namespace
00016 {
00017   //: Unroll the dot product of two vectors
00018   template <class T, unsigned n, unsigned index>
00019   struct bsta_von_mises_compute_dot
00020   {
00021     static inline T value(const vnl_vector_fixed<T,n>& v0,
00022                           const vnl_vector_fixed<T,n>& v1)
00023     {
00024       return v0[index-1]*v1[index-1]
00025            + bsta_von_mises_compute_dot<T,n,index-1>::value(v0, v1);
00026     }
00027   };
00028 
00029   //: base case
00030   // this is a partial specialization: expect MSVC6 to complain
00031   template <class T, unsigned n>
00032   struct bsta_von_mises_compute_dot<T,n,0>
00033   {
00034     static inline T value(const vnl_vector_fixed<T,n>& /*v0*/,
00035                           const vnl_vector_fixed<T,n>& /*v1*/)
00036     { return 0; }
00037   };
00038 
00039   //: base case
00040   // this is partial specialization: expect MSVC6 to complain
00041   template <class T>
00042       struct bsta_von_mises_compute_dot<T,1,1>
00043   {
00044     static inline T value(const T& v0, const T& v1)
00045     { return v0*v1; }
00046   };
00047 
00048   double I0(double X)
00049   {
00050     double Y,P1,P2,P3,P4,P5,P6,P7,Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9,AX,BX;
00051     P1=1.0; P2=3.5156229; P3=3.0899424; P4=1.2067429;
00052     P5=0.2659732; P6=0.360768e-1; P7=0.45813e-2;
00053     Q1=0.39894228; Q2=0.1328592e-1; Q3=0.225319e-2;
00054     Q4=-0.157565e-2; Q5=0.916281e-2; Q6=-0.2057706e-1;
00055     Q7=0.2635537e-1; Q8=-0.1647633e-1; Q9=0.392377e-2;
00056     if (vcl_fabs(X) < 3.75) {
00057       Y=(X/3.75)*(X/3.75);
00058       return P1+Y*(P2+Y*(P3+Y*(P4+Y*(P5+Y*(P6+Y*P7)))));
00059     }
00060     else {
00061       AX=vcl_fabs(X);
00062       Y=3.75/AX;
00063       BX=vcl_exp(AX)/vcl_sqrt(AX);
00064       AX=Q1+Y*(Q2+Y*(Q3+Y*(Q4+Y*(Q5+Y*(Q6+Y*(Q7+Y*(Q8+Y*Q9)))))));
00065       return AX*BX;
00066     }
00067   }
00068 }//namespace
00069 
00070 #if VCL_CAN_DO_PARTIAL_SPECIALIZATION
00071 template <class T>
00072 T bsta_von_mises<T,3>::prob_density( typename bsta_von_mises<T,3>::vector_type const& v) const
00073 {
00074   T dpt = bsta_von_mises_compute_dot<T,3,3>::value(mean_, v);
00075   double dp = static_cast<double>(dpt);
00076   double k = static_cast<double>(kappa_);
00077   double ex = vcl_exp(k*dp);
00078   double norm = k/(vcl_exp(k)-vcl_exp(-k));
00079   norm /= 2.0*vnl_math::pi;
00080   return static_cast<T>(norm*ex);
00081 }
00082 
00083 template <class T>
00084 T bsta_von_mises<T,3>::probability(typename bsta_von_mises<T,3>::vector_type const& v,const T theta_max) const
00085 {
00086   //get gamma, the angle between v and the mean
00087   // make sure v is normalized
00088   vector_type nv = v;
00089   nv.normalize();
00090   double cos_gam = static_cast<double>(bsta_von_mises_compute_dot<T,3,3>::value(mean_, nv));
00091   if (cos_gam>1.0) cos_gam=1.0;
00092   if (cos_gam<-1.0) cos_gam=-1.0;
00093   double gam = vcl_acos(cos_gam);
00094   double sin_gam = vcl_sin(gam),cos_2_gam = vcl_cos(2.0*gam);
00095   double cos_4_gam = vcl_cos(4.0*gam), tan_gam = sin_gam/cos_gam;
00096   double cos_gam_3 = cos_gam*cos_gam*cos_gam;
00097   double cos_theta_m = vcl_cos(theta_max);
00098   double cos_2_theta_m = vcl_cos(2.0*theta_max);
00099   double kap = static_cast<double>(kappa_);
00100   double prob = 0.0;
00101   if (kap<25) {
00102     double e_kap = vcl_exp(kap);
00103     double e_2_kap = e_kap*e_kap;
00104     double e_kap_cos_gam = vcl_exp(kap*cos_gam);
00105     double e_kap_cgam_cthm = vcl_exp(kap*cos_gam*cos_theta_m);
00106     double t1 = -1.0/(64.0*(e_2_kap -1));
00107     double t2 = (e_kap_cos_gam - e_kap_cgam_cthm);
00108     double t3 = (e_kap_cos_gam - cos_2_theta_m*e_kap_cgam_cthm);
00109     double t3a = (e_kap_cos_gam - cos_theta_m*e_kap_cgam_cthm);
00110     double t4 = (-16 + kap*kap*(cos_4_gam -1.0)-48.0*cos_2_gam);
00111     double t5 = t2*t4/cos_gam_3;
00112     double t6 = kap*t3*sin_gam - 4.0*tan_gam*t3a;
00113     double t7 = 8.0*kap*tan_gam*t6;
00114     double t8 = e_kap*(t5+t7);
00115     prob = t1*t8;
00116   }
00117   else {
00118     double e_kap_cos_gam = vcl_exp(kap*(cos_gam-1.0));
00119     double e_kap_cgam_cthm = vcl_exp(kap*(cos_gam*cos_theta_m-1.0));
00120     double t1 = -1.0/(64.0);
00121     double t2 = (e_kap_cos_gam - e_kap_cgam_cthm);
00122     double t3 = (e_kap_cos_gam - cos_2_theta_m*e_kap_cgam_cthm);
00123     double t3a = (e_kap_cos_gam - cos_theta_m*e_kap_cgam_cthm);
00124     double t4 = (-16 + kap*kap*(cos_4_gam -1.0)-48.0*cos_2_gam);
00125     double t5 = t2*t4/cos_gam_3;
00126     double t6 = kap*t3*sin_gam - 4.0*tan_gam*t3a;
00127     double t7 = 8.0*kap*tan_gam*t6;
00128     double t8 = t5+t7;
00129     if (t8==0)
00130       prob = t8;
00131     else
00132       prob = t1*t8;
00133   }
00134   return static_cast<T>(prob);
00135 }
00136 
00137 template <class T>
00138 T bsta_von_mises<T,2>::prob_density(typename bsta_von_mises<T,2>::vector_type const& v) const
00139 {
00140   T dpt = bsta_von_mises_compute_dot<T,2,2>::value(mean_, v);
00141   double dp = static_cast<double>(dpt);
00142   double k = static_cast<double>(kappa_);
00143   double ex = vcl_exp(k*dp);
00144   double i0 = I0(k);
00145   double norm = 1.0/i0;
00146   norm /= 2.0*vnl_math::pi;
00147   return static_cast<T>(norm*ex);
00148 }
00149 #endif //VCL_CAN_DO_PARTIAL_SPECIALIZATION
00150 
00151 
00152 #define BSTA_VON_MISES_INSTANTIATE(T,n) \
00153 template class bsta_von_mises<T,n >
00154 
00155 
00156 #endif // bsta_von_mises_txx_