NEURON
lufactor.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  Matrix factorisation routines to work with the other matrix files.
30 */
31 
32 /* LUfactor.c 1.5 11/25/87 */
33 static char rcsid[] = "lufactor.c,v 1.1 1997/12/04 17:55:32 hines Exp";
34 
35 #include <stdio.h>
36 #include "matrix.h"
37 #include "matrix2.h"
38 #include <math.h>
39 
40 
41 
42 /* Most matrix factorisation routines are in-situ unless otherwise specified */
43 
44 /* LUfactor -- gaussian elimination with scaled partial pivoting
45  -- Note: returns LU matrix which is A */
46 MAT *LUfactor(A,pivot)
47 MAT *A;
48 PERM *pivot;
49 {
50  u_int i, j, k, k_max, m, n;
51  int i_max;
52  Real **A_v, *A_piv, *A_row;
53  Real max1, temp, tiny;
54  static VEC *scale = VNULL;
55 
56  if ( A==(MAT *)NULL || pivot==(PERM *)NULL )
57  error(E_NULL,"LUfactor");
58  if ( pivot->size != A->m )
59  error(E_SIZES,"LUfactor");
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  tiny = 10.0/HUGE_VAL;
66 
67  /* initialise pivot with identity permutation */
68  for ( i=0; i<m; i++ )
69  pivot->pe[i] = i;
70 
71  /* set scale parameters */
72  for ( i=0; i<m; i++ )
73  {
74  max1 = 0.0;
75  for ( j=0; j<n; j++ )
76  {
77  temp = fabs(A_v[i][j]);
78  max1 = max(max1,temp);
79  }
80  scale->ve[i] = max1;
81  }
82 
83  /* main loop */
84  k_max = min(m,n)-1;
85  for ( k=0; k<k_max; k++ )
86  {
87  /* find best pivot row */
88  max1 = 0.0; i_max = -1;
89  for ( i=k; i<m; i++ )
90  if ( fabs(scale->ve[i]) >= tiny*fabs(A_v[i][k]) )
91  {
92  temp = fabs(A_v[i][k])/scale->ve[i];
93  if ( temp > max1 )
94  { max1 = temp; i_max = i; }
95  }
96 
97  /* if no pivot then ignore column k... */
98  if ( i_max == -1 )
99  {
100  /* set pivot entry A[k][k] exactly to zero,
101  rather than just "small" */
102  A_v[k][k] = 0.0;
103  continue;
104  }
105 
106  /* do we pivot ? */
107  if ( i_max != k ) /* yes we do... */
108  {
109  px_transp(pivot,i_max,k);
110  for ( j=0; j<n; j++ )
111  {
112  temp = A_v[i_max][j];
113  A_v[i_max][j] = A_v[k][j];
114  A_v[k][j] = temp;
115  }
116  }
117 
118  /* row operations */
119  for ( i=k+1; i<m; i++ ) /* for each row do... */
120  { /* Note: divide by zero should never happen */
121  temp = A_v[i][k] = A_v[i][k]/A_v[k][k];
122  A_piv = &(A_v[k][k+1]);
123  A_row = &(A_v[i][k+1]);
124  if ( k+1 < n )
125  __mltadd__(A_row,A_piv,-temp,(int)(n-(k+1)));
126  /*********************************************
127  for ( j=k+1; j<n; j++ )
128  A_v[i][j] -= temp*A_v[k][j];
129  (*A_row++) -= temp*(*A_piv++);
130  *********************************************/
131  }
132 
133  }
134 
135  return A;
136 }
137 
138 
139 /* LUsolve -- given an LU factorisation in A, solve Ax=b */
140 VEC *LUsolve(A,pivot,b,x)
141 MAT *A;
142 PERM *pivot;
143 VEC *b,*x;
144 {
145  if ( A==(MAT *)NULL || b==(VEC *)NULL || pivot==(PERM *)NULL )
146  error(E_NULL,"LUsolve");
147  if ( A->m != A->n || A->n != b->dim )
148  error(E_SIZES,"LUsolve");
149 
150  x = v_resize(x,b->dim);
151  px_vec(pivot,b,x); /* x := P.b */
152  Lsolve(A,x,x,1.0); /* implicit diagonal = 1 */
153  Usolve(A,x,x,0.0); /* explicit diagonal */
154 
155  return (x);
156 }
157 
158 /* LUTsolve -- given an LU factorisation in A, solve A^T.x=b */
159 VEC *LUTsolve(LU,pivot,b,x)
160 MAT *LU;
161 PERM *pivot;
162 VEC *b,*x;
163 {
164  if ( ! LU || ! b || ! pivot )
165  error(E_NULL,"LUTsolve");
166  if ( LU->m != LU->n || LU->n != b->dim )
167  error(E_SIZES,"LUTsolve");
168 
169  x = v_copy(b,x);
170  UTsolve(LU,x,x,0.0); /* explicit diagonal */
171  LTsolve(LU,x,x,1.0); /* implicit diagonal = 1 */
172  pxinv_vec(pivot,x,x); /* x := P^T.tmp */
173 
174  return (x);
175 }
176 
177 /* m_inverse -- returns inverse of A, provided A is not too rank deficient
178  -- uses LU factorisation */
180 MAT *A, *out;
181 {
182  int i;
183  static VEC *tmp = VNULL, *tmp2 = VNULL;
184  static MAT *A_cp = MNULL;
185  static PERM *pivot = PNULL;
186 
187  if ( ! A )
188  error(E_NULL,"m_inverse");
189  if ( A->m != A->n )
190  error(E_SQUARE,"m_inverse");
191  if ( ! out || out->m < A->m || out->n < A->n )
192  out = m_resize(out,A->m,A->n);
193 
194  A_cp = m_resize(A_cp,A->m,A->n);
195  A_cp = m_copy(A,A_cp);
196  tmp = v_resize(tmp,A->m);
197  tmp2 = v_resize(tmp2,A->m);
198  pivot = px_resize(pivot,A->m);
199  MEM_STAT_REG(A_cp,TYPE_MAT);
200  MEM_STAT_REG(tmp, TYPE_VEC);
201  MEM_STAT_REG(tmp2,TYPE_VEC);
202  MEM_STAT_REG(pivot,TYPE_PERM);
203  tracecatch(LUfactor(A_cp,pivot),"m_inverse");
204  for ( i = 0; i < A->n; i++ )
205  {
206  v_zero(tmp);
207  tmp->ve[i] = 1.0;
208  tracecatch(LUsolve(A_cp,pivot,tmp,tmp2),"m_inverse");
209  set_col(out,i,tmp2);
210  }
211 
212  return out;
213 }
214 
215 /* LUcondest -- returns an estimate of the condition number of LU given the
216  LU factorisation in compact form */
217 double LUcondest(LU,pivot)
218 MAT *LU;
219 PERM *pivot;
220 {
221  static VEC *y = VNULL, *z = VNULL;
222  Real cond_est=0.0, L_norm, U_norm, sum, tiny;
223  int i, j, n;
224 
225  if ( ! LU || ! pivot )
226  error(E_NULL,"LUcondest");
227  if ( LU->m != LU->n )
228  error(E_SQUARE,"LUcondest");
229  if ( LU->n != pivot->size )
230  error(E_SIZES,"LUcondest");
231 
232  tiny = 10.0/HUGE_VAL;
233 
234  n = LU->n;
235  y = v_resize(y,n);
236  z = v_resize(z,n);
239 
240  for ( i = 0; i < n; i++ )
241  {
242  sum = 0.0;
243  for ( j = 0; j < i; j++ )
244  sum -= LU->me[j][i]*y->ve[j];
245  sum -= (sum < 0.0) ? 1.0 : -1.0;
246  if ( fabs(LU->me[i][i]) <= tiny*fabs(sum) )
247  return HUGE_VAL;
248  y->ve[i] = sum / LU->me[i][i];
249  }
250 
251  catch(E_SING,
252  LTsolve(LU,y,y,1.0);
253  LUsolve(LU,pivot,y,z);
254  ,
255  return HUGE_VAL);
256 
257  /* now estimate norm of A (even though it is not directly available) */
258  /* actually computes ||L||_inf.||U||_inf */
259  U_norm = 0.0;
260  for ( i = 0; i < n; i++ )
261  {
262  sum = 0.0;
263  for ( j = i; j < n; j++ )
264  sum += fabs(LU->me[i][j]);
265  if ( sum > U_norm )
266  U_norm = sum;
267  }
268  L_norm = 0.0;
269  for ( i = 0; i < n; i++ )
270  {
271  sum = 1.0;
272  for ( j = 0; j < i; j++ )
273  sum += fabs(LU->me[i][j]);
274  if ( sum > L_norm )
275  L_norm = sum;
276  }
277 
278  tracecatch(cond_est = U_norm*L_norm*v_norm_inf(z)/v_norm_inf(y),
279  "LUcondest");
280 
281  return cond_est;
282 }
#define PNULL
Definition: matrix.h:633
VEC * UTsolve(MAT *A, VEC *b, VEC *x, double diag_val)
double max(double a, double b)
Definition: geometry3d.cpp:22
MAT * LUfactor(MAT *A, PERM *pivot)
Definition: lufactor.c:46
#define E_SING
Definition: err.h:98
#define v_norm_inf(x)
Definition: matrix.h:512
MAT * m_inverse(MAT *A, MAT *out)
Definition: lufactor.c:179
#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
static philox4x32_key_t k
Definition: nrnran123.cpp:11
#define m_copy(in, out)
Definition: matrix.h:403
VEC * px_vec(PERM *, VEC *, VEC *)
PERM * px_transp(PERM *px, u_int i, u_int j)
Definition: pxop.c:208
VEC * LTsolve(MAT *A, VEC *b, VEC *x, double diag_val)
Real * ve
Definition: matrix.h:69
Definition: matrix.h:67
#define v_copy(in, out)
Definition: matrix.h:404
u_int size
Definition: matrix.h:88
#define E_SIZES
Definition: err.h:95
uint32_t u_int
Definition: machine.h:38
int const size_t const size_t n
Definition: nrngsl.h:12
VEC * LUsolve(MAT *A, PERM *pivot, VEC *b, VEC *x)
Definition: lufactor.c:140
#define MNULL
Definition: matrix.h:632
void __mltadd__(Real *dp1, Real *dp2, double s, int len)
Definition: machine.c:76
PERM * px_resize(PERM *, int)
Definition: memory.c:399
u_int dim
Definition: matrix.h:68
#define tracecatch(ok_part, function)
Definition: err.h:166
static char rcsid[]
Definition: lufactor.c:33
#define E_NULL
Definition: err.h:102
size_t j
#define set_col(mat, col, vec)
Definition: matrix.h:564
VEC * LUTsolve(MAT *LU, PERM *pivot, VEC *b, VEC *x)
Definition: lufactor.c:159
#define HUGE_VAL
Definition: machine.h:244
#define E_SQUARE
Definition: err.h:103
VEC * Usolve(MAT *A, VEC *b, VEC *x, double diag_val)
#define TYPE_PERM
Definition: meminfo.h:51
VEC * v_zero(VEC *x)
Definition: init.c:40
VEC * pxinv_vec(PERM *, VEC *, VEC *)
static Object ** m_resize(void *v)
Definition: matrix.cpp:190
#define MEM_STAT_REG(var, type)
Definition: meminfo.h:133
#define i
Definition: md1redef.h:12
#define A(i)
Definition: multisplit.cpp:61
#define error(err_num, fn_name)
Definition: err.h:73
fabs
Definition: extdef.h:3
VEC * x
Definition: iter.h:64
#define TYPE_MAT
Definition: meminfo.h:49
#define VNULL
Definition: matrix.h:631
for(i=0;i< n;i++)
VEC * Lsolve(MAT *A, VEC *b, VEC *x, double diag_val)
Definition: matrix.h:87
return NULL
Definition: cabcode.cpp:461
Definition: matrix.h:73
u_int * pe
Definition: matrix.h:88
VEC * b
Definition: iter.h:66
double LUcondest(MAT *LU, PERM *pivot)
Definition: lufactor.c:217