glpfhv.c 27 KB

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