tutorial.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. /* tutorial.c 10/12/1993 */
  25. /* routines from Chapter 1 of Meschach */
  26. static char rcsid[] = "$Id: tutorial.c,v 1.3 1994/01/16 22:53:09 des Exp $";
  27. #include <math.h>
  28. #include "matrix.h"
  29. /* rk4 -- 4th order Runge--Kutta method */
  30. double rk4(f,t,x,h)
  31. double t, h;
  32. VEC *(*f)(), *x;
  33. {
  34. static VEC *v1=VNULL, *v2=VNULL, *v3=VNULL, *v4=VNULL;
  35. static VEC *temp=VNULL;
  36. /* do not work with NULL initial vector */
  37. if ( x == VNULL )
  38. error(E_NULL,"rk4");
  39. /* ensure that v1, ..., v4, temp are of the correct size */
  40. v1 = v_resize(v1,x->dim);
  41. v2 = v_resize(v2,x->dim);
  42. v3 = v_resize(v3,x->dim);
  43. v4 = v_resize(v4,x->dim);
  44. temp = v_resize(temp,x->dim);
  45. /* register workspace variables */
  46. MEM_STAT_REG(v1,TYPE_VEC);
  47. MEM_STAT_REG(v2,TYPE_VEC);
  48. MEM_STAT_REG(v3,TYPE_VEC);
  49. MEM_STAT_REG(v4,TYPE_VEC);
  50. MEM_STAT_REG(temp,TYPE_VEC);
  51. /* end of memory allocation */
  52. (*f)(t,x,v1); /* most compilers allow: "f(t,x,v1);" */
  53. v_mltadd(x,v1,0.5*h,temp); /* temp = x+.5*h*v1 */
  54. (*f)(t+0.5*h,temp,v2);
  55. v_mltadd(x,v2,0.5*h,temp); /* temp = x+.5*h*v2 */
  56. (*f)(t+0.5*h,temp,v3);
  57. v_mltadd(x,v3,h,temp); /* temp = x+h*v3 */
  58. (*f)(t+h,temp,v4);
  59. /* now add: v1+2*v2+2*v3+v4 */
  60. v_copy(v1,temp); /* temp = v1 */
  61. v_mltadd(temp,v2,2.0,temp); /* temp = v1+2*v2 */
  62. v_mltadd(temp,v3,2.0,temp); /* temp = v1+2*v2+2*v3 */
  63. v_add(temp,v4,temp); /* temp = v1+2*v2+2*v3+v4 */
  64. /* adjust x */
  65. v_mltadd(x,temp,h/6.0,x); /* x = x+(h/6)*temp */
  66. return t+h; /* return the new time */
  67. }
  68. /* rk4 -- 4th order Runge-Kutta method */
  69. /* another variant */
  70. double rk4_var(f,t,x,h)
  71. double t, h;
  72. VEC *(*f)(), *x;
  73. {
  74. static VEC *v1, *v2, *v3, *v4, *temp;
  75. /* do not work with NULL initial vector */
  76. if ( x == VNULL ) error(E_NULL,"rk4");
  77. /* ensure that v1, ..., v4, temp are of the correct size */
  78. v_resize_vars(x->dim, &v1, &v2, &v3, &v4, &temp, NULL);
  79. /* register workspace variables */
  80. mem_stat_reg_vars(0, TYPE_VEC, __FILE__, __LINE__,
  81. &v1, &v2, &v3, &v4, &temp, NULL);
  82. /* end of memory allocation */
  83. (*f)(t,x,v1); v_mltadd(x,v1,0.5*h,temp);
  84. (*f)(t+0.5*h,temp,v2); v_mltadd(x,v2,0.5*h,temp);
  85. (*f)(t+0.5*h,temp,v3); v_mltadd(x,v3,h,temp);
  86. (*f)(t+h,temp,v4);
  87. /* now add: temp = v1+2*v2+2*v3+v4 */
  88. v_linlist(temp, v1, 1.0, v2, 2.0, v3, 2.0, v4, 1.0, VNULL);
  89. /* adjust x */
  90. v_mltadd(x,temp,h/6.0,x); /* x = x+(h/6)*temp */
  91. return t+h; /* return the new time */
  92. }
  93. /* f -- right-hand side of ODE solver */
  94. VEC *f(t,x,out)
  95. VEC *x, *out;
  96. double t;
  97. {
  98. if ( x == VNULL || out == VNULL )
  99. error(E_NULL,"f");
  100. if ( x->dim != 2 || out->dim != 2 )
  101. error(E_SIZES,"f");
  102. out->ve[0] = x->ve[1];
  103. out->ve[1] = - x->ve[0];
  104. return out;
  105. }
  106. void tutor_rk4()
  107. {
  108. VEC *x;
  109. VEC *f();
  110. double h, t, t_fin;
  111. double rk4();
  112. input("Input initial time: ","%lf",&t);
  113. input("Input final time: ", "%lf",&t_fin);
  114. x = v_get(2); /* this is the size needed by f() */
  115. prompter("Input initial state:\n"); x = v_input(VNULL);
  116. input("Input step size: ", "%lf",&h);
  117. printf("# At time %g, the state is\n",t);
  118. v_output(x);
  119. while (t < t_fin)
  120. {
  121. /* you can use t = rk4_var(f,t,x,min(h,t_fin-t)); */
  122. t = rk4(f,t,x,min(h,t_fin-t)); /* new t is returned */
  123. printf("# At time %g, the state is\n",t);
  124. v_output(x);
  125. }
  126. }
  127. #include "matrix2.h"
  128. void tutor_ls()
  129. {
  130. MAT *A, *QR;
  131. VEC *b, *x, *diag;
  132. /* read in A matrix */
  133. printf("Input A matrix:\n");
  134. A = m_input(MNULL); /* A has whatever size is input */
  135. if ( A->m < A->n )
  136. {
  137. printf("Need m >= n to obtain least squares fit\n");
  138. exit(0);
  139. }
  140. printf("# A =\n"); m_output(A);
  141. diag = v_get(A->m);
  142. /* QR is to be the QR factorisation of A */
  143. QR = m_copy(A,MNULL);
  144. QRfactor(QR,diag);
  145. /* read in b vector */
  146. printf("Input b vector:\n");
  147. b = v_get(A->m);
  148. b = v_input(b);
  149. printf("# b =\n"); v_output(b);
  150. /* solve for x */
  151. x = QRsolve(QR,diag,b,VNULL);
  152. printf("Vector of best fit parameters is\n");
  153. v_output(x);
  154. /* ... and work out norm of errors... */
  155. printf("||A*x-b|| = %g\n",
  156. v_norm2(v_sub(mv_mlt(A,x,VNULL),b,VNULL)));
  157. }
  158. #include "iter.h"
  159. #define N 50
  160. #define VEC2MAT(v,m) vm_move((v),0,(m),0,0,N,N);
  161. #define PI 3.141592653589793116
  162. #define index(i,j) (N*((i)-1)+(j)-1)
  163. /* right hand side function (for generating b) */
  164. double f1(x,y)
  165. double x,y;
  166. {
  167. /* return 2.0*PI*PI*sin(PI*x)*sin(PI*y); */
  168. return exp(x*y);
  169. }
  170. /* discrete laplacian */
  171. SPMAT *laplacian(A)
  172. SPMAT *A;
  173. {
  174. Real h;
  175. int i,j;
  176. if (!A)
  177. A = sp_get(N*N,N*N,5);
  178. for ( i = 1; i <= N; i++ )
  179. for ( j = 1; j <= N; j++ )
  180. {
  181. if ( i < N )
  182. sp_set_val(A,index(i,j),index(i+1,j),-1.0);
  183. if ( i > 1 )
  184. sp_set_val(A,index(i,j),index(i-1,j),-1.0);
  185. if ( j < N )
  186. sp_set_val(A,index(i,j),index(i,j+1),-1.0);
  187. if ( j > 1 )
  188. sp_set_val(A,index(i,j),index(i,j-1),-1.0);
  189. sp_set_val(A,index(i,j),index(i,j),4.0);
  190. }
  191. return A;
  192. }
  193. /* generating right hand side */
  194. VEC *rhs_lap(b)
  195. VEC *b;
  196. {
  197. Real h,h2,x,y;
  198. int i,j;
  199. if (!b)
  200. b = v_get(N*N);
  201. h = 1.0/(N+1); /* for a unit square */
  202. h2 = h*h;
  203. x = 0.0;
  204. for ( i = 1; i <= N; i++ ) {
  205. x += h;
  206. y = 0.0;
  207. for ( j = 1; j <= N; j++ ) {
  208. y += h;
  209. b->ve[index(i,j)] = h2*f1(x,y);
  210. }
  211. }
  212. return b;
  213. }
  214. void tut_lap()
  215. {
  216. SPMAT *A, *LLT;
  217. VEC *b, *out, *x;
  218. MAT *B;
  219. int num_steps;
  220. FILE *fp;
  221. A = sp_get(N*N,N*N,5);
  222. b = v_get(N*N);
  223. laplacian(A);
  224. LLT = sp_copy(A);
  225. spICHfactor(LLT);
  226. out = v_get(A->m);
  227. x = v_get(A->m);
  228. rhs_lap(b); /* new rhs */
  229. iter_spcg(A,LLT,b,1e-6,out,1000,&num_steps);
  230. printf("Number of iterations = %d\n",num_steps);
  231. /* save b as a MATLAB matrix */
  232. fp = fopen("laplace.mat","w"); /* b will be saved in laplace.mat */
  233. if (fp == NULL) {
  234. printf("Cannot open %s\n","laplace.mat");
  235. exit(1);
  236. }
  237. /* b must be transformed to a matrix */
  238. B = m_get(N,N);
  239. VEC2MAT(out,B);
  240. m_save(fp,B,"sol"); /* sol is an internal name in MATLAB */
  241. }
  242. void main()
  243. {
  244. int i;
  245. input("Choose the problem (1=Runge-Kutta, 2=least squares,3=laplace): ",
  246. "%d",&i);
  247. switch (i) {
  248. case 1: tutor_rk4(); break;
  249. case 2: tutor_ls(); break;
  250. case 3: tut_lap(); break;
  251. default:
  252. printf(" Wrong value of i (only 1, 2 or 3)\n\n");
  253. break;
  254. }
  255. }