alpar@1
|
1 |
/* glpfhv.c (LP basis factorization, FHV eta file version) */
|
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 "glpfhv.h"
|
alpar@1
|
26 |
#include "glpenv.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 M_MAX 100000000 /* = 100*10^6 */
|
alpar@1
|
32 |
/* maximal order of the basis matrix */
|
alpar@1
|
33 |
|
alpar@1
|
34 |
/***********************************************************************
|
alpar@1
|
35 |
* NAME
|
alpar@1
|
36 |
*
|
alpar@1
|
37 |
* fhv_create_it - create LP basis factorization
|
alpar@1
|
38 |
*
|
alpar@1
|
39 |
* SYNOPSIS
|
alpar@1
|
40 |
*
|
alpar@1
|
41 |
* #include "glpfhv.h"
|
alpar@1
|
42 |
* FHV *fhv_create_it(void);
|
alpar@1
|
43 |
*
|
alpar@1
|
44 |
* DESCRIPTION
|
alpar@1
|
45 |
*
|
alpar@1
|
46 |
* The routine fhv_create_it creates a program object, which represents
|
alpar@1
|
47 |
* a factorization of LP basis.
|
alpar@1
|
48 |
*
|
alpar@1
|
49 |
* RETURNS
|
alpar@1
|
50 |
*
|
alpar@1
|
51 |
* The routine fhv_create_it returns a pointer to the object created. */
|
alpar@1
|
52 |
|
alpar@1
|
53 |
FHV *fhv_create_it(void)
|
alpar@1
|
54 |
{ FHV *fhv;
|
alpar@1
|
55 |
fhv = xmalloc(sizeof(FHV));
|
alpar@1
|
56 |
fhv->m_max = fhv->m = 0;
|
alpar@1
|
57 |
fhv->valid = 0;
|
alpar@1
|
58 |
fhv->luf = luf_create_it();
|
alpar@1
|
59 |
fhv->hh_max = 50;
|
alpar@1
|
60 |
fhv->hh_nfs = 0;
|
alpar@1
|
61 |
fhv->hh_ind = fhv->hh_ptr = fhv->hh_len = NULL;
|
alpar@1
|
62 |
fhv->p0_row = fhv->p0_col = NULL;
|
alpar@1
|
63 |
fhv->cc_ind = NULL;
|
alpar@1
|
64 |
fhv->cc_val = NULL;
|
alpar@1
|
65 |
fhv->upd_tol = 1e-6;
|
alpar@1
|
66 |
fhv->nnz_h = 0;
|
alpar@1
|
67 |
return fhv;
|
alpar@1
|
68 |
}
|
alpar@1
|
69 |
|
alpar@1
|
70 |
/***********************************************************************
|
alpar@1
|
71 |
* NAME
|
alpar@1
|
72 |
*
|
alpar@1
|
73 |
* fhv_factorize - compute LP basis factorization
|
alpar@1
|
74 |
*
|
alpar@1
|
75 |
* SYNOPSIS
|
alpar@1
|
76 |
*
|
alpar@1
|
77 |
* #include "glpfhv.h"
|
alpar@1
|
78 |
* int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
|
alpar@1
|
79 |
* int ind[], double val[]), void *info);
|
alpar@1
|
80 |
*
|
alpar@1
|
81 |
* DESCRIPTION
|
alpar@1
|
82 |
*
|
alpar@1
|
83 |
* The routine fhv_factorize computes the factorization of the basis
|
alpar@1
|
84 |
* matrix B specified by the routine col.
|
alpar@1
|
85 |
*
|
alpar@1
|
86 |
* The parameter fhv specified the basis factorization data structure
|
alpar@1
|
87 |
* created by the routine fhv_create_it.
|
alpar@1
|
88 |
*
|
alpar@1
|
89 |
* The parameter m specifies the order of B, m > 0.
|
alpar@1
|
90 |
*
|
alpar@1
|
91 |
* The formal routine col specifies the matrix B to be factorized. To
|
alpar@1
|
92 |
* obtain j-th column of A the routine fhv_factorize calls the routine
|
alpar@1
|
93 |
* col with the parameter j (1 <= j <= n). In response the routine col
|
alpar@1
|
94 |
* should store row indices and numerical values of non-zero elements
|
alpar@1
|
95 |
* of j-th column of B to locations ind[1,...,len] and val[1,...,len],
|
alpar@1
|
96 |
* respectively, where len is the number of non-zeros in j-th column
|
alpar@1
|
97 |
* returned on exit. Neither zero nor duplicate elements are allowed.
|
alpar@1
|
98 |
*
|
alpar@1
|
99 |
* The parameter info is a transit pointer passed to the routine col.
|
alpar@1
|
100 |
*
|
alpar@1
|
101 |
* RETURNS
|
alpar@1
|
102 |
*
|
alpar@1
|
103 |
* 0 The factorization has been successfully computed.
|
alpar@1
|
104 |
*
|
alpar@1
|
105 |
* FHV_ESING
|
alpar@1
|
106 |
* The specified matrix is singular within the working precision.
|
alpar@1
|
107 |
*
|
alpar@1
|
108 |
* FHV_ECOND
|
alpar@1
|
109 |
* The specified matrix is ill-conditioned.
|
alpar@1
|
110 |
*
|
alpar@1
|
111 |
* For more details see comments to the routine luf_factorize.
|
alpar@1
|
112 |
*
|
alpar@1
|
113 |
* ALGORITHM
|
alpar@1
|
114 |
*
|
alpar@1
|
115 |
* The routine fhv_factorize calls the routine luf_factorize (see the
|
alpar@1
|
116 |
* module GLPLUF), which actually computes LU-factorization of the basis
|
alpar@1
|
117 |
* matrix B in the form
|
alpar@1
|
118 |
*
|
alpar@1
|
119 |
* [B] = (F, V, P, Q),
|
alpar@1
|
120 |
*
|
alpar@1
|
121 |
* where F and V are such matrices that
|
alpar@1
|
122 |
*
|
alpar@1
|
123 |
* B = F * V,
|
alpar@1
|
124 |
*
|
alpar@1
|
125 |
* and P and Q are such permutation matrices that the matrix
|
alpar@1
|
126 |
*
|
alpar@1
|
127 |
* L = P * F * inv(P)
|
alpar@1
|
128 |
*
|
alpar@1
|
129 |
* is lower triangular with unity diagonal, and the matrix
|
alpar@1
|
130 |
*
|
alpar@1
|
131 |
* U = P * V * Q
|
alpar@1
|
132 |
*
|
alpar@1
|
133 |
* is upper triangular.
|
alpar@1
|
134 |
*
|
alpar@1
|
135 |
* In order to build the complete representation of the factorization
|
alpar@1
|
136 |
* (see formula (1) in the file glpfhv.h) the routine fhv_factorize just
|
alpar@1
|
137 |
* additionally sets H = I and P0 = P. */
|
alpar@1
|
138 |
|
alpar@1
|
139 |
int fhv_factorize(FHV *fhv, int m, int (*col)(void *info, int j,
|
alpar@1
|
140 |
int ind[], double val[]), void *info)
|
alpar@1
|
141 |
{ int ret;
|
alpar@1
|
142 |
if (m < 1)
|
alpar@1
|
143 |
xfault("fhv_factorize: m = %d; invalid parameter\n", m);
|
alpar@1
|
144 |
if (m > M_MAX)
|
alpar@1
|
145 |
xfault("fhv_factorize: m = %d; matrix too big\n", m);
|
alpar@1
|
146 |
fhv->m = m;
|
alpar@1
|
147 |
/* invalidate the factorization */
|
alpar@1
|
148 |
fhv->valid = 0;
|
alpar@1
|
149 |
/* allocate/reallocate arrays, if necessary */
|
alpar@1
|
150 |
if (fhv->hh_ind == NULL)
|
alpar@1
|
151 |
fhv->hh_ind = xcalloc(1+fhv->hh_max, sizeof(int));
|
alpar@1
|
152 |
if (fhv->hh_ptr == NULL)
|
alpar@1
|
153 |
fhv->hh_ptr = xcalloc(1+fhv->hh_max, sizeof(int));
|
alpar@1
|
154 |
if (fhv->hh_len == NULL)
|
alpar@1
|
155 |
fhv->hh_len = xcalloc(1+fhv->hh_max, sizeof(int));
|
alpar@1
|
156 |
if (fhv->m_max < m)
|
alpar@1
|
157 |
{ if (fhv->p0_row != NULL) xfree(fhv->p0_row);
|
alpar@1
|
158 |
if (fhv->p0_col != NULL) xfree(fhv->p0_col);
|
alpar@1
|
159 |
if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
|
alpar@1
|
160 |
if (fhv->cc_val != NULL) xfree(fhv->cc_val);
|
alpar@1
|
161 |
fhv->m_max = m + 100;
|
alpar@1
|
162 |
fhv->p0_row = xcalloc(1+fhv->m_max, sizeof(int));
|
alpar@1
|
163 |
fhv->p0_col = xcalloc(1+fhv->m_max, sizeof(int));
|
alpar@1
|
164 |
fhv->cc_ind = xcalloc(1+fhv->m_max, sizeof(int));
|
alpar@1
|
165 |
fhv->cc_val = xcalloc(1+fhv->m_max, sizeof(double));
|
alpar@1
|
166 |
}
|
alpar@1
|
167 |
/* try to factorize the basis matrix */
|
alpar@1
|
168 |
switch (luf_factorize(fhv->luf, m, col, info))
|
alpar@1
|
169 |
{ case 0:
|
alpar@1
|
170 |
break;
|
alpar@1
|
171 |
case LUF_ESING:
|
alpar@1
|
172 |
ret = FHV_ESING;
|
alpar@1
|
173 |
goto done;
|
alpar@1
|
174 |
case LUF_ECOND:
|
alpar@1
|
175 |
ret = FHV_ECOND;
|
alpar@1
|
176 |
goto done;
|
alpar@1
|
177 |
default:
|
alpar@1
|
178 |
xassert(fhv != fhv);
|
alpar@1
|
179 |
}
|
alpar@1
|
180 |
/* the basis matrix has been successfully factorized */
|
alpar@1
|
181 |
fhv->valid = 1;
|
alpar@1
|
182 |
/* H := I */
|
alpar@1
|
183 |
fhv->hh_nfs = 0;
|
alpar@1
|
184 |
/* P0 := P */
|
alpar@1
|
185 |
memcpy(&fhv->p0_row[1], &fhv->luf->pp_row[1], sizeof(int) * m);
|
alpar@1
|
186 |
memcpy(&fhv->p0_col[1], &fhv->luf->pp_col[1], sizeof(int) * m);
|
alpar@1
|
187 |
/* currently H has no factors */
|
alpar@1
|
188 |
fhv->nnz_h = 0;
|
alpar@1
|
189 |
ret = 0;
|
alpar@1
|
190 |
done: /* return to the calling program */
|
alpar@1
|
191 |
return ret;
|
alpar@1
|
192 |
}
|
alpar@1
|
193 |
|
alpar@1
|
194 |
/***********************************************************************
|
alpar@1
|
195 |
* NAME
|
alpar@1
|
196 |
*
|
alpar@1
|
197 |
* fhv_h_solve - solve system H*x = b or H'*x = b
|
alpar@1
|
198 |
*
|
alpar@1
|
199 |
* SYNOPSIS
|
alpar@1
|
200 |
*
|
alpar@1
|
201 |
* #include "glpfhv.h"
|
alpar@1
|
202 |
* void fhv_h_solve(FHV *fhv, int tr, double x[]);
|
alpar@1
|
203 |
*
|
alpar@1
|
204 |
* DESCRIPTION
|
alpar@1
|
205 |
*
|
alpar@1
|
206 |
* The routine fhv_h_solve solves either the system H*x = b (if the
|
alpar@1
|
207 |
* flag tr is zero) or the system H'*x = b (if the flag tr is non-zero),
|
alpar@1
|
208 |
* where the matrix H is a component of the factorization specified by
|
alpar@1
|
209 |
* the parameter fhv, H' is a matrix transposed to H.
|
alpar@1
|
210 |
*
|
alpar@1
|
211 |
* On entry the array x should contain elements of the right-hand side
|
alpar@1
|
212 |
* vector b in locations x[1], ..., x[m], where m is the order of the
|
alpar@1
|
213 |
* matrix H. On exit this array will contain elements of the solution
|
alpar@1
|
214 |
* vector x in the same locations. */
|
alpar@1
|
215 |
|
alpar@1
|
216 |
void fhv_h_solve(FHV *fhv, int tr, double x[])
|
alpar@1
|
217 |
{ int nfs = fhv->hh_nfs;
|
alpar@1
|
218 |
int *hh_ind = fhv->hh_ind;
|
alpar@1
|
219 |
int *hh_ptr = fhv->hh_ptr;
|
alpar@1
|
220 |
int *hh_len = fhv->hh_len;
|
alpar@1
|
221 |
int *sv_ind = fhv->luf->sv_ind;
|
alpar@1
|
222 |
double *sv_val = fhv->luf->sv_val;
|
alpar@1
|
223 |
int i, k, beg, end, ptr;
|
alpar@1
|
224 |
double temp;
|
alpar@1
|
225 |
if (!fhv->valid)
|
alpar@1
|
226 |
xfault("fhv_h_solve: the factorization is not valid\n");
|
alpar@1
|
227 |
if (!tr)
|
alpar@1
|
228 |
{ /* solve the system H*x = b */
|
alpar@1
|
229 |
for (k = 1; k <= nfs; k++)
|
alpar@1
|
230 |
{ i = hh_ind[k];
|
alpar@1
|
231 |
temp = x[i];
|
alpar@1
|
232 |
beg = hh_ptr[k];
|
alpar@1
|
233 |
end = beg + hh_len[k] - 1;
|
alpar@1
|
234 |
for (ptr = beg; ptr <= end; ptr++)
|
alpar@1
|
235 |
temp -= sv_val[ptr] * x[sv_ind[ptr]];
|
alpar@1
|
236 |
x[i] = temp;
|
alpar@1
|
237 |
}
|
alpar@1
|
238 |
}
|
alpar@1
|
239 |
else
|
alpar@1
|
240 |
{ /* solve the system H'*x = b */
|
alpar@1
|
241 |
for (k = nfs; k >= 1; k--)
|
alpar@1
|
242 |
{ i = hh_ind[k];
|
alpar@1
|
243 |
temp = x[i];
|
alpar@1
|
244 |
if (temp == 0.0) continue;
|
alpar@1
|
245 |
beg = hh_ptr[k];
|
alpar@1
|
246 |
end = beg + hh_len[k] - 1;
|
alpar@1
|
247 |
for (ptr = beg; ptr <= end; ptr++)
|
alpar@1
|
248 |
x[sv_ind[ptr]] -= sv_val[ptr] * temp;
|
alpar@1
|
249 |
}
|
alpar@1
|
250 |
}
|
alpar@1
|
251 |
return;
|
alpar@1
|
252 |
}
|
alpar@1
|
253 |
|
alpar@1
|
254 |
/***********************************************************************
|
alpar@1
|
255 |
* NAME
|
alpar@1
|
256 |
*
|
alpar@1
|
257 |
* fhv_ftran - perform forward transformation (solve system B*x = b)
|
alpar@1
|
258 |
*
|
alpar@1
|
259 |
* SYNOPSIS
|
alpar@1
|
260 |
*
|
alpar@1
|
261 |
* #include "glpfhv.h"
|
alpar@1
|
262 |
* void fhv_ftran(FHV *fhv, double x[]);
|
alpar@1
|
263 |
*
|
alpar@1
|
264 |
* DESCRIPTION
|
alpar@1
|
265 |
*
|
alpar@1
|
266 |
* The routine fhv_ftran performs forward transformation, i.e. solves
|
alpar@1
|
267 |
* the system B*x = b, where B is the basis matrix, x is the vector of
|
alpar@1
|
268 |
* unknowns to be computed, b is the vector of right-hand sides.
|
alpar@1
|
269 |
*
|
alpar@1
|
270 |
* On entry elements of the vector b should be stored in dense format
|
alpar@1
|
271 |
* in locations x[1], ..., x[m], where m is the number of rows. On exit
|
alpar@1
|
272 |
* the routine stores elements of the vector x in the same locations. */
|
alpar@1
|
273 |
|
alpar@1
|
274 |
void fhv_ftran(FHV *fhv, double x[])
|
alpar@1
|
275 |
{ int *pp_row = fhv->luf->pp_row;
|
alpar@1
|
276 |
int *pp_col = fhv->luf->pp_col;
|
alpar@1
|
277 |
int *p0_row = fhv->p0_row;
|
alpar@1
|
278 |
int *p0_col = fhv->p0_col;
|
alpar@1
|
279 |
if (!fhv->valid)
|
alpar@1
|
280 |
xfault("fhv_ftran: the factorization is not valid\n");
|
alpar@1
|
281 |
/* B = F*H*V, therefore inv(B) = inv(V)*inv(H)*inv(F) */
|
alpar@1
|
282 |
fhv->luf->pp_row = p0_row;
|
alpar@1
|
283 |
fhv->luf->pp_col = p0_col;
|
alpar@1
|
284 |
luf_f_solve(fhv->luf, 0, x);
|
alpar@1
|
285 |
fhv->luf->pp_row = pp_row;
|
alpar@1
|
286 |
fhv->luf->pp_col = pp_col;
|
alpar@1
|
287 |
fhv_h_solve(fhv, 0, x);
|
alpar@1
|
288 |
luf_v_solve(fhv->luf, 0, x);
|
alpar@1
|
289 |
return;
|
alpar@1
|
290 |
}
|
alpar@1
|
291 |
|
alpar@1
|
292 |
/***********************************************************************
|
alpar@1
|
293 |
* NAME
|
alpar@1
|
294 |
*
|
alpar@1
|
295 |
* fhv_btran - perform backward transformation (solve system B'*x = b)
|
alpar@1
|
296 |
*
|
alpar@1
|
297 |
* SYNOPSIS
|
alpar@1
|
298 |
*
|
alpar@1
|
299 |
* #include "glpfhv.h"
|
alpar@1
|
300 |
* void fhv_btran(FHV *fhv, double x[]);
|
alpar@1
|
301 |
*
|
alpar@1
|
302 |
* DESCRIPTION
|
alpar@1
|
303 |
*
|
alpar@1
|
304 |
* The routine fhv_btran performs backward transformation, i.e. solves
|
alpar@1
|
305 |
* the system B'*x = b, where B' is a matrix transposed to the basis
|
alpar@1
|
306 |
* matrix B, x is the vector of unknowns to be computed, b is the vector
|
alpar@1
|
307 |
* of right-hand sides.
|
alpar@1
|
308 |
*
|
alpar@1
|
309 |
* On entry elements of the vector b should be stored in dense format
|
alpar@1
|
310 |
* in locations x[1], ..., x[m], where m is the number of rows. On exit
|
alpar@1
|
311 |
* the routine stores elements of the vector x in the same locations. */
|
alpar@1
|
312 |
|
alpar@1
|
313 |
void fhv_btran(FHV *fhv, double x[])
|
alpar@1
|
314 |
{ int *pp_row = fhv->luf->pp_row;
|
alpar@1
|
315 |
int *pp_col = fhv->luf->pp_col;
|
alpar@1
|
316 |
int *p0_row = fhv->p0_row;
|
alpar@1
|
317 |
int *p0_col = fhv->p0_col;
|
alpar@1
|
318 |
if (!fhv->valid)
|
alpar@1
|
319 |
xfault("fhv_btran: the factorization is not valid\n");
|
alpar@1
|
320 |
/* B = F*H*V, therefore inv(B') = inv(F')*inv(H')*inv(V') */
|
alpar@1
|
321 |
luf_v_solve(fhv->luf, 1, x);
|
alpar@1
|
322 |
fhv_h_solve(fhv, 1, x);
|
alpar@1
|
323 |
fhv->luf->pp_row = p0_row;
|
alpar@1
|
324 |
fhv->luf->pp_col = p0_col;
|
alpar@1
|
325 |
luf_f_solve(fhv->luf, 1, x);
|
alpar@1
|
326 |
fhv->luf->pp_row = pp_row;
|
alpar@1
|
327 |
fhv->luf->pp_col = pp_col;
|
alpar@1
|
328 |
return;
|
alpar@1
|
329 |
}
|
alpar@1
|
330 |
|
alpar@1
|
331 |
/***********************************************************************
|
alpar@1
|
332 |
* NAME
|
alpar@1
|
333 |
*
|
alpar@1
|
334 |
* fhv_update_it - update LP basis factorization
|
alpar@1
|
335 |
*
|
alpar@1
|
336 |
* SYNOPSIS
|
alpar@1
|
337 |
*
|
alpar@1
|
338 |
* #include "glpfhv.h"
|
alpar@1
|
339 |
* int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
|
alpar@1
|
340 |
* const double val[]);
|
alpar@1
|
341 |
*
|
alpar@1
|
342 |
* DESCRIPTION
|
alpar@1
|
343 |
*
|
alpar@1
|
344 |
* The routine fhv_update_it updates the factorization of the basis
|
alpar@1
|
345 |
* matrix B after replacing its j-th column by a new vector.
|
alpar@1
|
346 |
*
|
alpar@1
|
347 |
* The parameter j specifies the number of column of B, which has been
|
alpar@1
|
348 |
* replaced, 1 <= j <= m, where m is the order of B.
|
alpar@1
|
349 |
*
|
alpar@1
|
350 |
* Row indices and numerical values of non-zero elements of the new
|
alpar@1
|
351 |
* column of B should be placed in locations ind[1], ..., ind[len] and
|
alpar@1
|
352 |
* val[1], ..., val[len], resp., where len is the number of non-zeros
|
alpar@1
|
353 |
* in the column. Neither zero nor duplicate elements are allowed.
|
alpar@1
|
354 |
*
|
alpar@1
|
355 |
* RETURNS
|
alpar@1
|
356 |
*
|
alpar@1
|
357 |
* 0 The factorization has been successfully updated.
|
alpar@1
|
358 |
*
|
alpar@1
|
359 |
* FHV_ESING
|
alpar@1
|
360 |
* The adjacent basis matrix is structurally singular, since after
|
alpar@1
|
361 |
* changing j-th column of matrix V by the new column (see algorithm
|
alpar@1
|
362 |
* below) the case k1 > k2 occured.
|
alpar@1
|
363 |
*
|
alpar@1
|
364 |
* FHV_ECHECK
|
alpar@1
|
365 |
* The factorization is inaccurate, since after transforming k2-th
|
alpar@1
|
366 |
* row of matrix U = P*V*Q, its diagonal element u[k2,k2] is zero or
|
alpar@1
|
367 |
* close to zero,
|
alpar@1
|
368 |
*
|
alpar@1
|
369 |
* FHV_ELIMIT
|
alpar@1
|
370 |
* Maximal number of H factors has been reached.
|
alpar@1
|
371 |
*
|
alpar@1
|
372 |
* FHV_EROOM
|
alpar@1
|
373 |
* Overflow of the sparse vector area.
|
alpar@1
|
374 |
*
|
alpar@1
|
375 |
* In case of non-zero return code the factorization becomes invalid.
|
alpar@1
|
376 |
* It should not be used until it has been recomputed with the routine
|
alpar@1
|
377 |
* fhv_factorize.
|
alpar@1
|
378 |
*
|
alpar@1
|
379 |
* ALGORITHM
|
alpar@1
|
380 |
*
|
alpar@1
|
381 |
* The routine fhv_update_it is based on the transformation proposed by
|
alpar@1
|
382 |
* Forrest and Tomlin.
|
alpar@1
|
383 |
*
|
alpar@1
|
384 |
* Let j-th column of the basis matrix B have been replaced by new
|
alpar@1
|
385 |
* column B[j]. In order to keep the equality B = F*H*V j-th column of
|
alpar@1
|
386 |
* matrix V should be replaced by the column inv(F*H)*B[j].
|
alpar@1
|
387 |
*
|
alpar@1
|
388 |
* From the standpoint of matrix U = P*V*Q, replacement of j-th column
|
alpar@1
|
389 |
* of matrix V is equivalent to replacement of k1-th column of matrix U,
|
alpar@1
|
390 |
* where k1 is determined by permutation matrix Q. Thus, matrix U loses
|
alpar@1
|
391 |
* its upper triangular form and becomes the following:
|
alpar@1
|
392 |
*
|
alpar@1
|
393 |
* 1 k1 k2 m
|
alpar@1
|
394 |
* 1 x x * x x x x x x x
|
alpar@1
|
395 |
* . x * x x x x x x x
|
alpar@1
|
396 |
* k1 . . * x x x x x x x
|
alpar@1
|
397 |
* . . * x x x x x x x
|
alpar@1
|
398 |
* . . * . x x x x x x
|
alpar@1
|
399 |
* . . * . . x x x x x
|
alpar@1
|
400 |
* . . * . . . x x x x
|
alpar@1
|
401 |
* k2 . . * . . . . x x x
|
alpar@1
|
402 |
* . . . . . . . . x x
|
alpar@1
|
403 |
* m . . . . . . . . . x
|
alpar@1
|
404 |
*
|
alpar@1
|
405 |
* where row index k2 corresponds to the lowest non-zero element of
|
alpar@1
|
406 |
* k1-th column.
|
alpar@1
|
407 |
*
|
alpar@1
|
408 |
* The routine moves rows and columns k1+1, k1+2, ..., k2 of matrix U
|
alpar@1
|
409 |
* by one position to the left and upwards and moves k1-th row and k1-th
|
alpar@1
|
410 |
* column to position k2. As the result of such symmetric permutations
|
alpar@1
|
411 |
* matrix U becomes the following:
|
alpar@1
|
412 |
*
|
alpar@1
|
413 |
* 1 k1 k2 m
|
alpar@1
|
414 |
* 1 x x x x x x x * x x
|
alpar@1
|
415 |
* . x x x x x x * x x
|
alpar@1
|
416 |
* k1 . . x x x x x * x x
|
alpar@1
|
417 |
* . . . x x x x * x x
|
alpar@1
|
418 |
* . . . . x x x * x x
|
alpar@1
|
419 |
* . . . . . x x * x x
|
alpar@1
|
420 |
* . . . . . . x * x x
|
alpar@1
|
421 |
* k2 . . x x x x x * x x
|
alpar@1
|
422 |
* . . . . . . . . x x
|
alpar@1
|
423 |
* m . . . . . . . . . x
|
alpar@1
|
424 |
*
|
alpar@1
|
425 |
* Then the routine performs gaussian elimination to eliminate elements
|
alpar@1
|
426 |
* u[k2,k1], u[k2,k1+1], ..., u[k2,k2-1] using diagonal elements
|
alpar@1
|
427 |
* u[k1,k1], u[k1+1,k1+1], ..., u[k2-1,k2-1] as pivots in the same way
|
alpar@1
|
428 |
* as described in comments to the routine luf_factorize (see the module
|
alpar@1
|
429 |
* GLPLUF). Note that actually all operations are performed on matrix V,
|
alpar@1
|
430 |
* not on matrix U. During the elimination process the routine permutes
|
alpar@1
|
431 |
* neither rows nor columns, so only k2-th row of matrix U is changed.
|
alpar@1
|
432 |
*
|
alpar@1
|
433 |
* To keep the main equality B = F*H*V, each time when the routine
|
alpar@1
|
434 |
* applies elementary gaussian transformation to the transformed row of
|
alpar@1
|
435 |
* matrix V (which corresponds to k2-th row of matrix U), it also adds
|
alpar@1
|
436 |
* a new element (gaussian multiplier) to the current row-like factor
|
alpar@1
|
437 |
* of matrix H, which corresponds to the transformed row of matrix V. */
|
alpar@1
|
438 |
|
alpar@1
|
439 |
int fhv_update_it(FHV *fhv, int j, int len, const int ind[],
|
alpar@1
|
440 |
const double val[])
|
alpar@1
|
441 |
{ int m = fhv->m;
|
alpar@1
|
442 |
LUF *luf = fhv->luf;
|
alpar@1
|
443 |
int *vr_ptr = luf->vr_ptr;
|
alpar@1
|
444 |
int *vr_len = luf->vr_len;
|
alpar@1
|
445 |
int *vr_cap = luf->vr_cap;
|
alpar@1
|
446 |
double *vr_piv = luf->vr_piv;
|
alpar@1
|
447 |
int *vc_ptr = luf->vc_ptr;
|
alpar@1
|
448 |
int *vc_len = luf->vc_len;
|
alpar@1
|
449 |
int *vc_cap = luf->vc_cap;
|
alpar@1
|
450 |
int *pp_row = luf->pp_row;
|
alpar@1
|
451 |
int *pp_col = luf->pp_col;
|
alpar@1
|
452 |
int *qq_row = luf->qq_row;
|
alpar@1
|
453 |
int *qq_col = luf->qq_col;
|
alpar@1
|
454 |
int *sv_ind = luf->sv_ind;
|
alpar@1
|
455 |
double *sv_val = luf->sv_val;
|
alpar@1
|
456 |
double *work = luf->work;
|
alpar@1
|
457 |
double eps_tol = luf->eps_tol;
|
alpar@1
|
458 |
int *hh_ind = fhv->hh_ind;
|
alpar@1
|
459 |
int *hh_ptr = fhv->hh_ptr;
|
alpar@1
|
460 |
int *hh_len = fhv->hh_len;
|
alpar@1
|
461 |
int *p0_row = fhv->p0_row;
|
alpar@1
|
462 |
int *p0_col = fhv->p0_col;
|
alpar@1
|
463 |
int *cc_ind = fhv->cc_ind;
|
alpar@1
|
464 |
double *cc_val = fhv->cc_val;
|
alpar@1
|
465 |
double upd_tol = fhv->upd_tol;
|
alpar@1
|
466 |
int i, i_beg, i_end, i_ptr, j_beg, j_end, j_ptr, k, k1, k2, p, q,
|
alpar@1
|
467 |
p_beg, p_end, p_ptr, ptr, ret;
|
alpar@1
|
468 |
double f, temp;
|
alpar@1
|
469 |
if (!fhv->valid)
|
alpar@1
|
470 |
xfault("fhv_update_it: the factorization is not valid\n");
|
alpar@1
|
471 |
if (!(1 <= j && j <= m))
|
alpar@1
|
472 |
xfault("fhv_update_it: j = %d; column number out of range\n",
|
alpar@1
|
473 |
j);
|
alpar@1
|
474 |
/* check if the new factor of matrix H can be created */
|
alpar@1
|
475 |
if (fhv->hh_nfs == fhv->hh_max)
|
alpar@1
|
476 |
{ /* maximal number of updates has been reached */
|
alpar@1
|
477 |
fhv->valid = 0;
|
alpar@1
|
478 |
ret = FHV_ELIMIT;
|
alpar@1
|
479 |
goto done;
|
alpar@1
|
480 |
}
|
alpar@1
|
481 |
/* convert new j-th column of B to dense format */
|
alpar@1
|
482 |
for (i = 1; i <= m; i++)
|
alpar@1
|
483 |
cc_val[i] = 0.0;
|
alpar@1
|
484 |
for (k = 1; k <= len; k++)
|
alpar@1
|
485 |
{ i = ind[k];
|
alpar@1
|
486 |
if (!(1 <= i && i <= m))
|
alpar@1
|
487 |
xfault("fhv_update_it: ind[%d] = %d; row number out of rang"
|
alpar@1
|
488 |
"e\n", k, i);
|
alpar@1
|
489 |
if (cc_val[i] != 0.0)
|
alpar@1
|
490 |
xfault("fhv_update_it: ind[%d] = %d; duplicate row index no"
|
alpar@1
|
491 |
"t allowed\n", k, i);
|
alpar@1
|
492 |
if (val[k] == 0.0)
|
alpar@1
|
493 |
xfault("fhv_update_it: val[%d] = %g; zero element not allow"
|
alpar@1
|
494 |
"ed\n", k, val[k]);
|
alpar@1
|
495 |
cc_val[i] = val[k];
|
alpar@1
|
496 |
}
|
alpar@1
|
497 |
/* new j-th column of V := inv(F * H) * (new B[j]) */
|
alpar@1
|
498 |
fhv->luf->pp_row = p0_row;
|
alpar@1
|
499 |
fhv->luf->pp_col = p0_col;
|
alpar@1
|
500 |
luf_f_solve(fhv->luf, 0, cc_val);
|
alpar@1
|
501 |
fhv->luf->pp_row = pp_row;
|
alpar@1
|
502 |
fhv->luf->pp_col = pp_col;
|
alpar@1
|
503 |
fhv_h_solve(fhv, 0, cc_val);
|
alpar@1
|
504 |
/* convert new j-th column of V to sparse format */
|
alpar@1
|
505 |
len = 0;
|
alpar@1
|
506 |
for (i = 1; i <= m; i++)
|
alpar@1
|
507 |
{ temp = cc_val[i];
|
alpar@1
|
508 |
if (temp == 0.0 || fabs(temp) < eps_tol) continue;
|
alpar@1
|
509 |
len++, cc_ind[len] = i, cc_val[len] = temp;
|
alpar@1
|
510 |
}
|
alpar@1
|
511 |
/* clear old content of j-th column of matrix V */
|
alpar@1
|
512 |
j_beg = vc_ptr[j];
|
alpar@1
|
513 |
j_end = j_beg + vc_len[j] - 1;
|
alpar@1
|
514 |
for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
|
alpar@1
|
515 |
{ /* get row index of v[i,j] */
|
alpar@1
|
516 |
i = sv_ind[j_ptr];
|
alpar@1
|
517 |
/* find v[i,j] in the i-th row */
|
alpar@1
|
518 |
i_beg = vr_ptr[i];
|
alpar@1
|
519 |
i_end = i_beg + vr_len[i] - 1;
|
alpar@1
|
520 |
for (i_ptr = i_beg; sv_ind[i_ptr] != j; i_ptr++) /* nop */;
|
alpar@1
|
521 |
xassert(i_ptr <= i_end);
|
alpar@1
|
522 |
/* remove v[i,j] from the i-th row */
|
alpar@1
|
523 |
sv_ind[i_ptr] = sv_ind[i_end];
|
alpar@1
|
524 |
sv_val[i_ptr] = sv_val[i_end];
|
alpar@1
|
525 |
vr_len[i]--;
|
alpar@1
|
526 |
}
|
alpar@1
|
527 |
/* now j-th column of matrix V is empty */
|
alpar@1
|
528 |
luf->nnz_v -= vc_len[j];
|
alpar@1
|
529 |
vc_len[j] = 0;
|
alpar@1
|
530 |
/* add new elements of j-th column of matrix V to corresponding
|
alpar@1
|
531 |
row lists; determine indices k1 and k2 */
|
alpar@1
|
532 |
k1 = qq_row[j], k2 = 0;
|
alpar@1
|
533 |
for (ptr = 1; ptr <= len; ptr++)
|
alpar@1
|
534 |
{ /* get row index of v[i,j] */
|
alpar@1
|
535 |
i = cc_ind[ptr];
|
alpar@1
|
536 |
/* at least one unused location is needed in i-th row */
|
alpar@1
|
537 |
if (vr_len[i] + 1 > vr_cap[i])
|
alpar@1
|
538 |
{ if (luf_enlarge_row(luf, i, vr_len[i] + 10))
|
alpar@1
|
539 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
540 |
fhv->valid = 0;
|
alpar@1
|
541 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
542 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
543 |
ret = FHV_EROOM;
|
alpar@1
|
544 |
goto done;
|
alpar@1
|
545 |
}
|
alpar@1
|
546 |
}
|
alpar@1
|
547 |
/* add v[i,j] to i-th row */
|
alpar@1
|
548 |
i_ptr = vr_ptr[i] + vr_len[i];
|
alpar@1
|
549 |
sv_ind[i_ptr] = j;
|
alpar@1
|
550 |
sv_val[i_ptr] = cc_val[ptr];
|
alpar@1
|
551 |
vr_len[i]++;
|
alpar@1
|
552 |
/* adjust index k2 */
|
alpar@1
|
553 |
if (k2 < pp_col[i]) k2 = pp_col[i];
|
alpar@1
|
554 |
}
|
alpar@1
|
555 |
/* capacity of j-th column (which is currently empty) should be
|
alpar@1
|
556 |
not less than len locations */
|
alpar@1
|
557 |
if (vc_cap[j] < len)
|
alpar@1
|
558 |
{ if (luf_enlarge_col(luf, j, len))
|
alpar@1
|
559 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
560 |
fhv->valid = 0;
|
alpar@1
|
561 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
562 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
563 |
ret = FHV_EROOM;
|
alpar@1
|
564 |
goto done;
|
alpar@1
|
565 |
}
|
alpar@1
|
566 |
}
|
alpar@1
|
567 |
/* add new elements of matrix V to j-th column list */
|
alpar@1
|
568 |
j_ptr = vc_ptr[j];
|
alpar@1
|
569 |
memmove(&sv_ind[j_ptr], &cc_ind[1], len * sizeof(int));
|
alpar@1
|
570 |
memmove(&sv_val[j_ptr], &cc_val[1], len * sizeof(double));
|
alpar@1
|
571 |
vc_len[j] = len;
|
alpar@1
|
572 |
luf->nnz_v += len;
|
alpar@1
|
573 |
/* if k1 > k2, diagonal element u[k2,k2] of matrix U is zero and
|
alpar@1
|
574 |
therefore the adjacent basis matrix is structurally singular */
|
alpar@1
|
575 |
if (k1 > k2)
|
alpar@1
|
576 |
{ fhv->valid = 0;
|
alpar@1
|
577 |
ret = FHV_ESING;
|
alpar@1
|
578 |
goto done;
|
alpar@1
|
579 |
}
|
alpar@1
|
580 |
/* perform implicit symmetric permutations of rows and columns of
|
alpar@1
|
581 |
matrix U */
|
alpar@1
|
582 |
i = pp_row[k1], j = qq_col[k1];
|
alpar@1
|
583 |
for (k = k1; k < k2; k++)
|
alpar@1
|
584 |
{ pp_row[k] = pp_row[k+1], pp_col[pp_row[k]] = k;
|
alpar@1
|
585 |
qq_col[k] = qq_col[k+1], qq_row[qq_col[k]] = k;
|
alpar@1
|
586 |
}
|
alpar@1
|
587 |
pp_row[k2] = i, pp_col[i] = k2;
|
alpar@1
|
588 |
qq_col[k2] = j, qq_row[j] = k2;
|
alpar@1
|
589 |
/* now i-th row of the matrix V is k2-th row of matrix U; since
|
alpar@1
|
590 |
no pivoting is used, only this row will be transformed */
|
alpar@1
|
591 |
/* copy elements of i-th row of matrix V to the working array and
|
alpar@1
|
592 |
remove these elements from matrix V */
|
alpar@1
|
593 |
for (j = 1; j <= m; j++) work[j] = 0.0;
|
alpar@1
|
594 |
i_beg = vr_ptr[i];
|
alpar@1
|
595 |
i_end = i_beg + vr_len[i] - 1;
|
alpar@1
|
596 |
for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
|
alpar@1
|
597 |
{ /* get column index of v[i,j] */
|
alpar@1
|
598 |
j = sv_ind[i_ptr];
|
alpar@1
|
599 |
/* store v[i,j] to the working array */
|
alpar@1
|
600 |
work[j] = sv_val[i_ptr];
|
alpar@1
|
601 |
/* find v[i,j] in the j-th column */
|
alpar@1
|
602 |
j_beg = vc_ptr[j];
|
alpar@1
|
603 |
j_end = j_beg + vc_len[j] - 1;
|
alpar@1
|
604 |
for (j_ptr = j_beg; sv_ind[j_ptr] != i; j_ptr++) /* nop */;
|
alpar@1
|
605 |
xassert(j_ptr <= j_end);
|
alpar@1
|
606 |
/* remove v[i,j] from the j-th column */
|
alpar@1
|
607 |
sv_ind[j_ptr] = sv_ind[j_end];
|
alpar@1
|
608 |
sv_val[j_ptr] = sv_val[j_end];
|
alpar@1
|
609 |
vc_len[j]--;
|
alpar@1
|
610 |
}
|
alpar@1
|
611 |
/* now i-th row of matrix V is empty */
|
alpar@1
|
612 |
luf->nnz_v -= vr_len[i];
|
alpar@1
|
613 |
vr_len[i] = 0;
|
alpar@1
|
614 |
/* create the next row-like factor of the matrix H; this factor
|
alpar@1
|
615 |
corresponds to i-th (transformed) row */
|
alpar@1
|
616 |
fhv->hh_nfs++;
|
alpar@1
|
617 |
hh_ind[fhv->hh_nfs] = i;
|
alpar@1
|
618 |
/* hh_ptr[] will be set later */
|
alpar@1
|
619 |
hh_len[fhv->hh_nfs] = 0;
|
alpar@1
|
620 |
/* up to (k2 - k1) free locations are needed to add new elements
|
alpar@1
|
621 |
to the non-trivial row of the row-like factor */
|
alpar@1
|
622 |
if (luf->sv_end - luf->sv_beg < k2 - k1)
|
alpar@1
|
623 |
{ luf_defrag_sva(luf);
|
alpar@1
|
624 |
if (luf->sv_end - luf->sv_beg < k2 - k1)
|
alpar@1
|
625 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
626 |
fhv->valid = luf->valid = 0;
|
alpar@1
|
627 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
628 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
629 |
ret = FHV_EROOM;
|
alpar@1
|
630 |
goto done;
|
alpar@1
|
631 |
}
|
alpar@1
|
632 |
}
|
alpar@1
|
633 |
/* eliminate subdiagonal elements of matrix U */
|
alpar@1
|
634 |
for (k = k1; k < k2; k++)
|
alpar@1
|
635 |
{ /* v[p,q] = u[k,k] */
|
alpar@1
|
636 |
p = pp_row[k], q = qq_col[k];
|
alpar@1
|
637 |
/* this is the crucial point, where even tiny non-zeros should
|
alpar@1
|
638 |
not be dropped */
|
alpar@1
|
639 |
if (work[q] == 0.0) continue;
|
alpar@1
|
640 |
/* compute gaussian multiplier f = v[i,q] / v[p,q] */
|
alpar@1
|
641 |
f = work[q] / vr_piv[p];
|
alpar@1
|
642 |
/* perform gaussian transformation:
|
alpar@1
|
643 |
(i-th row) := (i-th row) - f * (p-th row)
|
alpar@1
|
644 |
in order to eliminate v[i,q] = u[k2,k] */
|
alpar@1
|
645 |
p_beg = vr_ptr[p];
|
alpar@1
|
646 |
p_end = p_beg + vr_len[p] - 1;
|
alpar@1
|
647 |
for (p_ptr = p_beg; p_ptr <= p_end; p_ptr++)
|
alpar@1
|
648 |
work[sv_ind[p_ptr]] -= f * sv_val[p_ptr];
|
alpar@1
|
649 |
/* store new element (gaussian multiplier that corresponds to
|
alpar@1
|
650 |
p-th row) in the current row-like factor */
|
alpar@1
|
651 |
luf->sv_end--;
|
alpar@1
|
652 |
sv_ind[luf->sv_end] = p;
|
alpar@1
|
653 |
sv_val[luf->sv_end] = f;
|
alpar@1
|
654 |
hh_len[fhv->hh_nfs]++;
|
alpar@1
|
655 |
}
|
alpar@1
|
656 |
/* set pointer to the current row-like factor of the matrix H
|
alpar@1
|
657 |
(if no elements were added to this factor, it is unity matrix
|
alpar@1
|
658 |
and therefore can be discarded) */
|
alpar@1
|
659 |
if (hh_len[fhv->hh_nfs] == 0)
|
alpar@1
|
660 |
fhv->hh_nfs--;
|
alpar@1
|
661 |
else
|
alpar@1
|
662 |
{ hh_ptr[fhv->hh_nfs] = luf->sv_end;
|
alpar@1
|
663 |
fhv->nnz_h += hh_len[fhv->hh_nfs];
|
alpar@1
|
664 |
}
|
alpar@1
|
665 |
/* store new pivot which corresponds to u[k2,k2] */
|
alpar@1
|
666 |
vr_piv[i] = work[qq_col[k2]];
|
alpar@1
|
667 |
/* new elements of i-th row of matrix V (which are non-diagonal
|
alpar@1
|
668 |
elements u[k2,k2+1], ..., u[k2,m] of matrix U = P*V*Q) now are
|
alpar@1
|
669 |
contained in the working array; add them to matrix V */
|
alpar@1
|
670 |
len = 0;
|
alpar@1
|
671 |
for (k = k2+1; k <= m; k++)
|
alpar@1
|
672 |
{ /* get column index and value of v[i,j] = u[k2,k] */
|
alpar@1
|
673 |
j = qq_col[k];
|
alpar@1
|
674 |
temp = work[j];
|
alpar@1
|
675 |
/* if v[i,j] is close to zero, skip it */
|
alpar@1
|
676 |
if (fabs(temp) < eps_tol) continue;
|
alpar@1
|
677 |
/* at least one unused location is needed in j-th column */
|
alpar@1
|
678 |
if (vc_len[j] + 1 > vc_cap[j])
|
alpar@1
|
679 |
{ if (luf_enlarge_col(luf, j, vc_len[j] + 10))
|
alpar@1
|
680 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
681 |
fhv->valid = 0;
|
alpar@1
|
682 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
683 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
684 |
ret = FHV_EROOM;
|
alpar@1
|
685 |
goto done;
|
alpar@1
|
686 |
}
|
alpar@1
|
687 |
}
|
alpar@1
|
688 |
/* add v[i,j] to j-th column */
|
alpar@1
|
689 |
j_ptr = vc_ptr[j] + vc_len[j];
|
alpar@1
|
690 |
sv_ind[j_ptr] = i;
|
alpar@1
|
691 |
sv_val[j_ptr] = temp;
|
alpar@1
|
692 |
vc_len[j]++;
|
alpar@1
|
693 |
/* also store v[i,j] to the auxiliary array */
|
alpar@1
|
694 |
len++, cc_ind[len] = j, cc_val[len] = temp;
|
alpar@1
|
695 |
}
|
alpar@1
|
696 |
/* capacity of i-th row (which is currently empty) should be not
|
alpar@1
|
697 |
less than len locations */
|
alpar@1
|
698 |
if (vr_cap[i] < len)
|
alpar@1
|
699 |
{ if (luf_enlarge_row(luf, i, len))
|
alpar@1
|
700 |
{ /* overflow of the sparse vector area */
|
alpar@1
|
701 |
fhv->valid = 0;
|
alpar@1
|
702 |
luf->new_sva = luf->sv_size + luf->sv_size;
|
alpar@1
|
703 |
xassert(luf->new_sva > luf->sv_size);
|
alpar@1
|
704 |
ret = FHV_EROOM;
|
alpar@1
|
705 |
goto done;
|
alpar@1
|
706 |
}
|
alpar@1
|
707 |
}
|
alpar@1
|
708 |
/* add new elements to i-th row list */
|
alpar@1
|
709 |
i_ptr = vr_ptr[i];
|
alpar@1
|
710 |
memmove(&sv_ind[i_ptr], &cc_ind[1], len * sizeof(int));
|
alpar@1
|
711 |
memmove(&sv_val[i_ptr], &cc_val[1], len * sizeof(double));
|
alpar@1
|
712 |
vr_len[i] = len;
|
alpar@1
|
713 |
luf->nnz_v += len;
|
alpar@1
|
714 |
/* updating is finished; check that diagonal element u[k2,k2] is
|
alpar@1
|
715 |
not very small in absolute value among other elements in k2-th
|
alpar@1
|
716 |
row and k2-th column of matrix U = P*V*Q */
|
alpar@1
|
717 |
/* temp = max(|u[k2,*]|, |u[*,k2]|) */
|
alpar@1
|
718 |
temp = 0.0;
|
alpar@1
|
719 |
/* walk through k2-th row of U which is i-th row of V */
|
alpar@1
|
720 |
i = pp_row[k2];
|
alpar@1
|
721 |
i_beg = vr_ptr[i];
|
alpar@1
|
722 |
i_end = i_beg + vr_len[i] - 1;
|
alpar@1
|
723 |
for (i_ptr = i_beg; i_ptr <= i_end; i_ptr++)
|
alpar@1
|
724 |
if (temp < fabs(sv_val[i_ptr])) temp = fabs(sv_val[i_ptr]);
|
alpar@1
|
725 |
/* walk through k2-th column of U which is j-th column of V */
|
alpar@1
|
726 |
j = qq_col[k2];
|
alpar@1
|
727 |
j_beg = vc_ptr[j];
|
alpar@1
|
728 |
j_end = j_beg + vc_len[j] - 1;
|
alpar@1
|
729 |
for (j_ptr = j_beg; j_ptr <= j_end; j_ptr++)
|
alpar@1
|
730 |
if (temp < fabs(sv_val[j_ptr])) temp = fabs(sv_val[j_ptr]);
|
alpar@1
|
731 |
/* check that u[k2,k2] is not very small */
|
alpar@1
|
732 |
if (fabs(vr_piv[i]) < upd_tol * temp)
|
alpar@1
|
733 |
{ /* the factorization seems to be inaccurate and therefore must
|
alpar@1
|
734 |
be recomputed */
|
alpar@1
|
735 |
fhv->valid = 0;
|
alpar@1
|
736 |
ret = FHV_ECHECK;
|
alpar@1
|
737 |
goto done;
|
alpar@1
|
738 |
}
|
alpar@1
|
739 |
/* the factorization has been successfully updated */
|
alpar@1
|
740 |
ret = 0;
|
alpar@1
|
741 |
done: /* return to the calling program */
|
alpar@1
|
742 |
return ret;
|
alpar@1
|
743 |
}
|
alpar@1
|
744 |
|
alpar@1
|
745 |
/***********************************************************************
|
alpar@1
|
746 |
* NAME
|
alpar@1
|
747 |
*
|
alpar@1
|
748 |
* fhv_delete_it - delete LP basis factorization
|
alpar@1
|
749 |
*
|
alpar@1
|
750 |
* SYNOPSIS
|
alpar@1
|
751 |
*
|
alpar@1
|
752 |
* #include "glpfhv.h"
|
alpar@1
|
753 |
* void fhv_delete_it(FHV *fhv);
|
alpar@1
|
754 |
*
|
alpar@1
|
755 |
* DESCRIPTION
|
alpar@1
|
756 |
*
|
alpar@1
|
757 |
* The routine fhv_delete_it deletes LP basis factorization specified
|
alpar@1
|
758 |
* by the parameter fhv and frees all memory allocated to this program
|
alpar@1
|
759 |
* object. */
|
alpar@1
|
760 |
|
alpar@1
|
761 |
void fhv_delete_it(FHV *fhv)
|
alpar@1
|
762 |
{ luf_delete_it(fhv->luf);
|
alpar@1
|
763 |
if (fhv->hh_ind != NULL) xfree(fhv->hh_ind);
|
alpar@1
|
764 |
if (fhv->hh_ptr != NULL) xfree(fhv->hh_ptr);
|
alpar@1
|
765 |
if (fhv->hh_len != NULL) xfree(fhv->hh_len);
|
alpar@1
|
766 |
if (fhv->p0_row != NULL) xfree(fhv->p0_row);
|
alpar@1
|
767 |
if (fhv->p0_col != NULL) xfree(fhv->p0_col);
|
alpar@1
|
768 |
if (fhv->cc_ind != NULL) xfree(fhv->cc_ind);
|
alpar@1
|
769 |
if (fhv->cc_val != NULL) xfree(fhv->cc_val);
|
alpar@1
|
770 |
xfree(fhv);
|
alpar@1
|
771 |
return;
|
alpar@1
|
772 |
}
|
alpar@1
|
773 |
|
alpar@1
|
774 |
/* eof */
|