mfunc.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /**************************************************************************
  2. **
  3. ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
  4. **
  5. ** Meschach Library
  6. **
  7. ** This Meschach Library is provided "as is" without any express
  8. ** or implied warranty of any kind with respect to this software.
  9. ** In particular the authors shall not be liable for any direct,
  10. ** indirect, special, incidental or consequential damages arising
  11. ** in any way from use of the software.
  12. **
  13. ** Everyone is granted permission to copy, modify and redistribute this
  14. ** Meschach Library, provided:
  15. ** 1. All copies contain this copyright notice.
  16. ** 2. All modified copies shall carry a notice stating who
  17. ** made the last modification and the date of such modification.
  18. ** 3. No charge is made for this software or works derived from it.
  19. ** This clause shall not be construed as constraining other software
  20. ** distributed on the same medium as this software, nor is a
  21. ** distribution fee considered a charge.
  22. **
  23. ***************************************************************************/
  24. /*
  25. This file contains routines for computing functions of matrices
  26. especially polynomials and exponential functions
  27. Copyright (C) Teresa Leyk and David Stewart, 1993
  28. */
  29. #include <stdio.h>
  30. #include <math.h>
  31. #include "matrix.h"
  32. #include "matrix2.h"
  33. static char rcsid[] = "$Id: mfunc.c,v 1.2 1994/11/01 05:57:56 des Exp $";
  34. /* _m_pow -- computes integer powers of a square matrix A, A^p
  35. -- uses tmp as temporary workspace */
  36. #ifndef ANSI_C
  37. MAT *_m_pow(A, p, tmp, out)
  38. MAT *A, *tmp, *out;
  39. int p;
  40. #else
  41. MAT *_m_pow(const MAT *A, int p, MAT *tmp, MAT *out)
  42. #endif
  43. {
  44. int it_cnt, k, max_bit;
  45. /*
  46. File containing routines for evaluating matrix functions
  47. esp. the exponential function
  48. */
  49. #define Z(k) (((k) & 1) ? tmp : out)
  50. if ( ! A )
  51. error(E_NULL,"_m_pow");
  52. if ( A->m != A->n )
  53. error(E_SQUARE,"_m_pow");
  54. if ( p < 0 )
  55. error(E_NEG,"_m_pow");
  56. out = m_resize(out,A->m,A->n);
  57. tmp = m_resize(tmp,A->m,A->n);
  58. if ( p == 0 )
  59. m_ident(out);
  60. else if ( p > 0 )
  61. {
  62. it_cnt = 1;
  63. for ( max_bit = 0; ; max_bit++ )
  64. if ( (p >> (max_bit+1)) == 0 )
  65. break;
  66. tmp = m_copy(A,tmp);
  67. for ( k = 0; k < max_bit; k++ )
  68. {
  69. m_mlt(Z(it_cnt),Z(it_cnt),Z(it_cnt+1));
  70. it_cnt++;
  71. if ( p & (1 << (max_bit-1)) )
  72. {
  73. m_mlt(A,Z(it_cnt),Z(it_cnt+1));
  74. /* m_copy(Z(it_cnt),out); */
  75. it_cnt++;
  76. }
  77. p <<= 1;
  78. }
  79. if (it_cnt & 1)
  80. out = m_copy(Z(it_cnt),out);
  81. }
  82. return out;
  83. #undef Z
  84. }
  85. /* m_pow -- computes integer powers of a square matrix A, A^p */
  86. #ifndef ANSI_C
  87. MAT *m_pow(A, p, out)
  88. MAT *A, *out;
  89. int p;
  90. #else
  91. MAT *m_pow(const MAT *A, int p, MAT *out)
  92. #endif
  93. {
  94. STATIC MAT *wkspace=MNULL, *tmp=MNULL;
  95. if ( ! A )
  96. error(E_NULL,"m_pow");
  97. if ( A->m != A->n )
  98. error(E_SQUARE,"m_pow");
  99. wkspace = m_resize(wkspace,A->m,A->n);
  100. MEM_STAT_REG(wkspace,TYPE_MAT);
  101. if ( p < 0 )
  102. {
  103. tmp = m_resize(tmp,A->m,A->n);
  104. MEM_STAT_REG(tmp,TYPE_MAT);
  105. tracecatch(m_inverse(A,tmp),"m_pow");
  106. out = _m_pow(tmp, -p, wkspace, out);
  107. }
  108. else
  109. out = _m_pow(A, p, wkspace, out);
  110. #ifdef THREADSAFE
  111. M_FREE(wkspace); M_FREE(tmp);
  112. #endif
  113. return out;
  114. }
  115. /**************************************************/
  116. /* _m_exp -- compute matrix exponential of A and save it in out
  117. -- uses Pade approximation followed by repeated squaring
  118. -- eps is the tolerance used for the Pade approximation
  119. -- A is not changed
  120. -- q_out - degree of the Pade approximation (q_out,q_out)
  121. -- j_out - the power of 2 for scaling the matrix A
  122. such that ||A/2^j_out|| <= 0.5
  123. */
  124. #ifndef ANSI_C
  125. MAT *_m_exp(A,eps,out,q_out,j_out)
  126. MAT *A,*out;
  127. double eps;
  128. int *q_out, *j_out;
  129. #else
  130. MAT *_m_exp(MAT *A, double eps, MAT *out, int *q_out, int *j_out)
  131. #endif
  132. {
  133. STATIC MAT *D = MNULL, *Apow = MNULL, *N = MNULL, *Y = MNULL;
  134. STATIC VEC *c1 = VNULL, *tmp = VNULL;
  135. VEC y0, y1; /* additional structures */
  136. STATIC PERM *pivot = PNULL;
  137. int j, k, l, q, r, s, j2max, t;
  138. double inf_norm, eqq, power2, c, sign;
  139. if ( ! A )
  140. error(E_SIZES,"_m_exp");
  141. if ( A->m != A->n )
  142. error(E_SIZES,"_m_exp");
  143. if ( A == out )
  144. error(E_INSITU,"_m_exp");
  145. if ( eps < 0.0 )
  146. error(E_RANGE,"_m_exp");
  147. else if (eps == 0.0)
  148. eps = MACHEPS;
  149. N = m_resize(N,A->m,A->n);
  150. D = m_resize(D,A->m,A->n);
  151. Apow = m_resize(Apow,A->m,A->n);
  152. out = m_resize(out,A->m,A->n);
  153. MEM_STAT_REG(N,TYPE_MAT);
  154. MEM_STAT_REG(D,TYPE_MAT);
  155. MEM_STAT_REG(Apow,TYPE_MAT);
  156. /* normalise A to have ||A||_inf <= 1 */
  157. inf_norm = m_norm_inf(A);
  158. if (inf_norm <= 0.0) {
  159. m_ident(out);
  160. *q_out = -1;
  161. *j_out = 0;
  162. return out;
  163. }
  164. else {
  165. j2max = floor(1+log(inf_norm)/log(2.0));
  166. j2max = max(0, j2max);
  167. }
  168. power2 = 1.0;
  169. for ( k = 1; k <= j2max; k++ )
  170. power2 *= 2;
  171. power2 = 1.0/power2;
  172. if ( j2max > 0 )
  173. sm_mlt(power2,A,A);
  174. /* compute order for polynomial approximation */
  175. eqq = 1.0/6.0;
  176. for ( q = 1; eqq > eps; q++ )
  177. eqq /= 16.0*(2.0*q+1.0)*(2.0*q+3.0);
  178. /* construct vector of coefficients */
  179. c1 = v_resize(c1,q+1);
  180. MEM_STAT_REG(c1,TYPE_VEC);
  181. c1->ve[0] = 1.0;
  182. for ( k = 1; k <= q; k++ )
  183. c1->ve[k] = c1->ve[k-1]*(q-k+1)/((2*q-k+1)*(double)k);
  184. tmp = v_resize(tmp,A->n);
  185. MEM_STAT_REG(tmp,TYPE_VEC);
  186. s = (int)floor(sqrt((double)q/2.0));
  187. if ( s <= 0 ) s = 1;
  188. _m_pow(A,s,out,Apow);
  189. r = q/s;
  190. Y = m_resize(Y,s,A->n);
  191. MEM_STAT_REG(Y,TYPE_MAT);
  192. /* y0 and y1 are pointers to rows of Y, N and D */
  193. y0.dim = y0.max_dim = A->n;
  194. y1.dim = y1.max_dim = A->n;
  195. m_zero(Y);
  196. m_zero(N);
  197. m_zero(D);
  198. for( j = 0; j < A->n; j++ )
  199. {
  200. if (j > 0)
  201. Y->me[0][j-1] = 0.0;
  202. y0.ve = Y->me[0];
  203. y0.ve[j] = 1.0;
  204. for ( k = 0; k < s-1; k++ )
  205. {
  206. y1.ve = Y->me[k+1];
  207. mv_mlt(A,&y0,&y1);
  208. y0.ve = y1.ve;
  209. }
  210. y0.ve = N->me[j];
  211. y1.ve = D->me[j];
  212. t = s*r;
  213. for ( l = 0; l <= q-t; l++ )
  214. {
  215. c = c1->ve[t+l];
  216. sign = ((t+l) & 1) ? -1.0 : 1.0;
  217. __mltadd__(y0.ve,Y->me[l],c, Y->n);
  218. __mltadd__(y1.ve,Y->me[l],c*sign,Y->n);
  219. }
  220. for (k=1; k <= r; k++)
  221. {
  222. v_copy(mv_mlt(Apow,&y0,tmp),&y0);
  223. v_copy(mv_mlt(Apow,&y1,tmp),&y1);
  224. t = s*(r-k);
  225. for (l=0; l < s; l++)
  226. {
  227. c = c1->ve[t+l];
  228. sign = ((t+l) & 1) ? -1.0 : 1.0;
  229. __mltadd__(y0.ve,Y->me[l],c, Y->n);
  230. __mltadd__(y1.ve,Y->me[l],c*sign,Y->n);
  231. }
  232. }
  233. }
  234. pivot = px_resize(pivot,A->m);
  235. MEM_STAT_REG(pivot,TYPE_PERM);
  236. /* note that N and D are transposed,
  237. therefore we use LUTsolve;
  238. out is saved row-wise, and must be transposed
  239. after this */
  240. LUfactor(D,pivot);
  241. for (k=0; k < A->n; k++)
  242. {
  243. y0.ve = N->me[k];
  244. y1.ve = out->me[k];
  245. LUTsolve(D,pivot,&y0,&y1);
  246. }
  247. m_transp(out,out);
  248. /* Use recursive squaring to turn the normalised exponential to the
  249. true exponential */
  250. #define Z(k) ((k) & 1 ? Apow : out)
  251. for( k = 1; k <= j2max; k++)
  252. m_mlt(Z(k-1),Z(k-1),Z(k));
  253. if (Z(k) == out)
  254. m_copy(Apow,out);
  255. /* output parameters */
  256. *j_out = j2max;
  257. *q_out = q;
  258. /* restore the matrix A */
  259. sm_mlt(1.0/power2,A,A);
  260. #ifdef THREADSAFE
  261. M_FREE(D); M_FREE(Apow); M_FREE(N); M_FREE(Y);
  262. V_FREE(c1); V_FREE(tmp);
  263. PX_FREE(pivot);
  264. #endif
  265. return out;
  266. #undef Z
  267. }
  268. /* simple interface for _m_exp */
  269. #ifndef ANSI_C
  270. MAT *m_exp(A,eps,out)
  271. MAT *A,*out;
  272. double eps;
  273. #else
  274. MAT *m_exp(MAT *A, double eps, MAT *out)
  275. #endif
  276. {
  277. int q_out, j_out;
  278. return _m_exp(A,eps,out,&q_out,&j_out);
  279. }
  280. /*--------------------------------*/
  281. /* m_poly -- computes sum_i a[i].A^i, where i=0,1,...dim(a);
  282. -- uses C. Van Loan's fast and memory efficient method */
  283. #ifndef ANSI_C
  284. MAT *m_poly(A,a,out)
  285. MAT *A,*out;
  286. VEC *a;
  287. #else
  288. MAT *m_poly(const MAT *A, const VEC *a, MAT *out)
  289. #endif
  290. {
  291. STATIC MAT *Apow = MNULL, *Y = MNULL;
  292. STATIC VEC *tmp = VNULL;
  293. VEC y0, y1; /* additional vectors */
  294. int j, k, l, q, r, s, t;
  295. if ( ! A || ! a )
  296. error(E_NULL,"m_poly");
  297. if ( A->m != A->n )
  298. error(E_SIZES,"m_poly");
  299. if ( A == out )
  300. error(E_INSITU,"m_poly");
  301. out = m_resize(out,A->m,A->n);
  302. Apow = m_resize(Apow,A->m,A->n);
  303. MEM_STAT_REG(Apow,TYPE_MAT);
  304. tmp = v_resize(tmp,A->n);
  305. MEM_STAT_REG(tmp,TYPE_VEC);
  306. q = a->dim - 1;
  307. if ( q == 0 ) {
  308. m_zero(out);
  309. for (j=0; j < out->n; j++)
  310. out->me[j][j] = a->ve[0];
  311. return out;
  312. }
  313. else if ( q == 1) {
  314. sm_mlt(a->ve[1],A,out);
  315. for (j=0; j < out->n; j++)
  316. out->me[j][j] += a->ve[0];
  317. return out;
  318. }
  319. s = (int)floor(sqrt((double)q/2.0));
  320. if ( s <= 0 ) s = 1;
  321. _m_pow(A,s,out,Apow);
  322. r = q/s;
  323. Y = m_resize(Y,s,A->n);
  324. MEM_STAT_REG(Y,TYPE_MAT);
  325. /* pointers to rows of Y */
  326. y0.dim = y0.max_dim = A->n;
  327. y1.dim = y1.max_dim = A->n;
  328. m_zero(Y);
  329. m_zero(out);
  330. #define Z(k) ((k) & 1 ? tmp : &y0)
  331. #define ZZ(k) ((k) & 1 ? tmp->ve : y0.ve)
  332. for( j = 0; j < A->n; j++)
  333. {
  334. if( j > 0 )
  335. Y->me[0][j-1] = 0.0;
  336. Y->me[0][j] = 1.0;
  337. y0.ve = Y->me[0];
  338. for (k = 0; k < s-1; k++)
  339. {
  340. y1.ve = Y->me[k+1];
  341. mv_mlt(A,&y0,&y1);
  342. y0.ve = y1.ve;
  343. }
  344. y0.ve = out->me[j];
  345. t = s*r;
  346. for ( l = 0; l <= q-t; l++ )
  347. __mltadd__(y0.ve,Y->me[l],a->ve[t+l],Y->n);
  348. for (k=1; k <= r; k++)
  349. {
  350. mv_mlt(Apow,Z(k-1),Z(k));
  351. t = s*(r-k);
  352. for (l=0; l < s; l++)
  353. __mltadd__(ZZ(k),Y->me[l],a->ve[t+l],Y->n);
  354. }
  355. if (Z(k) == &y0) v_copy(tmp,&y0);
  356. }
  357. m_transp(out,out);
  358. #ifdef THREADSAFE
  359. M_FREE(Apow); M_FREE(Y); V_FREE(tmp);
  360. #endif
  361. return out;
  362. }