NEURON
lanczos.c
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 /**************************************************************************
4 **
5 ** Copyright (C) 1993 David E. Steward & Zbigniew Leyk, all rights reserved.
6 **
7 ** Meschach Library
8 **
9 ** This Meschach Library is provided "as is" without any express
10 ** or implied warranty of any kind with respect to this software.
11 ** In particular the authors shall not be liable for any direct,
12 ** indirect, special, incidental or consequential damages arising
13 ** in any way from use of the software.
14 **
15 ** Everyone is granted permission to copy, modify and redistribute this
16 ** Meschach Library, provided:
17 ** 1. All copies contain this copyright notice.
18 ** 2. All modified copies shall carry a notice stating who
19 ** made the last modification and the date of such modification.
20 ** 3. No charge is made for this software or works derived from it.
21 ** This clause shall not be construed as constraining other software
22 ** distributed on the same medium as this software, nor is a
23 ** distribution fee considered a charge.
24 **
25 ***************************************************************************/
26 
27 
28 /*
29  File containing Lanczos type routines for finding eigenvalues
30  of large, sparse, symmetic matrices
31 */
32 
33 #include <stdio.h>
34 #include <math.h>
35 #include "matrix.h"
36 #include "sparse.h"
37 
38 static char rcsid[] = "lanczos.c,v 1.1 1997/12/04 17:55:31 hines Exp";
39 
40 #ifdef ANSI_C
41 extern VEC *trieig(VEC *,VEC *,MAT *);
42 #else
43 extern VEC *trieig();
44 #endif
45 
46 /* lanczos -- raw lanczos algorithm -- no re-orthogonalisation
47  -- creates T matrix of size == m,
48  but no larger than before beta_k == 0
49  -- uses passed routine to do matrix-vector multiplies */
50 void lanczos(A_fn,A_params,m,x0,a,b,beta2,Q)
51 VEC *(*A_fn)(); /* VEC *(*A_fn)(void *A_params,VEC *in, VEC *out) */
52 void *A_params;
53 int m;
54 VEC *x0, *a, *b;
55 Real *beta2;
56 MAT *Q;
57 {
58  int j;
59  VEC *v, *w, *tmp;
60  Real alpha, beta;
61 
62  if ( ! A_fn || ! x0 || ! a || ! b )
63  error(E_NULL,"lanczos");
64  if ( m <= 0 )
65  error(E_BOUNDS,"lanczos");
66  if ( Q && ( Q->m < x0->dim || Q->n < m ) )
67  error(E_SIZES,"lanczos");
68 
69  a = v_resize(a,(u_int)m); b = v_resize(b,(u_int)(m-1));
70  v = v_get(x0->dim);
71  w = v_get(x0->dim);
72  tmp = v_get(x0->dim);
73 
74  beta = 1.0;
75  /* normalise x0 as w */
76  sv_mlt(1.0/v_norm2(x0),x0,w);
77 
78  (*A_fn)(A_params,w,v);
79 
80  for ( j = 0; j < m; j++ )
81  {
82  /* store w in Q if Q not NULL */
83  if ( Q )
84  set_col(Q,j,w);
85 
86  alpha = in_prod(w,v);
87  a->ve[j] = alpha;
88  v_mltadd(v,w,-alpha,v);
89  beta = v_norm2(v);
90  if ( beta == 0.0 )
91  {
92  v_resize(a,(u_int)j+1);
93  v_resize(b,(u_int)j);
94  *beta2 = 0.0;
95  if ( Q )
96  Q = m_resize(Q,Q->m,j+1);
97  return;
98  }
99  if ( j < m-1 )
100  b->ve[j] = beta;
101  v_copy(w,tmp);
102  sv_mlt(1/beta,v,w);
103  sv_mlt(-beta,tmp,v);
104  (*A_fn)(A_params,w,tmp);
105  v_add(v,tmp,v);
106  }
107  *beta2 = beta;
108 
109 
110  V_FREE(v); V_FREE(w); V_FREE(tmp);
111 }
112 #ifndef MAC
113 extern double frexp(), ldexp();
114 #endif
115 /* product -- returns the product of a long list of numbers
116  -- answer stored in mant (mantissa) and expt (exponent) */
117 static double product(a,offset,expt)
118 VEC *a;
119 double offset;
120 int *expt;
121 {
122  Real mant, tmp_fctr;
123  int i, tmp_expt;
124 
125  if ( ! a )
126  error(E_NULL,"product");
127 
128  mant = 1.0;
129  *expt = 0;
130  if ( offset == 0.0 )
131  for ( i = 0; i < a->dim; i++ )
132  {
133  mant *= frexp(a->ve[i],&tmp_expt);
134  *expt += tmp_expt;
135  if ( ! (i % 10) )
136  {
137  mant = frexp(mant,&tmp_expt);
138  *expt += tmp_expt;
139  }
140  }
141  else
142  for ( i = 0; i < a->dim; i++ )
143  {
144  tmp_fctr = a->ve[i] - offset;
145  tmp_fctr += (tmp_fctr > 0.0 ) ? -MACHEPS*offset :
146  MACHEPS*offset;
147  mant *= frexp(tmp_fctr,&tmp_expt);
148  *expt += tmp_expt;
149  if ( ! (i % 10) )
150  {
151  mant = frexp(mant,&tmp_expt);
152  *expt += tmp_expt;
153  }
154  }
155 
156  mant = frexp(mant,&tmp_expt);
157  *expt += tmp_expt;
158 
159  return mant;
160 }
161 
162 /* product2 -- returns the product of a long list of numbers
163  -- answer stored in mant (mantissa) and expt (exponent) */
164 static double product2(a,k,expt)
165 VEC *a;
166 int k; /* entry of a to leave out */
167 int *expt;
168 {
169  Real mant, mu, tmp_fctr;
170  int i, tmp_expt;
171 
172  if ( ! a )
173  error(E_NULL,"product2");
174  if ( k < 0 || k >= a->dim )
175  error(E_BOUNDS,"product2");
176 
177  mant = 1.0;
178  *expt = 0;
179  mu = a->ve[k];
180  for ( i = 0; i < a->dim; i++ )
181  {
182  if ( i == k )
183  continue;
184  tmp_fctr = a->ve[i] - mu;
185  tmp_fctr += ( tmp_fctr > 0.0 ) ? -MACHEPS*mu : MACHEPS*mu;
186  mant *= frexp(tmp_fctr,&tmp_expt);
187  *expt += tmp_expt;
188  if ( ! (i % 10) )
189  {
190  mant = frexp(mant,&tmp_expt);
191  *expt += tmp_expt;
192  }
193  }
194  mant = frexp(mant,&tmp_expt);
195  *expt += tmp_expt;
196 
197  return mant;
198 }
199 
200 /* dbl_cmp -- comparison function to pass to qsort() */
201 static int dbl_cmp(x,y)
202 Real *x, *y;
203 {
204  Real tmp;
205 
206  tmp = *x - *y;
207  return (tmp > 0 ? 1 : tmp < 0 ? -1: 0);
208 }
209 
210 /* lanczos2 -- lanczos + error estimate for every e-val
211  -- uses Cullum & Willoughby approach, Sparse Matrix Proc. 1978
212  -- returns multiple e-vals where multiple e-vals may not exist
213  -- returns evals vector */
214 VEC *lanczos2(A_fn,A_params,m,x0,evals,err_est)
215 VEC *(*A_fn)();
216 void *A_params;
217 int m;
218 VEC *x0; /* initial vector */
219 VEC *evals; /* eigenvalue vector */
220 VEC *err_est; /* error estimates of eigenvalues */
221 {
222  VEC *a;
223  static VEC *b=VNULL, *a2=VNULL, *b2=VNULL;
224  Real beta, pb_mant, det_mant, det_mant1, det_mant2;
225  int i, pb_expt, det_expt, det_expt1, det_expt2;
226 
227  if ( ! A_fn || ! x0 )
228  error(E_NULL,"lanczos2");
229  if ( m <= 0 )
230  error(E_RANGE,"lanczos2");
231 
232  a = evals;
233  a = v_resize(a,(u_int)m);
234  b = v_resize(b,(u_int)(m-1));
236 
237  lanczos(A_fn,A_params,m,x0,a,b,&beta,MNULL);
238 
239  /* printf("# beta =%g\n",beta); */
240  pb_mant = 0.0;
241  if ( err_est )
242  {
243  pb_mant = product(b,(double)0.0,&pb_expt);
244  /* printf("# pb_mant = %g, pb_expt = %d\n",pb_mant, pb_expt); */
245  }
246 
247  /* printf("# diags =\n"); out_vec(a); */
248  /* printf("# off diags =\n"); out_vec(b); */
249  a2 = v_resize(a2,a->dim - 1);
250  b2 = v_resize(b2,b->dim - 1);
253  for ( i = 0; i < a2->dim - 1; i++ )
254  {
255  a2->ve[i] = a->ve[i+1];
256  b2->ve[i] = b->ve[i+1];
257  }
258  a2->ve[a2->dim-1] = a->ve[a2->dim];
259 
260  trieig(a,b,MNULL);
261 
262  /* sort evals as a courtesy */
263  qsort((void *)(a->ve),(int)(a->dim),sizeof(Real),(int (*)())dbl_cmp);
264 
265  /* error estimates */
266  if ( err_est )
267  {
268  err_est = v_resize(err_est,(u_int)m);
269 
270  trieig(a2,b2,MNULL);
271  /* printf("# a =\n"); out_vec(a); */
272  /* printf("# a2 =\n"); out_vec(a2); */
273 
274  for ( i = 0; i < a->dim; i++ )
275  {
276  det_mant1 = product2(a,i,&det_expt1);
277  det_mant2 = product(a2,(double)a->ve[i],&det_expt2);
278  /* printf("# det_mant1=%g, det_expt1=%d\n",
279  det_mant1,det_expt1); */
280  /* printf("# det_mant2=%g, det_expt2=%d\n",
281  det_mant2,det_expt2); */
282  if ( det_mant1 == 0.0 )
283  { /* multiple e-val of T */
284  err_est->ve[i] = 0.0;
285  continue;
286  }
287  else if ( det_mant2 == 0.0 )
288  {
289  err_est->ve[i] = HUGE;
290  continue;
291  }
292  if ( (det_expt1 + det_expt2) % 2 )
293  /* if odd... */
294  det_mant = sqrt(2.0*fabs(det_mant1*det_mant2));
295  else /* if even... */
296  det_mant = sqrt(fabs(det_mant1*det_mant2));
297  det_expt = (det_expt1+det_expt2)/2;
298  err_est->ve[i] = fabs(beta*
299  ldexp(pb_mant/det_mant,pb_expt-det_expt));
300  }
301  }
302 
303  return a;
304 }
305 
306 /* sp_lanczos -- version that uses sparse matrix data structure */
307 void sp_lanczos(A,m,x0,a,b,beta2,Q)
308 SPMAT *A;
309 int m;
310 VEC *x0, *a, *b;
311 Real *beta2;
312 MAT *Q;
313 { lanczos(sp_mv_mlt,A,m,x0,a,b,beta2,Q); }
314 
315 /* sp_lanczos2 -- version of lanczos2() that uses sparse matrix data
316  structure */
317 VEC *sp_lanczos2(A,m,x0,evals,err_est)
318 SPMAT *A;
319 int m;
320 VEC *x0; /* initial vector */
321 VEC *evals; /* eigenvalue vector */
322 VEC *err_est; /* error estimates of eigenvalues */
323 { return lanczos2(sp_mv_mlt,A,m,x0,evals,err_est); }
324 
#define alpha
Definition: bkpfacto.c:43
#define error(err_num, fn_name)
Definition: err.h:73
#define E_RANGE
Definition: err.h:104
#define E_NULL
Definition: err.h:102
#define E_BOUNDS
Definition: err.h:96
#define E_SIZES
Definition: err.h:95
static Object ** v_add(void *v1)
Definition: ivocvect.cpp:2317
static double v_get(void *v)
Definition: ivocvect.cpp:1395
static Object ** v_resize(void *v)
Definition: ivocvect.cpp:1383
double ldexp()
void lanczos(VEC *(*A_fn)(), void *A_params, int m, VEC *x0, VEC *a, VEC *b, Real *beta2, MAT *Q)
Definition: lanczos.c:50
VEC * sp_lanczos2(SPMAT *A, int m, VEC *x0, VEC *evals, VEC *err_est)
Definition: lanczos.c:317
static int dbl_cmp(Real *x, Real *y)
Definition: lanczos.c:201
void sp_lanczos(SPMAT *A, int m, VEC *x0, VEC *a, VEC *b, Real *beta2, MAT *Q)
Definition: lanczos.c:307
static double product2(VEC *a, int k, int *expt)
Definition: lanczos.c:164
VEC * trieig(VEC *, VEC *, MAT *)
Definition: symmeig.c:49
VEC * lanczos2(VEC *(*A_fn)(), void *A_params, int m, VEC *x0, VEC *evals, VEC *err_est)
Definition: lanczos.c:214
double frexp()
static double product(VEC *a, double offset, int *expt)
Definition: lanczos.c:117
static char rcsid[]
Definition: lanczos.c:38
#define Real
Definition: machine.h:189
uint32_t u_int
Definition: machine.h:38
#define MACHEPS
Definition: machine.h:213
static Object ** m_resize(void *v)
Definition: matrix.cpp:191
#define VNULL
Definition: matrix.h:631
#define v_copy(in, out)
Definition: matrix.h:404
#define set_col(mat, col, vec)
Definition: matrix.h:564
#define in_prod(a, b)
Definition: matrix.h:485
#define MNULL
Definition: matrix.h:632
VEC * v_mltadd(VEC *, VEC *, double, VEC *)
VEC * sv_mlt(double, VEC *, VEC *)
#define v_norm2(x)
Definition: matrix.h:511
#define V_FREE(vec)
Definition: matrix.h:214
#define v
Definition: md1redef.h:4
#define i
Definition: md1redef.h:12
#define TYPE_VEC
Definition: meminfo.h:52
#define MEM_STAT_REG(var, type)
Definition: meminfo.h:133
sqrt
Definition: extdef.h:3
fabs
Definition: extdef.h:3
#define A(i)
Definition: multisplit.cpp:63
size_t j
static philox4x32_key_t k
Definition: nrnran123.cpp:11
VEC * sp_mv_mlt(SPMAT *A, VEC *x, VEC *out)
Definition: sparse.c:123
Definition: matrix.h:73
u_int n
Definition: matrix.h:74
u_int m
Definition: matrix.h:74
Definition: sparse.h:54
Definition: matrix.h:67
u_int dim
Definition: matrix.h:68
Real * ve
Definition: matrix.h:69