alpar@1
|
1 |
/* glplpf.c (LP basis factorization, Schur complement 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 "glplpf.h"
|
alpar@1
|
26 |
#include "glpenv.h"
|
alpar@1
|
27 |
#define xfault xerror
|
alpar@1
|
28 |
|
alpar@1
|
29 |
#define _GLPLPF_DEBUG 0
|
alpar@1
|
30 |
|
alpar@1
|
31 |
/* CAUTION: DO NOT CHANGE THE LIMIT BELOW */
|
alpar@1
|
32 |
|
alpar@1
|
33 |
#define M_MAX 100000000 /* = 100*10^6 */
|
alpar@1
|
34 |
/* maximal order of the basis matrix */
|
alpar@1
|
35 |
|
alpar@1
|
36 |
/***********************************************************************
|
alpar@1
|
37 |
* NAME
|
alpar@1
|
38 |
*
|
alpar@1
|
39 |
* lpf_create_it - create LP basis factorization
|
alpar@1
|
40 |
*
|
alpar@1
|
41 |
* SYNOPSIS
|
alpar@1
|
42 |
*
|
alpar@1
|
43 |
* #include "glplpf.h"
|
alpar@1
|
44 |
* LPF *lpf_create_it(void);
|
alpar@1
|
45 |
*
|
alpar@1
|
46 |
* DESCRIPTION
|
alpar@1
|
47 |
*
|
alpar@1
|
48 |
* The routine lpf_create_it creates a program object, which represents
|
alpar@1
|
49 |
* a factorization of LP basis.
|
alpar@1
|
50 |
*
|
alpar@1
|
51 |
* RETURNS
|
alpar@1
|
52 |
*
|
alpar@1
|
53 |
* The routine lpf_create_it returns a pointer to the object created. */
|
alpar@1
|
54 |
|
alpar@1
|
55 |
LPF *lpf_create_it(void)
|
alpar@1
|
56 |
{ LPF *lpf;
|
alpar@1
|
57 |
#if _GLPLPF_DEBUG
|
alpar@1
|
58 |
xprintf("lpf_create_it: warning: debug mode enabled\n");
|
alpar@1
|
59 |
#endif
|
alpar@1
|
60 |
lpf = xmalloc(sizeof(LPF));
|
alpar@1
|
61 |
lpf->valid = 0;
|
alpar@1
|
62 |
lpf->m0_max = lpf->m0 = 0;
|
alpar@1
|
63 |
lpf->luf = luf_create_it();
|
alpar@1
|
64 |
lpf->m = 0;
|
alpar@1
|
65 |
lpf->B = NULL;
|
alpar@1
|
66 |
lpf->n_max = 50;
|
alpar@1
|
67 |
lpf->n = 0;
|
alpar@1
|
68 |
lpf->R_ptr = lpf->R_len = NULL;
|
alpar@1
|
69 |
lpf->S_ptr = lpf->S_len = NULL;
|
alpar@1
|
70 |
lpf->scf = NULL;
|
alpar@1
|
71 |
lpf->P_row = lpf->P_col = NULL;
|
alpar@1
|
72 |
lpf->Q_row = lpf->Q_col = NULL;
|
alpar@1
|
73 |
lpf->v_size = 1000;
|
alpar@1
|
74 |
lpf->v_ptr = 0;
|
alpar@1
|
75 |
lpf->v_ind = NULL;
|
alpar@1
|
76 |
lpf->v_val = NULL;
|
alpar@1
|
77 |
lpf->work1 = lpf->work2 = NULL;
|
alpar@1
|
78 |
return lpf;
|
alpar@1
|
79 |
}
|
alpar@1
|
80 |
|
alpar@1
|
81 |
/***********************************************************************
|
alpar@1
|
82 |
* NAME
|
alpar@1
|
83 |
*
|
alpar@1
|
84 |
* lpf_factorize - compute LP basis factorization
|
alpar@1
|
85 |
*
|
alpar@1
|
86 |
* SYNOPSIS
|
alpar@1
|
87 |
*
|
alpar@1
|
88 |
* #include "glplpf.h"
|
alpar@1
|
89 |
* int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
|
alpar@1
|
90 |
* (void *info, int j, int ind[], double val[]), void *info);
|
alpar@1
|
91 |
*
|
alpar@1
|
92 |
* DESCRIPTION
|
alpar@1
|
93 |
*
|
alpar@1
|
94 |
* The routine lpf_factorize computes the factorization of the basis
|
alpar@1
|
95 |
* matrix B specified by the routine col.
|
alpar@1
|
96 |
*
|
alpar@1
|
97 |
* The parameter lpf specified the basis factorization data structure
|
alpar@1
|
98 |
* created with the routine lpf_create_it.
|
alpar@1
|
99 |
*
|
alpar@1
|
100 |
* The parameter m specifies the order of B, m > 0.
|
alpar@1
|
101 |
*
|
alpar@1
|
102 |
* The array bh specifies the basis header: bh[j], 1 <= j <= m, is the
|
alpar@1
|
103 |
* number of j-th column of B in some original matrix. The array bh is
|
alpar@1
|
104 |
* optional and can be specified as NULL.
|
alpar@1
|
105 |
*
|
alpar@1
|
106 |
* The formal routine col specifies the matrix B to be factorized. To
|
alpar@1
|
107 |
* obtain j-th column of A the routine lpf_factorize calls the routine
|
alpar@1
|
108 |
* col with the parameter j (1 <= j <= n). In response the routine col
|
alpar@1
|
109 |
* should store row indices and numerical values of non-zero elements
|
alpar@1
|
110 |
* of j-th column of B to locations ind[1,...,len] and val[1,...,len],
|
alpar@1
|
111 |
* respectively, where len is the number of non-zeros in j-th column
|
alpar@1
|
112 |
* returned on exit. Neither zero nor duplicate elements are allowed.
|
alpar@1
|
113 |
*
|
alpar@1
|
114 |
* The parameter info is a transit pointer passed to the routine col.
|
alpar@1
|
115 |
*
|
alpar@1
|
116 |
* RETURNS
|
alpar@1
|
117 |
*
|
alpar@1
|
118 |
* 0 The factorization has been successfully computed.
|
alpar@1
|
119 |
*
|
alpar@1
|
120 |
* LPF_ESING
|
alpar@1
|
121 |
* The specified matrix is singular within the working precision.
|
alpar@1
|
122 |
*
|
alpar@1
|
123 |
* LPF_ECOND
|
alpar@1
|
124 |
* The specified matrix is ill-conditioned.
|
alpar@1
|
125 |
*
|
alpar@1
|
126 |
* For more details see comments to the routine luf_factorize. */
|
alpar@1
|
127 |
|
alpar@1
|
128 |
int lpf_factorize(LPF *lpf, int m, const int bh[], int (*col)
|
alpar@1
|
129 |
(void *info, int j, int ind[], double val[]), void *info)
|
alpar@1
|
130 |
{ int k, ret;
|
alpar@1
|
131 |
#if _GLPLPF_DEBUG
|
alpar@1
|
132 |
int i, j, len, *ind;
|
alpar@1
|
133 |
double *B, *val;
|
alpar@1
|
134 |
#endif
|
alpar@1
|
135 |
xassert(bh == bh);
|
alpar@1
|
136 |
if (m < 1)
|
alpar@1
|
137 |
xfault("lpf_factorize: m = %d; invalid parameter\n", m);
|
alpar@1
|
138 |
if (m > M_MAX)
|
alpar@1
|
139 |
xfault("lpf_factorize: m = %d; matrix too big\n", m);
|
alpar@1
|
140 |
lpf->m0 = lpf->m = m;
|
alpar@1
|
141 |
/* invalidate the factorization */
|
alpar@1
|
142 |
lpf->valid = 0;
|
alpar@1
|
143 |
/* allocate/reallocate arrays, if necessary */
|
alpar@1
|
144 |
if (lpf->R_ptr == NULL)
|
alpar@1
|
145 |
lpf->R_ptr = xcalloc(1+lpf->n_max, sizeof(int));
|
alpar@1
|
146 |
if (lpf->R_len == NULL)
|
alpar@1
|
147 |
lpf->R_len = xcalloc(1+lpf->n_max, sizeof(int));
|
alpar@1
|
148 |
if (lpf->S_ptr == NULL)
|
alpar@1
|
149 |
lpf->S_ptr = xcalloc(1+lpf->n_max, sizeof(int));
|
alpar@1
|
150 |
if (lpf->S_len == NULL)
|
alpar@1
|
151 |
lpf->S_len = xcalloc(1+lpf->n_max, sizeof(int));
|
alpar@1
|
152 |
if (lpf->scf == NULL)
|
alpar@1
|
153 |
lpf->scf = scf_create_it(lpf->n_max);
|
alpar@1
|
154 |
if (lpf->v_ind == NULL)
|
alpar@1
|
155 |
lpf->v_ind = xcalloc(1+lpf->v_size, sizeof(int));
|
alpar@1
|
156 |
if (lpf->v_val == NULL)
|
alpar@1
|
157 |
lpf->v_val = xcalloc(1+lpf->v_size, sizeof(double));
|
alpar@1
|
158 |
if (lpf->m0_max < m)
|
alpar@1
|
159 |
{ if (lpf->P_row != NULL) xfree(lpf->P_row);
|
alpar@1
|
160 |
if (lpf->P_col != NULL) xfree(lpf->P_col);
|
alpar@1
|
161 |
if (lpf->Q_row != NULL) xfree(lpf->Q_row);
|
alpar@1
|
162 |
if (lpf->Q_col != NULL) xfree(lpf->Q_col);
|
alpar@1
|
163 |
if (lpf->work1 != NULL) xfree(lpf->work1);
|
alpar@1
|
164 |
if (lpf->work2 != NULL) xfree(lpf->work2);
|
alpar@1
|
165 |
lpf->m0_max = m + 100;
|
alpar@1
|
166 |
lpf->P_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
|
alpar@1
|
167 |
lpf->P_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
|
alpar@1
|
168 |
lpf->Q_row = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
|
alpar@1
|
169 |
lpf->Q_col = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(int));
|
alpar@1
|
170 |
lpf->work1 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
|
alpar@1
|
171 |
lpf->work2 = xcalloc(1+lpf->m0_max+lpf->n_max, sizeof(double));
|
alpar@1
|
172 |
}
|
alpar@1
|
173 |
/* try to factorize the basis matrix */
|
alpar@1
|
174 |
switch (luf_factorize(lpf->luf, m, col, info))
|
alpar@1
|
175 |
{ case 0:
|
alpar@1
|
176 |
break;
|
alpar@1
|
177 |
case LUF_ESING:
|
alpar@1
|
178 |
ret = LPF_ESING;
|
alpar@1
|
179 |
goto done;
|
alpar@1
|
180 |
case LUF_ECOND:
|
alpar@1
|
181 |
ret = LPF_ECOND;
|
alpar@1
|
182 |
goto done;
|
alpar@1
|
183 |
default:
|
alpar@1
|
184 |
xassert(lpf != lpf);
|
alpar@1
|
185 |
}
|
alpar@1
|
186 |
/* the basis matrix has been successfully factorized */
|
alpar@1
|
187 |
lpf->valid = 1;
|
alpar@1
|
188 |
#if _GLPLPF_DEBUG
|
alpar@1
|
189 |
/* store the basis matrix for debugging */
|
alpar@1
|
190 |
if (lpf->B != NULL) xfree(lpf->B);
|
alpar@1
|
191 |
xassert(m <= 32767);
|
alpar@1
|
192 |
lpf->B = B = xcalloc(1+m*m, sizeof(double));
|
alpar@1
|
193 |
ind = xcalloc(1+m, sizeof(int));
|
alpar@1
|
194 |
val = xcalloc(1+m, sizeof(double));
|
alpar@1
|
195 |
for (k = 1; k <= m * m; k++)
|
alpar@1
|
196 |
B[k] = 0.0;
|
alpar@1
|
197 |
for (j = 1; j <= m; j++)
|
alpar@1
|
198 |
{ len = col(info, j, ind, val);
|
alpar@1
|
199 |
xassert(0 <= len && len <= m);
|
alpar@1
|
200 |
for (k = 1; k <= len; k++)
|
alpar@1
|
201 |
{ i = ind[k];
|
alpar@1
|
202 |
xassert(1 <= i && i <= m);
|
alpar@1
|
203 |
xassert(B[(i - 1) * m + j] == 0.0);
|
alpar@1
|
204 |
xassert(val[k] != 0.0);
|
alpar@1
|
205 |
B[(i - 1) * m + j] = val[k];
|
alpar@1
|
206 |
}
|
alpar@1
|
207 |
}
|
alpar@1
|
208 |
xfree(ind);
|
alpar@1
|
209 |
xfree(val);
|
alpar@1
|
210 |
#endif
|
alpar@1
|
211 |
/* B = B0, so there are no additional rows/columns */
|
alpar@1
|
212 |
lpf->n = 0;
|
alpar@1
|
213 |
/* reset the Schur complement factorization */
|
alpar@1
|
214 |
scf_reset_it(lpf->scf);
|
alpar@1
|
215 |
/* P := Q := I */
|
alpar@1
|
216 |
for (k = 1; k <= m; k++)
|
alpar@1
|
217 |
{ lpf->P_row[k] = lpf->P_col[k] = k;
|
alpar@1
|
218 |
lpf->Q_row[k] = lpf->Q_col[k] = k;
|
alpar@1
|
219 |
}
|
alpar@1
|
220 |
/* make all SVA locations free */
|
alpar@1
|
221 |
lpf->v_ptr = 1;
|
alpar@1
|
222 |
ret = 0;
|
alpar@1
|
223 |
done: /* return to the calling program */
|
alpar@1
|
224 |
return ret;
|
alpar@1
|
225 |
}
|
alpar@1
|
226 |
|
alpar@1
|
227 |
/***********************************************************************
|
alpar@1
|
228 |
* The routine r_prod computes the product y := y + alpha * R * x,
|
alpar@1
|
229 |
* where x is a n-vector, alpha is a scalar, y is a m0-vector.
|
alpar@1
|
230 |
*
|
alpar@1
|
231 |
* Since matrix R is available by columns, the product is computed as
|
alpar@1
|
232 |
* a linear combination:
|
alpar@1
|
233 |
*
|
alpar@1
|
234 |
* y := y + alpha * (R[1] * x[1] + ... + R[n] * x[n]),
|
alpar@1
|
235 |
*
|
alpar@1
|
236 |
* where R[j] is j-th column of R. */
|
alpar@1
|
237 |
|
alpar@1
|
238 |
static void r_prod(LPF *lpf, double y[], double a, const double x[])
|
alpar@1
|
239 |
{ int n = lpf->n;
|
alpar@1
|
240 |
int *R_ptr = lpf->R_ptr;
|
alpar@1
|
241 |
int *R_len = lpf->R_len;
|
alpar@1
|
242 |
int *v_ind = lpf->v_ind;
|
alpar@1
|
243 |
double *v_val = lpf->v_val;
|
alpar@1
|
244 |
int j, beg, end, ptr;
|
alpar@1
|
245 |
double t;
|
alpar@1
|
246 |
for (j = 1; j <= n; j++)
|
alpar@1
|
247 |
{ if (x[j] == 0.0) continue;
|
alpar@1
|
248 |
/* y := y + alpha * R[j] * x[j] */
|
alpar@1
|
249 |
t = a * x[j];
|
alpar@1
|
250 |
beg = R_ptr[j];
|
alpar@1
|
251 |
end = beg + R_len[j];
|
alpar@1
|
252 |
for (ptr = beg; ptr < end; ptr++)
|
alpar@1
|
253 |
y[v_ind[ptr]] += t * v_val[ptr];
|
alpar@1
|
254 |
}
|
alpar@1
|
255 |
return;
|
alpar@1
|
256 |
}
|
alpar@1
|
257 |
|
alpar@1
|
258 |
/***********************************************************************
|
alpar@1
|
259 |
* The routine rt_prod computes the product y := y + alpha * R' * x,
|
alpar@1
|
260 |
* where R' is a matrix transposed to R, x is a m0-vector, alpha is a
|
alpar@1
|
261 |
* scalar, y is a n-vector.
|
alpar@1
|
262 |
*
|
alpar@1
|
263 |
* Since matrix R is available by columns, the product components are
|
alpar@1
|
264 |
* computed as inner products:
|
alpar@1
|
265 |
*
|
alpar@1
|
266 |
* y[j] := y[j] + alpha * (j-th column of R) * x
|
alpar@1
|
267 |
*
|
alpar@1
|
268 |
* for j = 1, 2, ..., n. */
|
alpar@1
|
269 |
|
alpar@1
|
270 |
static void rt_prod(LPF *lpf, double y[], double a, const double x[])
|
alpar@1
|
271 |
{ int n = lpf->n;
|
alpar@1
|
272 |
int *R_ptr = lpf->R_ptr;
|
alpar@1
|
273 |
int *R_len = lpf->R_len;
|
alpar@1
|
274 |
int *v_ind = lpf->v_ind;
|
alpar@1
|
275 |
double *v_val = lpf->v_val;
|
alpar@1
|
276 |
int j, beg, end, ptr;
|
alpar@1
|
277 |
double t;
|
alpar@1
|
278 |
for (j = 1; j <= n; j++)
|
alpar@1
|
279 |
{ /* t := (j-th column of R) * x */
|
alpar@1
|
280 |
t = 0.0;
|
alpar@1
|
281 |
beg = R_ptr[j];
|
alpar@1
|
282 |
end = beg + R_len[j];
|
alpar@1
|
283 |
for (ptr = beg; ptr < end; ptr++)
|
alpar@1
|
284 |
t += v_val[ptr] * x[v_ind[ptr]];
|
alpar@1
|
285 |
/* y[j] := y[j] + alpha * t */
|
alpar@1
|
286 |
y[j] += a * t;
|
alpar@1
|
287 |
}
|
alpar@1
|
288 |
return;
|
alpar@1
|
289 |
}
|
alpar@1
|
290 |
|
alpar@1
|
291 |
/***********************************************************************
|
alpar@1
|
292 |
* The routine s_prod computes the product y := y + alpha * S * x,
|
alpar@1
|
293 |
* where x is a m0-vector, alpha is a scalar, y is a n-vector.
|
alpar@1
|
294 |
*
|
alpar@1
|
295 |
* Since matrix S is available by rows, the product components are
|
alpar@1
|
296 |
* computed as inner products:
|
alpar@1
|
297 |
*
|
alpar@1
|
298 |
* y[i] = y[i] + alpha * (i-th row of S) * x
|
alpar@1
|
299 |
*
|
alpar@1
|
300 |
* for i = 1, 2, ..., n. */
|
alpar@1
|
301 |
|
alpar@1
|
302 |
static void s_prod(LPF *lpf, double y[], double a, const double x[])
|
alpar@1
|
303 |
{ int n = lpf->n;
|
alpar@1
|
304 |
int *S_ptr = lpf->S_ptr;
|
alpar@1
|
305 |
int *S_len = lpf->S_len;
|
alpar@1
|
306 |
int *v_ind = lpf->v_ind;
|
alpar@1
|
307 |
double *v_val = lpf->v_val;
|
alpar@1
|
308 |
int i, beg, end, ptr;
|
alpar@1
|
309 |
double t;
|
alpar@1
|
310 |
for (i = 1; i <= n; i++)
|
alpar@1
|
311 |
{ /* t := (i-th row of S) * x */
|
alpar@1
|
312 |
t = 0.0;
|
alpar@1
|
313 |
beg = S_ptr[i];
|
alpar@1
|
314 |
end = beg + S_len[i];
|
alpar@1
|
315 |
for (ptr = beg; ptr < end; ptr++)
|
alpar@1
|
316 |
t += v_val[ptr] * x[v_ind[ptr]];
|
alpar@1
|
317 |
/* y[i] := y[i] + alpha * t */
|
alpar@1
|
318 |
y[i] += a * t;
|
alpar@1
|
319 |
}
|
alpar@1
|
320 |
return;
|
alpar@1
|
321 |
}
|
alpar@1
|
322 |
|
alpar@1
|
323 |
/***********************************************************************
|
alpar@1
|
324 |
* The routine st_prod computes the product y := y + alpha * S' * x,
|
alpar@1
|
325 |
* where S' is a matrix transposed to S, x is a n-vector, alpha is a
|
alpar@1
|
326 |
* scalar, y is m0-vector.
|
alpar@1
|
327 |
*
|
alpar@1
|
328 |
* Since matrix R is available by rows, the product is computed as a
|
alpar@1
|
329 |
* linear combination:
|
alpar@1
|
330 |
*
|
alpar@1
|
331 |
* y := y + alpha * (S'[1] * x[1] + ... + S'[n] * x[n]),
|
alpar@1
|
332 |
*
|
alpar@1
|
333 |
* where S'[i] is i-th row of S. */
|
alpar@1
|
334 |
|
alpar@1
|
335 |
static void st_prod(LPF *lpf, double y[], double a, const double x[])
|
alpar@1
|
336 |
{ int n = lpf->n;
|
alpar@1
|
337 |
int *S_ptr = lpf->S_ptr;
|
alpar@1
|
338 |
int *S_len = lpf->S_len;
|
alpar@1
|
339 |
int *v_ind = lpf->v_ind;
|
alpar@1
|
340 |
double *v_val = lpf->v_val;
|
alpar@1
|
341 |
int i, beg, end, ptr;
|
alpar@1
|
342 |
double t;
|
alpar@1
|
343 |
for (i = 1; i <= n; i++)
|
alpar@1
|
344 |
{ if (x[i] == 0.0) continue;
|
alpar@1
|
345 |
/* y := y + alpha * S'[i] * x[i] */
|
alpar@1
|
346 |
t = a * x[i];
|
alpar@1
|
347 |
beg = S_ptr[i];
|
alpar@1
|
348 |
end = beg + S_len[i];
|
alpar@1
|
349 |
for (ptr = beg; ptr < end; ptr++)
|
alpar@1
|
350 |
y[v_ind[ptr]] += t * v_val[ptr];
|
alpar@1
|
351 |
}
|
alpar@1
|
352 |
return;
|
alpar@1
|
353 |
}
|
alpar@1
|
354 |
|
alpar@1
|
355 |
#if _GLPLPF_DEBUG
|
alpar@1
|
356 |
/***********************************************************************
|
alpar@1
|
357 |
* The routine check_error computes the maximal relative error between
|
alpar@1
|
358 |
* left- and right-hand sides for the system B * x = b (if tr is zero)
|
alpar@1
|
359 |
* or B' * x = b (if tr is non-zero), where B' is a matrix transposed
|
alpar@1
|
360 |
* to B. (This routine is intended for debugging only.) */
|
alpar@1
|
361 |
|
alpar@1
|
362 |
static void check_error(LPF *lpf, int tr, const double x[],
|
alpar@1
|
363 |
const double b[])
|
alpar@1
|
364 |
{ int m = lpf->m;
|
alpar@1
|
365 |
double *B = lpf->B;
|
alpar@1
|
366 |
int i, j;
|
alpar@1
|
367 |
double d, dmax = 0.0, s, t, tmax;
|
alpar@1
|
368 |
for (i = 1; i <= m; i++)
|
alpar@1
|
369 |
{ s = 0.0;
|
alpar@1
|
370 |
tmax = 1.0;
|
alpar@1
|
371 |
for (j = 1; j <= m; j++)
|
alpar@1
|
372 |
{ if (!tr)
|
alpar@1
|
373 |
t = B[m * (i - 1) + j] * x[j];
|
alpar@1
|
374 |
else
|
alpar@1
|
375 |
t = B[m * (j - 1) + i] * x[j];
|
alpar@1
|
376 |
if (tmax < fabs(t)) tmax = fabs(t);
|
alpar@1
|
377 |
s += t;
|
alpar@1
|
378 |
}
|
alpar@1
|
379 |
d = fabs(s - b[i]) / tmax;
|
alpar@1
|
380 |
if (dmax < d) dmax = d;
|
alpar@1
|
381 |
}
|
alpar@1
|
382 |
if (dmax > 1e-8)
|
alpar@1
|
383 |
xprintf("%s: dmax = %g; relative error too large\n",
|
alpar@1
|
384 |
!tr ? "lpf_ftran" : "lpf_btran", dmax);
|
alpar@1
|
385 |
return;
|
alpar@1
|
386 |
}
|
alpar@1
|
387 |
#endif
|
alpar@1
|
388 |
|
alpar@1
|
389 |
/***********************************************************************
|
alpar@1
|
390 |
* NAME
|
alpar@1
|
391 |
*
|
alpar@1
|
392 |
* lpf_ftran - perform forward transformation (solve system B*x = b)
|
alpar@1
|
393 |
*
|
alpar@1
|
394 |
* SYNOPSIS
|
alpar@1
|
395 |
*
|
alpar@1
|
396 |
* #include "glplpf.h"
|
alpar@1
|
397 |
* void lpf_ftran(LPF *lpf, double x[]);
|
alpar@1
|
398 |
*
|
alpar@1
|
399 |
* DESCRIPTION
|
alpar@1
|
400 |
*
|
alpar@1
|
401 |
* The routine lpf_ftran performs forward transformation, i.e. solves
|
alpar@1
|
402 |
* the system B*x = b, where B is the basis matrix, x is the vector of
|
alpar@1
|
403 |
* unknowns to be computed, b is the vector of right-hand sides.
|
alpar@1
|
404 |
*
|
alpar@1
|
405 |
* On entry elements of the vector b should be stored in dense format
|
alpar@1
|
406 |
* in locations x[1], ..., x[m], where m is the number of rows. On exit
|
alpar@1
|
407 |
* the routine stores elements of the vector x in the same locations.
|
alpar@1
|
408 |
*
|
alpar@1
|
409 |
* BACKGROUND
|
alpar@1
|
410 |
*
|
alpar@1
|
411 |
* Solution of the system B * x = b can be obtained by solving the
|
alpar@1
|
412 |
* following augmented system:
|
alpar@1
|
413 |
*
|
alpar@1
|
414 |
* ( B F^) ( x ) ( b )
|
alpar@1
|
415 |
* ( ) ( ) = ( )
|
alpar@1
|
416 |
* ( G^ H^) ( y ) ( 0 )
|
alpar@1
|
417 |
*
|
alpar@1
|
418 |
* which, using the main equality, can be written as follows:
|
alpar@1
|
419 |
*
|
alpar@1
|
420 |
* ( L0 0 ) ( U0 R ) ( x ) ( b )
|
alpar@1
|
421 |
* P ( ) ( ) Q ( ) = ( )
|
alpar@1
|
422 |
* ( S I ) ( 0 C ) ( y ) ( 0 )
|
alpar@1
|
423 |
*
|
alpar@1
|
424 |
* therefore,
|
alpar@1
|
425 |
*
|
alpar@1
|
426 |
* ( x ) ( U0 R )-1 ( L0 0 )-1 ( b )
|
alpar@1
|
427 |
* ( ) = Q' ( ) ( ) P' ( )
|
alpar@1
|
428 |
* ( y ) ( 0 C ) ( S I ) ( 0 )
|
alpar@1
|
429 |
*
|
alpar@1
|
430 |
* Thus, computing the solution includes the following steps:
|
alpar@1
|
431 |
*
|
alpar@1
|
432 |
* 1. Compute
|
alpar@1
|
433 |
*
|
alpar@1
|
434 |
* ( f ) ( b )
|
alpar@1
|
435 |
* ( ) = P' ( )
|
alpar@1
|
436 |
* ( g ) ( 0 )
|
alpar@1
|
437 |
*
|
alpar@1
|
438 |
* 2. Solve the system
|
alpar@1
|
439 |
*
|
alpar@1
|
440 |
* ( f1 ) ( L0 0 )-1 ( f ) ( L0 0 ) ( f1 ) ( f )
|
alpar@1
|
441 |
* ( ) = ( ) ( ) => ( ) ( ) = ( )
|
alpar@1
|
442 |
* ( g1 ) ( S I ) ( g ) ( S I ) ( g1 ) ( g )
|
alpar@1
|
443 |
*
|
alpar@1
|
444 |
* from which it follows that:
|
alpar@1
|
445 |
*
|
alpar@1
|
446 |
* { L0 * f1 = f f1 = inv(L0) * f
|
alpar@1
|
447 |
* { =>
|
alpar@1
|
448 |
* { S * f1 + g1 = g g1 = g - S * f1
|
alpar@1
|
449 |
*
|
alpar@1
|
450 |
* 3. Solve the system
|
alpar@1
|
451 |
*
|
alpar@1
|
452 |
* ( f2 ) ( U0 R )-1 ( f1 ) ( U0 R ) ( f2 ) ( f1 )
|
alpar@1
|
453 |
* ( ) = ( ) ( ) => ( ) ( ) = ( )
|
alpar@1
|
454 |
* ( g2 ) ( 0 C ) ( g1 ) ( 0 C ) ( g2 ) ( g1 )
|
alpar@1
|
455 |
*
|
alpar@1
|
456 |
* from which it follows that:
|
alpar@1
|
457 |
*
|
alpar@1
|
458 |
* { U0 * f2 + R * g2 = f1 f2 = inv(U0) * (f1 - R * g2)
|
alpar@1
|
459 |
* { =>
|
alpar@1
|
460 |
* { C * g2 = g1 g2 = inv(C) * g1
|
alpar@1
|
461 |
*
|
alpar@1
|
462 |
* 4. Compute
|
alpar@1
|
463 |
*
|
alpar@1
|
464 |
* ( x ) ( f2 )
|
alpar@1
|
465 |
* ( ) = Q' ( )
|
alpar@1
|
466 |
* ( y ) ( g2 ) */
|
alpar@1
|
467 |
|
alpar@1
|
468 |
void lpf_ftran(LPF *lpf, double x[])
|
alpar@1
|
469 |
{ int m0 = lpf->m0;
|
alpar@1
|
470 |
int m = lpf->m;
|
alpar@1
|
471 |
int n = lpf->n;
|
alpar@1
|
472 |
int *P_col = lpf->P_col;
|
alpar@1
|
473 |
int *Q_col = lpf->Q_col;
|
alpar@1
|
474 |
double *fg = lpf->work1;
|
alpar@1
|
475 |
double *f = fg;
|
alpar@1
|
476 |
double *g = fg + m0;
|
alpar@1
|
477 |
int i, ii;
|
alpar@1
|
478 |
#if _GLPLPF_DEBUG
|
alpar@1
|
479 |
double *b;
|
alpar@1
|
480 |
#endif
|
alpar@1
|
481 |
if (!lpf->valid)
|
alpar@1
|
482 |
xfault("lpf_ftran: the factorization is not valid\n");
|
alpar@1
|
483 |
xassert(0 <= m && m <= m0 + n);
|
alpar@1
|
484 |
#if _GLPLPF_DEBUG
|
alpar@1
|
485 |
/* save the right-hand side vector */
|
alpar@1
|
486 |
b = xcalloc(1+m, sizeof(double));
|
alpar@1
|
487 |
for (i = 1; i <= m; i++) b[i] = x[i];
|
alpar@1
|
488 |
#endif
|
alpar@1
|
489 |
/* (f g) := inv(P) * (b 0) */
|
alpar@1
|
490 |
for (i = 1; i <= m0 + n; i++)
|
alpar@1
|
491 |
fg[i] = ((ii = P_col[i]) <= m ? x[ii] : 0.0);
|
alpar@1
|
492 |
/* f1 := inv(L0) * f */
|
alpar@1
|
493 |
luf_f_solve(lpf->luf, 0, f);
|
alpar@1
|
494 |
/* g1 := g - S * f1 */
|
alpar@1
|
495 |
s_prod(lpf, g, -1.0, f);
|
alpar@1
|
496 |
/* g2 := inv(C) * g1 */
|
alpar@1
|
497 |
scf_solve_it(lpf->scf, 0, g);
|
alpar@1
|
498 |
/* f2 := inv(U0) * (f1 - R * g2) */
|
alpar@1
|
499 |
r_prod(lpf, f, -1.0, g);
|
alpar@1
|
500 |
luf_v_solve(lpf->luf, 0, f);
|
alpar@1
|
501 |
/* (x y) := inv(Q) * (f2 g2) */
|
alpar@1
|
502 |
for (i = 1; i <= m; i++)
|
alpar@1
|
503 |
x[i] = fg[Q_col[i]];
|
alpar@1
|
504 |
#if _GLPLPF_DEBUG
|
alpar@1
|
505 |
/* check relative error in solution */
|
alpar@1
|
506 |
check_error(lpf, 0, x, b);
|
alpar@1
|
507 |
xfree(b);
|
alpar@1
|
508 |
#endif
|
alpar@1
|
509 |
return;
|
alpar@1
|
510 |
}
|
alpar@1
|
511 |
|
alpar@1
|
512 |
/***********************************************************************
|
alpar@1
|
513 |
* NAME
|
alpar@1
|
514 |
*
|
alpar@1
|
515 |
* lpf_btran - perform backward transformation (solve system B'*x = b)
|
alpar@1
|
516 |
*
|
alpar@1
|
517 |
* SYNOPSIS
|
alpar@1
|
518 |
*
|
alpar@1
|
519 |
* #include "glplpf.h"
|
alpar@1
|
520 |
* void lpf_btran(LPF *lpf, double x[]);
|
alpar@1
|
521 |
*
|
alpar@1
|
522 |
* DESCRIPTION
|
alpar@1
|
523 |
*
|
alpar@1
|
524 |
* The routine lpf_btran performs backward transformation, i.e. solves
|
alpar@1
|
525 |
* the system B'*x = b, where B' is a matrix transposed to the basis
|
alpar@1
|
526 |
* matrix B, x is the vector of unknowns to be computed, b is the vector
|
alpar@1
|
527 |
* of right-hand sides.
|
alpar@1
|
528 |
*
|
alpar@1
|
529 |
* On entry elements of the vector b should be stored in dense format
|
alpar@1
|
530 |
* in locations x[1], ..., x[m], where m is the number of rows. On exit
|
alpar@1
|
531 |
* the routine stores elements of the vector x in the same locations.
|
alpar@1
|
532 |
*
|
alpar@1
|
533 |
* BACKGROUND
|
alpar@1
|
534 |
*
|
alpar@1
|
535 |
* Solution of the system B' * x = b, where B' is a matrix transposed
|
alpar@1
|
536 |
* to B, can be obtained by solving the following augmented system:
|
alpar@1
|
537 |
*
|
alpar@1
|
538 |
* ( B F^)T ( x ) ( b )
|
alpar@1
|
539 |
* ( ) ( ) = ( )
|
alpar@1
|
540 |
* ( G^ H^) ( y ) ( 0 )
|
alpar@1
|
541 |
*
|
alpar@1
|
542 |
* which, using the main equality, can be written as follows:
|
alpar@1
|
543 |
*
|
alpar@1
|
544 |
* T ( U0 R )T ( L0 0 )T T ( x ) ( b )
|
alpar@1
|
545 |
* Q ( ) ( ) P ( ) = ( )
|
alpar@1
|
546 |
* ( 0 C ) ( S I ) ( y ) ( 0 )
|
alpar@1
|
547 |
*
|
alpar@1
|
548 |
* or, equivalently, as follows:
|
alpar@1
|
549 |
*
|
alpar@1
|
550 |
* ( U'0 0 ) ( L'0 S') ( x ) ( b )
|
alpar@1
|
551 |
* Q' ( ) ( ) P' ( ) = ( )
|
alpar@1
|
552 |
* ( R' C') ( 0 I ) ( y ) ( 0 )
|
alpar@1
|
553 |
*
|
alpar@1
|
554 |
* therefore,
|
alpar@1
|
555 |
*
|
alpar@1
|
556 |
* ( x ) ( L'0 S')-1 ( U'0 0 )-1 ( b )
|
alpar@1
|
557 |
* ( ) = P ( ) ( ) Q ( )
|
alpar@1
|
558 |
* ( y ) ( 0 I ) ( R' C') ( 0 )
|
alpar@1
|
559 |
*
|
alpar@1
|
560 |
* Thus, computing the solution includes the following steps:
|
alpar@1
|
561 |
*
|
alpar@1
|
562 |
* 1. Compute
|
alpar@1
|
563 |
*
|
alpar@1
|
564 |
* ( f ) ( b )
|
alpar@1
|
565 |
* ( ) = Q ( )
|
alpar@1
|
566 |
* ( g ) ( 0 )
|
alpar@1
|
567 |
*
|
alpar@1
|
568 |
* 2. Solve the system
|
alpar@1
|
569 |
*
|
alpar@1
|
570 |
* ( f1 ) ( U'0 0 )-1 ( f ) ( U'0 0 ) ( f1 ) ( f )
|
alpar@1
|
571 |
* ( ) = ( ) ( ) => ( ) ( ) = ( )
|
alpar@1
|
572 |
* ( g1 ) ( R' C') ( g ) ( R' C') ( g1 ) ( g )
|
alpar@1
|
573 |
*
|
alpar@1
|
574 |
* from which it follows that:
|
alpar@1
|
575 |
*
|
alpar@1
|
576 |
* { U'0 * f1 = f f1 = inv(U'0) * f
|
alpar@1
|
577 |
* { =>
|
alpar@1
|
578 |
* { R' * f1 + C' * g1 = g g1 = inv(C') * (g - R' * f1)
|
alpar@1
|
579 |
*
|
alpar@1
|
580 |
* 3. Solve the system
|
alpar@1
|
581 |
*
|
alpar@1
|
582 |
* ( f2 ) ( L'0 S')-1 ( f1 ) ( L'0 S') ( f2 ) ( f1 )
|
alpar@1
|
583 |
* ( ) = ( ) ( ) => ( ) ( ) = ( )
|
alpar@1
|
584 |
* ( g2 ) ( 0 I ) ( g1 ) ( 0 I ) ( g2 ) ( g1 )
|
alpar@1
|
585 |
*
|
alpar@1
|
586 |
* from which it follows that:
|
alpar@1
|
587 |
*
|
alpar@1
|
588 |
* { L'0 * f2 + S' * g2 = f1
|
alpar@1
|
589 |
* { => f2 = inv(L'0) * ( f1 - S' * g2)
|
alpar@1
|
590 |
* { g2 = g1
|
alpar@1
|
591 |
*
|
alpar@1
|
592 |
* 4. Compute
|
alpar@1
|
593 |
*
|
alpar@1
|
594 |
* ( x ) ( f2 )
|
alpar@1
|
595 |
* ( ) = P ( )
|
alpar@1
|
596 |
* ( y ) ( g2 ) */
|
alpar@1
|
597 |
|
alpar@1
|
598 |
void lpf_btran(LPF *lpf, double x[])
|
alpar@1
|
599 |
{ int m0 = lpf->m0;
|
alpar@1
|
600 |
int m = lpf->m;
|
alpar@1
|
601 |
int n = lpf->n;
|
alpar@1
|
602 |
int *P_row = lpf->P_row;
|
alpar@1
|
603 |
int *Q_row = lpf->Q_row;
|
alpar@1
|
604 |
double *fg = lpf->work1;
|
alpar@1
|
605 |
double *f = fg;
|
alpar@1
|
606 |
double *g = fg + m0;
|
alpar@1
|
607 |
int i, ii;
|
alpar@1
|
608 |
#if _GLPLPF_DEBUG
|
alpar@1
|
609 |
double *b;
|
alpar@1
|
610 |
#endif
|
alpar@1
|
611 |
if (!lpf->valid)
|
alpar@1
|
612 |
xfault("lpf_btran: the factorization is not valid\n");
|
alpar@1
|
613 |
xassert(0 <= m && m <= m0 + n);
|
alpar@1
|
614 |
#if _GLPLPF_DEBUG
|
alpar@1
|
615 |
/* save the right-hand side vector */
|
alpar@1
|
616 |
b = xcalloc(1+m, sizeof(double));
|
alpar@1
|
617 |
for (i = 1; i <= m; i++) b[i] = x[i];
|
alpar@1
|
618 |
#endif
|
alpar@1
|
619 |
/* (f g) := Q * (b 0) */
|
alpar@1
|
620 |
for (i = 1; i <= m0 + n; i++)
|
alpar@1
|
621 |
fg[i] = ((ii = Q_row[i]) <= m ? x[ii] : 0.0);
|
alpar@1
|
622 |
/* f1 := inv(U'0) * f */
|
alpar@1
|
623 |
luf_v_solve(lpf->luf, 1, f);
|
alpar@1
|
624 |
/* g1 := inv(C') * (g - R' * f1) */
|
alpar@1
|
625 |
rt_prod(lpf, g, -1.0, f);
|
alpar@1
|
626 |
scf_solve_it(lpf->scf, 1, g);
|
alpar@1
|
627 |
/* g2 := g1 */
|
alpar@1
|
628 |
g = g;
|
alpar@1
|
629 |
/* f2 := inv(L'0) * (f1 - S' * g2) */
|
alpar@1
|
630 |
st_prod(lpf, f, -1.0, g);
|
alpar@1
|
631 |
luf_f_solve(lpf->luf, 1, f);
|
alpar@1
|
632 |
/* (x y) := P * (f2 g2) */
|
alpar@1
|
633 |
for (i = 1; i <= m; i++)
|
alpar@1
|
634 |
x[i] = fg[P_row[i]];
|
alpar@1
|
635 |
#if _GLPLPF_DEBUG
|
alpar@1
|
636 |
/* check relative error in solution */
|
alpar@1
|
637 |
check_error(lpf, 1, x, b);
|
alpar@1
|
638 |
xfree(b);
|
alpar@1
|
639 |
#endif
|
alpar@1
|
640 |
return;
|
alpar@1
|
641 |
}
|
alpar@1
|
642 |
|
alpar@1
|
643 |
/***********************************************************************
|
alpar@1
|
644 |
* The routine enlarge_sva enlarges the Sparse Vector Area to new_size
|
alpar@1
|
645 |
* locations by reallocating the arrays v_ind and v_val. */
|
alpar@1
|
646 |
|
alpar@1
|
647 |
static void enlarge_sva(LPF *lpf, int new_size)
|
alpar@1
|
648 |
{ int v_size = lpf->v_size;
|
alpar@1
|
649 |
int used = lpf->v_ptr - 1;
|
alpar@1
|
650 |
int *v_ind = lpf->v_ind;
|
alpar@1
|
651 |
double *v_val = lpf->v_val;
|
alpar@1
|
652 |
xassert(v_size < new_size);
|
alpar@1
|
653 |
while (v_size < new_size) v_size += v_size;
|
alpar@1
|
654 |
lpf->v_size = v_size;
|
alpar@1
|
655 |
lpf->v_ind = xcalloc(1+v_size, sizeof(int));
|
alpar@1
|
656 |
lpf->v_val = xcalloc(1+v_size, sizeof(double));
|
alpar@1
|
657 |
xassert(used >= 0);
|
alpar@1
|
658 |
memcpy(&lpf->v_ind[1], &v_ind[1], used * sizeof(int));
|
alpar@1
|
659 |
memcpy(&lpf->v_val[1], &v_val[1], used * sizeof(double));
|
alpar@1
|
660 |
xfree(v_ind);
|
alpar@1
|
661 |
xfree(v_val);
|
alpar@1
|
662 |
return;
|
alpar@1
|
663 |
}
|
alpar@1
|
664 |
|
alpar@1
|
665 |
/***********************************************************************
|
alpar@1
|
666 |
* NAME
|
alpar@1
|
667 |
*
|
alpar@1
|
668 |
* lpf_update_it - update LP basis factorization
|
alpar@1
|
669 |
*
|
alpar@1
|
670 |
* SYNOPSIS
|
alpar@1
|
671 |
*
|
alpar@1
|
672 |
* #include "glplpf.h"
|
alpar@1
|
673 |
* int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
|
alpar@1
|
674 |
* const double val[]);
|
alpar@1
|
675 |
*
|
alpar@1
|
676 |
* DESCRIPTION
|
alpar@1
|
677 |
*
|
alpar@1
|
678 |
* The routine lpf_update_it updates the factorization of the basis
|
alpar@1
|
679 |
* matrix B after replacing its j-th column by a new vector.
|
alpar@1
|
680 |
*
|
alpar@1
|
681 |
* The parameter j specifies the number of column of B, which has been
|
alpar@1
|
682 |
* replaced, 1 <= j <= m, where m is the order of B.
|
alpar@1
|
683 |
*
|
alpar@1
|
684 |
* The parameter bh specifies the basis header entry for the new column
|
alpar@1
|
685 |
* of B, which is the number of the new column in some original matrix.
|
alpar@1
|
686 |
* This parameter is optional and can be specified as 0.
|
alpar@1
|
687 |
*
|
alpar@1
|
688 |
* Row indices and numerical values of non-zero elements of the new
|
alpar@1
|
689 |
* column of B should be placed in locations ind[1], ..., ind[len] and
|
alpar@1
|
690 |
* val[1], ..., val[len], resp., where len is the number of non-zeros
|
alpar@1
|
691 |
* in the column. Neither zero nor duplicate elements are allowed.
|
alpar@1
|
692 |
*
|
alpar@1
|
693 |
* RETURNS
|
alpar@1
|
694 |
*
|
alpar@1
|
695 |
* 0 The factorization has been successfully updated.
|
alpar@1
|
696 |
*
|
alpar@1
|
697 |
* LPF_ESING
|
alpar@1
|
698 |
* New basis B is singular within the working precision.
|
alpar@1
|
699 |
*
|
alpar@1
|
700 |
* LPF_ELIMIT
|
alpar@1
|
701 |
* Maximal number of additional rows and columns has been reached.
|
alpar@1
|
702 |
*
|
alpar@1
|
703 |
* BACKGROUND
|
alpar@1
|
704 |
*
|
alpar@1
|
705 |
* Let j-th column of the current basis matrix B have to be replaced by
|
alpar@1
|
706 |
* a new column a. This replacement is equivalent to removing the old
|
alpar@1
|
707 |
* j-th column by fixing it at zero and introducing the new column as
|
alpar@1
|
708 |
* follows:
|
alpar@1
|
709 |
*
|
alpar@1
|
710 |
* ( B F^| a )
|
alpar@1
|
711 |
* ( B F^) ( | )
|
alpar@1
|
712 |
* ( ) ---> ( G^ H^| 0 )
|
alpar@1
|
713 |
* ( G^ H^) (-------+---)
|
alpar@1
|
714 |
* ( e'j 0 | 0 )
|
alpar@1
|
715 |
*
|
alpar@1
|
716 |
* where ej is a unit vector with 1 in j-th position which used to fix
|
alpar@1
|
717 |
* the old j-th column of B (at zero). Then using the main equality we
|
alpar@1
|
718 |
* have:
|
alpar@1
|
719 |
*
|
alpar@1
|
720 |
* ( B F^| a ) ( B0 F | f )
|
alpar@1
|
721 |
* ( | ) ( P 0 ) ( | ) ( Q 0 )
|
alpar@1
|
722 |
* ( G^ H^| 0 ) = ( ) ( G H | g ) ( ) =
|
alpar@1
|
723 |
* (-------+---) ( 0 1 ) (-------+---) ( 0 1 )
|
alpar@1
|
724 |
* ( e'j 0 | 0 ) ( v' w'| 0 )
|
alpar@1
|
725 |
*
|
alpar@1
|
726 |
* [ ( B0 F )| ( f ) ] [ ( B0 F ) | ( f ) ]
|
alpar@1
|
727 |
* [ P ( )| P ( ) ] ( Q 0 ) [ P ( ) Q| P ( ) ]
|
alpar@1
|
728 |
* = [ ( G H )| ( g ) ] ( ) = [ ( G H ) | ( g ) ]
|
alpar@1
|
729 |
* [------------+-------- ] ( 0 1 ) [-------------+---------]
|
alpar@1
|
730 |
* [ ( v' w')| 0 ] [ ( v' w') Q| 0 ]
|
alpar@1
|
731 |
*
|
alpar@1
|
732 |
* where:
|
alpar@1
|
733 |
*
|
alpar@1
|
734 |
* ( a ) ( f ) ( f ) ( a )
|
alpar@1
|
735 |
* ( ) = P ( ) => ( ) = P' * ( )
|
alpar@1
|
736 |
* ( 0 ) ( g ) ( g ) ( 0 )
|
alpar@1
|
737 |
*
|
alpar@1
|
738 |
* ( ej ) ( v ) ( v ) ( ej )
|
alpar@1
|
739 |
* ( e'j 0 ) = ( v' w' ) Q => ( ) = Q' ( ) => ( ) = Q ( )
|
alpar@1
|
740 |
* ( 0 ) ( w ) ( w ) ( 0 )
|
alpar@1
|
741 |
*
|
alpar@1
|
742 |
* On the other hand:
|
alpar@1
|
743 |
*
|
alpar@1
|
744 |
* ( B0| F f )
|
alpar@1
|
745 |
* ( P 0 ) (---+------) ( Q 0 ) ( B0 new F )
|
alpar@1
|
746 |
* ( ) ( G | H g ) ( ) = new P ( ) new Q
|
alpar@1
|
747 |
* ( 0 1 ) ( | ) ( 0 1 ) ( new G new H )
|
alpar@1
|
748 |
* ( v'| w' 0 )
|
alpar@1
|
749 |
*
|
alpar@1
|
750 |
* where:
|
alpar@1
|
751 |
* ( G ) ( H g )
|
alpar@1
|
752 |
* new F = ( F f ), new G = ( ), new H = ( ),
|
alpar@1
|
753 |
* ( v') ( w' 0 )
|
alpar@1
|
754 |
*
|
alpar@1
|
755 |
* ( P 0 ) ( Q 0 )
|
alpar@1
|
756 |
* new P = ( ) , new Q = ( ) .
|
alpar@1
|
757 |
* ( 0 1 ) ( 0 1 )
|
alpar@1
|
758 |
*
|
alpar@1
|
759 |
* The factorization structure for the new augmented matrix remains the
|
alpar@1
|
760 |
* same, therefore:
|
alpar@1
|
761 |
*
|
alpar@1
|
762 |
* ( B0 new F ) ( L0 0 ) ( U0 new R )
|
alpar@1
|
763 |
* new P ( ) new Q = ( ) ( )
|
alpar@1
|
764 |
* ( new G new H ) ( new S I ) ( 0 new C )
|
alpar@1
|
765 |
*
|
alpar@1
|
766 |
* where:
|
alpar@1
|
767 |
*
|
alpar@1
|
768 |
* new F = L0 * new R =>
|
alpar@1
|
769 |
*
|
alpar@1
|
770 |
* new R = inv(L0) * new F = inv(L0) * (F f) = ( R inv(L0)*f )
|
alpar@1
|
771 |
*
|
alpar@1
|
772 |
* new G = new S * U0 =>
|
alpar@1
|
773 |
*
|
alpar@1
|
774 |
* ( G ) ( S )
|
alpar@1
|
775 |
* new S = new G * inv(U0) = ( ) * inv(U0) = ( )
|
alpar@1
|
776 |
* ( v') ( v'*inv(U0) )
|
alpar@1
|
777 |
*
|
alpar@1
|
778 |
* new H = new S * new R + new C =>
|
alpar@1
|
779 |
*
|
alpar@1
|
780 |
* new C = new H - new S * new R =
|
alpar@1
|
781 |
*
|
alpar@1
|
782 |
* ( H g ) ( S )
|
alpar@1
|
783 |
* = ( ) - ( ) * ( R inv(L0)*f ) =
|
alpar@1
|
784 |
* ( w' 0 ) ( v'*inv(U0) )
|
alpar@1
|
785 |
*
|
alpar@1
|
786 |
* ( H - S*R g - S*inv(L0)*f ) ( C x )
|
alpar@1
|
787 |
* = ( ) = ( )
|
alpar@1
|
788 |
* ( w'- v'*inv(U0)*R -v'*inv(U0)*inv(L0)*f) ( y' z )
|
alpar@1
|
789 |
*
|
alpar@1
|
790 |
* Note that new C is resulted by expanding old C with new column x,
|
alpar@1
|
791 |
* row y', and diagonal element z, where:
|
alpar@1
|
792 |
*
|
alpar@1
|
793 |
* x = g - S * inv(L0) * f = g - S * (new column of R)
|
alpar@1
|
794 |
*
|
alpar@1
|
795 |
* y = w - R'* inv(U'0)* v = w - R'* (new row of S)
|
alpar@1
|
796 |
*
|
alpar@1
|
797 |
* z = - (new row of S) * (new column of R)
|
alpar@1
|
798 |
*
|
alpar@1
|
799 |
* Finally, to replace old B by new B we have to permute j-th and last
|
alpar@1
|
800 |
* (just added) columns of the matrix
|
alpar@1
|
801 |
*
|
alpar@1
|
802 |
* ( B F^| a )
|
alpar@1
|
803 |
* ( | )
|
alpar@1
|
804 |
* ( G^ H^| 0 )
|
alpar@1
|
805 |
* (-------+---)
|
alpar@1
|
806 |
* ( e'j 0 | 0 )
|
alpar@1
|
807 |
*
|
alpar@1
|
808 |
* and to keep the main equality do the same for matrix Q. */
|
alpar@1
|
809 |
|
alpar@1
|
810 |
int lpf_update_it(LPF *lpf, int j, int bh, int len, const int ind[],
|
alpar@1
|
811 |
const double val[])
|
alpar@1
|
812 |
{ int m0 = lpf->m0;
|
alpar@1
|
813 |
int m = lpf->m;
|
alpar@1
|
814 |
#if _GLPLPF_DEBUG
|
alpar@1
|
815 |
double *B = lpf->B;
|
alpar@1
|
816 |
#endif
|
alpar@1
|
817 |
int n = lpf->n;
|
alpar@1
|
818 |
int *R_ptr = lpf->R_ptr;
|
alpar@1
|
819 |
int *R_len = lpf->R_len;
|
alpar@1
|
820 |
int *S_ptr = lpf->S_ptr;
|
alpar@1
|
821 |
int *S_len = lpf->S_len;
|
alpar@1
|
822 |
int *P_row = lpf->P_row;
|
alpar@1
|
823 |
int *P_col = lpf->P_col;
|
alpar@1
|
824 |
int *Q_row = lpf->Q_row;
|
alpar@1
|
825 |
int *Q_col = lpf->Q_col;
|
alpar@1
|
826 |
int v_ptr = lpf->v_ptr;
|
alpar@1
|
827 |
int *v_ind = lpf->v_ind;
|
alpar@1
|
828 |
double *v_val = lpf->v_val;
|
alpar@1
|
829 |
double *a = lpf->work2; /* new column */
|
alpar@1
|
830 |
double *fg = lpf->work1, *f = fg, *g = fg + m0;
|
alpar@1
|
831 |
double *vw = lpf->work2, *v = vw, *w = vw + m0;
|
alpar@1
|
832 |
double *x = g, *y = w, z;
|
alpar@1
|
833 |
int i, ii, k, ret;
|
alpar@1
|
834 |
xassert(bh == bh);
|
alpar@1
|
835 |
if (!lpf->valid)
|
alpar@1
|
836 |
xfault("lpf_update_it: the factorization is not valid\n");
|
alpar@1
|
837 |
if (!(1 <= j && j <= m))
|
alpar@1
|
838 |
xfault("lpf_update_it: j = %d; column number out of range\n",
|
alpar@1
|
839 |
j);
|
alpar@1
|
840 |
xassert(0 <= m && m <= m0 + n);
|
alpar@1
|
841 |
/* check if the basis factorization can be expanded */
|
alpar@1
|
842 |
if (n == lpf->n_max)
|
alpar@1
|
843 |
{ lpf->valid = 0;
|
alpar@1
|
844 |
ret = LPF_ELIMIT;
|
alpar@1
|
845 |
goto done;
|
alpar@1
|
846 |
}
|
alpar@1
|
847 |
/* convert new j-th column of B to dense format */
|
alpar@1
|
848 |
for (i = 1; i <= m; i++)
|
alpar@1
|
849 |
a[i] = 0.0;
|
alpar@1
|
850 |
for (k = 1; k <= len; k++)
|
alpar@1
|
851 |
{ i = ind[k];
|
alpar@1
|
852 |
if (!(1 <= i && i <= m))
|
alpar@1
|
853 |
xfault("lpf_update_it: ind[%d] = %d; row number out of rang"
|
alpar@1
|
854 |
"e\n", k, i);
|
alpar@1
|
855 |
if (a[i] != 0.0)
|
alpar@1
|
856 |
xfault("lpf_update_it: ind[%d] = %d; duplicate row index no"
|
alpar@1
|
857 |
"t allowed\n", k, i);
|
alpar@1
|
858 |
if (val[k] == 0.0)
|
alpar@1
|
859 |
xfault("lpf_update_it: val[%d] = %g; zero element not allow"
|
alpar@1
|
860 |
"ed\n", k, val[k]);
|
alpar@1
|
861 |
a[i] = val[k];
|
alpar@1
|
862 |
}
|
alpar@1
|
863 |
#if _GLPLPF_DEBUG
|
alpar@1
|
864 |
/* change column in the basis matrix for debugging */
|
alpar@1
|
865 |
for (i = 1; i <= m; i++)
|
alpar@1
|
866 |
B[(i - 1) * m + j] = a[i];
|
alpar@1
|
867 |
#endif
|
alpar@1
|
868 |
/* (f g) := inv(P) * (a 0) */
|
alpar@1
|
869 |
for (i = 1; i <= m0+n; i++)
|
alpar@1
|
870 |
fg[i] = ((ii = P_col[i]) <= m ? a[ii] : 0.0);
|
alpar@1
|
871 |
/* (v w) := Q * (ej 0) */
|
alpar@1
|
872 |
for (i = 1; i <= m0+n; i++) vw[i] = 0.0;
|
alpar@1
|
873 |
vw[Q_col[j]] = 1.0;
|
alpar@1
|
874 |
/* f1 := inv(L0) * f (new column of R) */
|
alpar@1
|
875 |
luf_f_solve(lpf->luf, 0, f);
|
alpar@1
|
876 |
/* v1 := inv(U'0) * v (new row of S) */
|
alpar@1
|
877 |
luf_v_solve(lpf->luf, 1, v);
|
alpar@1
|
878 |
/* we need at most 2 * m0 available locations in the SVA to store
|
alpar@1
|
879 |
new column of matrix R and new row of matrix S */
|
alpar@1
|
880 |
if (lpf->v_size < v_ptr + m0 + m0)
|
alpar@1
|
881 |
{ enlarge_sva(lpf, v_ptr + m0 + m0);
|
alpar@1
|
882 |
v_ind = lpf->v_ind;
|
alpar@1
|
883 |
v_val = lpf->v_val;
|
alpar@1
|
884 |
}
|
alpar@1
|
885 |
/* store new column of R */
|
alpar@1
|
886 |
R_ptr[n+1] = v_ptr;
|
alpar@1
|
887 |
for (i = 1; i <= m0; i++)
|
alpar@1
|
888 |
{ if (f[i] != 0.0)
|
alpar@1
|
889 |
v_ind[v_ptr] = i, v_val[v_ptr] = f[i], v_ptr++;
|
alpar@1
|
890 |
}
|
alpar@1
|
891 |
R_len[n+1] = v_ptr - lpf->v_ptr;
|
alpar@1
|
892 |
lpf->v_ptr = v_ptr;
|
alpar@1
|
893 |
/* store new row of S */
|
alpar@1
|
894 |
S_ptr[n+1] = v_ptr;
|
alpar@1
|
895 |
for (i = 1; i <= m0; i++)
|
alpar@1
|
896 |
{ if (v[i] != 0.0)
|
alpar@1
|
897 |
v_ind[v_ptr] = i, v_val[v_ptr] = v[i], v_ptr++;
|
alpar@1
|
898 |
}
|
alpar@1
|
899 |
S_len[n+1] = v_ptr - lpf->v_ptr;
|
alpar@1
|
900 |
lpf->v_ptr = v_ptr;
|
alpar@1
|
901 |
/* x := g - S * f1 (new column of C) */
|
alpar@1
|
902 |
s_prod(lpf, x, -1.0, f);
|
alpar@1
|
903 |
/* y := w - R' * v1 (new row of C) */
|
alpar@1
|
904 |
rt_prod(lpf, y, -1.0, v);
|
alpar@1
|
905 |
/* z := - v1 * f1 (new diagonal element of C) */
|
alpar@1
|
906 |
z = 0.0;
|
alpar@1
|
907 |
for (i = 1; i <= m0; i++) z -= v[i] * f[i];
|
alpar@1
|
908 |
/* update factorization of new matrix C */
|
alpar@1
|
909 |
switch (scf_update_exp(lpf->scf, x, y, z))
|
alpar@1
|
910 |
{ case 0:
|
alpar@1
|
911 |
break;
|
alpar@1
|
912 |
case SCF_ESING:
|
alpar@1
|
913 |
lpf->valid = 0;
|
alpar@1
|
914 |
ret = LPF_ESING;
|
alpar@1
|
915 |
goto done;
|
alpar@1
|
916 |
case SCF_ELIMIT:
|
alpar@1
|
917 |
xassert(lpf != lpf);
|
alpar@1
|
918 |
default:
|
alpar@1
|
919 |
xassert(lpf != lpf);
|
alpar@1
|
920 |
}
|
alpar@1
|
921 |
/* expand matrix P */
|
alpar@1
|
922 |
P_row[m0+n+1] = P_col[m0+n+1] = m0+n+1;
|
alpar@1
|
923 |
/* expand matrix Q */
|
alpar@1
|
924 |
Q_row[m0+n+1] = Q_col[m0+n+1] = m0+n+1;
|
alpar@1
|
925 |
/* permute j-th and last (just added) column of matrix Q */
|
alpar@1
|
926 |
i = Q_col[j], ii = Q_col[m0+n+1];
|
alpar@1
|
927 |
Q_row[i] = m0+n+1, Q_col[m0+n+1] = i;
|
alpar@1
|
928 |
Q_row[ii] = j, Q_col[j] = ii;
|
alpar@1
|
929 |
/* increase the number of additional rows and columns */
|
alpar@1
|
930 |
lpf->n++;
|
alpar@1
|
931 |
xassert(lpf->n <= lpf->n_max);
|
alpar@1
|
932 |
/* the factorization has been successfully updated */
|
alpar@1
|
933 |
ret = 0;
|
alpar@1
|
934 |
done: /* return to the calling program */
|
alpar@1
|
935 |
return ret;
|
alpar@1
|
936 |
}
|
alpar@1
|
937 |
|
alpar@1
|
938 |
/***********************************************************************
|
alpar@1
|
939 |
* NAME
|
alpar@1
|
940 |
*
|
alpar@1
|
941 |
* lpf_delete_it - delete LP basis factorization
|
alpar@1
|
942 |
*
|
alpar@1
|
943 |
* SYNOPSIS
|
alpar@1
|
944 |
*
|
alpar@1
|
945 |
* #include "glplpf.h"
|
alpar@1
|
946 |
* void lpf_delete_it(LPF *lpf)
|
alpar@1
|
947 |
*
|
alpar@1
|
948 |
* DESCRIPTION
|
alpar@1
|
949 |
*
|
alpar@1
|
950 |
* The routine lpf_delete_it deletes LP basis factorization specified
|
alpar@1
|
951 |
* by the parameter lpf and frees all memory allocated to this program
|
alpar@1
|
952 |
* object. */
|
alpar@1
|
953 |
|
alpar@1
|
954 |
void lpf_delete_it(LPF *lpf)
|
alpar@1
|
955 |
{ luf_delete_it(lpf->luf);
|
alpar@1
|
956 |
#if _GLPLPF_DEBUG
|
alpar@1
|
957 |
if (lpf->B != NULL) xfree(lpf->B);
|
alpar@1
|
958 |
#else
|
alpar@1
|
959 |
xassert(lpf->B == NULL);
|
alpar@1
|
960 |
#endif
|
alpar@1
|
961 |
if (lpf->R_ptr != NULL) xfree(lpf->R_ptr);
|
alpar@1
|
962 |
if (lpf->R_len != NULL) xfree(lpf->R_len);
|
alpar@1
|
963 |
if (lpf->S_ptr != NULL) xfree(lpf->S_ptr);
|
alpar@1
|
964 |
if (lpf->S_len != NULL) xfree(lpf->S_len);
|
alpar@1
|
965 |
if (lpf->scf != NULL) scf_delete_it(lpf->scf);
|
alpar@1
|
966 |
if (lpf->P_row != NULL) xfree(lpf->P_row);
|
alpar@1
|
967 |
if (lpf->P_col != NULL) xfree(lpf->P_col);
|
alpar@1
|
968 |
if (lpf->Q_row != NULL) xfree(lpf->Q_row);
|
alpar@1
|
969 |
if (lpf->Q_col != NULL) xfree(lpf->Q_col);
|
alpar@1
|
970 |
if (lpf->v_ind != NULL) xfree(lpf->v_ind);
|
alpar@1
|
971 |
if (lpf->v_val != NULL) xfree(lpf->v_val);
|
alpar@1
|
972 |
if (lpf->work1 != NULL) xfree(lpf->work1);
|
alpar@1
|
973 |
if (lpf->work2 != NULL) xfree(lpf->work2);
|
alpar@1
|
974 |
xfree(lpf);
|
alpar@1
|
975 |
return;
|
alpar@1
|
976 |
}
|
alpar@1
|
977 |
|
alpar@1
|
978 |
/* eof */
|