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