alpar@1
|
1 |
/* glpluf.c (LU-factorization) */
|
alpar@1
|
2 |
|
alpar@1
|
3 |
/***********************************************************************
|
alpar@1
|
4 |
* This code is part of GLPK (GNU Linear Programming Kit).
|
alpar@1
|
5 |
*
|
alpar@1
|
6 |
* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
alpar@1
|
7 |
* 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
|
alpar@1
|
8 |
* Moscow Aviation Institute, Moscow, Russia. All rights reserved.
|
alpar@1
|
9 |
* E-mail: <mao@gnu.org>.
|
alpar@1
|
10 |
*
|
alpar@1
|
11 |
* GLPK is free software: you can redistribute it and/or modify it
|
alpar@1
|
12 |
* under the terms of the GNU General Public License as published by
|
alpar@1
|
13 |
* the Free Software Foundation, either version 3 of the License, or
|
alpar@1
|
14 |
* (at your option) any later version.
|
alpar@1
|
15 |
*
|
alpar@1
|
16 |
* GLPK is distributed in the hope that it will be useful, but WITHOUT
|
alpar@1
|
17 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
alpar@1
|
18 |
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
alpar@1
|
19 |
* License for more details.
|
alpar@1
|
20 |
*
|
alpar@1
|
21 |
* You should have received a copy of the GNU General Public License
|
alpar@1
|
22 |
* along with GLPK. If not, see <http://www.gnu.org/licenses/>.
|
alpar@1
|
23 |
***********************************************************************/
|
alpar@1
|
24 |
|
alpar@1
|
25 |
#include "glpenv.h"
|
alpar@1
|
26 |
#include "glpluf.h"
|
alpar@1
|
27 |
#define xfault xerror
|
alpar@1
|
28 |
|
alpar@1
|
29 |
/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
|
alpar@1
|
30 |
|
alpar@1
|
31 |
#define N_MAX 100000000 /* = 100*10^6 */
|
alpar@1
|
32 |
/* maximal order of the original matrix */
|
alpar@1
|
33 |
|
alpar@1
|
34 |
/***********************************************************************
|
alpar@1
|
35 |
* NAME
|
alpar@1
|
36 |
*
|
alpar@1
|
37 |
* luf_create_it - create LU-factorization
|
alpar@1
|
38 |
*
|
alpar@1
|
39 |
* SYNOPSIS
|
alpar@1
|
40 |
*
|
alpar@1
|
41 |
* #include "glpluf.h"
|
alpar@1
|
42 |
* LUF *luf_create_it(void);
|
alpar@1
|
43 |
*
|
alpar@1
|
44 |
* DESCRIPTION
|
alpar@1
|
45 |
*
|
alpar@1
|
46 |
* The routine luf_create_it creates a program object, which represents
|
alpar@1
|
47 |
* LU-factorization of a square matrix.
|
alpar@1
|
48 |
*
|
alpar@1
|
49 |
* RETURNS
|
alpar@1
|
50 |
*
|
alpar@1
|
51 |
* The routine luf_create_it returns a pointer to the object created. */
|
alpar@1
|
52 |
|
alpar@1
|
53 |
LUF *luf_create_it(void)
|
alpar@1
|
54 |
{ LUF *luf;
|
alpar@1
|
55 |
luf = xmalloc(sizeof(LUF));
|
alpar@1
|
56 |
luf->n_max = luf->n = 0;
|
alpar@1
|
57 |
luf->valid = 0;
|
alpar@1
|
58 |
luf->fr_ptr = luf->fr_len = NULL;
|
alpar@1
|
59 |
luf->fc_ptr = luf->fc_len = NULL;
|
alpar@1
|
60 |
luf->vr_ptr = luf->vr_len = luf->vr_cap = NULL;
|
alpar@1
|
61 |
luf->vr_piv = NULL;
|
alpar@1
|
62 |
luf->vc_ptr = luf->vc_len = luf->vc_cap = NULL;
|
alpar@1
|
63 |
luf->pp_row = luf->pp_col = NULL;
|
alpar@1
|
64 |
luf->qq_row = luf->qq_col = NULL;
|
alpar@1
|
65 |
luf->sv_size = 0;
|
alpar@1
|
66 |
luf->sv_beg = luf->sv_end = 0;
|
alpar@1
|
67 |
luf->sv_ind = NULL;
|
alpar@1
|
68 |
luf->sv_val = NULL;
|
alpar@1
|
69 |
luf->sv_head = luf->sv_tail = 0;
|
alpar@1
|
70 |
luf->sv_prev = luf->sv_next = NULL;
|
alpar@1
|
71 |
luf->vr_max = NULL;
|
alpar@1
|
72 |
luf->rs_head = luf->rs_prev = luf->rs_next = NULL;
|
alpar@1
|
73 |
luf->cs_head = luf->cs_prev = luf->cs_next = NULL;
|
alpar@1
|
74 |
luf->flag = NULL;
|
alpar@1
|
75 |
luf->work = NULL;
|
alpar@1
|
76 |
luf->new_sva = 0;
|
alpar@1
|
77 |
luf->piv_tol = 0.10;
|
alpar@1
|
78 |
luf->piv_lim = 4;
|
alpar@1
|
79 |
luf->suhl = 1;
|
alpar@1
|
80 |
luf->eps_tol = 1e-15;
|
alpar@1
|
81 |
luf->max_gro = 1e+10;
|
alpar@1
|
82 |
luf->nnz_a = luf->nnz_f = luf->nnz_v = 0;
|
alpar@1
|
83 |
luf->max_a = luf->big_v = 0.0;
|
alpar@1
|
84 |
luf->rank = 0;
|
alpar@1
|
85 |
return luf;
|
alpar@1
|
86 |
}
|
alpar@1
|
87 |
|
alpar@1
|
88 |
/***********************************************************************
|
alpar@1
|
89 |
* NAME
|
alpar@1
|
90 |
*
|
alpar@1
|
91 |
* luf_defrag_sva - defragment the sparse vector area
|
alpar@1
|
92 |
*
|
alpar@1
|
93 |
* SYNOPSIS
|
alpar@1
|
94 |
*
|
alpar@1
|
95 |
* #include "glpluf.h"
|
alpar@1
|
96 |
* void luf_defrag_sva(LUF *luf);
|
alpar@1
|
97 |
*
|
alpar@1
|
98 |
* DESCRIPTION
|
alpar@1
|
99 |
*
|
alpar@1
|
100 |
* The routine luf_defrag_sva defragments the sparse vector area (SVA)
|
alpar@1
|
101 |
* gathering all unused locations in one continuous extent. In order to
|
alpar@1
|
102 |
* do that the routine moves all unused locations from the left part of
|
alpar@1
|
103 |
* SVA (which contains rows and columns of the matrix V) to the middle
|
alpar@1
|
104 |
* part (which contains free locations). This is attained by relocating
|
alpar@1
|
105 |
* elements of rows and columns of the matrix V toward the beginning of
|
alpar@1
|
106 |
* the left part.
|
alpar@1
|
107 |
*
|
alpar@1
|
108 |
* NOTE that this "garbage collection" involves changing row and column
|
alpar@1
|
109 |
* pointers of the matrix V. */
|
alpar@1
|
110 |
|
alpar@1
|
111 |
void luf_defrag_sva(LUF *luf)
|
alpar@1
|
112 |
{ int n = luf->n;
|
alpar@1
|
113 |
int *vr_ptr = luf->vr_ptr;
|
alpar@1
|
114 |
int *vr_len = luf->vr_len;
|
alpar@1
|
115 |
int *vr_cap = luf->vr_cap;
|
alpar@1
|
116 |
int *vc_ptr = luf->vc_ptr;
|
alpar@1
|
117 |
int *vc_len = luf->vc_len;
|
alpar@1
|
118 |
int *vc_cap = luf->vc_cap;
|
alpar@1
|
119 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
120 |
double *sv_val = luf->sv_val;
|
alpar@1
|
121 |
int *sv_next = luf->sv_next;
|
alpar@1
|
122 |
int sv_beg = 1;
|
alpar@1
|
123 |
int i, j, k;
|
alpar@1
|
124 |
/* skip rows and columns, which do not need to be relocated */
|
alpar@1
|
125 |
for (k = luf->sv_head; k != 0; k = sv_next[k])
|
alpar@1
|
126 |
{ if (k <= n)
|
alpar@1
|
127 |
{ /* i-th row of the matrix V */
|
alpar@1
|
128 |
i = k;
|
alpar@1
|
129 |
if (vr_ptr[i] != sv_beg) break;
|
alpar@1
|
130 |
vr_cap[i] = vr_len[i];
|
alpar@1
|
131 |
sv_beg += vr_cap[i];
|
alpar@1
|
132 |
}
|
alpar@1
|
133 |
else
|
alpar@1
|
134 |
{ /* j-th column of the matrix V */
|
alpar@1
|
135 |
j = k - n;
|
alpar@1
|
136 |
if (vc_ptr[j] != sv_beg) break;
|
alpar@1
|
137 |
vc_cap[j] = vc_len[j];
|
alpar@1
|
138 |
sv_beg += vc_cap[j];
|
alpar@1
|
139 |
}
|
alpar@1
|
140 |
}
|
alpar@1
|
141 |
/* relocate other rows and columns in order to gather all unused
|
alpar@1
|
142 |
locations in one continuous extent */
|
alpar@1
|
143 |
for (k = k; k != 0; k = sv_next[k])
|
alpar@1
|
144 |
{ if (k <= n)
|
alpar@1
|
145 |
{ /* i-th row of the matrix V */
|
alpar@1
|
146 |
i = k;
|
alpar@1
|
147 |
memmove(&sv_ind[sv_beg], &sv_ind[vr_ptr[i]],
|
alpar@1
|
148 |
vr_len[i] * sizeof(int));
|
alpar@1
|
149 |
memmove(&sv_val[sv_beg], &sv_val[vr_ptr[i]],
|
alpar@1
|
150 |
vr_len[i] * sizeof(double));
|
alpar@1
|
151 |
vr_ptr[i] = sv_beg;
|
alpar@1
|
152 |
vr_cap[i] = vr_len[i];
|
alpar@1
|
153 |
sv_beg += vr_cap[i];
|
alpar@1
|
154 |
}
|
alpar@1
|
155 |
else
|
alpar@1
|
156 |
{ /* j-th column of the matrix V */
|
alpar@1
|
157 |
j = k - n;
|
alpar@1
|
158 |
memmove(&sv_ind[sv_beg], &sv_ind[vc_ptr[j]],
|
alpar@1
|
159 |
vc_len[j] * sizeof(int));
|
alpar@1
|
160 |
memmove(&sv_val[sv_beg], &sv_val[vc_ptr[j]],
|
alpar@1
|
161 |
vc_len[j] * sizeof(double));
|
alpar@1
|
162 |
vc_ptr[j] = sv_beg;
|
alpar@1
|
163 |
vc_cap[j] = vc_len[j];
|
alpar@1
|
164 |
sv_beg += vc_cap[j];
|
alpar@1
|
165 |
}
|
alpar@1
|
166 |
}
|
alpar@1
|
167 |
/* set new pointer to the beginning of the free part */
|
alpar@1
|
168 |
luf->sv_beg = sv_beg;
|
alpar@1
|
169 |
return;
|
alpar@1
|
170 |
}
|
alpar@1
|
171 |
|
alpar@1
|
172 |
/***********************************************************************
|
alpar@1
|
173 |
* NAME
|
alpar@1
|
174 |
*
|
alpar@1
|
175 |
* luf_enlarge_row - enlarge row capacity
|
alpar@1
|
176 |
*
|
alpar@1
|
177 |
* SYNOPSIS
|
alpar@1
|
178 |
*
|
alpar@1
|
179 |
* #include "glpluf.h"
|
alpar@1
|
180 |
* int luf_enlarge_row(LUF *luf, int i, int cap);
|
alpar@1
|
181 |
*
|
alpar@1
|
182 |
* DESCRIPTION
|
alpar@1
|
183 |
*
|
alpar@1
|
184 |
* The routine luf_enlarge_row enlarges capacity of the i-th row of the
|
alpar@1
|
185 |
* matrix V to cap locations (assuming that its current capacity is less
|
alpar@1
|
186 |
* than cap). In order to do that the routine relocates elements of the
|
alpar@1
|
187 |
* i-th row to the end of the left part of SVA (which contains rows and
|
alpar@1
|
188 |
* columns of the matrix V) and then expands the left part by allocating
|
alpar@1
|
189 |
* cap free locations from the free part. If there are less than cap
|
alpar@1
|
190 |
* free locations, the routine defragments the sparse vector area.
|
alpar@1
|
191 |
*
|
alpar@1
|
192 |
* Due to "garbage collection" this operation may change row and column
|
alpar@1
|
193 |
* pointers of the matrix V.
|
alpar@1
|
194 |
*
|
alpar@1
|
195 |
* RETURNS
|
alpar@1
|
196 |
*
|
alpar@1
|
197 |
* If no error occured, the routine returns zero. Otherwise, in case of
|
alpar@1
|
198 |
* overflow of the sparse vector area, the routine returns non-zero. */
|
alpar@1
|
199 |
|
alpar@1
|
200 |
int luf_enlarge_row(LUF *luf, int i, int cap)
|
alpar@1
|
201 |
{ int n = luf->n;
|
alpar@1
|
202 |
int *vr_ptr = luf->vr_ptr;
|
alpar@1
|
203 |
int *vr_len = luf->vr_len;
|
alpar@1
|
204 |
int *vr_cap = luf->vr_cap;
|
alpar@1
|
205 |
int *vc_cap = luf->vc_cap;
|
alpar@1
|
206 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
207 |
double *sv_val = luf->sv_val;
|
alpar@1
|
208 |
int *sv_prev = luf->sv_prev;
|
alpar@1
|
209 |
int *sv_next = luf->sv_next;
|
alpar@1
|
210 |
int ret = 0;
|
alpar@1
|
211 |
int cur, k, kk;
|
alpar@1
|
212 |
xassert(1 <= i && i <= n);
|
alpar@1
|
213 |
xassert(vr_cap[i] < cap);
|
alpar@1
|
214 |
/* if there are less than cap free locations, defragment SVA */
|
alpar@1
|
215 |
if (luf->sv_end - luf->sv_beg < cap)
|
alpar@1
|
216 |
{ luf_defrag_sva(luf);
|
alpar@1
|
217 |
if (luf->sv_end - luf->sv_beg < cap)
|
alpar@1
|
218 |
{ ret = 1;
|
alpar@1
|
219 |
goto done;
|
alpar@1
|
220 |
}
|
alpar@1
|
221 |
}
|
alpar@1
|
222 |
/* save current capacity of the i-th row */
|
alpar@1
|
223 |
cur = vr_cap[i];
|
alpar@1
|
224 |
/* copy existing elements to the beginning of the free part */
|
alpar@1
|
225 |
memmove(&sv_ind[luf->sv_beg], &sv_ind[vr_ptr[i]],
|
alpar@1
|
226 |
vr_len[i] * sizeof(int));
|
alpar@1
|
227 |
memmove(&sv_val[luf->sv_beg], &sv_val[vr_ptr[i]],
|
alpar@1
|
228 |
vr_len[i] * sizeof(double));
|
alpar@1
|
229 |
/* set new pointer and new capacity of the i-th row */
|
alpar@1
|
230 |
vr_ptr[i] = luf->sv_beg;
|
alpar@1
|
231 |
vr_cap[i] = cap;
|
alpar@1
|
232 |
/* set new pointer to the beginning of the free part */
|
alpar@1
|
233 |
luf->sv_beg += cap;
|
alpar@1
|
234 |
/* now the i-th row starts in the rightmost location among other
|
alpar@1
|
235 |
rows and columns of the matrix V, so its node should be moved
|
alpar@1
|
236 |
to the end of the row/column linked list */
|
alpar@1
|
237 |
k = i;
|
alpar@1
|
238 |
/* remove the i-th row node from the linked list */
|
alpar@1
|
239 |
if (sv_prev[k] == 0)
|
alpar@1
|
240 |
luf->sv_head = sv_next[k];
|
alpar@1
|
241 |
else
|
alpar@1
|
242 |
{ /* capacity of the previous row/column can be increased at the
|
alpar@1
|
243 |
expense of old locations of the i-th row */
|
alpar@1
|
244 |
kk = sv_prev[k];
|
alpar@1
|
245 |
if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
|
alpar@1
|
246 |
sv_next[sv_prev[k]] = sv_next[k];
|
alpar@1
|
247 |
}
|
alpar@1
|
248 |
if (sv_next[k] == 0)
|
alpar@1
|
249 |
luf->sv_tail = sv_prev[k];
|
alpar@1
|
250 |
else
|
alpar@1
|
251 |
sv_prev[sv_next[k]] = sv_prev[k];
|
alpar@1
|
252 |
/* insert the i-th row node to the end of the linked list */
|
alpar@1
|
253 |
sv_prev[k] = luf->sv_tail;
|
alpar@1
|
254 |
sv_next[k] = 0;
|
alpar@1
|
255 |
if (sv_prev[k] == 0)
|
alpar@1
|
256 |
luf->sv_head = k;
|
alpar@1
|
257 |
else
|
alpar@1
|
258 |
sv_next[sv_prev[k]] = k;
|
alpar@1
|
259 |
luf->sv_tail = k;
|
alpar@1
|
260 |
done: return ret;
|
alpar@1
|
261 |
}
|
alpar@1
|
262 |
|
alpar@1
|
263 |
/***********************************************************************
|
alpar@1
|
264 |
* NAME
|
alpar@1
|
265 |
*
|
alpar@1
|
266 |
* luf_enlarge_col - enlarge column capacity
|
alpar@1
|
267 |
*
|
alpar@1
|
268 |
* SYNOPSIS
|
alpar@1
|
269 |
*
|
alpar@1
|
270 |
* #include "glpluf.h"
|
alpar@1
|
271 |
* int luf_enlarge_col(LUF *luf, int j, int cap);
|
alpar@1
|
272 |
*
|
alpar@1
|
273 |
* DESCRIPTION
|
alpar@1
|
274 |
*
|
alpar@1
|
275 |
* The routine luf_enlarge_col enlarges capacity of the j-th column of
|
alpar@1
|
276 |
* the matrix V to cap locations (assuming that its current capacity is
|
alpar@1
|
277 |
* less than cap). In order to do that the routine relocates elements
|
alpar@1
|
278 |
* of the j-th column to the end of the left part of SVA (which contains
|
alpar@1
|
279 |
* rows and columns of the matrix V) and then expands the left part by
|
alpar@1
|
280 |
* allocating cap free locations from the free part. If there are less
|
alpar@1
|
281 |
* than cap free locations, the routine defragments the sparse vector
|
alpar@1
|
282 |
* area.
|
alpar@1
|
283 |
*
|
alpar@1
|
284 |
* Due to "garbage collection" this operation may change row and column
|
alpar@1
|
285 |
* pointers of the matrix V.
|
alpar@1
|
286 |
*
|
alpar@1
|
287 |
* RETURNS
|
alpar@1
|
288 |
*
|
alpar@1
|
289 |
* If no error occured, the routine returns zero. Otherwise, in case of
|
alpar@1
|
290 |
* overflow of the sparse vector area, the routine returns non-zero. */
|
alpar@1
|
291 |
|
alpar@1
|
292 |
int luf_enlarge_col(LUF *luf, int j, int cap)
|
alpar@1
|
293 |
{ int n = luf->n;
|
alpar@1
|
294 |
int *vr_cap = luf->vr_cap;
|
alpar@1
|
295 |
int *vc_ptr = luf->vc_ptr;
|
alpar@1
|
296 |
int *vc_len = luf->vc_len;
|
alpar@1
|
297 |
int *vc_cap = luf->vc_cap;
|
alpar@1
|
298 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
299 |
double *sv_val = luf->sv_val;
|
alpar@1
|
300 |
int *sv_prev = luf->sv_prev;
|
alpar@1
|
301 |
int *sv_next = luf->sv_next;
|
alpar@1
|
302 |
int ret = 0;
|
alpar@1
|
303 |
int cur, k, kk;
|
alpar@1
|
304 |
xassert(1 <= j && j <= n);
|
alpar@1
|
305 |
xassert(vc_cap[j] < cap);
|
alpar@1
|
306 |
/* if there are less than cap free locations, defragment SVA */
|
alpar@1
|
307 |
if (luf->sv_end - luf->sv_beg < cap)
|
alpar@1
|
308 |
{ luf_defrag_sva(luf);
|
alpar@1
|
309 |
if (luf->sv_end - luf->sv_beg < cap)
|
alpar@1
|
310 |
{ ret = 1;
|
alpar@1
|
311 |
goto done;
|
alpar@1
|
312 |
}
|
alpar@1
|
313 |
}
|
alpar@1
|
314 |
/* save current capacity of the j-th column */
|
alpar@1
|
315 |
cur = vc_cap[j];
|
alpar@1
|
316 |
/* copy existing elements to the beginning of the free part */
|
alpar@1
|
317 |
memmove(&sv_ind[luf->sv_beg], &sv_ind[vc_ptr[j]],
|
alpar@1
|
318 |
vc_len[j] * sizeof(int));
|
alpar@1
|
319 |
memmove(&sv_val[luf->sv_beg], &sv_val[vc_ptr[j]],
|
alpar@1
|
320 |
vc_len[j] * sizeof(double));
|
alpar@1
|
321 |
/* set new pointer and new capacity of the j-th column */
|
alpar@1
|
322 |
vc_ptr[j] = luf->sv_beg;
|
alpar@1
|
323 |
vc_cap[j] = cap;
|
alpar@1
|
324 |
/* set new pointer to the beginning of the free part */
|
alpar@1
|
325 |
luf->sv_beg += cap;
|
alpar@1
|
326 |
/* now the j-th column starts in the rightmost location among
|
alpar@1
|
327 |
other rows and columns of the matrix V, so its node should be
|
alpar@1
|
328 |
moved to the end of the row/column linked list */
|
alpar@1
|
329 |
k = n + j;
|
alpar@1
|
330 |
/* remove the j-th column node from the linked list */
|
alpar@1
|
331 |
if (sv_prev[k] == 0)
|
alpar@1
|
332 |
luf->sv_head = sv_next[k];
|
alpar@1
|
333 |
else
|
alpar@1
|
334 |
{ /* capacity of the previous row/column can be increased at the
|
alpar@1
|
335 |
expense of old locations of the j-th column */
|
alpar@1
|
336 |
kk = sv_prev[k];
|
alpar@1
|
337 |
if (kk <= n) vr_cap[kk] += cur; else vc_cap[kk-n] += cur;
|
alpar@1
|
338 |
sv_next[sv_prev[k]] = sv_next[k];
|
alpar@1
|
339 |
}
|
alpar@1
|
340 |
if (sv_next[k] == 0)
|
alpar@1
|
341 |
luf->sv_tail = sv_prev[k];
|
alpar@1
|
342 |
else
|
alpar@1
|
343 |
sv_prev[sv_next[k]] = sv_prev[k];
|
alpar@1
|
344 |
/* insert the j-th column node to the end of the linked list */
|
alpar@1
|
345 |
sv_prev[k] = luf->sv_tail;
|
alpar@1
|
346 |
sv_next[k] = 0;
|
alpar@1
|
347 |
if (sv_prev[k] == 0)
|
alpar@1
|
348 |
luf->sv_head = k;
|
alpar@1
|
349 |
else
|
alpar@1
|
350 |
sv_next[sv_prev[k]] = k;
|
alpar@1
|
351 |
luf->sv_tail = k;
|
alpar@1
|
352 |
done: return ret;
|
alpar@1
|
353 |
}
|
alpar@1
|
354 |
|
alpar@1
|
355 |
/***********************************************************************
|
alpar@1
|
356 |
* reallocate - reallocate LU-factorization arrays
|
alpar@1
|
357 |
*
|
alpar@1
|
358 |
* This routine reallocates arrays, whose size depends of n, the order
|
alpar@1
|
359 |
* of the matrix A to be factorized. */
|
alpar@1
|
360 |
|
alpar@1
|
361 |
static void reallocate(LUF *luf, int n)
|
alpar@1
|
362 |
{ int n_max = luf->n_max;
|
alpar@1
|
363 |
luf->n = n;
|
alpar@1
|
364 |
if (n <= n_max) goto done;
|
alpar@1
|
365 |
if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
|
alpar@1
|
366 |
if (luf->fr_len != NULL) xfree(luf->fr_len);
|
alpar@1
|
367 |
if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
|
alpar@1
|
368 |
if (luf->fc_len != NULL) xfree(luf->fc_len);
|
alpar@1
|
369 |
if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
|
alpar@1
|
370 |
if (luf->vr_len != NULL) xfree(luf->vr_len);
|
alpar@1
|
371 |
if (luf->vr_cap != NULL) xfree(luf->vr_cap);
|
alpar@1
|
372 |
if (luf->vr_piv != NULL) xfree(luf->vr_piv);
|
alpar@1
|
373 |
if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
|
alpar@1
|
374 |
if (luf->vc_len != NULL) xfree(luf->vc_len);
|
alpar@1
|
375 |
if (luf->vc_cap != NULL) xfree(luf->vc_cap);
|
alpar@1
|
376 |
if (luf->pp_row != NULL) xfree(luf->pp_row);
|
alpar@1
|
377 |
if (luf->pp_col != NULL) xfree(luf->pp_col);
|
alpar@1
|
378 |
if (luf->qq_row != NULL) xfree(luf->qq_row);
|
alpar@1
|
379 |
if (luf->qq_col != NULL) xfree(luf->qq_col);
|
alpar@1
|
380 |
if (luf->sv_prev != NULL) xfree(luf->sv_prev);
|
alpar@1
|
381 |
if (luf->sv_next != NULL) xfree(luf->sv_next);
|
alpar@1
|
382 |
if (luf->vr_max != NULL) xfree(luf->vr_max);
|
alpar@1
|
383 |
if (luf->rs_head != NULL) xfree(luf->rs_head);
|
alpar@1
|
384 |
if (luf->rs_prev != NULL) xfree(luf->rs_prev);
|
alpar@1
|
385 |
if (luf->rs_next != NULL) xfree(luf->rs_next);
|
alpar@1
|
386 |
if (luf->cs_head != NULL) xfree(luf->cs_head);
|
alpar@1
|
387 |
if (luf->cs_prev != NULL) xfree(luf->cs_prev);
|
alpar@1
|
388 |
if (luf->cs_next != NULL) xfree(luf->cs_next);
|
alpar@1
|
389 |
if (luf->flag != NULL) xfree(luf->flag);
|
alpar@1
|
390 |
if (luf->work != NULL) xfree(luf->work);
|
alpar@1
|
391 |
luf->n_max = n_max = n + 100;
|
alpar@1
|
392 |
luf->fr_ptr = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
393 |
luf->fr_len = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
394 |
luf->fc_ptr = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
395 |
luf->fc_len = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
396 |
luf->vr_ptr = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
397 |
luf->vr_len = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
398 |
luf->vr_cap = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
399 |
luf->vr_piv = xcalloc(1+n_max, sizeof(double));
|
alpar@1
|
400 |
luf->vc_ptr = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
401 |
luf->vc_len = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
402 |
luf->vc_cap = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
403 |
luf->pp_row = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
404 |
luf->pp_col = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
405 |
luf->qq_row = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
406 |
luf->qq_col = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
407 |
luf->sv_prev = xcalloc(1+n_max+n_max, sizeof(int));
|
alpar@1
|
408 |
luf->sv_next = xcalloc(1+n_max+n_max, sizeof(int));
|
alpar@1
|
409 |
luf->vr_max = xcalloc(1+n_max, sizeof(double));
|
alpar@1
|
410 |
luf->rs_head = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
411 |
luf->rs_prev = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
412 |
luf->rs_next = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
413 |
luf->cs_head = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
414 |
luf->cs_prev = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
415 |
luf->cs_next = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
416 |
luf->flag = xcalloc(1+n_max, sizeof(int));
|
alpar@1
|
417 |
luf->work = xcalloc(1+n_max, sizeof(double));
|
alpar@1
|
418 |
done: return;
|
alpar@1
|
419 |
}
|
alpar@1
|
420 |
|
alpar@1
|
421 |
/***********************************************************************
|
alpar@1
|
422 |
* initialize - initialize LU-factorization data structures
|
alpar@1
|
423 |
*
|
alpar@1
|
424 |
* This routine initializes data structures for subsequent computing
|
alpar@1
|
425 |
* the LU-factorization of a given matrix A, which is specified by the
|
alpar@1
|
426 |
* formal routine col. On exit V = A and F = P = Q = I, where I is the
|
alpar@1
|
427 |
* unity matrix. (Row-wise representation of the matrix F is not used
|
alpar@1
|
428 |
* at the factorization stage and therefore is not initialized.)
|
alpar@1
|
429 |
*
|
alpar@1
|
430 |
* If no error occured, the routine returns zero. Otherwise, in case of
|
alpar@1
|
431 |
* overflow of the sparse vector area, the routine returns non-zero. */
|
alpar@1
|
432 |
|
alpar@1
|
433 |
static int initialize(LUF *luf, int (*col)(void *info, int j, int rn[],
|
alpar@1
|
434 |
double aj[]), void *info)
|
alpar@1
|
435 |
{ int n = luf->n;
|
alpar@1
|
436 |
int *fc_ptr = luf->fc_ptr;
|
alpar@1
|
437 |
int *fc_len = luf->fc_len;
|
alpar@1
|
438 |
int *vr_ptr = luf->vr_ptr;
|
alpar@1
|
439 |
int *vr_len = luf->vr_len;
|
alpar@1
|
440 |
int *vr_cap = luf->vr_cap;
|
alpar@1
|
441 |
int *vc_ptr = luf->vc_ptr;
|
alpar@1
|
442 |
int *vc_len = luf->vc_len;
|
alpar@1
|
443 |
int *vc_cap = luf->vc_cap;
|
alpar@1
|
444 |
int *pp_row = luf->pp_row;
|
alpar@1
|
445 |
int *pp_col = luf->pp_col;
|
alpar@1
|
446 |
int *qq_row = luf->qq_row;
|
alpar@1
|
447 |
int *qq_col = luf->qq_col;
|
alpar@1
|
448 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
449 |
double *sv_val = luf->sv_val;
|
alpar@1
|
450 |
int *sv_prev = luf->sv_prev;
|
alpar@1
|
451 |
int *sv_next = luf->sv_next;
|
alpar@1
|
452 |
double *vr_max = luf->vr_max;
|
alpar@1
|
453 |
int *rs_head = luf->rs_head;
|
alpar@1
|
454 |
int *rs_prev = luf->rs_prev;
|
alpar@1
|
455 |
int *rs_next = luf->rs_next;
|
alpar@1
|
456 |
int *cs_head = luf->cs_head;
|
alpar@1
|
457 |
int *cs_prev = luf->cs_prev;
|
alpar@1
|
458 |
int *cs_next = luf->cs_next;
|
alpar@1
|
459 |
int *flag = luf->flag;
|
alpar@1
|
460 |
double *work = luf->work;
|
alpar@1
|
461 |
int ret = 0;
|
alpar@1
|
462 |
int i, i_ptr, j, j_beg, j_end, k, len, nnz, sv_beg, sv_end, ptr;
|
alpar@1
|
463 |
double big, val;
|
alpar@1
|
464 |
/* free all locations of the sparse vector area */
|
alpar@1
|
465 |
sv_beg = 1;
|
alpar@1
|
466 |
sv_end = luf->sv_size + 1;
|
alpar@1
|
467 |
/* (row-wise representation of the matrix F is not initialized,
|
alpar@1
|
468 |
because it is not used at the factorization stage) */
|
alpar@1
|
469 |
/* build the matrix F in column-wise format (initially F = I) */
|
alpar@1
|
470 |
for (j = 1; j <= n; j++)
|
alpar@1
|
471 |
{ fc_ptr[j] = sv_end;
|
alpar@1
|
472 |
fc_len[j] = 0;
|
alpar@1
|
473 |
}
|
alpar@1
|
474 |
/* clear rows of the matrix V; clear the flag array */
|
alpar@1
|
475 |
for (i = 1; i <= n; i++)
|
alpar@1
|
476 |
vr_len[i] = vr_cap[i] = 0, flag[i] = 0;
|
alpar@1
|
477 |
/* build the matrix V in column-wise format (initially V = A);
|
alpar@1
|
478 |
count non-zeros in rows of this matrix; count total number of
|
alpar@1
|
479 |
non-zeros; compute largest of absolute values of elements */
|
alpar@1
|
480 |
nnz = 0;
|
alpar@1
|
481 |
big = 0.0;
|
alpar@1
|
482 |
for (j = 1; j <= n; j++)
|
alpar@1
|
483 |
{ int *rn = pp_row;
|
alpar@1
|
484 |
double *aj = work;
|
alpar@1
|
485 |
/* obtain j-th column of the matrix A */
|
alpar@1
|
486 |
len = col(info, j, rn, aj);
|
alpar@1
|
487 |
if (!(0 <= len && len <= n))
|
alpar@1
|
488 |
xfault("luf_factorize: j = %d; len = %d; invalid column len"
|
alpar@1
|
489 |
"gth\n", j, len);
|
alpar@1
|
490 |
/* check for free locations */
|
alpar@1
|
491 |
if (sv_end - sv_beg < len)
|
alpar@1
|
492 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
493 |
ret = 1;
|
alpar@1
|
494 |
goto done;
|
alpar@1
|
495 |
}
|
alpar@1
|
496 |
/* set pointer to the j-th column */
|
alpar@1
|
497 |
vc_ptr[j] = sv_beg;
|
alpar@1
|
498 |
/* set length of the j-th column */
|
alpar@1
|
499 |
vc_len[j] = vc_cap[j] = len;
|
alpar@1
|
500 |
/* count total number of non-zeros */
|
alpar@1
|
501 |
nnz += len;
|
alpar@1
|
502 |
/* walk through elements of the j-th column */
|
alpar@1
|
503 |
for (ptr = 1; ptr <= len; ptr++)
|
alpar@1
|
504 |
{ /* get row index and numerical value of a[i,j] */
|
alpar@1
|
505 |
i = rn[ptr];
|
alpar@1
|
506 |
val = aj[ptr];
|
alpar@1
|
507 |
if (!(1 <= i && i <= n))
|
alpar@1
|
508 |
xfault("luf_factorize: i = %d; j = %d; invalid row index"
|
alpar@1
|
509 |
"\n", i, j);
|
alpar@1
|
510 |
if (flag[i])
|
alpar@1
|
511 |
xfault("luf_factorize: i = %d; j = %d; duplicate element"
|
alpar@1
|
512 |
" not allowed\n", i, j);
|
alpar@1
|
513 |
if (val == 0.0)
|
alpar@1
|
514 |
xfault("luf_factorize: i = %d; j = %d; zero element not "
|
alpar@1
|
515 |
"allowed\n", i, j);
|
alpar@1
|
516 |
/* add new element v[i,j] = a[i,j] to j-th column */
|
alpar@1
|
517 |
sv_ind[sv_beg] = i;
|
alpar@1
|
518 |
sv_val[sv_beg] = val;
|
alpar@1
|
519 |
sv_beg++;
|
alpar@1
|
520 |
/* big := max(big, |a[i,j]|) */
|
alpar@1
|
521 |
if (val < 0.0) val = - val;
|
alpar@1
|
522 |
if (big < val) big = val;
|
alpar@1
|
523 |
/* mark non-zero in the i-th position of the j-th column */
|
alpar@1
|
524 |
flag[i] = 1;
|
alpar@1
|
525 |
/* increase length of the i-th row */
|
alpar@1
|
526 |
vr_cap[i]++;
|
alpar@1
|
527 |
}
|
alpar@1
|
528 |
/* reset all non-zero marks */
|
alpar@1
|
529 |
for (ptr = 1; ptr <= len; ptr++) flag[rn[ptr]] = 0;
|
alpar@1
|
530 |
}
|
alpar@1
|
531 |
/* allocate rows of the matrix V */
|
alpar@1
|
532 |
for (i = 1; i <= n; i++)
|
alpar@1
|
533 |
{ /* get length of the i-th row */
|
alpar@1
|
534 |
len = vr_cap[i];
|
alpar@1
|
535 |
/* check for free locations */
|
alpar@1
|
536 |
if (sv_end - sv_beg < len)
|
alpar@1
|
537 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
538 |
ret = 1;
|
alpar@1
|
539 |
goto done;
|
alpar@1
|
540 |
}
|
alpar@1
|
541 |
/* set pointer to the i-th row */
|
alpar@1
|
542 |
vr_ptr[i] = sv_beg;
|
alpar@1
|
543 |
/* reserve locations for the i-th row */
|
alpar@1
|
544 |
sv_beg += len;
|
alpar@1
|
545 |
}
|
alpar@1
|
546 |
/* build the matrix V in row-wise format using representation of
|
alpar@1
|
547 |
this matrix in column-wise format */
|
alpar@1
|
548 |
for (j = 1; j <= n; j++)
|
alpar@1
|
549 |
{ /* walk through elements of the j-th column */
|
alpar@1
|
550 |
j_beg = vc_ptr[j];
|
alpar@1
|
551 |
j_end = j_beg + vc_len[j] - 1;
|
alpar@1
|
552 |
for (k = j_beg; k <= j_end; k++)
|
alpar@1
|
553 |
{ /* get row index and numerical value of v[i,j] */
|
alpar@1
|
554 |
i = sv_ind[k];
|
alpar@1
|
555 |
val = sv_val[k];
|
alpar@1
|
556 |
/* store element in the i-th row */
|
alpar@1
|
557 |
i_ptr = vr_ptr[i] + vr_len[i];
|
alpar@1
|
558 |
sv_ind[i_ptr] = j;
|
alpar@1
|
559 |
sv_val[i_ptr] = val;
|
alpar@1
|
560 |
/* increase count of the i-th row */
|
alpar@1
|
561 |
vr_len[i]++;
|
alpar@1
|
562 |
}
|
alpar@1
|
563 |
}
|
alpar@1
|
564 |
/* initialize the matrices P and Q (initially P = Q = I) */
|
alpar@1
|
565 |
for (k = 1; k <= n; k++)
|
alpar@1
|
566 |
pp_row[k] = pp_col[k] = qq_row[k] = qq_col[k] = k;
|
alpar@1
|
567 |
/* set sva partitioning pointers */
|
alpar@1
|
568 |
luf->sv_beg = sv_beg;
|
alpar@1
|
569 |
luf->sv_end = sv_end;
|
alpar@1
|
570 |
/* the initial physical order of rows and columns of the matrix V
|
alpar@1
|
571 |
is n+1, ..., n+n, 1, ..., n (firstly columns, then rows) */
|
alpar@1
|
572 |
luf->sv_head = n+1;
|
alpar@1
|
573 |
luf->sv_tail = n;
|
alpar@1
|
574 |
for (i = 1; i <= n; i++)
|
alpar@1
|
575 |
{ sv_prev[i] = i-1;
|
alpar@1
|
576 |
sv_next[i] = i+1;
|
alpar@1
|
577 |
}
|
alpar@1
|
578 |
sv_prev[1] = n+n;
|
alpar@1
|
579 |
sv_next[n] = 0;
|
alpar@1
|
580 |
for (j = 1; j <= n; j++)
|
alpar@1
|
581 |
{ sv_prev[n+j] = n+j-1;
|
alpar@1
|
582 |
sv_next[n+j] = n+j+1;
|
alpar@1
|
583 |
}
|
alpar@1
|
584 |
sv_prev[n+1] = 0;
|
alpar@1
|
585 |
sv_next[n+n] = 1;
|
alpar@1
|
586 |
/* clear working arrays */
|
alpar@1
|
587 |
for (k = 1; k <= n; k++)
|
alpar@1
|
588 |
{ flag[k] = 0;
|
alpar@1
|
589 |
work[k] = 0.0;
|
alpar@1
|
590 |
}
|
alpar@1
|
591 |
/* initialize some statistics */
|
alpar@1
|
592 |
luf->nnz_a = nnz;
|
alpar@1
|
593 |
luf->nnz_f = 0;
|
alpar@1
|
594 |
luf->nnz_v = nnz;
|
alpar@1
|
595 |
luf->max_a = big;
|
alpar@1
|
596 |
luf->big_v = big;
|
alpar@1
|
597 |
luf->rank = -1;
|
alpar@1
|
598 |
/* initially the active submatrix is the entire matrix V */
|
alpar@1
|
599 |
/* largest of absolute values of elements in each active row is
|
alpar@1
|
600 |
unknown yet */
|
alpar@1
|
601 |
for (i = 1; i <= n; i++) vr_max[i] = -1.0;
|
alpar@1
|
602 |
/* build linked lists of active rows */
|
alpar@1
|
603 |
for (len = 0; len <= n; len++) rs_head[len] = 0;
|
alpar@1
|
604 |
for (i = 1; i <= n; i++)
|
alpar@1
|
605 |
{ len = vr_len[i];
|
alpar@1
|
606 |
rs_prev[i] = 0;
|
alpar@1
|
607 |
rs_next[i] = rs_head[len];
|
alpar@1
|
608 |
if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
|
alpar@1
|
609 |
rs_head[len] = i;
|
alpar@1
|
610 |
}
|
alpar@1
|
611 |
/* build linked lists of active columns */
|
alpar@1
|
612 |
for (len = 0; len <= n; len++) cs_head[len] = 0;
|
alpar@1
|
613 |
for (j = 1; j <= n; j++)
|
alpar@1
|
614 |
{ len = vc_len[j];
|
alpar@1
|
615 |
cs_prev[j] = 0;
|
alpar@1
|
616 |
cs_next[j] = cs_head[len];
|
alpar@1
|
617 |
if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
|
alpar@1
|
618 |
cs_head[len] = j;
|
alpar@1
|
619 |
}
|
alpar@1
|
620 |
done: /* return to the factorizing routine */
|
alpar@1
|
621 |
return ret;
|
alpar@1
|
622 |
}
|
alpar@1
|
623 |
|
alpar@1
|
624 |
/***********************************************************************
|
alpar@1
|
625 |
* find_pivot - choose a pivot element
|
alpar@1
|
626 |
*
|
alpar@1
|
627 |
* This routine chooses a pivot element in the active submatrix of the
|
alpar@1
|
628 |
* matrix U = P*V*Q.
|
alpar@1
|
629 |
*
|
alpar@1
|
630 |
* It is assumed that on entry the matrix U has the following partially
|
alpar@1
|
631 |
* triangularized form:
|
alpar@1
|
632 |
*
|
alpar@1
|
633 |
* 1 k n
|
alpar@1
|
634 |
* 1 x x x x x x x x x x
|
alpar@1
|
635 |
* . x x x x x x x x x
|
alpar@1
|
636 |
* . . x x x x x x x x
|
alpar@1
|
637 |
* . . . x x x x x x x
|
alpar@1
|
638 |
* k . . . . * * * * * *
|
alpar@1
|
639 |
* . . . . * * * * * *
|
alpar@1
|
640 |
* . . . . * * * * * *
|
alpar@1
|
641 |
* . . . . * * * * * *
|
alpar@1
|
642 |
* . . . . * * * * * *
|
alpar@1
|
643 |
* n . . . . * * * * * *
|
alpar@1
|
644 |
*
|
alpar@1
|
645 |
* where rows and columns k, k+1, ..., n belong to the active submatrix
|
alpar@1
|
646 |
* (elements of the active submatrix are marked by '*').
|
alpar@1
|
647 |
*
|
alpar@1
|
648 |
* Since the matrix U = P*V*Q is not stored, the routine works with the
|
alpar@1
|
649 |
* matrix V. It is assumed that the row-wise representation corresponds
|
alpar@1
|
650 |
* to the matrix V, but the column-wise representation corresponds to
|
alpar@1
|
651 |
* the active submatrix of the matrix V, i.e. elements of the matrix V,
|
alpar@1
|
652 |
* which doesn't belong to the active submatrix, are missing from the
|
alpar@1
|
653 |
* column linked lists. It is also assumed that each active row of the
|
alpar@1
|
654 |
* matrix V is in the set R[len], where len is number of non-zeros in
|
alpar@1
|
655 |
* the row, and each active column of the matrix V is in the set C[len],
|
alpar@1
|
656 |
* where len is number of non-zeros in the column (in the latter case
|
alpar@1
|
657 |
* only elements of the active submatrix are counted; such elements are
|
alpar@1
|
658 |
* marked by '*' on the figure above).
|
alpar@1
|
659 |
*
|
alpar@1
|
660 |
* For the reason of numerical stability the routine applies so called
|
alpar@1
|
661 |
* threshold pivoting proposed by J.Reid. It is assumed that an element
|
alpar@1
|
662 |
* v[i,j] can be selected as a pivot candidate if it is not very small
|
alpar@1
|
663 |
* (in absolute value) among other elements in the same row, i.e. if it
|
alpar@1
|
664 |
* satisfies to the stability condition |v[i,j]| >= tol * max|v[i,*]|,
|
alpar@1
|
665 |
* where 0 < tol < 1 is a given tolerance.
|
alpar@1
|
666 |
*
|
alpar@1
|
667 |
* In order to keep sparsity of the matrix V the routine uses Markowitz
|
alpar@1
|
668 |
* strategy, trying to choose such element v[p,q], which satisfies to
|
alpar@1
|
669 |
* the stability condition (see above) and has smallest Markowitz cost
|
alpar@1
|
670 |
* (nr[p]-1) * (nc[q]-1), where nr[p] and nc[q] are numbers of non-zero
|
alpar@1
|
671 |
* elements, respectively, in the p-th row and in the q-th column of the
|
alpar@1
|
672 |
* active submatrix.
|
alpar@1
|
673 |
*
|
alpar@1
|
674 |
* In order to reduce the search, i.e. not to walk through all elements
|
alpar@1
|
675 |
* of the active submatrix, the routine exploits a technique proposed by
|
alpar@1
|
676 |
* I.Duff. This technique is based on using the sets R[len] and C[len]
|
alpar@1
|
677 |
* of active rows and columns.
|
alpar@1
|
678 |
*
|
alpar@1
|
679 |
* If the pivot element v[p,q] has been chosen, the routine stores its
|
alpar@1
|
680 |
* indices to the locations *p and *q and returns zero. Otherwise, if
|
alpar@1
|
681 |
* the active submatrix is empty and therefore the pivot element can't
|
alpar@1
|
682 |
* be chosen, the routine returns non-zero. */
|
alpar@1
|
683 |
|
alpar@1
|
684 |
static int find_pivot(LUF *luf, int *_p, int *_q)
|
alpar@1
|
685 |
{ int n = luf->n;
|
alpar@1
|
686 |
int *vr_ptr = luf->vr_ptr;
|
alpar@1
|
687 |
int *vr_len = luf->vr_len;
|
alpar@1
|
688 |
int *vc_ptr = luf->vc_ptr;
|
alpar@1
|
689 |
int *vc_len = luf->vc_len;
|
alpar@1
|
690 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
691 |
double *sv_val = luf->sv_val;
|
alpar@1
|
692 |
double *vr_max = luf->vr_max;
|
alpar@1
|
693 |
int *rs_head = luf->rs_head;
|
alpar@1
|
694 |
int *rs_next = luf->rs_next;
|
alpar@1
|
695 |
int *cs_head = luf->cs_head;
|
alpar@1
|
696 |
int *cs_prev = luf->cs_prev;
|
alpar@1
|
697 |
int *cs_next = luf->cs_next;
|
alpar@1
|
698 |
double piv_tol = luf->piv_tol;
|
alpar@1
|
699 |
int piv_lim = luf->piv_lim;
|
alpar@1
|
700 |
int suhl = luf->suhl;
|
alpar@1
|
701 |
int p, q, len, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr,
|
alpar@1
|
702 |
ncand, next_j, min_p, min_q, min_len;
|
alpar@1
|
703 |
double best, cost, big, temp;
|
alpar@1
|
704 |
/* initially no pivot candidates have been found so far */
|
alpar@1
|
705 |
p = q = 0, best = DBL_MAX, ncand = 0;
|
alpar@1
|
706 |
/* if in the active submatrix there is a column that has the only
|
alpar@1
|
707 |
non-zero (column singleton), choose it as pivot */
|
alpar@1
|
708 |
j = cs_head[1];
|
alpar@1
|
709 |
if (j != 0)
|
alpar@1
|
710 |
{ xassert(vc_len[j] == 1);
|
alpar@1
|
711 |
p = sv_ind[vc_ptr[j]], q = j;
|
alpar@1
|
712 |
goto done;
|
alpar@1
|
713 |
}
|
alpar@1
|
714 |
/* if in the active submatrix there is a row that has the only
|
alpar@1
|
715 |
non-zero (row singleton), choose it as pivot */
|
alpar@1
|
716 |
i = rs_head[1];
|
alpar@1
|
717 |
if (i != 0)
|
alpar@1
|
718 |
{ xassert(vr_len[i] == 1);
|
alpar@1
|
719 |
p = i, q = sv_ind[vr_ptr[i]];
|
alpar@1
|
720 |
goto done;
|
alpar@1
|
721 |
}
|
alpar@1
|
722 |
/* there are no singletons in the active submatrix; walk through
|
alpar@1
|
723 |
other non-empty rows and columns */
|
alpar@1
|
724 |
for (len = 2; len <= n; len++)
|
alpar@1
|
725 |
{ /* consider active columns that have len non-zeros */
|
alpar@1
|
726 |
for (j = cs_head[len]; j != 0; j = next_j)
|
alpar@1
|
727 |
{ /* the j-th column has len non-zeros */
|
alpar@1
|
728 |
j_beg = vc_ptr[j];
|
alpar@1
|
729 |
j_end = j_beg + vc_len[j] - 1;
|
alpar@1
|
730 |
/* save pointer to the next column with the same length */
|
alpar@1
|
731 |
next_j = cs_next[j];
|
alpar@1
|
732 |
/* find an element in the j-th column, which is placed in a
|
alpar@1
|
733 |
row with minimal number of non-zeros and satisfies to the
|
alpar@1
|
734 |
stability condition (such element may not exist) */
|
alpar@1
|
735 |
min_p = min_q = 0, min_len = INT_MAX;
|
alpar@1
|
736 |
for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
|
alpar@1
|
737 |
{ /* get row index of v[i,j] */
|
alpar@1
|
738 |
i = sv_ind[j_ptr];
|
alpar@1
|
739 |
i_beg = vr_ptr[i];
|
alpar@1
|
740 |
i_end = i_beg + vr_len[i] - 1;
|
alpar@1
|
741 |
/* if the i-th row is not shorter than that one, where
|
alpar@1
|
742 |
minimal element is currently placed, skip v[i,j] */
|
alpar@1
|
743 |
if (vr_len[i] >= min_len) continue;
|
alpar@1
|
744 |
/* determine the largest of absolute values of elements
|
alpar@1
|
745 |
in the i-th row */
|
alpar@1
|
746 |
big = vr_max[i];
|
alpar@1
|
747 |
if (big < 0.0)
|
alpar@1
|
748 |
{ /* the largest value is unknown yet; compute it */
|
alpar@1
|
749 |
for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
|
alpar@1
|
750 |
{ temp = sv_val[i_ptr];
|
alpar@1
|
751 |
if (temp < 0.0) temp = - temp;
|
alpar@1
|
752 |
if (big < temp) big = temp;
|
alpar@1
|
753 |
}
|
alpar@1
|
754 |
vr_max[i] = big;
|
alpar@1
|
755 |
}
|
alpar@1
|
756 |
/* find v[i,j] in the i-th row */
|
alpar@1
|
757 |
for (i_ptr = vr_ptr[i]; sv_ind[i_ptr] != j; i_ptr++);
|
alpar@1
|
758 |
xassert(i_ptr <= i_end);
|
alpar@1
|
759 |
/* if v[i,j] doesn't satisfy to the stability condition,
|
alpar@1
|
760 |
skip it */
|
alpar@1
|
761 |
temp = sv_val[i_ptr];
|
alpar@1
|
762 |
if (temp < 0.0) temp = - temp;
|
alpar@1
|
763 |
if (temp < piv_tol * big) continue;
|
alpar@1
|
764 |
/* v[i,j] is better than the current minimal element */
|
alpar@1
|
765 |
min_p = i, min_q = j, min_len = vr_len[i];
|
alpar@1
|
766 |
/* if Markowitz cost of the current minimal element is
|
alpar@1
|
767 |
not greater than (len-1)**2, it can be chosen right
|
alpar@1
|
768 |
now; this heuristic reduces the search and works well
|
alpar@1
|
769 |
in many cases */
|
alpar@1
|
770 |
if (min_len <= len)
|
alpar@1
|
771 |
{ p = min_p, q = min_q;
|
alpar@1
|
772 |
goto done;
|
alpar@1
|
773 |
}
|
alpar@1
|
774 |
}
|
alpar@1
|
775 |
/* the j-th column has been scanned */
|
alpar@1
|
776 |
if (min_p != 0)
|
alpar@1
|
777 |
{ /* the minimal element is a next pivot candidate */
|
alpar@1
|
778 |
ncand++;
|
alpar@1
|
779 |
/* compute its Markowitz cost */
|
alpar@1
|
780 |
cost = (double)(min_len - 1) * (double)(len - 1);
|
alpar@1
|
781 |
/* choose between the minimal element and the current
|
alpar@1
|
782 |
candidate */
|
alpar@1
|
783 |
if (cost < best) p = min_p, q = min_q, best = cost;
|
alpar@1
|
784 |
/* if piv_lim candidates have been considered, there are
|
alpar@1
|
785 |
doubts that a much better candidate exists; therefore
|
alpar@1
|
786 |
it's time to terminate the search */
|
alpar@1
|
787 |
if (ncand == piv_lim) goto done;
|
alpar@1
|
788 |
}
|
alpar@1
|
789 |
else
|
alpar@1
|
790 |
{ /* the j-th column has no elements, which satisfy to the
|
alpar@1
|
791 |
stability condition; Uwe Suhl suggests to exclude such
|
alpar@1
|
792 |
column from the further consideration until it becomes
|
alpar@1
|
793 |
a column singleton; in hard cases this significantly
|
alpar@1
|
794 |
reduces a time needed for pivot searching */
|
alpar@1
|
795 |
if (suhl)
|
alpar@1
|
796 |
{ /* remove the j-th column from the active set */
|
alpar@1
|
797 |
if (cs_prev[j] == 0)
|
alpar@1
|
798 |
cs_head[len] = cs_next[j];
|
alpar@1
|
799 |
else
|
alpar@1
|
800 |
cs_next[cs_prev[j]] = cs_next[j];
|
alpar@1
|
801 |
if (cs_next[j] == 0)
|
alpar@1
|
802 |
/* nop */;
|
alpar@1
|
803 |
else
|
alpar@1
|
804 |
cs_prev[cs_next[j]] = cs_prev[j];
|
alpar@1
|
805 |
/* the following assignment is used to avoid an error
|
alpar@1
|
806 |
when the routine eliminate (see below) will try to
|
alpar@1
|
807 |
remove the j-th column from the active set */
|
alpar@1
|
808 |
cs_prev[j] = cs_next[j] = j;
|
alpar@1
|
809 |
}
|
alpar@1
|
810 |
}
|
alpar@1
|
811 |
}
|
alpar@1
|
812 |
/* consider active rows that have len non-zeros */
|
alpar@1
|
813 |
for (i = rs_head[len]; i != 0; i = rs_next[i])
|
alpar@1
|
814 |
{ /* the i-th row has len non-zeros */
|
alpar@1
|
815 |
i_beg = vr_ptr[i];
|
alpar@1
|
816 |
i_end = i_beg + vr_len[i] - 1;
|
alpar@1
|
817 |
/* determine the largest of absolute values of elements in
|
alpar@1
|
818 |
the i-th row */
|
alpar@1
|
819 |
big = vr_max[i];
|
alpar@1
|
820 |
if (big < 0.0)
|
alpar@1
|
821 |
{ /* the largest value is unknown yet; compute it */
|
alpar@1
|
822 |
for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
|
alpar@1
|
823 |
{ temp = sv_val[i_ptr];
|
alpar@1
|
824 |
if (temp < 0.0) temp = - temp;
|
alpar@1
|
825 |
if (big < temp) big = temp;
|
alpar@1
|
826 |
}
|
alpar@1
|
827 |
vr_max[i] = big;
|
alpar@1
|
828 |
}
|
alpar@1
|
829 |
/* find an element in the i-th row, which is placed in a
|
alpar@1
|
830 |
column with minimal number of non-zeros and satisfies to
|
alpar@1
|
831 |
the stability condition (such element always exists) */
|
alpar@1
|
832 |
min_p = min_q = 0, min_len = INT_MAX;
|
alpar@1
|
833 |
for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
|
alpar@1
|
834 |
{ /* get column index of v[i,j] */
|
alpar@1
|
835 |
j = sv_ind[i_ptr];
|
alpar@1
|
836 |
/* if the j-th column is not shorter than that one, where
|
alpar@1
|
837 |
minimal element is currently placed, skip v[i,j] */
|
alpar@1
|
838 |
if (vc_len[j] >= min_len) continue;
|
alpar@1
|
839 |
/* if v[i,j] doesn't satisfy to the stability condition,
|
alpar@1
|
840 |
skip it */
|
alpar@1
|
841 |
temp = sv_val[i_ptr];
|
alpar@1
|
842 |
if (temp < 0.0) temp = - temp;
|
alpar@1
|
843 |
if (temp < piv_tol * big) continue;
|
alpar@1
|
844 |
/* v[i,j] is better than the current minimal element */
|
alpar@1
|
845 |
min_p = i, min_q = j, min_len = vc_len[j];
|
alpar@1
|
846 |
/* if Markowitz cost of the current minimal element is
|
alpar@1
|
847 |
not greater than (len-1)**2, it can be chosen right
|
alpar@1
|
848 |
now; this heuristic reduces the search and works well
|
alpar@1
|
849 |
in many cases */
|
alpar@1
|
850 |
if (min_len <= len)
|
alpar@1
|
851 |
{ p = min_p, q = min_q;
|
alpar@1
|
852 |
goto done;
|
alpar@1
|
853 |
}
|
alpar@1
|
854 |
}
|
alpar@1
|
855 |
/* the i-th row has been scanned */
|
alpar@1
|
856 |
if (min_p != 0)
|
alpar@1
|
857 |
{ /* the minimal element is a next pivot candidate */
|
alpar@1
|
858 |
ncand++;
|
alpar@1
|
859 |
/* compute its Markowitz cost */
|
alpar@1
|
860 |
cost = (double)(len - 1) * (double)(min_len - 1);
|
alpar@1
|
861 |
/* choose between the minimal element and the current
|
alpar@1
|
862 |
candidate */
|
alpar@1
|
863 |
if (cost < best) p = min_p, q = min_q, best = cost;
|
alpar@1
|
864 |
/* if piv_lim candidates have been considered, there are
|
alpar@1
|
865 |
doubts that a much better candidate exists; therefore
|
alpar@1
|
866 |
it's time to terminate the search */
|
alpar@1
|
867 |
if (ncand == piv_lim) goto done;
|
alpar@1
|
868 |
}
|
alpar@1
|
869 |
else
|
alpar@1
|
870 |
{ /* this can't be because this can never be */
|
alpar@1
|
871 |
xassert(min_p != min_p);
|
alpar@1
|
872 |
}
|
alpar@1
|
873 |
}
|
alpar@1
|
874 |
}
|
alpar@1
|
875 |
done: /* bring the pivot to the factorizing routine */
|
alpar@1
|
876 |
*_p = p, *_q = q;
|
alpar@1
|
877 |
return (p == 0);
|
alpar@1
|
878 |
}
|
alpar@1
|
879 |
|
alpar@1
|
880 |
/***********************************************************************
|
alpar@1
|
881 |
* eliminate - perform gaussian elimination.
|
alpar@1
|
882 |
*
|
alpar@1
|
883 |
* This routine performs elementary gaussian transformations in order
|
alpar@1
|
884 |
* to eliminate subdiagonal elements in the k-th column of the matrix
|
alpar@1
|
885 |
* U = P*V*Q using the pivot element u[k,k], where k is the number of
|
alpar@1
|
886 |
* the current elimination step.
|
alpar@1
|
887 |
*
|
alpar@1
|
888 |
* The parameters p and q are, respectively, row and column indices of
|
alpar@1
|
889 |
* the element v[p,q], which corresponds to the element u[k,k].
|
alpar@1
|
890 |
*
|
alpar@1
|
891 |
* Each time when the routine applies the elementary transformation to
|
alpar@1
|
892 |
* a non-pivot row of the matrix V, it stores the corresponding element
|
alpar@1
|
893 |
* to the matrix F in order to keep the main equality A = F*V.
|
alpar@1
|
894 |
*
|
alpar@1
|
895 |
* The routine assumes that on entry the matrices L = P*F*inv(P) and
|
alpar@1
|
896 |
* U = P*V*Q are the following:
|
alpar@1
|
897 |
*
|
alpar@1
|
898 |
* 1 k 1 k n
|
alpar@1
|
899 |
* 1 1 . . . . . . . . . 1 x x x x x x x x x x
|
alpar@1
|
900 |
* x 1 . . . . . . . . . x x x x x x x x x
|
alpar@1
|
901 |
* x x 1 . . . . . . . . . x x x x x x x x
|
alpar@1
|
902 |
* x x x 1 . . . . . . . . . x x x x x x x
|
alpar@1
|
903 |
* k x x x x 1 . . . . . k . . . . * * * * * *
|
alpar@1
|
904 |
* x x x x _ 1 . . . . . . . . # * * * * *
|
alpar@1
|
905 |
* x x x x _ . 1 . . . . . . . # * * * * *
|
alpar@1
|
906 |
* x x x x _ . . 1 . . . . . . # * * * * *
|
alpar@1
|
907 |
* x x x x _ . . . 1 . . . . . # * * * * *
|
alpar@1
|
908 |
* n x x x x _ . . . . 1 n . . . . # * * * * *
|
alpar@1
|
909 |
*
|
alpar@1
|
910 |
* matrix L matrix U
|
alpar@1
|
911 |
*
|
alpar@1
|
912 |
* where rows and columns of the matrix U with numbers k, k+1, ..., n
|
alpar@1
|
913 |
* form the active submatrix (eliminated elements are marked by '#' and
|
alpar@1
|
914 |
* other elements of the active submatrix are marked by '*'). Note that
|
alpar@1
|
915 |
* each eliminated non-zero element u[i,k] of the matrix U gives the
|
alpar@1
|
916 |
* corresponding element l[i,k] of the matrix L (marked by '_').
|
alpar@1
|
917 |
*
|
alpar@1
|
918 |
* Actually all operations are performed on the matrix V. Should note
|
alpar@1
|
919 |
* that the row-wise representation corresponds to the matrix V, but the
|
alpar@1
|
920 |
* column-wise representation corresponds to the active submatrix of the
|
alpar@1
|
921 |
* matrix V, i.e. elements of the matrix V, which doesn't belong to the
|
alpar@1
|
922 |
* active submatrix, are missing from the column linked lists.
|
alpar@1
|
923 |
*
|
alpar@1
|
924 |
* Let u[k,k] = v[p,q] be the pivot. In order to eliminate subdiagonal
|
alpar@1
|
925 |
* elements u[i',k] = v[i,q], i' = k+1, k+2, ..., n, the routine applies
|
alpar@1
|
926 |
* the following elementary gaussian transformations:
|
alpar@1
|
927 |
*
|
alpar@1
|
928 |
* (i-th row of V) := (i-th row of V) - f[i,p] * (p-th row of V),
|
alpar@1
|
929 |
*
|
alpar@1
|
930 |
* where f[i,p] = v[i,q] / v[p,q] is a gaussian multiplier.
|
alpar@1
|
931 |
*
|
alpar@1
|
932 |
* Additionally, in order to keep the main equality A = F*V, each time
|
alpar@1
|
933 |
* when the routine applies the transformation to i-th row of the matrix
|
alpar@1
|
934 |
* V, it also adds f[i,p] as a new element to the matrix F.
|
alpar@1
|
935 |
*
|
alpar@1
|
936 |
* IMPORTANT: On entry the working arrays flag and work should contain
|
alpar@1
|
937 |
* zeros. This status is provided by the routine on exit.
|
alpar@1
|
938 |
*
|
alpar@1
|
939 |
* If no error occured, the routine returns zero. Otherwise, in case of
|
alpar@1
|
940 |
* overflow of the sparse vector area, the routine returns non-zero. */
|
alpar@1
|
941 |
|
alpar@1
|
942 |
static int eliminate(LUF *luf, int p, int q)
|
alpar@1
|
943 |
{ int n = luf->n;
|
alpar@1
|
944 |
int *fc_ptr = luf->fc_ptr;
|
alpar@1
|
945 |
int *fc_len = luf->fc_len;
|
alpar@1
|
946 |
int *vr_ptr = luf->vr_ptr;
|
alpar@1
|
947 |
int *vr_len = luf->vr_len;
|
alpar@1
|
948 |
int *vr_cap = luf->vr_cap;
|
alpar@1
|
949 |
double *vr_piv = luf->vr_piv;
|
alpar@1
|
950 |
int *vc_ptr = luf->vc_ptr;
|
alpar@1
|
951 |
int *vc_len = luf->vc_len;
|
alpar@1
|
952 |
int *vc_cap = luf->vc_cap;
|
alpar@1
|
953 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
954 |
double *sv_val = luf->sv_val;
|
alpar@1
|
955 |
int *sv_prev = luf->sv_prev;
|
alpar@1
|
956 |
int *sv_next = luf->sv_next;
|
alpar@1
|
957 |
double *vr_max = luf->vr_max;
|
alpar@1
|
958 |
int *rs_head = luf->rs_head;
|
alpar@1
|
959 |
int *rs_prev = luf->rs_prev;
|
alpar@1
|
960 |
int *rs_next = luf->rs_next;
|
alpar@1
|
961 |
int *cs_head = luf->cs_head;
|
alpar@1
|
962 |
int *cs_prev = luf->cs_prev;
|
alpar@1
|
963 |
int *cs_next = luf->cs_next;
|
alpar@1
|
964 |
int *flag = luf->flag;
|
alpar@1
|
965 |
double *work = luf->work;
|
alpar@1
|
966 |
double eps_tol = luf->eps_tol;
|
alpar@1
|
967 |
/* at this stage the row-wise representation of the matrix F is
|
alpar@1
|
968 |
not used, so fr_len can be used as a working array */
|
alpar@1
|
969 |
int *ndx = luf->fr_len;
|
alpar@1
|
970 |
int ret = 0;
|
alpar@1
|
971 |
int len, fill, i, i_beg, i_end, i_ptr, j, j_beg, j_end, j_ptr, k,
|
alpar@1
|
972 |
p_beg, p_end, p_ptr, q_beg, q_end, q_ptr;
|
alpar@1
|
973 |
double fip, val, vpq, temp;
|
alpar@1
|
974 |
xassert(1 <= p && p <= n);
|
alpar@1
|
975 |
xassert(1 <= q && q <= n);
|
alpar@1
|
976 |
/* remove the p-th (pivot) row from the active set; this row will
|
alpar@1
|
977 |
never return there */
|
alpar@1
|
978 |
if (rs_prev[p] == 0)
|
alpar@1
|
979 |
rs_head[vr_len[p]] = rs_next[p];
|
alpar@1
|
980 |
else
|
alpar@1
|
981 |
rs_next[rs_prev[p]] = rs_next[p];
|
alpar@1
|
982 |
if (rs_next[p] == 0)
|
alpar@1
|
983 |
;
|
alpar@1
|
984 |
else
|
alpar@1
|
985 |
rs_prev[rs_next[p]] = rs_prev[p];
|
alpar@1
|
986 |
/* remove the q-th (pivot) column from the active set; this column
|
alpar@1
|
987 |
will never return there */
|
alpar@1
|
988 |
if (cs_prev[q] == 0)
|
alpar@1
|
989 |
cs_head[vc_len[q]] = cs_next[q];
|
alpar@1
|
990 |
else
|
alpar@1
|
991 |
cs_next[cs_prev[q]] = cs_next[q];
|
alpar@1
|
992 |
if (cs_next[q] == 0)
|
alpar@1
|
993 |
;
|
alpar@1
|
994 |
else
|
alpar@1
|
995 |
cs_prev[cs_next[q]] = cs_prev[q];
|
alpar@1
|
996 |
/* find the pivot v[p,q] = u[k,k] in the p-th row */
|
alpar@1
|
997 |
p_beg = vr_ptr[p];
|
alpar@1
|
998 |
p_end = p_beg + vr_len[p] - 1;
|
alpar@1
|
999 |
for (p_ptr = p_beg; sv_ind[p_ptr] != q; p_ptr++) /* nop */;
|
alpar@1
|
1000 |
xassert(p_ptr <= p_end);
|
alpar@1
|
1001 |
/* store value of the pivot */
|
alpar@1
|
1002 |
vpq = (vr_piv[p] = sv_val[p_ptr]);
|
alpar@1
|
1003 |
/* remove the pivot from the p-th row */
|
alpar@1
|
1004 |
sv_ind[p_ptr] = sv_ind[p_end];
|
alpar@1
|
1005 |
sv_val[p_ptr] = sv_val[p_end];
|
alpar@1
|
1006 |
vr_len[p]--;
|
alpar@1
|
1007 |
p_end--;
|
alpar@1
|
1008 |
/* find the pivot v[p,q] = u[k,k] in the q-th column */
|
alpar@1
|
1009 |
q_beg = vc_ptr[q];
|
alpar@1
|
1010 |
q_end = q_beg + vc_len[q] - 1;
|
alpar@1
|
1011 |
for (q_ptr = q_beg; sv_ind[q_ptr] != p; q_ptr++) /* nop */;
|
alpar@1
|
1012 |
xassert(q_ptr <= q_end);
|
alpar@1
|
1013 |
/* remove the pivot from the q-th column */
|
alpar@1
|
1014 |
sv_ind[q_ptr] = sv_ind[q_end];
|
alpar@1
|
1015 |
vc_len[q]--;
|
alpar@1
|
1016 |
q_end--;
|
alpar@1
|
1017 |
/* walk through the p-th (pivot) row, which doesn't contain the
|
alpar@1
|
1018 |
pivot v[p,q] already, and do the following... */
|
alpar@1
|
1019 |
for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
|
alpar@1
|
1020 |
{ /* get column index of v[p,j] */
|
alpar@1
|
1021 |
j = sv_ind[p_ptr];
|
alpar@1
|
1022 |
/* store v[p,j] to the working array */
|
alpar@1
|
1023 |
flag[j] = 1;
|
alpar@1
|
1024 |
work[j] = sv_val[p_ptr];
|
alpar@1
|
1025 |
/* remove the j-th column from the active set; this column will
|
alpar@1
|
1026 |
return there later with new length */
|
alpar@1
|
1027 |
if (cs_prev[j] == 0)
|
alpar@1
|
1028 |
cs_head[vc_len[j]] = cs_next[j];
|
alpar@1
|
1029 |
else
|
alpar@1
|
1030 |
cs_next[cs_prev[j]] = cs_next[j];
|
alpar@1
|
1031 |
if (cs_next[j] == 0)
|
alpar@1
|
1032 |
;
|
alpar@1
|
1033 |
else
|
alpar@1
|
1034 |
cs_prev[cs_next[j]] = cs_prev[j];
|
alpar@1
|
1035 |
/* find v[p,j] in the j-th column */
|
alpar@1
|
1036 |
j_beg = vc_ptr[j];
|
alpar@1
|
1037 |
j_end = j_beg + vc_len[j] - 1;
|
alpar@1
|
1038 |
for (j_ptr = j_beg; sv_ind[j_ptr] != p; j_ptr++) /* nop */;
|
alpar@1
|
1039 |
xassert(j_ptr <= j_end);
|
alpar@1
|
1040 |
/* since v[p,j] leaves the active submatrix, remove it from the
|
alpar@1
|
1041 |
j-th column; however, v[p,j] is kept in the p-th row */
|
alpar@1
|
1042 |
sv_ind[j_ptr] = sv_ind[j_end];
|
alpar@1
|
1043 |
vc_len[j]--;
|
alpar@1
|
1044 |
}
|
alpar@1
|
1045 |
/* walk through the q-th (pivot) column, which doesn't contain the
|
alpar@1
|
1046 |
pivot v[p,q] already, and perform gaussian elimination */
|
alpar@1
|
1047 |
while (q_beg <= q_end)
|
alpar@1
|
1048 |
{ /* element v[i,q] should be eliminated */
|
alpar@1
|
1049 |
/* get row index of v[i,q] */
|
alpar@1
|
1050 |
i = sv_ind[q_beg];
|
alpar@1
|
1051 |
/* remove the i-th row from the active set; later this row will
|
alpar@1
|
1052 |
return there with new length */
|
alpar@1
|
1053 |
if (rs_prev[i] == 0)
|
alpar@1
|
1054 |
rs_head[vr_len[i]] = rs_next[i];
|
alpar@1
|
1055 |
else
|
alpar@1
|
1056 |
rs_next[rs_prev[i]] = rs_next[i];
|
alpar@1
|
1057 |
if (rs_next[i] == 0)
|
alpar@1
|
1058 |
;
|
alpar@1
|
1059 |
else
|
alpar@1
|
1060 |
rs_prev[rs_next[i]] = rs_prev[i];
|
alpar@1
|
1061 |
/* find v[i,q] in the i-th row */
|
alpar@1
|
1062 |
i_beg = vr_ptr[i];
|
alpar@1
|
1063 |
i_end = i_beg + vr_len[i] - 1;
|
alpar@1
|
1064 |
for (i_ptr = i_beg; sv_ind[i_ptr] != q; i_ptr++) /* nop */;
|
alpar@1
|
1065 |
xassert(i_ptr <= i_end);
|
alpar@1
|
1066 |
/* compute gaussian multiplier f[i,p] = v[i,q] / v[p,q] */
|
alpar@1
|
1067 |
fip = sv_val[i_ptr] / vpq;
|
alpar@1
|
1068 |
/* since v[i,q] should be eliminated, remove it from the i-th
|
alpar@1
|
1069 |
row */
|
alpar@1
|
1070 |
sv_ind[i_ptr] = sv_ind[i_end];
|
alpar@1
|
1071 |
sv_val[i_ptr] = sv_val[i_end];
|
alpar@1
|
1072 |
vr_len[i]--;
|
alpar@1
|
1073 |
i_end--;
|
alpar@1
|
1074 |
/* and from the q-th column */
|
alpar@1
|
1075 |
sv_ind[q_beg] = sv_ind[q_end];
|
alpar@1
|
1076 |
vc_len[q]--;
|
alpar@1
|
1077 |
q_end--;
|
alpar@1
|
1078 |
/* perform gaussian transformation:
|
alpar@1
|
1079 |
(i-th row) := (i-th row) - f[i,p] * (p-th row)
|
alpar@1
|
1080 |
note that now the p-th row, which is in the working array,
|
alpar@1
|
1081 |
doesn't contain the pivot v[p,q], and the i-th row doesn't
|
alpar@1
|
1082 |
contain the eliminated element v[i,q] */
|
alpar@1
|
1083 |
/* walk through the i-th row and transform existing non-zero
|
alpar@1
|
1084 |
elements */
|
alpar@1
|
1085 |
fill = vr_len[p];
|
alpar@1
|
1086 |
for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
|
alpar@1
|
1087 |
{ /* get column index of v[i,j] */
|
alpar@1
|
1088 |
j = sv_ind[i_ptr];
|
alpar@1
|
1089 |
/* v[i,j] := v[i,j] - f[i,p] * v[p,j] */
|
alpar@1
|
1090 |
if (flag[j])
|
alpar@1
|
1091 |
{ /* v[p,j] != 0 */
|
alpar@1
|
1092 |
temp = (sv_val[i_ptr] -= fip * work[j]);
|
alpar@1
|
1093 |
if (temp < 0.0) temp = - temp;
|
alpar@1
|
1094 |
flag[j] = 0;
|
alpar@1
|
1095 |
fill--; /* since both v[i,j] and v[p,j] exist */
|
alpar@1
|
1096 |
if (temp == 0.0 || temp < eps_tol)
|
alpar@1
|
1097 |
{ /* new v[i,j] is closer to zero; replace it by exact
|
alpar@1
|
1098 |
zero, i.e. remove it from the active submatrix */
|
alpar@1
|
1099 |
/* remove v[i,j] from the i-th row */
|
alpar@1
|
1100 |
sv_ind[i_ptr] = sv_ind[i_end];
|
alpar@1
|
1101 |
sv_val[i_ptr] = sv_val[i_end];
|
alpar@1
|
1102 |
vr_len[i]--;
|
alpar@1
|
1103 |
i_ptr--;
|
alpar@1
|
1104 |
i_end--;
|
alpar@1
|
1105 |
/* find v[i,j] in the j-th column */
|
alpar@1
|
1106 |
j_beg = vc_ptr[j];
|
alpar@1
|
1107 |
j_end = j_beg + vc_len[j] - 1;
|
alpar@1
|
1108 |
for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++);
|
alpar@1
|
1109 |
xassert(j_ptr <= j_end);
|
alpar@1
|
1110 |
/* remove v[i,j] from the j-th column */
|
alpar@1
|
1111 |
sv_ind[j_ptr] = sv_ind[j_end];
|
alpar@1
|
1112 |
vc_len[j]--;
|
alpar@1
|
1113 |
}
|
alpar@1
|
1114 |
else
|
alpar@1
|
1115 |
{ /* v_big := max(v_big, |v[i,j]|) */
|
alpar@1
|
1116 |
if (luf->big_v < temp) luf->big_v = temp;
|
alpar@1
|
1117 |
}
|
alpar@1
|
1118 |
}
|
alpar@1
|
1119 |
}
|
alpar@1
|
1120 |
/* now flag is the pattern of the set v[p,*] \ v[i,*], and fill
|
alpar@1
|
1121 |
is number of non-zeros in this set; therefore up to fill new
|
alpar@1
|
1122 |
non-zeros may appear in the i-th row */
|
alpar@1
|
1123 |
if (vr_len[i] + fill > vr_cap[i])
|
alpar@1
|
1124 |
{ /* enlarge the i-th row */
|
alpar@1
|
1125 |
if (luf_enlarge_row(luf, i, vr_len[i] + fill))
|
alpar@1
|
1126 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1127 |
ret = 1;
|
alpar@1
|
1128 |
goto done;
|
alpar@1
|
1129 |
}
|
alpar@1
|
1130 |
/* defragmentation may change row and column pointers of the
|
alpar@1
|
1131 |
matrix V */
|
alpar@1
|
1132 |
p_beg = vr_ptr[p];
|
alpar@1
|
1133 |
p_end = p_beg + vr_len[p] - 1;
|
alpar@1
|
1134 |
q_beg = vc_ptr[q];
|
alpar@1
|
1135 |
q_end = q_beg + vc_len[q] - 1;
|
alpar@1
|
1136 |
}
|
alpar@1
|
1137 |
/* walk through the p-th (pivot) row and create new elements
|
alpar@1
|
1138 |
of the i-th row that appear due to fill-in; column indices
|
alpar@1
|
1139 |
of these new elements are accumulated in the array ndx */
|
alpar@1
|
1140 |
len = 0;
|
alpar@1
|
1141 |
for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
|
alpar@1
|
1142 |
{ /* get column index of v[p,j], which may cause fill-in */
|
alpar@1
|
1143 |
j = sv_ind[p_ptr];
|
alpar@1
|
1144 |
if (flag[j])
|
alpar@1
|
1145 |
{ /* compute new non-zero v[i,j] = 0 - f[i,p] * v[p,j] */
|
alpar@1
|
1146 |
temp = (val = - fip * work[j]);
|
alpar@1
|
1147 |
if (temp < 0.0) temp = - temp;
|
alpar@1
|
1148 |
if (temp == 0.0 || temp < eps_tol)
|
alpar@1
|
1149 |
/* if v[i,j] is closer to zero; just ignore it */;
|
alpar@1
|
1150 |
else
|
alpar@1
|
1151 |
{ /* add v[i,j] to the i-th row */
|
alpar@1
|
1152 |
i_ptr = vr_ptr[i] + vr_len[i];
|
alpar@1
|
1153 |
sv_ind[i_ptr] = j;
|
alpar@1
|
1154 |
sv_val[i_ptr] = val;
|
alpar@1
|
1155 |
vr_len[i]++;
|
alpar@1
|
1156 |
/* remember column index of v[i,j] */
|
alpar@1
|
1157 |
ndx[++len] = j;
|
alpar@1
|
1158 |
/* big_v := max(big_v, |v[i,j]|) */
|
alpar@1
|
1159 |
if (luf->big_v < temp) luf->big_v = temp;
|
alpar@1
|
1160 |
}
|
alpar@1
|
1161 |
}
|
alpar@1
|
1162 |
else
|
alpar@1
|
1163 |
{ /* there is no fill-in, because v[i,j] already exists in
|
alpar@1
|
1164 |
the i-th row; restore the flag of the element v[p,j],
|
alpar@1
|
1165 |
which was reset before */
|
alpar@1
|
1166 |
flag[j] = 1;
|
alpar@1
|
1167 |
}
|
alpar@1
|
1168 |
}
|
alpar@1
|
1169 |
/* add new non-zeros v[i,j] to the corresponding columns */
|
alpar@1
|
1170 |
for (k = 1; k <= len; k++)
|
alpar@1
|
1171 |
{ /* get column index of new non-zero v[i,j] */
|
alpar@1
|
1172 |
j = ndx[k];
|
alpar@1
|
1173 |
/* one free location is needed in the j-th column */
|
alpar@1
|
1174 |
if (vc_len[j] + 1 > vc_cap[j])
|
alpar@1
|
1175 |
{ /* enlarge the j-th column */
|
alpar@1
|
1176 |
if (luf_enlarge_col(luf, j, vc_len[j] + 10))
|
alpar@1
|
1177 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1178 |
ret = 1;
|
alpar@1
|
1179 |
goto done;
|
alpar@1
|
1180 |
}
|
alpar@1
|
1181 |
/* defragmentation may change row and column pointers of
|
alpar@1
|
1182 |
the matrix V */
|
alpar@1
|
1183 |
p_beg = vr_ptr[p];
|
alpar@1
|
1184 |
p_end = p_beg + vr_len[p] - 1;
|
alpar@1
|
1185 |
q_beg = vc_ptr[q];
|
alpar@1
|
1186 |
q_end = q_beg + vc_len[q] - 1;
|
alpar@1
|
1187 |
}
|
alpar@1
|
1188 |
/* add new non-zero v[i,j] to the j-th column */
|
alpar@1
|
1189 |
j_ptr = vc_ptr[j] + vc_len[j];
|
alpar@1
|
1190 |
sv_ind[j_ptr] = i;
|
alpar@1
|
1191 |
vc_len[j]++;
|
alpar@1
|
1192 |
}
|
alpar@1
|
1193 |
/* now the i-th row has been completely transformed, therefore
|
alpar@1
|
1194 |
it can return to the active set with new length */
|
alpar@1
|
1195 |
rs_prev[i] = 0;
|
alpar@1
|
1196 |
rs_next[i] = rs_head[vr_len[i]];
|
alpar@1
|
1197 |
if (rs_next[i] != 0) rs_prev[rs_next[i]] = i;
|
alpar@1
|
1198 |
rs_head[vr_len[i]] = i;
|
alpar@1
|
1199 |
/* the largest of absolute values of elements in the i-th row
|
alpar@1
|
1200 |
is currently unknown */
|
alpar@1
|
1201 |
vr_max[i] = -1.0;
|
alpar@1
|
1202 |
/* at least one free location is needed to store the gaussian
|
alpar@1
|
1203 |
multiplier */
|
alpar@1
|
1204 |
if (luf->sv_end - luf->sv_beg < 1)
|
alpar@1
|
1205 |
{ /* there are no free locations at all; defragment SVA */
|
alpar@1
|
1206 |
luf_defrag_sva(luf);
|
alpar@1
|
1207 |
if (luf->sv_end - luf->sv_beg < 1)
|
alpar@1
|
1208 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1209 |
ret = 1;
|
alpar@1
|
1210 |
goto done;
|
alpar@1
|
1211 |
}
|
alpar@1
|
1212 |
/* defragmentation may change row and column pointers of the
|
alpar@1
|
1213 |
matrix V */
|
alpar@1
|
1214 |
p_beg = vr_ptr[p];
|
alpar@1
|
1215 |
p_end = p_beg + vr_len[p] - 1;
|
alpar@1
|
1216 |
q_beg = vc_ptr[q];
|
alpar@1
|
1217 |
q_end = q_beg + vc_len[q] - 1;
|
alpar@1
|
1218 |
}
|
alpar@1
|
1219 |
/* add the element f[i,p], which is the gaussian multiplier,
|
alpar@1
|
1220 |
to the matrix F */
|
alpar@1
|
1221 |
luf->sv_end--;
|
alpar@1
|
1222 |
sv_ind[luf->sv_end] = i;
|
alpar@1
|
1223 |
sv_val[luf->sv_end] = fip;
|
alpar@1
|
1224 |
fc_len[p]++;
|
alpar@1
|
1225 |
/* end of elimination loop */
|
alpar@1
|
1226 |
}
|
alpar@1
|
1227 |
/* at this point the q-th (pivot) column should be empty */
|
alpar@1
|
1228 |
xassert(vc_len[q] == 0);
|
alpar@1
|
1229 |
/* reset capacity of the q-th column */
|
alpar@1
|
1230 |
vc_cap[q] = 0;
|
alpar@1
|
1231 |
/* remove node of the q-th column from the addressing list */
|
alpar@1
|
1232 |
k = n + q;
|
alpar@1
|
1233 |
if (sv_prev[k] == 0)
|
alpar@1
|
1234 |
luf->sv_head = sv_next[k];
|
alpar@1
|
1235 |
else
|
alpar@1
|
1236 |
sv_next[sv_prev[k]] = sv_next[k];
|
alpar@1
|
1237 |
if (sv_next[k] == 0)
|
alpar@1
|
1238 |
luf->sv_tail = sv_prev[k];
|
alpar@1
|
1239 |
else
|
alpar@1
|
1240 |
sv_prev[sv_next[k]] = sv_prev[k];
|
alpar@1
|
1241 |
/* the p-th column of the matrix F has been completely built; set
|
alpar@1
|
1242 |
its pointer */
|
alpar@1
|
1243 |
fc_ptr[p] = luf->sv_end;
|
alpar@1
|
1244 |
/* walk through the p-th (pivot) row and do the following... */
|
alpar@1
|
1245 |
for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
|
alpar@1
|
1246 |
{ /* get column index of v[p,j] */
|
alpar@1
|
1247 |
j = sv_ind[p_ptr];
|
alpar@1
|
1248 |
/* erase v[p,j] from the working array */
|
alpar@1
|
1249 |
flag[j] = 0;
|
alpar@1
|
1250 |
work[j] = 0.0;
|
alpar@1
|
1251 |
/* the j-th column has been completely transformed, therefore
|
alpar@1
|
1252 |
it can return to the active set with new length; however
|
alpar@1
|
1253 |
the special case c_prev[j] = c_next[j] = j means that the
|
alpar@1
|
1254 |
routine find_pivot excluded the j-th column from the active
|
alpar@1
|
1255 |
set due to Uwe Suhl's rule, and therefore in this case the
|
alpar@1
|
1256 |
column can return to the active set only if it is a column
|
alpar@1
|
1257 |
singleton */
|
alpar@1
|
1258 |
if (!(vc_len[j] != 1 && cs_prev[j] == j && cs_next[j] == j))
|
alpar@1
|
1259 |
{ cs_prev[j] = 0;
|
alpar@1
|
1260 |
cs_next[j] = cs_head[vc_len[j]];
|
alpar@1
|
1261 |
if (cs_next[j] != 0) cs_prev[cs_next[j]] = j;
|
alpar@1
|
1262 |
cs_head[vc_len[j]] = j;
|
alpar@1
|
1263 |
}
|
alpar@1
|
1264 |
}
|
alpar@1
|
1265 |
done: /* return to the factorizing routine */
|
alpar@1
|
1266 |
return ret;
|
alpar@1
|
1267 |
}
|
alpar@1
|
1268 |
|
alpar@1
|
1269 |
/***********************************************************************
|
alpar@1
|
1270 |
* build_v_cols - build the matrix V in column-wise format
|
alpar@1
|
1271 |
*
|
alpar@1
|
1272 |
* This routine builds the column-wise representation of the matrix V
|
alpar@1
|
1273 |
* using its row-wise representation.
|
alpar@1
|
1274 |
*
|
alpar@1
|
1275 |
* If no error occured, the routine returns zero. Otherwise, in case of
|
alpar@1
|
1276 |
* overflow of the sparse vector area, the routine returns non-zero. */
|
alpar@1
|
1277 |
|
alpar@1
|
1278 |
static int build_v_cols(LUF *luf)
|
alpar@1
|
1279 |
{ int n = luf->n;
|
alpar@1
|
1280 |
int *vr_ptr = luf->vr_ptr;
|
alpar@1
|
1281 |
int *vr_len = luf->vr_len;
|
alpar@1
|
1282 |
int *vc_ptr = luf->vc_ptr;
|
alpar@1
|
1283 |
int *vc_len = luf->vc_len;
|
alpar@1
|
1284 |
int *vc_cap = luf->vc_cap;
|
alpar@1
|
1285 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
1286 |
double *sv_val = luf->sv_val;
|
alpar@1
|
1287 |
int *sv_prev = luf->sv_prev;
|
alpar@1
|
1288 |
int *sv_next = luf->sv_next;
|
alpar@1
|
1289 |
int ret = 0;
|
alpar@1
|
1290 |
int i, i_beg, i_end, i_ptr, j, j_ptr, k, nnz;
|
alpar@1
|
1291 |
/* it is assumed that on entry all columns of the matrix V are
|
alpar@1
|
1292 |
empty, i.e. vc_len[j] = vc_cap[j] = 0 for all j = 1, ..., n,
|
alpar@1
|
1293 |
and have been removed from the addressing list */
|
alpar@1
|
1294 |
/* count non-zeros in columns of the matrix V; count total number
|
alpar@1
|
1295 |
of non-zeros in this matrix */
|
alpar@1
|
1296 |
nnz = 0;
|
alpar@1
|
1297 |
for (i = 1; i <= n; i++)
|
alpar@1
|
1298 |
{ /* walk through elements of the i-th row and count non-zeros
|
alpar@1
|
1299 |
in the corresponding columns */
|
alpar@1
|
1300 |
i_beg = vr_ptr[i];
|
alpar@1
|
1301 |
i_end = i_beg + vr_len[i] - 1;
|
alpar@1
|
1302 |
for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
|
alpar@1
|
1303 |
vc_cap[sv_ind[i_ptr]]++;
|
alpar@1
|
1304 |
/* count total number of non-zeros */
|
alpar@1
|
1305 |
nnz += vr_len[i];
|
alpar@1
|
1306 |
}
|
alpar@1
|
1307 |
/* store total number of non-zeros */
|
alpar@1
|
1308 |
luf->nnz_v = nnz;
|
alpar@1
|
1309 |
/* check for free locations */
|
alpar@1
|
1310 |
if (luf->sv_end - luf->sv_beg < nnz)
|
alpar@1
|
1311 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1312 |
ret = 1;
|
alpar@1
|
1313 |
goto done;
|
alpar@1
|
1314 |
}
|
alpar@1
|
1315 |
/* allocate columns of the matrix V */
|
alpar@1
|
1316 |
for (j = 1; j <= n; j++)
|
alpar@1
|
1317 |
{ /* set pointer to the j-th column */
|
alpar@1
|
1318 |
vc_ptr[j] = luf->sv_beg;
|
alpar@1
|
1319 |
/* reserve locations for the j-th column */
|
alpar@1
|
1320 |
luf->sv_beg += vc_cap[j];
|
alpar@1
|
1321 |
}
|
alpar@1
|
1322 |
/* build the matrix V in column-wise format using this matrix in
|
alpar@1
|
1323 |
row-wise format */
|
alpar@1
|
1324 |
for (i = 1; i <= n; i++)
|
alpar@1
|
1325 |
{ /* walk through elements of the i-th row */
|
alpar@1
|
1326 |
i_beg = vr_ptr[i];
|
alpar@1
|
1327 |
i_end = i_beg + vr_len[i] - 1;
|
alpar@1
|
1328 |
for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
|
alpar@1
|
1329 |
{ /* get column index */
|
alpar@1
|
1330 |
j = sv_ind[i_ptr];
|
alpar@1
|
1331 |
/* store element in the j-th column */
|
alpar@1
|
1332 |
j_ptr = vc_ptr[j] + vc_len[j];
|
alpar@1
|
1333 |
sv_ind[j_ptr] = i;
|
alpar@1
|
1334 |
sv_val[j_ptr] = sv_val[i_ptr];
|
alpar@1
|
1335 |
/* increase length of the j-th column */
|
alpar@1
|
1336 |
vc_len[j]++;
|
alpar@1
|
1337 |
}
|
alpar@1
|
1338 |
}
|
alpar@1
|
1339 |
/* now columns are placed in the sparse vector area behind rows
|
alpar@1
|
1340 |
in the order n+1, n+2, ..., n+n; so insert column nodes in the
|
alpar@1
|
1341 |
addressing list using this order */
|
alpar@1
|
1342 |
for (k = n+1; k <= n+n; k++)
|
alpar@1
|
1343 |
{ sv_prev[k] = k-1;
|
alpar@1
|
1344 |
sv_next[k] = k+1;
|
alpar@1
|
1345 |
}
|
alpar@1
|
1346 |
sv_prev[n+1] = luf->sv_tail;
|
alpar@1
|
1347 |
sv_next[luf->sv_tail] = n+1;
|
alpar@1
|
1348 |
sv_next[n+n] = 0;
|
alpar@1
|
1349 |
luf->sv_tail = n+n;
|
alpar@1
|
1350 |
done: /* return to the factorizing routine */
|
alpar@1
|
1351 |
return ret;
|
alpar@1
|
1352 |
}
|
alpar@1
|
1353 |
|
alpar@1
|
1354 |
/***********************************************************************
|
alpar@1
|
1355 |
* build_f_rows - build the matrix F in row-wise format
|
alpar@1
|
1356 |
*
|
alpar@1
|
1357 |
* This routine builds the row-wise representation of the matrix F using
|
alpar@1
|
1358 |
* its column-wise representation.
|
alpar@1
|
1359 |
*
|
alpar@1
|
1360 |
* If no error occured, the routine returns zero. Otherwise, in case of
|
alpar@1
|
1361 |
* overflow of the sparse vector area, the routine returns non-zero. */
|
alpar@1
|
1362 |
|
alpar@1
|
1363 |
static int build_f_rows(LUF *luf)
|
alpar@1
|
1364 |
{ int n = luf->n;
|
alpar@1
|
1365 |
int *fr_ptr = luf->fr_ptr;
|
alpar@1
|
1366 |
int *fr_len = luf->fr_len;
|
alpar@1
|
1367 |
int *fc_ptr = luf->fc_ptr;
|
alpar@1
|
1368 |
int *fc_len = luf->fc_len;
|
alpar@1
|
1369 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
1370 |
double *sv_val = luf->sv_val;
|
alpar@1
|
1371 |
int ret = 0;
|
alpar@1
|
1372 |
int i, j, j_beg, j_end, j_ptr, ptr, nnz;
|
alpar@1
|
1373 |
/* clear rows of the matrix F */
|
alpar@1
|
1374 |
for (i = 1; i <= n; i++) fr_len[i] = 0;
|
alpar@1
|
1375 |
/* count non-zeros in rows of the matrix F; count total number of
|
alpar@1
|
1376 |
non-zeros in this matrix */
|
alpar@1
|
1377 |
nnz = 0;
|
alpar@1
|
1378 |
for (j = 1; j <= n; j++)
|
alpar@1
|
1379 |
{ /* walk through elements of the j-th column and count non-zeros
|
alpar@1
|
1380 |
in the corresponding rows */
|
alpar@1
|
1381 |
j_beg = fc_ptr[j];
|
alpar@1
|
1382 |
j_end = j_beg + fc_len[j] - 1;
|
alpar@1
|
1383 |
for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
|
alpar@1
|
1384 |
fr_len[sv_ind[j_ptr]]++;
|
alpar@1
|
1385 |
/* increase total number of non-zeros */
|
alpar@1
|
1386 |
nnz += fc_len[j];
|
alpar@1
|
1387 |
}
|
alpar@1
|
1388 |
/* store total number of non-zeros */
|
alpar@1
|
1389 |
luf->nnz_f = nnz;
|
alpar@1
|
1390 |
/* check for free locations */
|
alpar@1
|
1391 |
if (luf->sv_end - luf->sv_beg < nnz)
|
alpar@1
|
1392 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1393 |
ret = 1;
|
alpar@1
|
1394 |
goto done;
|
alpar@1
|
1395 |
}
|
alpar@1
|
1396 |
/* allocate rows of the matrix F */
|
alpar@1
|
1397 |
for (i = 1; i <= n; i++)
|
alpar@1
|
1398 |
{ /* set pointer to the end of the i-th row; later this pointer
|
alpar@1
|
1399 |
will be set to the beginning of the i-th row */
|
alpar@1
|
1400 |
fr_ptr[i] = luf->sv_end;
|
alpar@1
|
1401 |
/* reserve locations for the i-th row */
|
alpar@1
|
1402 |
luf->sv_end -= fr_len[i];
|
alpar@1
|
1403 |
}
|
alpar@1
|
1404 |
/* build the matrix F in row-wise format using this matrix in
|
alpar@1
|
1405 |
column-wise format */
|
alpar@1
|
1406 |
for (j = 1; j <= n; j++)
|
alpar@1
|
1407 |
{ /* walk through elements of the j-th column */
|
alpar@1
|
1408 |
j_beg = fc_ptr[j];
|
alpar@1
|
1409 |
j_end = j_beg + fc_len[j] - 1;
|
alpar@1
|
1410 |
for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
|
alpar@1
|
1411 |
{ /* get row index */
|
alpar@1
|
1412 |
i = sv_ind[j_ptr];
|
alpar@1
|
1413 |
/* store element in the i-th row */
|
alpar@1
|
1414 |
ptr = --fr_ptr[i];
|
alpar@1
|
1415 |
sv_ind[ptr] = j;
|
alpar@1
|
1416 |
sv_val[ptr] = sv_val[j_ptr];
|
alpar@1
|
1417 |
}
|
alpar@1
|
1418 |
}
|
alpar@1
|
1419 |
done: /* return to the factorizing routine */
|
alpar@1
|
1420 |
return ret;
|
alpar@1
|
1421 |
}
|
alpar@1
|
1422 |
|
alpar@1
|
1423 |
/***********************************************************************
|
alpar@1
|
1424 |
* NAME
|
alpar@1
|
1425 |
*
|
alpar@1
|
1426 |
* luf_factorize - compute LU-factorization
|
alpar@1
|
1427 |
*
|
alpar@1
|
1428 |
* SYNOPSIS
|
alpar@1
|
1429 |
*
|
alpar@1
|
1430 |
* #include "glpluf.h"
|
alpar@1
|
1431 |
* int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
|
alpar@1
|
1432 |
* int ind[], double val[]), void *info);
|
alpar@1
|
1433 |
*
|
alpar@1
|
1434 |
* DESCRIPTION
|
alpar@1
|
1435 |
*
|
alpar@1
|
1436 |
* The routine luf_factorize computes LU-factorization of a specified
|
alpar@1
|
1437 |
* square matrix A.
|
alpar@1
|
1438 |
*
|
alpar@1
|
1439 |
* The parameter luf specifies LU-factorization program object created
|
alpar@1
|
1440 |
* by the routine luf_create_it.
|
alpar@1
|
1441 |
*
|
alpar@1
|
1442 |
* The parameter n specifies the order of A, n > 0.
|
alpar@1
|
1443 |
*
|
alpar@1
|
1444 |
* The formal routine col specifies the matrix A to be factorized. To
|
alpar@1
|
1445 |
* obtain j-th column of A the routine luf_factorize calls the routine
|
alpar@1
|
1446 |
* col with the parameter j (1 <= j <= n). In response the routine col
|
alpar@1
|
1447 |
* should store row indices and numerical values of non-zero elements
|
alpar@1
|
1448 |
* of j-th column of A to locations ind[1,...,len] and val[1,...,len],
|
alpar@1
|
1449 |
* respectively, where len is the number of non-zeros in j-th column
|
alpar@1
|
1450 |
* returned on exit. Neither zero nor duplicate elements are allowed.
|
alpar@1
|
1451 |
*
|
alpar@1
|
1452 |
* The parameter info is a transit pointer passed to the routine col.
|
alpar@1
|
1453 |
*
|
alpar@1
|
1454 |
* RETURNS
|
alpar@1
|
1455 |
*
|
alpar@1
|
1456 |
* 0 LU-factorization has been successfully computed.
|
alpar@1
|
1457 |
*
|
alpar@1
|
1458 |
* LUF_ESING
|
alpar@1
|
1459 |
* The specified matrix is singular within the working precision.
|
alpar@1
|
1460 |
* (On some elimination step the active submatrix is exactly zero,
|
alpar@1
|
1461 |
* so no pivot can be chosen.)
|
alpar@1
|
1462 |
*
|
alpar@1
|
1463 |
* LUF_ECOND
|
alpar@1
|
1464 |
* The specified matrix is ill-conditioned.
|
alpar@1
|
1465 |
* (On some elimination step too intensive growth of elements of the
|
alpar@1
|
1466 |
* active submatix has been detected.)
|
alpar@1
|
1467 |
*
|
alpar@1
|
1468 |
* If matrix A is well scaled, the return code LUF_ECOND may also mean
|
alpar@1
|
1469 |
* that the threshold pivoting tolerance piv_tol should be increased.
|
alpar@1
|
1470 |
*
|
alpar@1
|
1471 |
* In case of non-zero return code the factorization becomes invalid.
|
alpar@1
|
1472 |
* It should not be used in other operations until the cause of failure
|
alpar@1
|
1473 |
* has been eliminated and the factorization has been recomputed again
|
alpar@1
|
1474 |
* with the routine luf_factorize.
|
alpar@1
|
1475 |
*
|
alpar@1
|
1476 |
* REPAIRING SINGULAR MATRIX
|
alpar@1
|
1477 |
*
|
alpar@1
|
1478 |
* If the routine luf_factorize returns non-zero code, it provides all
|
alpar@1
|
1479 |
* necessary information that can be used for "repairing" the matrix A,
|
alpar@1
|
1480 |
* where "repairing" means replacing linearly dependent columns of the
|
alpar@1
|
1481 |
* matrix A by appropriate columns of the unity matrix. This feature is
|
alpar@1
|
1482 |
* needed when this routine is used for factorizing the basis matrix
|
alpar@1
|
1483 |
* within the simplex method procedure.
|
alpar@1
|
1484 |
*
|
alpar@1
|
1485 |
* On exit linearly dependent columns of the (partially transformed)
|
alpar@1
|
1486 |
* matrix U have numbers rank+1, rank+2, ..., n, where rank is estimated
|
alpar@1
|
1487 |
* rank of the matrix A stored by the routine to the member luf->rank.
|
alpar@1
|
1488 |
* The correspondence between columns of A and U is the same as between
|
alpar@1
|
1489 |
* columns of V and U. Thus, linearly dependent columns of the matrix A
|
alpar@1
|
1490 |
* have numbers qq_col[rank+1], qq_col[rank+2], ..., qq_col[n], where
|
alpar@1
|
1491 |
* qq_col is the column-like representation of the permutation matrix Q.
|
alpar@1
|
1492 |
* It is understood that each j-th linearly dependent column of the
|
alpar@1
|
1493 |
* matrix U should be replaced by the unity vector, where all elements
|
alpar@1
|
1494 |
* are zero except the unity diagonal element u[j,j]. On the other hand
|
alpar@1
|
1495 |
* j-th row of the matrix U corresponds to the row of the matrix V (and
|
alpar@1
|
1496 |
* therefore of the matrix A) with the number pp_row[j], where pp_row is
|
alpar@1
|
1497 |
* the row-like representation of the permutation matrix P. Thus, each
|
alpar@1
|
1498 |
* j-th linearly dependent column of the matrix U should be replaced by
|
alpar@1
|
1499 |
* column of the unity matrix with the number pp_row[j].
|
alpar@1
|
1500 |
*
|
alpar@1
|
1501 |
* The code that repairs the matrix A may look like follows:
|
alpar@1
|
1502 |
*
|
alpar@1
|
1503 |
* for (j = rank+1; j <= n; j++)
|
alpar@1
|
1504 |
* { replace the column qq_col[j] of the matrix A by the column
|
alpar@1
|
1505 |
* pp_row[j] of the unity matrix;
|
alpar@1
|
1506 |
* }
|
alpar@1
|
1507 |
*
|
alpar@1
|
1508 |
* where rank, pp_row, and qq_col are members of the structure LUF. */
|
alpar@1
|
1509 |
|
alpar@1
|
1510 |
int luf_factorize(LUF *luf, int n, int (*col)(void *info, int j,
|
alpar@1
|
1511 |
int ind[], double val[]), void *info)
|
alpar@1
|
1512 |
{ int *pp_row, *pp_col, *qq_row, *qq_col;
|
alpar@1
|
1513 |
double max_gro = luf->max_gro;
|
alpar@1
|
1514 |
int i, j, k, p, q, t, ret;
|
alpar@1
|
1515 |
if (n < 1)
|
alpar@1
|
1516 |
xfault("luf_factorize: n = %d; invalid parameter\n", n);
|
alpar@1
|
1517 |
if (n > N_MAX)
|
alpar@1
|
1518 |
xfault("luf_factorize: n = %d; matrix too big\n", n);
|
alpar@1
|
1519 |
/* invalidate the factorization */
|
alpar@1
|
1520 |
luf->valid = 0;
|
alpar@1
|
1521 |
/* reallocate arrays, if necessary */
|
alpar@1
|
1522 |
reallocate(luf, n);
|
alpar@1
|
1523 |
pp_row = luf->pp_row;
|
alpar@1
|
1524 |
pp_col = luf->pp_col;
|
alpar@1
|
1525 |
qq_row = luf->qq_row;
|
alpar@1
|
1526 |
qq_col = luf->qq_col;
|
alpar@1
|
1527 |
/* estimate initial size of the SVA, if not specified */
|
alpar@1
|
1528 |
if (luf->sv_size == 0 && luf->new_sva == 0)
|
alpar@1
|
1529 |
luf->new_sva = 5 * (n + 10);
|
alpar@1
|
1530 |
more: /* reallocate the sparse vector area, if required */
|
alpar@1
|
1531 |
if (luf->new_sva > 0)
|
alpar@1
|
1532 |
{ if (luf->sv_ind != NULL) xfree(luf->sv_ind);
|
alpar@1
|
1533 |
if (luf->sv_val != NULL) xfree(luf->sv_val);
|
alpar@1
|
1534 |
luf->sv_size = luf->new_sva;
|
alpar@1
|
1535 |
luf->sv_ind = xcalloc(1+luf->sv_size, sizeof(int));
|
alpar@1
|
1536 |
luf->sv_val = xcalloc(1+luf->sv_size, sizeof(double));
|
alpar@1
|
1537 |
luf->new_sva = 0;
|
alpar@1
|
1538 |
}
|
alpar@1
|
1539 |
/* initialize LU-factorization data structures */
|
alpar@1
|
1540 |
if (initialize(luf, col, info))
|
alpar@1
|
1541 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1542 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
1543 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
1544 |
goto more;
|
alpar@1
|
1545 |
}
|
alpar@1
|
1546 |
/* main elimination loop */
|
alpar@1
|
1547 |
for (k = 1; k <= n; k++)
|
alpar@1
|
1548 |
{ /* choose a pivot element v[p,q] */
|
alpar@1
|
1549 |
if (find_pivot(luf, &p, &q))
|
alpar@1
|
1550 |
{ /* no pivot can be chosen, because the active submatrix is
|
alpar@1
|
1551 |
exactly zero */
|
alpar@1
|
1552 |
luf->rank = k - 1;
|
alpar@1
|
1553 |
ret = LUF_ESING;
|
alpar@1
|
1554 |
goto done;
|
alpar@1
|
1555 |
}
|
alpar@1
|
1556 |
/* let v[p,q] correspond to u[i',j']; permute k-th and i'-th
|
alpar@1
|
1557 |
rows and k-th and j'-th columns of the matrix U = P*V*Q to
|
alpar@1
|
1558 |
move the element u[i',j'] to the position u[k,k] */
|
alpar@1
|
1559 |
i = pp_col[p], j = qq_row[q];
|
alpar@1
|
1560 |
xassert(k <= i && i <= n && k <= j && j <= n);
|
alpar@1
|
1561 |
/* permute k-th and i-th rows of the matrix U */
|
alpar@1
|
1562 |
t = pp_row[k];
|
alpar@1
|
1563 |
pp_row[i] = t, pp_col[t] = i;
|
alpar@1
|
1564 |
pp_row[k] = p, pp_col[p] = k;
|
alpar@1
|
1565 |
/* permute k-th and j-th columns of the matrix U */
|
alpar@1
|
1566 |
t = qq_col[k];
|
alpar@1
|
1567 |
qq_col[j] = t, qq_row[t] = j;
|
alpar@1
|
1568 |
qq_col[k] = q, qq_row[q] = k;
|
alpar@1
|
1569 |
/* eliminate subdiagonal elements of k-th column of the matrix
|
alpar@1
|
1570 |
U = P*V*Q using the pivot element u[k,k] = v[p,q] */
|
alpar@1
|
1571 |
if (eliminate(luf, p, q))
|
alpar@1
|
1572 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1573 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
1574 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
1575 |
goto more;
|
alpar@1
|
1576 |
}
|
alpar@1
|
1577 |
/* check relative growth of elements of the matrix V */
|
alpar@1
|
1578 |
if (luf->big_v > max_gro * luf->max_a)
|
alpar@1
|
1579 |
{ /* the growth is too intensive, therefore most probably the
|
alpar@1
|
1580 |
matrix A is ill-conditioned */
|
alpar@1
|
1581 |
luf->rank = k - 1;
|
alpar@1
|
1582 |
ret = LUF_ECOND;
|
alpar@1
|
1583 |
goto done;
|
alpar@1
|
1584 |
}
|
alpar@1
|
1585 |
}
|
alpar@1
|
1586 |
/* now the matrix U = P*V*Q is upper triangular, the matrix V has
|
alpar@1
|
1587 |
been built in row-wise format, and the matrix F has been built
|
alpar@1
|
1588 |
in column-wise format */
|
alpar@1
|
1589 |
/* defragment the sparse vector area in order to merge all free
|
alpar@1
|
1590 |
locations in one continuous extent */
|
alpar@1
|
1591 |
luf_defrag_sva(luf);
|
alpar@1
|
1592 |
/* build the matrix V in column-wise format */
|
alpar@1
|
1593 |
if (build_v_cols(luf))
|
alpar@1
|
1594 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1595 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
1596 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
1597 |
goto more;
|
alpar@1
|
1598 |
}
|
alpar@1
|
1599 |
/* build the matrix F in row-wise format */
|
alpar@1
|
1600 |
if (build_f_rows(luf))
|
alpar@1
|
1601 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
1602 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
1603 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
1604 |
goto more;
|
alpar@1
|
1605 |
}
|
alpar@1
|
1606 |
/* the LU-factorization has been successfully computed */
|
alpar@1
|
1607 |
luf->valid = 1;
|
alpar@1
|
1608 |
luf->rank = n;
|
alpar@1
|
1609 |
ret = 0;
|
alpar@1
|
1610 |
/* if there are few free locations in the sparse vector area, try
|
alpar@1
|
1611 |
increasing its size in the future */
|
alpar@1
|
1612 |
t = 3 * (n + luf->nnz_v) + 2 * luf->nnz_f;
|
alpar@1
|
1613 |
if (luf->sv_size < t)
|
alpar@1
|
1614 |
{ luf->new_sva = luf->sv_size;
|
alpar@1
|
1615 |
while (luf->new_sva < t)
|
alpar@1
|
1616 |
{ k = luf->new_sva;
|
alpar@1
|
1617 |
luf->new_sva = k + k;
|
alpar@1
|
1618 |
xassert(luf->new_sva > k);
|
alpar@1
|
1619 |
}
|
alpar@1
|
1620 |
}
|
alpar@1
|
1621 |
done: /* return to the calling program */
|
alpar@1
|
1622 |
return ret;
|
alpar@1
|
1623 |
}
|
alpar@1
|
1624 |
|
alpar@1
|
1625 |
/***********************************************************************
|
alpar@1
|
1626 |
* NAME
|
alpar@1
|
1627 |
*
|
alpar@1
|
1628 |
* luf_f_solve - solve system F*x = b or F'*x = b
|
alpar@1
|
1629 |
*
|
alpar@1
|
1630 |
* SYNOPSIS
|
alpar@1
|
1631 |
*
|
alpar@1
|
1632 |
* #include "glpluf.h"
|
alpar@1
|
1633 |
* void luf_f_solve(LUF *luf, int tr, double x[]);
|
alpar@1
|
1634 |
*
|
alpar@1
|
1635 |
* DESCRIPTION
|
alpar@1
|
1636 |
*
|
alpar@1
|
1637 |
* The routine luf_f_solve solves either the system F*x = b (if the
|
alpar@1
|
1638 |
* flag tr is zero) or the system F'*x = b (if the flag tr is non-zero),
|
alpar@1
|
1639 |
* where the matrix F is a component of LU-factorization specified by
|
alpar@1
|
1640 |
* the parameter luf, F' is a matrix transposed to F.
|
alpar@1
|
1641 |
*
|
alpar@1
|
1642 |
* On entry the array x should contain elements of the right-hand side
|
alpar@1
|
1643 |
* vector b in locations x[1], ..., x[n], where n is the order of the
|
alpar@1
|
1644 |
* matrix F. On exit this array will contain elements of the solution
|
alpar@1
|
1645 |
* vector x in the same locations. */
|
alpar@1
|
1646 |
|
alpar@1
|
1647 |
void luf_f_solve(LUF *luf, int tr, double x[])
|
alpar@1
|
1648 |
{ int n = luf->n;
|
alpar@1
|
1649 |
int *fr_ptr = luf->fr_ptr;
|
alpar@1
|
1650 |
int *fr_len = luf->fr_len;
|
alpar@1
|
1651 |
int *fc_ptr = luf->fc_ptr;
|
alpar@1
|
1652 |
int *fc_len = luf->fc_len;
|
alpar@1
|
1653 |
int *pp_row = luf->pp_row;
|
alpar@1
|
1654 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
1655 |
double *sv_val = luf->sv_val;
|
alpar@1
|
1656 |
int i, j, k, beg, end, ptr;
|
alpar@1
|
1657 |
double xk;
|
alpar@1
|
1658 |
if (!luf->valid)
|
alpar@1
|
1659 |
xfault("luf_f_solve: LU-factorization is not valid\n");
|
alpar@1
|
1660 |
if (!tr)
|
alpar@1
|
1661 |
{ /* solve the system F*x = b */
|
alpar@1
|
1662 |
for (j = 1; j <= n; j++)
|
alpar@1
|
1663 |
{ k = pp_row[j];
|
alpar@1
|
1664 |
xk = x[k];
|
alpar@1
|
1665 |
if (xk != 0.0)
|
alpar@1
|
1666 |
{ beg = fc_ptr[k];
|
alpar@1
|
1667 |
end = beg + fc_len[k] - 1;
|
alpar@1
|
1668 |
for (ptr = beg; ptr <= end; ptr++)
|
alpar@1
|
1669 |
x[sv_ind[ptr]] -= sv_val[ptr] * xk;
|
alpar@1
|
1670 |
}
|
alpar@1
|
1671 |
}
|
alpar@1
|
1672 |
}
|
alpar@1
|
1673 |
else
|
alpar@1
|
1674 |
{ /* solve the system F'*x = b */
|
alpar@1
|
1675 |
for (i = n; i >= 1; i--)
|
alpar@1
|
1676 |
{ k = pp_row[i];
|
alpar@1
|
1677 |
xk = x[k];
|
alpar@1
|
1678 |
if (xk != 0.0)
|
alpar@1
|
1679 |
{ beg = fr_ptr[k];
|
alpar@1
|
1680 |
end = beg + fr_len[k] - 1;
|
alpar@1
|
1681 |
for (ptr = beg; ptr <= end; ptr++)
|
alpar@1
|
1682 |
x[sv_ind[ptr]] -= sv_val[ptr] * xk;
|
alpar@1
|
1683 |
}
|
alpar@1
|
1684 |
}
|
alpar@1
|
1685 |
}
|
alpar@1
|
1686 |
return;
|
alpar@1
|
1687 |
}
|
alpar@1
|
1688 |
|
alpar@1
|
1689 |
/***********************************************************************
|
alpar@1
|
1690 |
* NAME
|
alpar@1
|
1691 |
*
|
alpar@1
|
1692 |
* luf_v_solve - solve system V*x = b or V'*x = b
|
alpar@1
|
1693 |
*
|
alpar@1
|
1694 |
* SYNOPSIS
|
alpar@1
|
1695 |
*
|
alpar@1
|
1696 |
* #include "glpluf.h"
|
alpar@1
|
1697 |
* void luf_v_solve(LUF *luf, int tr, double x[]);
|
alpar@1
|
1698 |
*
|
alpar@1
|
1699 |
* DESCRIPTION
|
alpar@1
|
1700 |
*
|
alpar@1
|
1701 |
* The routine luf_v_solve solves either the system V*x = b (if the
|
alpar@1
|
1702 |
* flag tr is zero) or the system V'*x = b (if the flag tr is non-zero),
|
alpar@1
|
1703 |
* where the matrix V is a component of LU-factorization specified by
|
alpar@1
|
1704 |
* the parameter luf, V' is a matrix transposed to V.
|
alpar@1
|
1705 |
*
|
alpar@1
|
1706 |
* On entry the array x should contain elements of the right-hand side
|
alpar@1
|
1707 |
* vector b in locations x[1], ..., x[n], where n is the order of the
|
alpar@1
|
1708 |
* matrix V. On exit this array will contain elements of the solution
|
alpar@1
|
1709 |
* vector x in the same locations. */
|
alpar@1
|
1710 |
|
alpar@1
|
1711 |
void luf_v_solve(LUF *luf, int tr, double x[])
|
alpar@1
|
1712 |
{ int n = luf->n;
|
alpar@1
|
1713 |
int *vr_ptr = luf->vr_ptr;
|
alpar@1
|
1714 |
int *vr_len = luf->vr_len;
|
alpar@1
|
1715 |
double *vr_piv = luf->vr_piv;
|
alpar@1
|
1716 |
int *vc_ptr = luf->vc_ptr;
|
alpar@1
|
1717 |
int *vc_len = luf->vc_len;
|
alpar@1
|
1718 |
int *pp_row = luf->pp_row;
|
alpar@1
|
1719 |
int *qq_col = luf->qq_col;
|
alpar@1
|
1720 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
1721 |
double *sv_val = luf->sv_val;
|
alpar@1
|
1722 |
double *b = luf->work;
|
alpar@1
|
1723 |
int i, j, k, beg, end, ptr;
|
alpar@1
|
1724 |
double temp;
|
alpar@1
|
1725 |
if (!luf->valid)
|
alpar@1
|
1726 |
xfault("luf_v_solve: LU-factorization is not valid\n");
|
alpar@1
|
1727 |
for (k = 1; k <= n; k++) b[k] = x[k], x[k] = 0.0;
|
alpar@1
|
1728 |
if (!tr)
|
alpar@1
|
1729 |
{ /* solve the system V*x = b */
|
alpar@1
|
1730 |
for (k = n; k >= 1; k--)
|
alpar@1
|
1731 |
{ i = pp_row[k], j = qq_col[k];
|
alpar@1
|
1732 |
temp = b[i];
|
alpar@1
|
1733 |
if (temp != 0.0)
|
alpar@1
|
1734 |
{ x[j] = (temp /= vr_piv[i]);
|
alpar@1
|
1735 |
beg = vc_ptr[j];
|
alpar@1
|
1736 |
end = beg + vc_len[j] - 1;
|
alpar@1
|
1737 |
for (ptr = beg; ptr <= end; ptr++)
|
alpar@1
|
1738 |
b[sv_ind[ptr]] -= sv_val[ptr] * temp;
|
alpar@1
|
1739 |
}
|
alpar@1
|
1740 |
}
|
alpar@1
|
1741 |
}
|
alpar@1
|
1742 |
else
|
alpar@1
|
1743 |
{ /* solve the system V'*x = b */
|
alpar@1
|
1744 |
for (k = 1; k <= n; k++)
|
alpar@1
|
1745 |
{ i = pp_row[k], j = qq_col[k];
|
alpar@1
|
1746 |
temp = b[j];
|
alpar@1
|
1747 |
if (temp != 0.0)
|
alpar@1
|
1748 |
{ x[i] = (temp /= vr_piv[i]);
|
alpar@1
|
1749 |
beg = vr_ptr[i];
|
alpar@1
|
1750 |
end = beg + vr_len[i] - 1;
|
alpar@1
|
1751 |
for (ptr = beg; ptr <= end; ptr++)
|
alpar@1
|
1752 |
b[sv_ind[ptr]] -= sv_val[ptr] * temp;
|
alpar@1
|
1753 |
}
|
alpar@1
|
1754 |
}
|
alpar@1
|
1755 |
}
|
alpar@1
|
1756 |
return;
|
alpar@1
|
1757 |
}
|
alpar@1
|
1758 |
|
alpar@1
|
1759 |
/***********************************************************************
|
alpar@1
|
1760 |
* NAME
|
alpar@1
|
1761 |
*
|
alpar@1
|
1762 |
* luf_a_solve - solve system A*x = b or A'*x = b
|
alpar@1
|
1763 |
*
|
alpar@1
|
1764 |
* SYNOPSIS
|
alpar@1
|
1765 |
*
|
alpar@1
|
1766 |
* #include "glpluf.h"
|
alpar@1
|
1767 |
* void luf_a_solve(LUF *luf, int tr, double x[]);
|
alpar@1
|
1768 |
*
|
alpar@1
|
1769 |
* DESCRIPTION
|
alpar@1
|
1770 |
*
|
alpar@1
|
1771 |
* The routine luf_a_solve solves either the system A*x = b (if the
|
alpar@1
|
1772 |
* flag tr is zero) or the system A'*x = b (if the flag tr is non-zero),
|
alpar@1
|
1773 |
* where the parameter luf specifies LU-factorization of the matrix A,
|
alpar@1
|
1774 |
* A' is a matrix transposed to A.
|
alpar@1
|
1775 |
*
|
alpar@1
|
1776 |
* On entry the array x should contain elements of the right-hand side
|
alpar@1
|
1777 |
* vector b in locations x[1], ..., x[n], where n is the order of the
|
alpar@1
|
1778 |
* matrix A. On exit this array will contain elements of the solution
|
alpar@1
|
1779 |
* vector x in the same locations. */
|
alpar@1
|
1780 |
|
alpar@1
|
1781 |
void luf_a_solve(LUF *luf, int tr, double x[])
|
alpar@1
|
1782 |
{ if (!luf->valid)
|
alpar@1
|
1783 |
xfault("luf_a_solve: LU-factorization is not valid\n");
|
alpar@1
|
1784 |
if (!tr)
|
alpar@1
|
1785 |
{ /* A = F*V, therefore inv(A) = inv(V)*inv(F) */
|
alpar@1
|
1786 |
luf_f_solve(luf, 0, x);
|
alpar@1
|
1787 |
luf_v_solve(luf, 0, x);
|
alpar@1
|
1788 |
}
|
alpar@1
|
1789 |
else
|
alpar@1
|
1790 |
{ /* A' = V'*F', therefore inv(A') = inv(F')*inv(V') */
|
alpar@1
|
1791 |
luf_v_solve(luf, 1, x);
|
alpar@1
|
1792 |
luf_f_solve(luf, 1, x);
|
alpar@1
|
1793 |
}
|
alpar@1
|
1794 |
return;
|
alpar@1
|
1795 |
}
|
alpar@1
|
1796 |
|
alpar@1
|
1797 |
/***********************************************************************
|
alpar@1
|
1798 |
* NAME
|
alpar@1
|
1799 |
*
|
alpar@1
|
1800 |
* luf_delete_it - delete LU-factorization
|
alpar@1
|
1801 |
*
|
alpar@1
|
1802 |
* SYNOPSIS
|
alpar@1
|
1803 |
*
|
alpar@1
|
1804 |
* #include "glpluf.h"
|
alpar@1
|
1805 |
* void luf_delete_it(LUF *luf);
|
alpar@1
|
1806 |
*
|
alpar@1
|
1807 |
* DESCRIPTION
|
alpar@1
|
1808 |
*
|
alpar@1
|
1809 |
* The routine luf_delete deletes LU-factorization specified by the
|
alpar@1
|
1810 |
* parameter luf and frees all the memory allocated to this program
|
alpar@1
|
1811 |
* object. */
|
alpar@1
|
1812 |
|
alpar@1
|
1813 |
void luf_delete_it(LUF *luf)
|
alpar@1
|
1814 |
{ if (luf->fr_ptr != NULL) xfree(luf->fr_ptr);
|
alpar@1
|
1815 |
if (luf->fr_len != NULL) xfree(luf->fr_len);
|
alpar@1
|
1816 |
if (luf->fc_ptr != NULL) xfree(luf->fc_ptr);
|
alpar@1
|
1817 |
if (luf->fc_len != NULL) xfree(luf->fc_len);
|
alpar@1
|
1818 |
if (luf->vr_ptr != NULL) xfree(luf->vr_ptr);
|
alpar@1
|
1819 |
if (luf->vr_len != NULL) xfree(luf->vr_len);
|
alpar@1
|
1820 |
if (luf->vr_cap != NULL) xfree(luf->vr_cap);
|
alpar@1
|
1821 |
if (luf->vr_piv != NULL) xfree(luf->vr_piv);
|
alpar@1
|
1822 |
if (luf->vc_ptr != NULL) xfree(luf->vc_ptr);
|
alpar@1
|
1823 |
if (luf->vc_len != NULL) xfree(luf->vc_len);
|
alpar@1
|
1824 |
if (luf->vc_cap != NULL) xfree(luf->vc_cap);
|
alpar@1
|
1825 |
if (luf->pp_row != NULL) xfree(luf->pp_row);
|
alpar@1
|
1826 |
if (luf->pp_col != NULL) xfree(luf->pp_col);
|
alpar@1
|
1827 |
if (luf->qq_row != NULL) xfree(luf->qq_row);
|
alpar@1
|
1828 |
if (luf->qq_col != NULL) xfree(luf->qq_col);
|
alpar@1
|
1829 |
if (luf->sv_ind != NULL) xfree(luf->sv_ind);
|
alpar@1
|
1830 |
if (luf->sv_val != NULL) xfree(luf->sv_val);
|
alpar@1
|
1831 |
if (luf->sv_prev != NULL) xfree(luf->sv_prev);
|
alpar@1
|
1832 |
if (luf->sv_next != NULL) xfree(luf->sv_next);
|
alpar@1
|
1833 |
if (luf->vr_max != NULL) xfree(luf->vr_max);
|
alpar@1
|
1834 |
if (luf->rs_head != NULL) xfree(luf->rs_head);
|
alpar@1
|
1835 |
if (luf->rs_prev != NULL) xfree(luf->rs_prev);
|
alpar@1
|
1836 |
if (luf->rs_next != NULL) xfree(luf->rs_next);
|
alpar@1
|
1837 |
if (luf->cs_head != NULL) xfree(luf->cs_head);
|
alpar@1
|
1838 |
if (luf->cs_prev != NULL) xfree(luf->cs_prev);
|
alpar@1
|
1839 |
if (luf->cs_next != NULL) xfree(luf->cs_next);
|
alpar@1
|
1840 |
if (luf->flag != NULL) xfree(luf->flag);
|
alpar@1
|
1841 |
if (luf->work != NULL) xfree(luf->work);
|
alpar@1
|
1842 |
xfree(luf);
|
alpar@1
|
1843 |
return;
|
alpar@1
|
1844 |
}
|
alpar@1
|
1845 |
|
alpar@1
|
1846 |
/* eof */
|