NEURON
zlufctr.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  Matrix factorisation routines to work with the other matrix files.
29  Complex version
30 */
31 
32 static char rcsid[] = "zlufctr.c,v 1.1 1997/12/04 17:56:09 hines Exp";
33 
34 #include <stdio.h>
35 #include "zmatrix.h"
36 #include "zmatrix2.h"
37 #include <math.h>
38 
39 #define is_zero(z) ((z).re == 0.0 && (z).im == 0.0)
40 
41 
42 /* Most matrix factorisation routines are in-situ unless otherwise specified */
43 
44 /* zLUfactor -- Gaussian elimination with scaled partial pivoting
45  -- Note: returns LU matrix which is A */
46 ZMAT *zLUfactor(A,pivot)
47 ZMAT *A;
48 PERM *pivot;
49 {
50  u_int i, j, k, k_max, m, n;
51  int i_max;
52  Real dtemp, max1;
53  complex **A_v, *A_piv, *A_row, temp;
54  static VEC *scale = VNULL;
55 
56  if ( A==ZMNULL || pivot==PNULL )
57  error(E_NULL,"zLUfactor");
58  if ( pivot->size != A->m )
59  error(E_SIZES,"zLUfactor");
60  m = A->m; n = A->n;
61  scale = v_resize(scale,A->m);
62  MEM_STAT_REG(scale,TYPE_VEC);
63  A_v = A->me;
64 
65  /* initialise pivot with identity permutation */
66  for ( i=0; i<m; i++ )
67  pivot->pe[i] = i;
68 
69  /* set scale parameters */
70  for ( i=0; i<m; i++ )
71  {
72  max1 = 0.0;
73  for ( j=0; j<n; j++ )
74  {
75  dtemp = zabs(A_v[i][j]);
76  max1 = max(max1,dtemp);
77  }
78  scale->ve[i] = max1;
79  }
80 
81  /* main loop */
82  k_max = min(m,n)-1;
83  for ( k=0; k<k_max; k++ )
84  {
85  /* find best pivot row */
86  max1 = 0.0; i_max = -1;
87  for ( i=k; i<m; i++ )
88  if ( scale->ve[i] > 0.0 )
89  {
90  dtemp = zabs(A_v[i][k])/scale->ve[i];
91  if ( dtemp > max1 )
92  { max1 = dtemp; i_max = i; }
93  }
94 
95  /* if no pivot then ignore column k... */
96  if ( i_max == -1 )
97  continue;
98 
99  /* do we pivot ? */
100  if ( i_max != k ) /* yes we do... */
101  {
102  px_transp(pivot,i_max,k);
103  for ( j=0; j<n; j++ )
104  {
105  temp = A_v[i_max][j];
106  A_v[i_max][j] = A_v[k][j];
107  A_v[k][j] = temp;
108  }
109  }
110 
111  /* row operations */
112  for ( i=k+1; i<m; i++ ) /* for each row do... */
113  { /* Note: divide by zero should never happen */
114  temp = A_v[i][k] = zdiv(A_v[i][k],A_v[k][k]);
115  A_piv = &(A_v[k][k+1]);
116  A_row = &(A_v[i][k+1]);
117  temp.re = - temp.re;
118  temp.im = - temp.im;
119  if ( k+1 < n )
120  __zmltadd__(A_row,A_piv,temp,(int)(n-(k+1)),Z_NOCONJ);
121  /*********************************************
122  for ( j=k+1; j<n; j++ )
123  A_v[i][j] -= temp*A_v[k][j];
124  (*A_row++) -= temp*(*A_piv++);
125  *********************************************/
126  }
127  }
128 
129  return A;
130 }
131 
132 
133 /* zLUsolve -- given an LU factorisation in A, solve Ax=b */
134 ZVEC *zLUsolve(A,pivot,b,x)
135 ZMAT *A;
136 PERM *pivot;
137 ZVEC *b,*x;
138 {
139  if ( A==ZMNULL || b==ZVNULL || pivot==PNULL )
140  error(E_NULL,"zLUsolve");
141  if ( A->m != A->n || A->n != b->dim )
142  error(E_SIZES,"zLUsolve");
143 
144  x = px_zvec(pivot,b,x); /* x := P.b */
145  zLsolve(A,x,x,1.0); /* implicit diagonal = 1 */
146  zUsolve(A,x,x,0.0); /* explicit diagonal */
147 
148  return (x);
149 }
150 
151 /* zLUAsolve -- given an LU factorisation in A, solve A^*.x=b */
152 ZVEC *zLUAsolve(LU,pivot,b,x)
153 ZMAT *LU;
154 PERM *pivot;
155 ZVEC *b,*x;
156 {
157  if ( ! LU || ! b || ! pivot )
158  error(E_NULL,"zLUAsolve");
159  if ( LU->m != LU->n || LU->n != b->dim )
160  error(E_SIZES,"zLUAsolve");
161 
162  x = zv_copy(b,x);
163  zUAsolve(LU,x,x,0.0); /* explicit diagonal */
164  zLAsolve(LU,x,x,1.0); /* implicit diagonal = 1 */
165  pxinv_zvec(pivot,x,x); /* x := P^*.x */
166 
167  return (x);
168 }
169 
170 /* zm_inverse -- returns inverse of A, provided A is not too rank deficient
171  -- uses LU factorisation */
173 ZMAT *A, *out;
174 {
175  int i;
176  ZVEC *tmp, *tmp2;
177  ZMAT *A_cp;
178  PERM *pivot;
179 
180  if ( ! A )
181  error(E_NULL,"zm_inverse");
182  if ( A->m != A->n )
183  error(E_SQUARE,"zm_inverse");
184  if ( ! out || out->m < A->m || out->n < A->n )
185  out = zm_resize(out,A->m,A->n);
186 
187  A_cp = zm_copy(A,ZMNULL);
188  tmp = zv_get(A->m);
189  tmp2 = zv_get(A->m);
190  pivot = px_get(A->m);
191  tracecatch(zLUfactor(A_cp,pivot),"zm_inverse");
192  for ( i = 0; i < A->n; i++ )
193  {
194  zv_zero(tmp);
195  tmp->ve[i].re = 1.0;
196  tmp->ve[i].im = 0.0;
197  tracecatch(zLUsolve(A_cp,pivot,tmp,tmp2),"m_inverse");
198  zset_col(out,i,tmp2);
199  }
200 
201  ZM_FREE(A_cp);
202  ZV_FREE(tmp); ZV_FREE(tmp2);
203  PX_FREE(pivot);
204 
205  return out;
206 }
207 
208 /* zLUcondest -- returns an estimate of the condition number of LU given the
209  LU factorisation in compact form */
210 double zLUcondest(LU,pivot)
211 ZMAT *LU;
212 PERM *pivot;
213 {
214  static ZVEC *y = ZVNULL, *z = ZVNULL;
215  Real cond_est, L_norm, U_norm, norm, sn_inv;
216  complex sum;
217  int i, j, n;
218 
219  if ( ! LU || ! pivot )
220  error(E_NULL,"zLUcondest");
221  if ( LU->m != LU->n )
222  error(E_SQUARE,"zLUcondest");
223  if ( LU->n != pivot->size )
224  error(E_SIZES,"zLUcondest");
225 
226  n = LU->n;
227  y = zv_resize(y,n);
228  z = zv_resize(z,n);
229  MEM_STAT_REG(y,TYPE_ZVEC);
230  MEM_STAT_REG(z,TYPE_ZVEC);
231 
232  cond_est = 0.0; /* should never be returned */
233 
234  for ( i = 0; i < n; i++ )
235  {
236  sum.re = 1.0;
237  sum.im = 0.0;
238  for ( j = 0; j < i; j++ )
239  /* sum -= LU->me[j][i]*y->ve[j]; */
240  sum = zsub(sum,zmlt(LU->me[j][i],y->ve[j]));
241  /* sum -= (sum < 0.0) ? 1.0 : -1.0; */
242  sn_inv = 1.0 / zabs(sum);
243  sum.re += sum.re * sn_inv;
244  sum.im += sum.im * sn_inv;
245  if ( is_zero(LU->me[i][i]) )
246  return HUGE;
247  /* y->ve[i] = sum / LU->me[i][i]; */
248  y->ve[i] = zdiv(sum,LU->me[i][i]);
249  }
250 
251  zLAsolve(LU,y,y,1.0);
252  zLUsolve(LU,pivot,y,z);
253 
254  /* now estimate norm of A (even though it is not directly available) */
255  /* actually computes ||L||_inf.||U||_inf */
256  U_norm = 0.0;
257  for ( i = 0; i < n; i++ )
258  {
259  norm = 0.0;
260  for ( j = i; j < n; j++ )
261  norm += zabs(LU->me[i][j]);
262  if ( norm > U_norm )
263  U_norm = norm;
264  }
265  L_norm = 0.0;
266  for ( i = 0; i < n; i++ )
267  {
268  norm = 1.0;
269  for ( j = 0; j < i; j++ )
270  norm += zabs(LU->me[i][j]);
271  if ( norm > L_norm )
272  L_norm = norm;
273  }
274 
275  tracecatch(cond_est = U_norm*L_norm*zv_norm_inf(z)/zv_norm_inf(y),
276  "LUcondest");
277 
278  return cond_est;
279 }
#define PNULL
Definition: matrix.h:633
double max(double a, double b)
Definition: geometry3d.cpp:22
#define Z_NOCONJ
Definition: zmatrix.h:61
Real im
Definition: zmatrix.h:40
#define zm_copy(A, B)
Definition: zmatrix.h:264
ZVEC * zLsolve(ZMAT *matrix, ZVEC *b, ZVEC *out, double diag)
Definition: zsolve.c:102
#define is_zero(z)
Definition: zlufctr.c:39
u_int dim
Definition: zmatrix.h:45
#define ZVNULL
Definition: zmatrix.h:57
#define TYPE_VEC
Definition: meminfo.h:52
#define min(a, b)
Definition: matrix.h:157
#define Real
Definition: machine.h:189
static Object ** v_resize(void *v)
Definition: ivocvect.cpp:1297
ZVEC * pxinv_zvec(PERM *pi, ZVEC *in, ZVEC *out)
Definition: zvecop.c:466
ZVEC * px_zvec(PERM *pi, ZVEC *in, ZVEC *out)
Definition: zvecop.c:397
ZVEC * zLUAsolve(ZMAT *LU, PERM *pivot, ZVEC *b, ZVEC *x)
Definition: zlufctr.c:152
#define ZMNULL
Definition: zmatrix.h:58
void __zmltadd__(complex *zp1, complex *zp2, complex s, int len, int flag)
Definition: zmachine.c:87
ZVEC * zLUsolve(ZMAT *A, PERM *pivot, ZVEC *b, ZVEC *x)
Definition: zlufctr.c:134
static philox4x32_key_t k
Definition: nrnran123.cpp:11
ZVEC * zv_get(int dim)
Definition: zmemory.c:122
Definition: zmatrix.h:50
Definition: zmatrix.h:44
complex zmlt(complex z1, complex z2)
Definition: zfunc.c:121
PERM * px_transp(PERM *px, u_int i, u_int j)
Definition: pxop.c:208
Real * ve
Definition: matrix.h:69
Definition: matrix.h:67
double zLUcondest(ZMAT *LU, PERM *pivot)
Definition: zlufctr.c:210
u_int size
Definition: matrix.h:88
#define E_SIZES
Definition: err.h:95
uint32_t u_int
Definition: machine.h:38
ZMAT * zm_resize(ZMAT *A, int new_m, int new_n)
Definition: zmemory.c:227
int const size_t const size_t n
Definition: nrngsl.h:12
ZVEC * zUAsolve(ZMAT *U, ZVEC *b, ZVEC *out, double diag)
Definition: zsolve.c:157
complex * ve
Definition: zmatrix.h:46
#define zv_norm_inf(x)
Definition: zmatrix.h:280
Real re
Definition: zmatrix.h:40
#define zv_copy(x, y)
Definition: zmatrix.h:263
#define tracecatch(ok_part, function)
Definition: err.h:166
#define ZV_FREE(x)
Definition: zmatrix.h:273
ZMAT * zm_inverse(ZMAT *A, ZMAT *out)
Definition: zlufctr.c:172
#define E_NULL
Definition: err.h:102
size_t j
#define E_SQUARE
Definition: err.h:103
#define ZM_FREE(A)
Definition: zmatrix.h:274
#define PX_FREE(px)
Definition: matrix.h:215
ZVEC * zv_zero(ZVEC *x)
Definition: zmemory.c:39
ZMAT * zset_col(ZMAT *mat, int col, ZVEC *vec)
Definition: zmatop.c:565
ZVEC * zv_resize(ZVEC *x, int new_dim)
Definition: zmemory.c:362
#define MEM_STAT_REG(var, type)
Definition: meminfo.h:133
PERM * px_get(int)
#define i
Definition: md1redef.h:12
#define A(i)
Definition: multisplit.cpp:61
complex zdiv(complex z1, complex z2)
Definition: zfunc.c:166
ZVEC * zUsolve(ZMAT *matrix, ZVEC *b, ZVEC *out, double diag)
Definition: zsolve.c:46
#define error(err_num, fn_name)
Definition: err.h:73
ZVEC * zLAsolve(ZMAT *L, ZVEC *b, ZVEC *out, double diag)
Definition: zsolve.c:244
double zabs(complex z)
Definition: zfunc.c:65
#define VNULL
Definition: matrix.h:631
static char rcsid[]
Definition: zlufctr.c:32
for(i=0;i< n;i++)
Definition: matrix.h:87
ZMAT * zLUfactor(ZMAT *A, PERM *pivot)
Definition: zlufctr.c:46
u_int * pe
Definition: matrix.h:88
complex zsub(complex z1, complex z2)
Definition: zfunc.c:107