NEURON
bkpfacto.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 static char rcsid[] = "bkpfacto.c,v 1.1 1997/12/04 17:55:14 hines Exp";
33 
34 #include <stdio.h>
35 #include "matrix.h"
36 #include "matrix2.h"
37 #include <math.h>
38 
39 #define btos(x) ((x) ? "TRUE" : "FALSE")
40 
41 /* Most matrix factorisation routines are in-situ unless otherwise specified */
42 
43 #define alpha 0.6403882032022076 /* = (1+sqrt(17))/8 */
44 
45 /* sqr -- returns square of x -- utility function */
46 double sqr(x)
47 double x;
48 { return x*x; }
49 
50 /* interchange -- a row/column swap routine */
51 static void interchange(A,i,j)
52 MAT *A; /* assumed != NULL & also SQUARE */
53 int i, j; /* assumed in range */
54 {
55  Real **A_me, tmp;
56  int k, n;
57 
58  A_me = A->me; n = A->n;
59  if ( i == j )
60  return;
61  if ( i > j )
62  { k = i; i = j; j = k; }
63  for ( k = 0; k < i; k++ )
64  {
65  /* tmp = A_me[k][i]; */
66  tmp = m_entry(A,k,i);
67  /* A_me[k][i] = A_me[k][j]; */
68  m_set_val(A,k,i,m_entry(A,k,j));
69  /* A_me[k][j] = tmp; */
70  m_set_val(A,k,j,tmp);
71  }
72  for ( k = j+1; k < n; k++ )
73  {
74  /* tmp = A_me[j][k]; */
75  tmp = m_entry(A,j,k);
76  /* A_me[j][k] = A_me[i][k]; */
77  m_set_val(A,j,k,m_entry(A,i,k));
78  /* A_me[i][k] = tmp; */
79  m_set_val(A,i,k,tmp);
80  }
81  for ( k = i+1; k < j; k++ )
82  {
83  /* tmp = A_me[k][j]; */
84  tmp = m_entry(A,k,j);
85  /* A_me[k][j] = A_me[i][k]; */
86  m_set_val(A,k,j,m_entry(A,i,k));
87  /* A_me[i][k] = tmp; */
88  m_set_val(A,i,k,tmp);
89  }
90  /* tmp = A_me[i][i]; */
91  tmp = m_entry(A,i,i);
92  /* A_me[i][i] = A_me[j][j]; */
93  m_set_val(A,i,i,m_entry(A,j,j));
94  /* A_me[j][j] = tmp; */
95  m_set_val(A,j,j,tmp);
96 }
97 
98 /* BKPfactor -- Bunch-Kaufman-Parlett factorisation of A in-situ
99  -- A is factored into the form P'AP = MDM' where
100  P is a permutation matrix, M lower triangular and D is block
101  diagonal with blocks of size 1 or 2
102  -- P is stored in pivot; blocks[i]==i iff D[i][i] is a block */
103 MAT *BKPfactor(A,pivot,blocks)
104 MAT *A;
105 PERM *pivot, *blocks;
106 {
107  int i, j, k, n, onebyone, r;
108  Real **A_me, aii, aip1, aip1i, lambda, sigma, tmp;
109  Real det, s, t;
110 
111  if ( ! A || ! pivot || ! blocks )
112  error(E_NULL,"BKPfactor");
113  if ( A->m != A->n )
114  error(E_SQUARE,"BKPfactor");
115  if ( A->m != pivot->size || pivot->size != blocks->size )
116  error(E_SIZES,"BKPfactor");
117 
118  n = A->n;
119  A_me = A->me;
120  px_ident(pivot); px_ident(blocks);
121 
122  for ( i = 0; i < n; i = onebyone ? i+1 : i+2 )
123  {
124  /* printf("# Stage: %d\n",i); */
125  aii = fabs(m_entry(A,i,i));
126  lambda = 0.0; r = (i+1 < n) ? i+1 : i;
127  for ( k = i+1; k < n; k++ )
128  {
129  tmp = fabs(m_entry(A,i,k));
130  if ( tmp >= lambda )
131  {
132  lambda = tmp;
133  r = k;
134  }
135  }
136  /* printf("# lambda = %g, r = %d\n", lambda, r); */
137  /* printf("# |A[%d][%d]| = %g\n",r,r,fabs(m_entry(A,r,r))); */
138 
139  /* determine if 1x1 or 2x2 block, and do pivoting if needed */
140  if ( aii >= alpha*lambda )
141  {
142  onebyone = TRUE;
143  goto dopivot;
144  }
145  /* compute sigma */
146  sigma = 0.0;
147  for ( k = i; k < n; k++ )
148  {
149  if ( k == r )
150  continue;
151  tmp = ( k > r ) ? fabs(m_entry(A,r,k)) :
152  fabs(m_entry(A,k,r));
153  if ( tmp > sigma )
154  sigma = tmp;
155  }
156  if ( aii*sigma >= alpha*sqr(lambda) )
157  onebyone = TRUE;
158  else if ( fabs(m_entry(A,r,r)) >= alpha*sigma )
159  {
160  /* printf("# Swapping rows/cols %d and %d\n",i,r); */
161  interchange(A,i,r);
162  px_transp(pivot,i,r);
163  onebyone = TRUE;
164  }
165  else
166  {
167  /* printf("# Swapping rows/cols %d and %d\n",i+1,r); */
168  interchange(A,i+1,r);
169  px_transp(pivot,i+1,r);
170  px_transp(blocks,i,i+1);
171  onebyone = FALSE;
172  }
173  /* printf("onebyone = %s\n",btos(onebyone)); */
174  /* printf("# Matrix so far (@checkpoint A) =\n"); */
175  /* m_output(A); */
176  /* printf("# pivot =\n"); px_output(pivot); */
177  /* printf("# blocks =\n"); px_output(blocks); */
178 
179 dopivot:
180  if ( onebyone )
181  { /* do one by one block */
182  if ( m_entry(A,i,i) != 0.0 )
183  {
184  aii = m_entry(A,i,i);
185  for ( j = i+1; j < n; j++ )
186  {
187  tmp = m_entry(A,i,j)/aii;
188  for ( k = j; k < n; k++ )
189  m_sub_val(A,j,k,tmp*m_entry(A,i,k));
190  m_set_val(A,i,j,tmp);
191  }
192  }
193  }
194  else /* onebyone == FALSE */
195  { /* do two by two block */
196  det = m_entry(A,i,i)*m_entry(A,i+1,i+1)-sqr(m_entry(A,i,i+1));
197  /* Must have det < 0 */
198  /* printf("# det = %g\n",det); */
199  aip1i = m_entry(A,i,i+1)/det;
200  aii = m_entry(A,i,i)/det;
201  aip1 = m_entry(A,i+1,i+1)/det;
202  for ( j = i+2; j < n; j++ )
203  {
204  s = - aip1i*m_entry(A,i+1,j) + aip1*m_entry(A,i,j);
205  t = - aip1i*m_entry(A,i,j) + aii*m_entry(A,i+1,j);
206  for ( k = j; k < n; k++ )
207  m_sub_val(A,j,k,m_entry(A,i,k)*s + m_entry(A,i+1,k)*t);
208  m_set_val(A,i,j,s);
209  m_set_val(A,i+1,j,t);
210  }
211  }
212  /* printf("# Matrix so far (@checkpoint B) =\n"); */
213  /* m_output(A); */
214  /* printf("# pivot =\n"); px_output(pivot); */
215  /* printf("# blocks =\n"); px_output(blocks); */
216  }
217 
218  /* set lower triangular half */
219  for ( i = 0; i < A->m; i++ )
220  for ( j = 0; j < i; j++ )
221  m_set_val(A,i,j,m_entry(A,j,i));
222 
223  return A;
224 }
225 
226 /* BKPsolve -- solves A.x = b where A has been factored a la BKPfactor()
227  -- returns x, which is created if NULL */
228 VEC *BKPsolve(A,pivot,block,b,x)
229 MAT *A;
230 PERM *pivot, *block;
231 VEC *b, *x;
232 {
233  static VEC *tmp=VNULL; /* dummy storage needed */
234  int i, j, n, onebyone;
235  Real **A_me, a11, a12, a22, b1, b2, det, sum, *tmp_ve, tmp_diag;
236 
237  if ( ! A || ! pivot || ! block || ! b )
238  error(E_NULL,"BKPsolve");
239  if ( A->m != A->n )
240  error(E_SQUARE,"BKPsolve");
241  n = A->n;
242  if ( b->dim != n || pivot->size != n || block->size != n )
243  error(E_SIZES,"BKPsolve");
244  x = v_resize(x,n);
245  tmp = v_resize(tmp,n);
246  MEM_STAT_REG(tmp,TYPE_VEC);
247 
248  A_me = A->me; tmp_ve = tmp->ve;
249 
250  px_vec(pivot,b,tmp);
251  /* solve for lower triangular part */
252  for ( i = 0; i < n; i++ )
253  {
254  sum = v_entry(tmp,i);
255  if ( block->pe[i] < i )
256  for ( j = 0; j < i-1; j++ )
257  sum -= m_entry(A,i,j)*v_entry(tmp,j);
258  else
259  for ( j = 0; j < i; j++ )
260  sum -= m_entry(A,i,j)*v_entry(tmp,j);
261  v_set_val(tmp,i,sum);
262  }
263  /* printf("# BKPsolve: solving L part: tmp =\n"); v_output(tmp); */
264  /* solve for diagonal part */
265  for ( i = 0; i < n; i = onebyone ? i+1 : i+2 )
266  {
267  onebyone = ( block->pe[i] == i );
268  if ( onebyone )
269  {
270  tmp_diag = m_entry(A,i,i);
271  if ( tmp_diag == 0.0 )
272  error(E_SING,"BKPsolve");
273  /* tmp_ve[i] /= tmp_diag; */
274  v_set_val(tmp,i,v_entry(tmp,i) / tmp_diag);
275  }
276  else
277  {
278  a11 = m_entry(A,i,i);
279  a22 = m_entry(A,i+1,i+1);
280  a12 = m_entry(A,i+1,i);
281  b1 = v_entry(tmp,i); b2 = v_entry(tmp,i+1);
282  det = a11*a22-a12*a12; /* < 0 : see BKPfactor() */
283  if ( det == 0.0 )
284  error(E_SING,"BKPsolve");
285  det = 1/det;
286  v_set_val(tmp,i,det*(a22*b1-a12*b2));
287  v_set_val(tmp,i+1,det*(a11*b2-a12*b1));
288  }
289  }
290  /* printf("# BKPsolve: solving D part: tmp =\n"); v_output(tmp); */
291  /* solve for transpose of lower traingular part */
292  for ( i = n-1; i >= 0; i-- )
293  { /* use symmetry of factored form to get stride 1 */
294  sum = v_entry(tmp,i);
295  if ( block->pe[i] > i )
296  for ( j = i+2; j < n; j++ )
297  sum -= m_entry(A,i,j)*v_entry(tmp,j);
298  else
299  for ( j = i+1; j < n; j++ )
300  sum -= m_entry(A,i,j)*v_entry(tmp,j);
301  v_set_val(tmp,i,sum);
302  }
303 
304  /* printf("# BKPsolve: solving L^T part: tmp =\n");v_output(tmp); */
305  /* and do final permutation */
306  x = pxinv_vec(pivot,tmp,x);
307 
308  return x;
309 }
310 
311 
312 
#define E_SING
Definition: err.h:98
#define m_sub_val(A, i, j, val)
Definition: matrix.h:283
VEC * BKPsolve(MAT *A, PERM *pivot, PERM *block, VEC *b, VEC *x)
Definition: bkpfacto.c:228
MAT * BKPfactor(MAT *A, PERM *pivot, PERM *blocks)
Definition: bkpfacto.c:103
#define TYPE_VEC
Definition: meminfo.h:52
#define Real
Definition: machine.h:189
static Object ** v_resize(void *v)
Definition: ivocvect.cpp:1297
#define TRUE
Definition: err.c:57
#define m_set_val(A, i, j, val)
Definition: matrix.h:277
static philox4x32_key_t k
Definition: nrnran123.cpp:11
VEC * px_vec(PERM *, VEC *, VEC *)
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
static void interchange(MAT *A, int i, int j)
Definition: bkpfacto.c:51
u_int size
Definition: matrix.h:88
#define E_SIZES
Definition: err.h:95
int const size_t const size_t n
Definition: nrngsl.h:12
_CONST char * s
Definition: system.cpp:74
u_int dim
Definition: matrix.h:68
#define E_NULL
Definition: err.h:102
size_t j
#define v_set_val(x, i, val)
Definition: matrix.h:265
#define alpha
Definition: bkpfacto.c:43
#define E_SQUARE
Definition: err.h:103
#define v_entry(x, i)
Definition: matrix.h:262
static char rcsid[]
Definition: bkpfacto.c:32
VEC * pxinv_vec(PERM *, VEC *, VEC *)
#define MEM_STAT_REG(var, type)
Definition: meminfo.h:133
#define FALSE
Definition: err.c:56
#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
#define VNULL
Definition: matrix.h:631
double t
Definition: init.cpp:123
Definition: matrix.h:87
PERM * px_ident(PERM *px)
Definition: init.c:108
Definition: matrix.h:73
u_int * pe
Definition: matrix.h:88
#define m_entry(A, i, j)
Definition: matrix.h:274
double sqr(double x)
Definition: bkpfacto.c:46