NEURON
solve.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 /* solve.c 1.2 11/25/87 */
33 static char rcsid[] = "solve.c,v 1.1 1997/12/04 17:55:47 hines Exp";
34 
35 #include <stdio.h>
36 #include "matrix2.h"
37 #include <math.h>
38 
39 
40 
41 
42 
43 /* Most matrix factorisation routines are in-situ unless otherwise specified */
44 
45 /* Usolve -- back substitution with optional over-riding diagonal
46  -- can be in-situ but doesn't need to be */
47 VEC *Usolve(matrix,b,out,diag)
48 MAT *matrix;
49 VEC *b, *out;
50 double diag;
51 {
52  u_int dim /* , j */;
53  int i, i_lim;
54  Real **mat_ent, *mat_row, *b_ent, *out_ent, *out_col, sum, tiny;
55 
56  if ( matrix==(MAT *)NULL || b==(VEC *)NULL )
57  error(E_NULL,"Usolve");
58  dim = min(matrix->m,matrix->n);
59  if ( b->dim < dim )
60  error(E_SIZES,"Usolve");
61  if ( out==(VEC *)NULL || out->dim < dim )
62  out = v_resize(out,matrix->n);
63  mat_ent = matrix->me; b_ent = b->ve; out_ent = out->ve;
64 
65  tiny = 10.0/HUGE_VAL;
66 
67  for ( i=dim-1; i>=0; i-- )
68  if ( b_ent[i] != 0.0 )
69  break;
70  else
71  out_ent[i] = 0.0;
72  i_lim = i;
73 
74  for ( ; i>=0; i-- )
75  {
76  sum = b_ent[i];
77  mat_row = &(mat_ent[i][i+1]);
78  out_col = &(out_ent[i+1]);
79  sum -= __ip__(mat_row,out_col,i_lim-i);
80  /******************************************************
81  for ( j=i+1; j<=i_lim; j++ )
82  sum -= mat_ent[i][j]*out_ent[j];
83  sum -= (*mat_row++)*(*out_col++);
84  ******************************************************/
85  if ( diag==0.0 )
86  {
87  if ( fabs(mat_ent[i][i]) <= tiny*fabs(sum) )
88  error(E_SING,"Usolve");
89  else
90  out_ent[i] = sum/mat_ent[i][i];
91  }
92  else
93  out_ent[i] = sum/diag;
94  }
95 
96  return (out);
97 }
98 
99 /* Lsolve -- forward elimination with (optional) default diagonal value */
100 VEC *Lsolve(matrix,b,out,diag)
101 MAT *matrix;
102 VEC *b,*out;
103 double diag;
104 {
105  u_int dim, i, i_lim /* , j */;
106  Real **mat_ent, *mat_row, *b_ent, *out_ent, *out_col, sum, tiny;
107 
108  if ( matrix==(MAT *)NULL || b==(VEC *)NULL )
109  error(E_NULL,"Lsolve");
110  dim = min(matrix->m,matrix->n);
111  if ( b->dim < dim )
112  error(E_SIZES,"Lsolve");
113  if ( out==(VEC *)NULL || out->dim < dim )
114  out = v_resize(out,matrix->n);
115  mat_ent = matrix->me; b_ent = b->ve; out_ent = out->ve;
116 
117  for ( i=0; i<dim; i++ )
118  if ( b_ent[i] != 0.0 )
119  break;
120  else
121  out_ent[i] = 0.0;
122  i_lim = i;
123 
124  tiny = 10.0/HUGE_VAL;
125 
126  for ( ; i<dim; i++ )
127  {
128  sum = b_ent[i];
129  mat_row = &(mat_ent[i][i_lim]);
130  out_col = &(out_ent[i_lim]);
131  sum -= __ip__(mat_row,out_col,(int)(i-i_lim));
132  /*****************************************************
133  for ( j=i_lim; j<i; j++ )
134  sum -= mat_ent[i][j]*out_ent[j];
135  sum -= (*mat_row++)*(*out_col++);
136  ******************************************************/
137  if ( diag==0.0 )
138  {
139  if ( fabs(mat_ent[i][i]) <= tiny*fabs(sum) )
140  error(E_SING,"Lsolve");
141  else
142  out_ent[i] = sum/mat_ent[i][i];
143  }
144  else
145  out_ent[i] = sum/diag;
146  }
147 
148  return (out);
149 }
150 
151 
152 /* UTsolve -- forward elimination with (optional) default diagonal value
153  using UPPER triangular part of matrix */
154 VEC *UTsolve(U,b,out,diag)
155 MAT *U;
156 VEC *b,*out;
157 double diag;
158 {
159  u_int dim, i, i_lim;
160  Real **U_me, *b_ve, *out_ve, tmp, invdiag, tiny;
161 
162  if ( ! U || ! b )
163  error(E_NULL,"UTsolve");
164  dim = min(U->m,U->n);
165  if ( b->dim < dim )
166  error(E_SIZES,"UTsolve");
167  out = v_resize(out,U->n);
168  U_me = U->me; b_ve = b->ve; out_ve = out->ve;
169 
170  tiny = 10.0/HUGE_VAL;
171 
172  for ( i=0; i<dim; i++ )
173  if ( b_ve[i] != 0.0 )
174  break;
175  else
176  out_ve[i] = 0.0;
177  i_lim = i;
178  if ( b != out )
179  {
180  __zero__(out_ve,out->dim);
181  MEM_COPY(&(b_ve[i_lim]),&(out_ve[i_lim]),(dim-i_lim)*sizeof(Real));
182  }
183 
184  if ( diag == 0.0 )
185  {
186  for ( ; i<dim; i++ )
187  {
188  tmp = U_me[i][i];
189  if ( fabs(tmp) <= tiny*fabs(out_ve[i]) )
190  error(E_SING,"UTsolve");
191  out_ve[i] /= tmp;
192  __mltadd__(&(out_ve[i+1]),&(U_me[i][i+1]),-out_ve[i],dim-i-1);
193  }
194  }
195  else
196  {
197  invdiag = 1.0/diag;
198  for ( ; i<dim; i++ )
199  {
200  out_ve[i] *= invdiag;
201  __mltadd__(&(out_ve[i+1]),&(U_me[i][i+1]),-out_ve[i],dim-i-1);
202  }
203  }
204  return (out);
205 }
206 
207 /* Dsolve -- solves Dx=b where D is the diagonal of A -- may be in-situ */
208 VEC *Dsolve(A,b,x)
209 MAT *A;
210 VEC *b,*x;
211 {
212  u_int dim, i;
213  Real tiny;
214 
215  if ( ! A || ! b )
216  error(E_NULL,"Dsolve");
217  dim = min(A->m,A->n);
218  if ( b->dim < dim )
219  error(E_SIZES,"Dsolve");
220  x = v_resize(x,A->n);
221 
222  tiny = 10.0/HUGE_VAL;
223 
224  dim = b->dim;
225  for ( i=0; i<dim; i++ )
226  if ( fabs(A->me[i][i]) <= tiny*fabs(b->ve[i]) )
227  error(E_SING,"Dsolve");
228  else
229  x->ve[i] = b->ve[i]/A->me[i][i];
230 
231  return (x);
232 }
233 
234 /* LTsolve -- back substitution with optional over-riding diagonal
235  using the LOWER triangular part of matrix
236  -- can be in-situ but doesn't need to be */
237 VEC *LTsolve(L,b,out,diag)
238 MAT *L;
239 VEC *b, *out;
240 double diag;
241 {
242  u_int dim;
243  int i, i_lim;
244  Real **L_me, *b_ve, *out_ve, tmp, invdiag, tiny;
245 
246  if ( ! L || ! b )
247  error(E_NULL,"LTsolve");
248  dim = min(L->m,L->n);
249  if ( b->dim < dim )
250  error(E_SIZES,"LTsolve");
251  out = v_resize(out,L->n);
252  L_me = L->me; b_ve = b->ve; out_ve = out->ve;
253 
254  tiny = 10.0/HUGE_VAL;
255 
256  for ( i=dim-1; i>=0; i-- )
257  if ( b_ve[i] != 0.0 )
258  break;
259  i_lim = i;
260 
261  if ( b != out )
262  {
263  __zero__(out_ve,out->dim);
264  MEM_COPY(b_ve,out_ve,(i_lim+1)*sizeof(Real));
265  }
266 
267  if ( diag == 0.0 )
268  {
269  for ( ; i>=0; i-- )
270  {
271  tmp = L_me[i][i];
272  if ( fabs(tmp) <= tiny*fabs(out_ve[i]) )
273  error(E_SING,"LTsolve");
274  out_ve[i] /= tmp;
275  __mltadd__(out_ve,L_me[i],-out_ve[i],i);
276  }
277  }
278  else
279  {
280  invdiag = 1.0/diag;
281  for ( ; i>=0; i-- )
282  {
283  out_ve[i] *= invdiag;
284  __mltadd__(out_ve,L_me[i],-out_ve[i],i);
285  }
286  }
287 
288  return (out);
289 }
#define E_SING
Definition: err.h:98
VEC * UTsolve(MAT *U, VEC *b, VEC *out, double diag)
Definition: solve.c:154
#define diag(s)
Definition: fmenu.cpp:188
#define min(a, b)
Definition: matrix.h:157
VEC * Usolve(MAT *matrix, VEC *b, VEC *out, double diag)
Definition: solve.c:47
#define Real
Definition: machine.h:189
static Object ** v_resize(void *v)
Definition: ivocvect.cpp:1297
Real * ve
Definition: matrix.h:69
Definition: matrix.h:67
#define E_SIZES
Definition: err.h:95
uint32_t u_int
Definition: machine.h:38
void __mltadd__(Real *dp1, Real *dp2, double s, int len)
Definition: machine.c:76
u_int dim
Definition: matrix.h:68
VEC * Dsolve(MAT *A, VEC *b, VEC *x)
Definition: solve.c:208
VEC * LTsolve(MAT *L, VEC *b, VEC *out, double diag)
Definition: solve.c:237
void MEM_COPY(char *from, char *to, int len)
Definition: extras.c:37
#define E_NULL
Definition: err.h:102
#define HUGE_VAL
Definition: machine.h:244
void __zero__(Real *dp, int len)
Definition: machine.c:133
double __ip__(Real *dp1, Real *dp2, int len)
Definition: machine.c:40
#define i
Definition: md1redef.h:12
#define A(i)
Definition: multisplit.cpp:61
VEC * Lsolve(MAT *matrix, VEC *b, VEC *out, double diag)
Definition: solve.c:100
#define error(err_num, fn_name)
Definition: err.h:73
fabs
Definition: extdef.h:3
static char rcsid[]
Definition: solve.c:33
return NULL
Definition: cabcode.cpp:461
Definition: matrix.h:73