Mercurial > octave
comparison src/expm.cc @ 50:6028dcac27ef
[project @ 1993-08-11 20:48:00 by jwe]
Initial revision
author | jwe |
---|---|
date | Wed, 11 Aug 1993 20:48:00 +0000 |
parents | |
children | 9eda1009cf95 |
comparison
equal
deleted
inserted
replaced
49:445ea777560a | 50:6028dcac27ef |
---|---|
1 // tc-expm.cc -*- C++ -*- | |
2 /* | |
3 | |
4 Copyright (C) 1993 John W. Eaton | |
5 | |
6 This file is part of Octave. | |
7 | |
8 Octave is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
10 Free Software Foundation; either version 2, or (at your option) any | |
11 later version. | |
12 | |
13 Octave is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with Octave; see the file COPYING. If not, write to the Free | |
20 Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
21 | |
22 */ | |
23 | |
24 // Written by A. S. Hodel <scotte@eng.auburn.edu> | |
25 | |
26 #ifdef __GNUG__ | |
27 #pragma implementation | |
28 #endif | |
29 | |
30 #include <math.h> | |
31 | |
32 #include "Matrix.h" | |
33 | |
34 #include "tree-const.h" | |
35 #include "user-prefs.h" | |
36 #include "gripes.h" | |
37 #include "error.h" | |
38 #include "f-expm.h" | |
39 | |
40 #ifdef WITH_DLD | |
41 tree_constant * | |
42 builtin_matrix_exp_2 (tree_constant *args, int nargin, int nargout) | |
43 { | |
44 tree_constant *retval = new tree_constant [2]; | |
45 retval[0] = matrix_exp (args[1]); | |
46 return retval; | |
47 } | |
48 #endif | |
49 | |
50 extern "C" | |
51 { | |
52 double F77_FCN (dlange) (const char*, const int*, const int*, | |
53 const double*, const int*, double*); | |
54 | |
55 double F77_FCN (zlange) (const char*, const int*, const int*, | |
56 const Complex*, const int*, double*); | |
57 } | |
58 | |
59 // XXX FIXME XXX | |
60 extern int empty_arg (tree_constant&); | |
61 | |
62 tree_constant | |
63 matrix_exp (const tree_constant& a) | |
64 { | |
65 tree_constant retval; | |
66 tree_constant tmp = a.make_numeric (); | |
67 | |
68 // Constants for matrix exponential calculation. | |
69 | |
70 static double padec[] = | |
71 { | |
72 5.0000000000000000e-1, | |
73 1.1666666666666667e-1, | |
74 1.6666666666666667e-2, | |
75 1.6025641025641026e-3, | |
76 1.0683760683760684e-4, | |
77 4.8562548562548563e-6, | |
78 1.3875013875013875e-7, | |
79 1.9270852604185938e-9, | |
80 }; | |
81 | |
82 if (empty_arg (tmp)) | |
83 { | |
84 int flag = user_pref.propagate_empty_matrices; | |
85 if (flag != 0) | |
86 { | |
87 if (flag < 0) | |
88 gripe_empty_arg ("expm", 0); | |
89 Matrix m; | |
90 retval = tree_constant (m); | |
91 } | |
92 else gripe_empty_arg ("expm", 1); | |
93 } | |
94 else if (tmp.rows () != tmp.columns ()) | |
95 gripe_square_matrix_required ("expm"); | |
96 else | |
97 { | |
98 int i, j; | |
99 int n_cols = tmp.columns (); | |
100 | |
101 char* balance_job = "B"; // variables for balancing | |
102 | |
103 int sqpow; // power for scaling and squaring | |
104 double inf_norm; // norm of preconditioned matrix | |
105 int minus_one_j; // used in computing pade approx | |
106 | |
107 switch (tmp.const_type ()) | |
108 { | |
109 case tree_constant_rep::complex_matrix_constant: | |
110 { | |
111 ComplexMatrix m = tmp.complex_matrix_value (); | |
112 Complex trshift = 0.0; // trace shift value | |
113 | |
114 // Preconditioning step 1: trace normalization. | |
115 | |
116 for (i = 0; i < n_cols; i++) | |
117 trshift += m.elem (i, i); | |
118 trshift /= n_cols; | |
119 for (i = 0; i < n_cols; i++) | |
120 m.elem (i, i) -= trshift; | |
121 | |
122 // Preconditioning step 2: eigenvalue balancing. | |
123 | |
124 ComplexAEPBALANCE mbal (m, balance_job); | |
125 m = mbal.balanced_matrix (); | |
126 ComplexMatrix d = mbal.balancing_matrix (); | |
127 | |
128 // Preconditioning step 3: scaling. | |
129 | |
130 ColumnVector work (n_cols); | |
131 inf_norm = F77_FCN (zlange) ("I", &n_cols, &n_cols, m. | |
132 fortran_vec (), &n_cols, | |
133 work.fortran_vec ()); | |
134 | |
135 sqpow = 1.0 + log (inf_norm) / log (2.0); | |
136 | |
137 // Check whether we need to square at all. | |
138 | |
139 if (sqpow <= 0.0) | |
140 sqpow = 0.0; | |
141 else | |
142 { | |
143 for (inf_norm = 1.0, i = 0; i < sqpow; i++) | |
144 inf_norm *= 2.0; | |
145 | |
146 m = m / inf_norm; | |
147 } | |
148 | |
149 // npp, dpp: pade' approx polynomial matrices. | |
150 | |
151 ComplexMatrix npp (n_cols, n_cols, 0.0); | |
152 ComplexMatrix dpp = npp; | |
153 | |
154 // Now powers a^8 ... a^1. | |
155 | |
156 minus_one_j = -1; | |
157 for (j = 7; j >= 0; j--) | |
158 { | |
159 npp = m * npp + m * padec[j]; | |
160 dpp = m * dpp + m * (minus_one_j * padec[j]); | |
161 minus_one_j *= -1; | |
162 } | |
163 | |
164 // Zero power. | |
165 | |
166 dpp = -dpp; | |
167 for (j = 0; j < n_cols; j++) | |
168 { | |
169 npp.elem (j, j) += 1.0; | |
170 dpp.elem (j, j) += 1.0; | |
171 } | |
172 | |
173 // Compute pade approximation = inverse (dpp) * npp. | |
174 | |
175 ComplexMatrix result = dpp.solve (npp); | |
176 | |
177 // Reverse preconditioning step 3: repeated squaring. | |
178 | |
179 while (sqpow) | |
180 { | |
181 result = result * result; | |
182 sqpow--; | |
183 } | |
184 | |
185 // reverse preconditioning step 2: inverse balancing XXX FIXME XXX: | |
186 // should probably do this with lapack calls instead of a complete | |
187 // matrix inversion. | |
188 | |
189 result = result.transpose (); | |
190 d = d.transpose (); | |
191 result = result * d; | |
192 result = d.solve (result); | |
193 result = result.transpose (); | |
194 | |
195 // Reverse preconditioning step 1: fix trace normalization. | |
196 | |
197 result = result * exp (trshift); | |
198 | |
199 retval = tree_constant (result); | |
200 } | |
201 break; | |
202 case tree_constant_rep::complex_scalar_constant: | |
203 { | |
204 Complex c = tmp.complex_value (); | |
205 retval = tree_constant (exp (c)); | |
206 } | |
207 break; | |
208 case tree_constant_rep::matrix_constant: | |
209 { | |
210 | |
211 // Compute the exponential. | |
212 | |
213 Matrix m = tmp.matrix_value (); | |
214 | |
215 double trshift = 0; // trace shift value | |
216 | |
217 // Preconditioning step 1: trace normalization. | |
218 | |
219 for (i = 0; i < n_cols; i++) | |
220 trshift += m.elem (i, i); | |
221 trshift /= n_cols; | |
222 for (i = 0; i < n_cols; i++) | |
223 m.elem (i, i) -= trshift; | |
224 | |
225 // Preconditioning step 2: balancing. | |
226 | |
227 AEPBALANCE mbal (m, balance_job); | |
228 m = mbal.balanced_matrix (); | |
229 Matrix d = mbal.balancing_matrix (); | |
230 | |
231 // Preconditioning step 3: scaling. | |
232 | |
233 ColumnVector work(n_cols); | |
234 inf_norm = F77_FCN (dlange) ("I", &n_cols, &n_cols, | |
235 m.fortran_vec (), &n_cols, | |
236 work.fortran_vec ()); | |
237 | |
238 sqpow = 1.0 + log (inf_norm) / log (2.0); | |
239 | |
240 // Check whether we need to square at all. | |
241 | |
242 if (sqpow <= 0.0) | |
243 sqpow = 0.0; | |
244 else | |
245 { | |
246 for (inf_norm = 1.0, i = 0; i < sqpow; i++) | |
247 inf_norm *= 2.0; | |
248 | |
249 m = m / inf_norm; | |
250 } | |
251 | |
252 // npp, dpp: pade' approx polynomial matrices. | |
253 | |
254 Matrix npp (n_cols, n_cols, 0.0); | |
255 Matrix dpp = npp; | |
256 | |
257 // now powers a^8 ... a^1. | |
258 | |
259 minus_one_j = -1; | |
260 for (j = 7; j >= 0; j--) | |
261 { | |
262 npp = m * npp + m * padec[j]; | |
263 dpp = m * dpp + m * (minus_one_j * padec[j]); | |
264 minus_one_j *= -1; | |
265 } | |
266 // Zero power. | |
267 | |
268 dpp = -dpp; | |
269 for(j = 0; j < n_cols; j++) | |
270 { | |
271 npp.elem (j, j) += 1.0; | |
272 dpp.elem (j, j) += 1.0; | |
273 } | |
274 | |
275 // Compute pade approximation = inverse (dpp) * npp. | |
276 | |
277 Matrix result = dpp.solve (npp); | |
278 | |
279 // Reverse preconditioning step 3: repeated squaring. | |
280 | |
281 while(sqpow) | |
282 { | |
283 result = result * result; | |
284 sqpow--; | |
285 } | |
286 | |
287 // Reverse preconditioning step 2: inverse balancing. | |
288 | |
289 result = result.transpose(); | |
290 d = d.transpose (); | |
291 result = result * d; | |
292 result = d.solve (result); | |
293 result = result.transpose (); | |
294 | |
295 // Reverse preconditioning step 1: fix trace normalization. | |
296 | |
297 result = result * exp (trshift); | |
298 | |
299 retval = tree_constant (result); | |
300 } | |
301 break; | |
302 case tree_constant_rep::scalar_constant: | |
303 { | |
304 double d = tmp.double_value (); | |
305 retval = tree_constant (exp (d)); | |
306 } | |
307 break; | |
308 default: | |
309 panic_impossible(); | |
310 break; | |
311 } | |
312 } | |
313 return retval; | |
314 } | |
315 | |
316 /* | |
317 ;;; Local Variables: *** | |
318 ;;; mode: C++ *** | |
319 ;;; page-delimiter: "^/\\*" *** | |
320 ;;; End: *** | |
321 */ |