Algorithms.tcc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * NICE-Core - efficient algebra and computer vision methods
  3. * - libbasicvector - A simple vector library
  4. * See file License for license information.
  5. */
  6. #include "core/vector/Algorithms.h"
  7. #include <core/basics/Log.h>
  8. #include <core/vector/SVD.h>
  9. #ifdef NICE_USELIB_LINAL
  10. #include <LinAl/algorithms.h>
  11. #endif
  12. namespace NICE {
  13. template<class T>
  14. inline T mean(const VectorT<T> &v) {
  15. //#ifdef NICE_USELIB_IPP
  16. T m;
  17. IppStatus ret = ippsMean(v.getDataPointer(),v.size(),&m,ippAlgHintFast);
  18. if(ret!=ippStsNoErr)
  19. _THROW_EVector(ippGetStatusString(ret));
  20. return m;
  21. //#else
  22. // _THROW_EVector("Not yet implementent without IPP.");
  23. //#endif // NICE_USELIB_IPP
  24. }
  25. template<class T>
  26. inline T det(const MatrixT<T> &A) {
  27. #ifdef NICE_USELIB_IPP
  28. size_t msize=A.cols();
  29. if(msize!=A.rows())
  30. _THROW_EMatrix("det(MatrixT<T>): matrix is not symmetric");
  31. size_t tsize=sizeof(T);
  32. T buffer[msize*msize+msize];
  33. T result;
  34. IppStatus ret = ippmDet_m(A.getDataPointer(),msize*tsize,tsize,msize,buffer,&result);
  35. // ippStsSingularErr not defined
  36. if(ret==ippStsSingularErr)
  37. return static_cast<T>(0);
  38. if(ret!=ippStsNoErr)
  39. _THROW_EMatrix(ippGetStatusString(ret));
  40. return result;
  41. #else
  42. #ifdef NICE_USELIB_LINAL
  43. return LinAl::det(A.linal());
  44. #else
  45. _THROW_EVector("Not yet implementent without IPP.");
  46. #endif
  47. #endif // NICE_USELIB_IPP
  48. }
  49. template<class T>
  50. inline T det(const RowMatrixT<T> &A) {
  51. #ifdef NICE_USELIB_IPP
  52. size_t msize=A.cols();
  53. if(msize!=A.rows())
  54. _THROW_EMatrix("det(MatrixT<T>): matrix is not symmetric");
  55. size_t tsize=sizeof(T);
  56. T buffer[msize*msize+msize];
  57. T result;
  58. IppStatus ret = ippmDet_m(A.getDataPointer(),msize*tsize,tsize,msize,buffer,&result);
  59. // ippStsSingularErr not defined
  60. if(ret==ippStsSingularErr)
  61. return static_cast<T>(0);
  62. if(ret!=ippStsNoErr)
  63. _THROW_EMatrix(ippGetStatusString(ret));
  64. return result;
  65. #else
  66. #ifdef NICE_USELIB_LINAL
  67. return LinAl::det(A.linal());
  68. #else
  69. _THROW_EVector("Not yet implementent without IPP.");
  70. #endif
  71. #endif // NICE_USELIB_IPP
  72. }
  73. template<class T>
  74. void choleskyDecomp ( const MatrixT<T> & A, MatrixT<T> & G, bool resetUpperTriangle )
  75. {
  76. if ( A.rows() != A.cols() )
  77. fthrow(Exception, "Matrix is not quadratic !");
  78. const int size = A.rows();
  79. G.resize ( size, size );
  80. if ( resetUpperTriangle )
  81. G.set(0.0);
  82. int i,j,k;
  83. double sum;
  84. for (i=0;i<size;i++) {
  85. bool divide=true;
  86. for (j=0;j<i;j++) G(j,i)=0.0;
  87. for (;j<size;j++) {
  88. sum=A(i,j);
  89. for (k=i-1;k>=0;k--) sum -= G(i,k)*G(j,k);
  90. if (i == j) {
  91. // The following applies if A, with rounding errors, is not positive definite
  92. if (isZero(sum, 1e-16)) {
  93. G(i,i)=0.0;
  94. divide=false;
  95. } else if (sum<0.0) {
  96. // A is (numerically) not positive definite.
  97. fthrow(Exception, "Cholesky decomposition failed (sum=" << sum << ")");
  98. }
  99. G(i,i)=sqrt(sum);
  100. } else {
  101. if (!divide) G(j,i)=0.0;
  102. else G(j,i)=sum/G(i,i);
  103. }
  104. }
  105. }
  106. }
  107. template<class T>
  108. void choleskyInvert ( const MatrixT<T> & Gmatrix, MatrixT<T> & AinvMatrix )
  109. {
  110. if ( Gmatrix.rows() != Gmatrix.cols() )
  111. fthrow(Exception, "Matrix is not quadratic !");
  112. AinvMatrix.resize ( Gmatrix.rows(), Gmatrix.cols() );
  113. const T *G = Gmatrix.getDataPointer();
  114. T *Ainv = AinvMatrix.getDataPointer();
  115. int i,k,j;
  116. T sum;
  117. int size = Gmatrix.rows();
  118. for (j=0;j<size;j++) {
  119. for (i=0;i<size;i++) {
  120. sum = (i==j)?1.0:0.0;
  121. for (k=i-1;k>=0;k--) sum -= G[k*size+i]*Ainv[k+j*size];
  122. if (almostZero(G[i*size+i])) Ainv[i+j*size]=0.0;
  123. else Ainv[i+j*size]=sum/G[i*size+i];
  124. }
  125. for (i=size-1;i>=0;i--) {
  126. for (sum=Ainv[i+j*size],k=i+1;k<size;k++) sum -= G[i*size+k]*Ainv[k+j*size];
  127. if (almostZero(G[i*size+i])) Ainv[i+j*size]=0.0;
  128. else Ainv[i+j*size]=sum/G[i*size+i];
  129. }
  130. }
  131. }
  132. template<class T>
  133. void choleskySolve ( const MatrixT<T> & Gmatrix, const VectorT<T> & b, VectorT<T> & x )
  134. {
  135. if ( Gmatrix.rows() != Gmatrix.cols() )
  136. fthrow(Exception, "Matrix is not quadratic !");
  137. if ( b.size() != Gmatrix.cols() )
  138. fthrow(Exception, "Matrix or right hand side of the linear system has wrong dimensions !");
  139. int size = Gmatrix.rows();
  140. const T* G = Gmatrix.getDataPointer();
  141. int i,k;
  142. double sum;
  143. x.resize(size);
  144. // Solve L y = b, storing y in x.
  145. for (i=0;i<size;i++) {
  146. for (sum=b[i],k=i-1;k>=0;k--) sum -= G[k*size+i]*x[k];
  147. x[i]=sum/G[i*size+i];
  148. }
  149. // Solve LT x = y
  150. for (i=size-1;i>=0;i--) {
  151. for (sum=x[i],k=i+1;k<size;k++) sum -= G[i*size+k]*x[k];
  152. x[i]=sum/G[i*size+i];
  153. }
  154. }
  155. template<class T>
  156. double triangleMatrixDet ( const MatrixT<T> & Gmatrix, bool ignoreZero )
  157. {
  158. if ( Gmatrix.rows() != Gmatrix.cols() )
  159. fthrow(Exception, "Matrix is not quadratic !");
  160. int i;
  161. int size = Gmatrix.rows();
  162. const T* G = Gmatrix.getDataPointer();
  163. double ret = 1.0;
  164. for (i=0;i<size;i++) {
  165. if (almostZero(G[i*size+i])) {
  166. if (ignoreZero) continue;
  167. else return 0.0;
  168. }
  169. ret *= G[i*size+i];
  170. }
  171. return ret;
  172. }
  173. template<class T>
  174. double triangleMatrixLogDet ( const MatrixT<T> & Gmatrix, bool ignoreZero )
  175. {
  176. int i;
  177. int size = Gmatrix.rows();
  178. const T* G = Gmatrix.getDataPointer();
  179. double ret = 0.0;
  180. for (i=0;i<size;i++) {
  181. if (almostZero(G[i*size+i])) {
  182. if (ignoreZero) continue;
  183. else return - std::numeric_limits<double>::infinity();
  184. }
  185. ret += log(G[i*size+i]);
  186. }
  187. return ret;
  188. }
  189. template<class T>
  190. inline void lnIP(VectorT<T> &v) {
  191. #ifdef NICE_USELIB_IPP
  192. IppStatus ret = ippsLn_I(v.getDataPointer(),v.size());
  193. if(ret!=ippStsNoErr)
  194. _THROW_EVector(ippGetStatusString(ret));
  195. #else
  196. _THROW_EVector("Not yet implementent without IPP.");
  197. #endif // NICE_USELIB_IPP
  198. }
  199. template<class T>
  200. inline VectorT<T> *ln(const VectorT<T> &v, VectorT<T> *buffer) {
  201. #ifdef NICE_USELIB_IPP
  202. VectorT<T> *result;
  203. if(buffer==NULL || buffer->size()!=v.size()) {
  204. result=new VectorT<T>(v.size());
  205. } else {
  206. result=buffer;
  207. }
  208. IppStatus ret = ippsLn(v.getDataPointer(),result->getDataPointer(),v.size());
  209. if(ret!=ippStsNoErr)
  210. _THROW_EVector(ippGetStatusString(ret));
  211. return result;
  212. #else
  213. _THROW_EVector("Not yet implementent without IPP.");
  214. #endif // NICE_USELIB_IPP
  215. }
  216. template<class T>
  217. inline VectorT<T> *createGaussFunc(float sigma, VectorT<T> *buffer)
  218. {
  219. #ifdef NICE_USELIB_IPP
  220. int resultlength;
  221. VectorT<T> *result;
  222. if(buffer==NULL || buffer->size()<3) {
  223. int length=static_cast<int>(2.0*sigma*sigma-0.5);
  224. if(length<1) length=0;
  225. float base[] = {0.25, 0.5, 0.25};
  226. resultlength=3+length*2;
  227. result= new VectorT<T>(resultlength);
  228. ippsCopy(base, result->getDataPointer(), 3);
  229. T tmp[resultlength];
  230. for(int i=0;i<length;i++) {
  231. ippsConv(base,3,result->getDataPointer(),3+i*2,tmp);
  232. ippsCopy(tmp, result->getDataPointer(), 3+(i+1)*2);
  233. }
  234. } else {
  235. resultlength=buffer->size();
  236. result=buffer;
  237. float ssq=sigma*sigma;
  238. if(sigma<=0) {
  239. ssq=(resultlength-1)/4;
  240. }
  241. float norm=sqrt(2.*M_PI*ssq);
  242. float l=-(resultlength-1)/2.0;
  243. for(int i=0;i<resultlength;l+=1.0,i++) {
  244. (*result)[i]=exp(-l*l/(2*ssq))/norm;
  245. }
  246. }
  247. return result;
  248. #else
  249. _THROW_EVector("Not yet implementent without IPP.");
  250. #endif // NICE_USELIB_IPP
  251. }
  252. template<class T>
  253. inline void solveLinearEquationQR(const MatrixT<T> &A, const VectorT<T> &b, VectorT<T> &x)
  254. {
  255. #ifdef NICE_USELIB_IPP
  256. // FIXME: this method seems to be buggy :)
  257. size_t in_s = A.cols();
  258. if (in_s != b.size())
  259. _THROW_EMatrix("solveLinearEquationQR: size of input vector b does not fit");
  260. size_t out_s = A.rows();
  261. if (x.size() == 0) {
  262. x.resize(out_s);
  263. }
  264. if (out_s != x.size())
  265. _THROW_EMatrix("solveLinearEquationQR: size of output vector x does not fit");
  266. T QR[in_s*out_s];
  267. int stride = sizeof(T);
  268. int stride_src = out_s*sizeof(T);
  269. T Buffer[in_s];
  270. IppStatus status
  271. = ippmQRDecomp_m(A.getDataPointer(),stride_src, stride, Buffer,
  272. QR, stride_src, stride, out_s, in_s);
  273. if (status != ippStsOk)
  274. _THROW_EVector(ippGetStatusString(status));
  275. status = ippmQRBackSubst_mv(QR, stride_src, stride, Buffer,
  276. b.getDataPointer(), stride,
  277. x.getDataPointer(), stride, out_s, in_s);
  278. if (status != ippStsOk)
  279. _THROW_EVector(ippGetStatusString(status));
  280. #else
  281. _THROW_EVector("Not yet implementent without IPP.");
  282. #endif // NICE_USELIB_IPP
  283. }
  284. template<class T>
  285. inline void solveMDLgreedy(const MatrixT<T> &C, VectorT<T> &h)
  286. {
  287. #ifdef NICE_USELIB_IPP
  288. if (C.rows() != C.cols())
  289. _THROW_EMatrix("solveMDLgreedy: matrix C is not quadratic");
  290. size_t size = h.size();
  291. if (C.rows() != size)
  292. _THROW_EMatrix("solveMDLgreedy: size of output vector h does not fit");
  293. VectorT<T> temp(size);
  294. T maximum = 0.0;
  295. T current = 0.0;
  296. int position = -1;
  297. h *= 0;
  298. int Stride = sizeof(T);
  299. int srcStride = size * sizeof(T);
  300. do {
  301. position = -1;
  302. for (uint i = 0; i < size; i++) {
  303. if (not h(i)) {
  304. h(i) = 1;
  305. ippmMul_tv_32f(C.getDataPointer(), srcStride,
  306. Stride, size, size,
  307. h.getDataPointer(), Stride, size,
  308. temp.getDataPointer(), Stride);
  309. temp *= h;
  310. current = temp.Sum();
  311. if (current > maximum) {
  312. maximum = current;
  313. position = i;
  314. }
  315. h(i) = 0;
  316. }
  317. }
  318. if (position > -1)
  319. h(position) = 1;
  320. } while (position > -1);
  321. #else
  322. _THROW_EVector("Not yet implementent without IPP.");
  323. #endif // NICE_USELIB_IPP
  324. }
  325. template<class T>
  326. MatrixT<T> invert(const MatrixT<T>& w) {
  327. #ifdef NICE_USELIB_IPP
  328. size_t size = w.cols();
  329. if (size != w.rows()) {
  330. _THROW_EMatrix("invert: matrix is not square.");
  331. }
  332. MatrixT<T> result(w.rows(), w.cols());
  333. T* buffer = new T[size * size + size];
  334. int stride1 = sizeof(T);
  335. int stride2 = size * sizeof(T);
  336. IppStatus status = ippmInvert_m(w.getDataPointer(), stride1, stride2,
  337. buffer, result.getDataPointer(),
  338. stride1, stride2, size);
  339. if (status != ippStsOk) {
  340. _THROW_EVector(ippGetStatusString(status));
  341. }
  342. return result;
  343. #else
  344. #ifdef NICE_USELIB_LINAL
  345. LinAl::MatrixCF<T> copy(w.linal());
  346. try {
  347. copy.LUinvert();
  348. } catch (std::exception& e) {
  349. fthrowc(Exception, "Invert failed", e);
  350. }
  351. MatrixT<T> result(copy);
  352. return result;
  353. #else
  354. _THROW_EVector("Not yet implementent without IPP or LinAl.");
  355. #endif
  356. #endif // NICE_USELIB_IPP
  357. }
  358. template<class T>
  359. void invert3x3UpperTriangle(MatrixT<T>& w) {
  360. w(0, 2) = (w(0, 1) * w(1, 2) - w(0, 2) * w(1, 1))
  361. / (w(0, 0) * w(1, 1) * w(2, 2));
  362. w(1, 2) = -w(1, 2) / (w(1, 1) * w(2, 2));
  363. w(2, 2) = 1.0 / w(2, 2);
  364. w(0, 1) = -w(0, 1) / (w(0, 0) * w(1, 1));
  365. w(1, 1) = 1.0 / w(1, 1);
  366. w(0, 0) = 1.0 / w(0, 0);
  367. }
  368. template<class T>
  369. void invert3x3LowerTriangle(MatrixT<T>& w) {
  370. w(2, 0) = (w(1, 0) * w(2, 1) - w(2, 0) * w(1, 1))
  371. / (w(0, 0) * w(1, 1) * w(2, 2));
  372. w(2, 1) = -w(2, 1) / (w(1, 1) * w(2, 2));
  373. w(2, 2) = 1.0 / w(2, 2);
  374. w(1, 0) = -w(1, 0) / (w(0, 0) * w(1, 1));
  375. w(1, 1) = 1.0 / w(1, 1);
  376. w(0, 0) = 1.0 / w(0, 0);
  377. }
  378. }